feat(config): run the claude agents headless

`transport="stream_json"` puts them on `claude -p` with piped stdin
instead of a pseudo-tty. The pi is the machine the PTY path hurt most:
seconds per spawn waiting for an Ink render loop to settle — which is
why `startup_delay` had crept to 60s — and the occasional prompt lost to
a swallowed paste. Neither failure mode has an analogue on a pipe.

`include_partial_messages` comes with it, so Anthropic-API clients get
token-level SSE rather than one delta per finished block.

Drops `--remote-control`: it only means anything for an interactive
session, and the transport would strip it anyway.
This commit is contained in:
hh
2026-07-28 03:01:06 +02:00
parent d44938367b
commit 967cc82ee6
2 changed files with 17 additions and 2 deletions
+4 -1
View File
@@ -123,4 +123,7 @@ docker compose restart gateway
## Gotchas
- **claude in the container doesn't see the vault** - `cwd=VAULT` in `config.py` resolves to `/vault` *inside* the container, not on the host. Don't change it.
- **gateway hangs on `JSONL file did not appear within 30s`** - claude's onboarding wasn't clicked through (see step 3). Re-enter interactively with `docker exec -it beaver-gateway ...`, click trust folder + bypass permissions, exit.
- **a claude turn fails immediately** - check `docker logs beaver-gateway` for the claude stderr it now quotes back. Usually auth: re-run step 3's `claude /login`.
- **the admin terminal viewer is read-only** - claude agents run headless (`transport="stream_json"` in `config.py`), so what the viewer shows is the JSON event stream, not a TUI you can type into. Flip that agent to `transport="pty"` if you genuinely need a keyboard on a live session.
The claude agents used to hang on `JSONL file did not appear within 30s` when the TUI's onboarding hadn't been clicked through. That path is gone with the headless transport — prompts go into a pipe, not a terminal.
+13 -1
View File
@@ -95,7 +95,19 @@ def claude(name: str, model: str, effort: str | None = None) -> ClaudeAgent:
cwd=VAULT,
options=ClaudeCodeOptions(
effort=effort,
extra_args=("--remote-control",),
# Headless `claude -p` instead of driving the TUI over a
# pseudo-tty. The pi is exactly the machine the PTY path hurt
# most: it spent seconds per spawn waiting for an Ink render
# loop to settle (hence startup_delay creeping to 60s) and
# occasionally lost a prompt to a swallowed paste. Piped
# stdin has neither problem, and gives us token streaming.
#
# Dropped with it: `--remote-control`, which only exists for
# interactive sessions, and the admin terminal's ability to
# type into a stuck session by hand — the failure mode that
# was for is what this transport removes.
transport="stream_json",
include_partial_messages=True,
disallowed_tools=("AskUserQuestion", "ExitPlanMode", "EnterPlanMode"),
),
expose_mcps=(