Files
Bellhop/SESSION_PLAN.md
prosolis 5a706fedc4 Begin Go rewrite: remove Python, scaffold module and config
Pivot from FastAPI web portal to a Matrix command bot (modeled on Pete).
Users will issue !movie / !tv / !music commands in allowlisted rooms; the
bot performs a top-hit search against Radarr/Sonarr/Lidarr and adds it.

This commit is session 1 of a multi-session rewrite (see SESSION_PLAN.md):
  - Delete app/, requirements.txt, old Dockerfile, .env.example
  - Add go.mod (mautrix-go + yaml.v3)
  - Add internal/config: YAML loader with ${ENV} expansion, validates
    matrix creds, allowed_rooms, and per-service *arr config
  - Reset .gitignore / .dockerignore for the Go layout
2026-05-24 20:09:52 -07:00

58 lines
2.8 KiB
Markdown

# Bellhop Go Rewrite — Session Plan
Rewriting Bellhop from a Python FastAPI web portal into a Go-based Matrix command bot, modeled after [Pete](../pete). Users issue commands like `!movie dune` in allowlisted Matrix rooms; the bot performs the top-hit search against Radarr/Sonarr/Lidarr and adds the result.
## Design decisions (locked in)
- **Command UX:** top-hit auto-add (no numbered picker, no reaction selector).
- **Authz:** any member of an allowlisted room ID can issue commands. No per-user list.
- **Old Python code:** deleted, clean-slate Go rewrite.
- **Module layout:** mirrors Pete (`main.go` + `internal/<pkg>/`).
- **Config:** YAML with `${ENV_VAR}` expansion (Pete-style).
- **Matrix client:** mautrix-go with cryptohelper for E2EE support.
## Session breakdown
- [x] **Session 1 — Foundation**
- Delete Python (`app/`, `requirements.txt`, `Dockerfile`, `.env.example`)
- Reset `.gitignore` / `.dockerignore` for Go
- `go.mod` (mautrix + yaml)
- `internal/config/config.go` — YAML loader: matrix creds, `allowed_rooms`, `services.{radarr,sonarr,lidarr}`
- [ ] **Session 2 — Matrix client** (`internal/matrix/`)
- Adapt Pete's `client.go`: login + device persistence + cryptohelper
- Sync loop, auto-join on invite
- Message handler scoped to `allowed_rooms` (not channel-name map like Pete)
- Threaded reply helper for command responses
- Drop Pete-specific bits: image upload, reaction handler, story formatting
- [ ] **Session 3 — *arr clients** (`internal/arr/`)
- One file per service or a single generic client (TBD in session)
- `Search(term) → []Result` and `Add(result) → error`
- Radarr: `/api/v3/movie/lookup` + POST `/api/v3/movie`
- Sonarr: `/api/v3/series/lookup` + POST `/api/v3/series`
- Lidarr: `/api/v1/artist/lookup` + POST `/api/v1/artist`
- All adds: monitored=true, search-on-add=true, quality profile + root folder from config
- Unit tests with httptest
- [ ] **Session 4 — Command dispatch + main** (`internal/bot/`, `main.go`)
- Parse `<prefix><cmd> <query>` (default prefix `!`)
- Commands: `movie`, `tv`, `music`, `help`
- On match: search → take `[0]` → add → reply with title/year (or error)
- "Service not configured" reply if the corresponding *arr block is absent
- `main.go`: load config, init matrix, wire handler, SIGINT/SIGTERM shutdown
- [ ] **Session 5 — Ship polish**
- Multi-stage Dockerfile (`golang:1.25-alpine``alpine:3.21`, build with `-tags goolm`)
- `config.example.yaml`
- Rewrite `README.md`: command UX, install, config reference, Docker
- `go build ./...` + `go vet ./...` clean
## Out of scope (for now)
- Reaction-based result picker
- Per-user allowlist or power-level gating
- Persistent request audit log (the Matrix room itself is the audit trail since requests are in-channel)
- Removal/cancellation commands
- Search-only mode (browse without adding)