Files
Keysat 28c974fe1d Mark Phase 3 (Spark Control) done; trim spec to live command contract
Shipped in Spark Control v0.21.0: status badge + Update/Restart/Stop-Start/Logs
tile. All three exit criteria confirmed. matrix-bridge needed no code change.

- AGENTS.md: Current state + ROADMAP Phase 3 -> DONE; Deploy switched scp -> git
  pull (Update button); D10 stamped; new Infra fact for the Spark->Gitea path and
  the load-bearing IdentitiesOnly ssh-config pin the Update button depends on.
- spark-control-integration.md: trimmed from dev spec to live contract (dropped
  sudo -iu fallback and dev-side scaffolding; folded in direct-as-modelo, the
  Gitea key gotcha, restart cadence, and the LAN-only HTTP API).
- README: dropped stale "pre-Phase 0" status; Setup reframed for a fresh install.

Deferred follow-up: badge reflects container liveness only, not Matrix
connectivity; HEALTHCHECK + {{.State.Health.Status}} is the matrix-bridge-side fix.
2026-06-15 23:19:30 -05:00

5.0 KiB
Raw Permalink Blame History

ROADMAP — matrix-bridge

Phased build plan. Near-term status lives in AGENTS.md## Current state; this file is the longer arc. Substance threshold is N = 3 real uses per phase — exits are falsifiable (it worked 3 real times), never checkboxes.

Phase 0 (the current first milestone) lives in AGENTS.md ## Current state; it writes no bot code — foundation + proving the manual chain by hand. The phases below are what comes after it.


Phase 1 — Single-room bot

  • matrix-nio bot in a container on the Spark, logged in as a bot Matrix user.
  • One hardcoded room → one repo. Any message in it spawns a session via the Mac wrapper.
  • Carry over from Phase 0's proven launch chain (ssh mac-bridge → gui-launch.sh → launch-claude.sh):
    • Bake the SSH key + mac-bridge config into the container (modelo's ~/.ssh won't exist there).
    • Named sessions for the phone app. Pass claude -n "<repo> — <topic>" so the Remote Control conversation index is readable (project + topic). Bot derives <topic> from the message; confirm whether the app labels off -n or --remote-control <name>. Plumb a name arg through the wrappers.
    • Quote-safe message passing. Bot builds the SSH command with shlex.quote; gui-launch.sh already isolates the osascript/shell layers via a %q temp script — stress-test with hostile text.
    • Fail loud, not silent. Detect a stalled launch (untrusted-repo trust gate, or a reset Terminal Automation grant) and report it back into the room instead of hanging.
  • Exit (falsifiable): 3 consecutive real messages each correctly launch a drivable session on the phone.

Phase 2 — Multi-room routing — DONE (2026-06-15)

  • Room → repo mapping table; the bot routes by room_id (config over code).
  • Exit (falsifiable): 3 real uses across ≥2 rooms, correct repo every time, zero wrong-directory launches. Met — owner-confirmed N=3 pass.

Phase 3 — Spark Control integration — DONE (2026-06-16)

  • Bot container status surfaced on the Spark Control dashboard.
  • One-click update (pull + restart) wired the same way Spark Control drives the Sparks today (SSH/commands behind a button).
  • Exit (falsifiable): bot status is visible and the bot can be updated/restarted from the panel. Met — shipped in Spark Control v0.21.0; all three controls confirmed working.
  • Shipped: matrix-bridge tile (status badge + Update / Restart / Stop-Start / Logs) running the spec's SSH commands; the Spark's ~/matrix-bridge is now a Gitea clone tracking master. matrix-bridge needed no code change. Deviation: Spark Control connects directly as modelo (no sudo wrap — no passwordless sudo on this Spark). Live command contract + the Gitea key pin the Update button depends on: docs/spark-control-integration.md.
  • Deferred follow-up: badge reflects container liveness only, not Matrix connectivity — a Docker HEALTHCHECK (bot-side liveness signal) would let the tile read {{.State.Health.Status}}. matrix-bridge-side change; do it if/when "running but silent" bites.

Phase 4+ — Future direction (documented, not yet scoped to build)

  • Intent-routing brain (D8). Qwen3 via Spark Control as a smart dispatcher: given knowledge of all repos/contexts, parse a freeform message and decide which repo/context applies and what context to inject — not a task-vs-session classifier. MUST run on a local model. Depends on the deterministic core (Phases 12) working first; the architecture must not foreclose it.
  • Thread-based session continuity. A Matrix thread = a distinct session/sub-context within a repo. The first natural extension after multi-room routing.
  • Nextcloud / CalDAV output integration. Routing Claude/bot outputs into Nextcloud (Matrix ↔ Claude ↔ Nextcloud). Real interest, unscoped — not until Nextcloud Tasks/CalDAV is actually in use.
  • E2EE (D9). Add matrix-nio end-to-end encryption (libolm) if the bot ever handles sensitive content over untrusted transport. Low priority while everything is WireGuard-local.
  • Headless "ask" mode — SHIPPED 2026-06-16. A ?-prefixed message runs claude -p "<rest>" one-shot in the room's repo and posts the full answer back into the room — Matrix as a request/response interface, not just a trigger. Built via scripts/ask-claude.sh (login-shell wrapper) + the bot's ?-dispatch (run_ask/ask). Resolved design choices: selector = ? prefix (per-message; the room still picks the repo); output posted in full, chunked under Matrix's event cap (no truncation — chosen explicitly); auth = the long-lived claude setup-token (CLAUDE_CODE_OAUTH_TOKEN, Approach A / D12) because a non-GUI SSH session can't reach the Keychain; sovereignty unchanged (claude -p uses the subscription, no frontier API on payloads). Remaining open Qs: very-long-output handling beyond chunking (thread / attach file); the first-run folder-trust gate for a repo claude has never been opened in.