diff --git a/README.md b/README.md index 4c7addd..6a94f13 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/config.py b/config.py index d7a219e..818d815 100644 --- a/config.py +++ b/config.py @@ -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=(