Files
Bellhop/SESSION_PLAN.md
prosolis 5c7d21e574 Session 2: Matrix client with E2EE and room-scoped handler
Adapted from Pete: password login + device persistence, cryptohelper
with cross-signing bootstrap, sync loop with auto-join on invite, and
PostThreadedReply for command responses. Messages outside allowed_rooms
are dropped.
2026-05-24 20:16:09 -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)