Add headless "ask" mode: ?-prefixed message runs claude -p, answer posted back
A message starting with `?` in a mapped room runs `claude -p` one-shot in that repo on the Mac and posts the full answer back into the room — Matrix as a request/response interface, not just a trigger. Non-`?` messages keep launching interactive sessions as before. New scripts/ask-claude.sh is a login-shell wrapper (so ~/.zprofile puts claude on PATH) that exports CLAUDE_CODE_OAUTH_TOKEN from the Mac's .env and runs `claude -p "$prompt" < /dev/null`, printing the answer to stdout. The bot adds a `?`-dispatch with run_ask/ask: SSH stdout captured, 300s timeout, fail-loud, output chunked under Matrix's event cap (no truncation). Headless claude -p needs the long-lived token because a non-GUI SSH session can't reach the login Keychain (reports "Not logged in") — the deliberate Approach A that the interactive GUI-Terminal path (D11) avoided. Token is kept Mac-side only; the Spark never runs claude. Sovereignty unchanged: claude -p uses the subscription, no frontier API touches message payloads. Proven live on the Spark; fresh-eyes reviewed before commit.
This commit is contained in:
@@ -74,8 +74,12 @@ v1 decision surface.
|
||||
- `config.example.toml` — room→repo mapping template; the real `config.toml` is gitignored.
|
||||
- `scripts/gui-launch.sh` — opens the desktop Terminal via `osascript` (Approach B, D11); calls
|
||||
`launch-claude.sh` inside it. The bot invokes this over SSH.
|
||||
- `src/bot.py` — the matrix-nio bot (Phase 1): listens in mapped rooms; on a message runs
|
||||
`ssh mac-bridge gui-launch.sh`; fans out for all-projects; reports failures back to the room.
|
||||
- `scripts/ask-claude.sh` — headless `?`-ask wrapper (`#!/bin/zsh -l`): runs `claude -p` in the repo
|
||||
and prints the answer to stdout for the bot to capture and post back. Uses `CLAUDE_CODE_OAUTH_TOKEN`
|
||||
(Mac-side `.env`) because a non-GUI SSH session can't reach the login Keychain (D12).
|
||||
- `src/bot.py` — the matrix-nio bot (Phase 1): listens in mapped rooms; a plain message runs
|
||||
`ssh mac-bridge gui-launch.sh` (interactive, to the phone), a `?`-prefixed message runs
|
||||
`ask-claude.sh` (headless, answer posted back); fans out for all-projects; reports failures back.
|
||||
- `requirements.txt` (matrix-nio) · `.env.example` (credential schema; real `.env` gitignored).
|
||||
- `.claude/` — Claude wiring (dir only for now).
|
||||
- `Dockerfile` · `docker-compose.yml` · `docker-entrypoint.sh` · `.dockerignore` — the Phase 1
|
||||
@@ -125,6 +129,13 @@ Condensed from the scoping workshop. Each: the call, why, what it beat.
|
||||
and is fully unattended, but adds a credential to manage; kept as the documented fallback if the
|
||||
Mac is ever driven headless (logged out). *Cost:* requires the Mac logged in + a one-time
|
||||
Terminal Automation grant.
|
||||
- **D12 — Headless "ask" mode uses the long-lived token; interactive stays GUI-Terminal (2026-06-16).**
|
||||
A `?`-prefixed message runs `claude -p` headlessly over plain SSH and posts the answer back, so its
|
||||
stdout must be captured over the SSH pipe — which rules out the GUI-Terminal path (D11), and a
|
||||
non-GUI session reports "Not logged in." Ask mode therefore deliberately adopts the long-lived
|
||||
`claude setup-token` (`CLAUDE_CODE_OAUTH_TOKEN`) that D11 deferred — kept **Mac-side only** (in
|
||||
`.env`; the Spark never runs claude). Interactive launches keep the token-free GUI-Terminal path.
|
||||
*Sovereignty unchanged:* `claude -p` uses the subscription, no frontier API touches message payloads.
|
||||
|
||||
## Sovereignty constraint
|
||||
|
||||
@@ -223,9 +234,21 @@ once" is not done.
|
||||
(`modelo@10.59.211.6` — reachable over WireGuard but not authenticated; Phase 0 only set up the
|
||||
reverse, `mac-bridge`). So deploys/restarts on the Spark are run by the owner from the Spark, not
|
||||
driven from the Mac — until Phase 3 wires it behind Spark Control.
|
||||
- **Headless "ask" mode — SHIPPED + proven on the Spark (2026-06-16).** A `?`-prefixed message in a
|
||||
mapped room runs `claude -p` one-shot in that repo on the Mac and posts the **full** answer back
|
||||
into the room (Matrix as request/response, not just a trigger); non-`?` messages launch
|
||||
interactively as before. New `scripts/ask-claude.sh` (login-shell wrapper: extracts
|
||||
`CLAUDE_CODE_OAUTH_TOKEN` from the Mac's `.env`, runs `claude -p "$prompt" < /dev/null`); `bot.py`
|
||||
gained the `?`-dispatch + `run_ask`/`ask` (SSH stdout captured, 300s timeout, fail-loud, output
|
||||
chunked under Matrix's ~64KB cap). *Why a token (D12):* a non-GUI SSH session can't reach the login
|
||||
Keychain, so headless `claude -p` reports "Not logged in" — Approach A, kept Mac-side only (the
|
||||
Spark never runs claude). Fresh-eyes reviewed before commit; P1 nits fixed (reap killed ssh on
|
||||
timeout; treat rc=0 + empty output as success, not failure). *Proven:* a real `?`-ask in an
|
||||
already-trusted repo returned the answer into the room. *Open edge:* a `?`-ask in a repo `claude`
|
||||
has **never** been opened in may stall on the first-run folder-trust gate (Phase 0 caveat) — add a
|
||||
trust flag to the wrapper if/when hit, not preemptively.
|
||||
- **Next (open — discuss before building):** Phase 2 (multi-room routing) is effectively already
|
||||
satisfied — the bot was built multi-room (11 rooms + all-projects) and routed correctly across 2
|
||||
rooms in the Phase 1 proof; only a formal confirmation pass remains. Live candidates: **Phase 3**
|
||||
(Spark Control: bot status + one-click update/restart on the dashboard, the SSH-behind-buttons
|
||||
pattern — also closes the owner-run-ops gap above) or the **headless "ask" mode** from
|
||||
`ROADMAP.md` (a message runs `claude -p` and posts the answer back into the room).
|
||||
satisfied (built multi-room; routed correctly across rooms in the Phase 1 proof) — only a formal
|
||||
confirmation pass remains. Main remaining candidate: **Phase 3** (Spark Control: bot status +
|
||||
one-click update/restart on the dashboard, the SSH-behind-buttons pattern — also closes the
|
||||
owner-run-ops gap above). Other backlog in `ROADMAP.md`.
|
||||
|
||||
Reference in New Issue
Block a user