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

2.8 KiB

Bellhop Go Rewrite — Session Plan

Rewriting Bellhop from a Python FastAPI web portal into a Go-based Matrix command bot, modeled after 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

  • 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-alpinealpine: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)