Add the ability to launch and manage a persistent goose orchestrator
directly from the goosetown-ui server via the Agent Client Protocol (ACP).
Previously, running a goosetown session required manually starting a
goose process in a separate terminal with the right wall/telepathy files,
then pointing the UI at it with --session and --wall flags. This was
fragile and required coordinating multiple terminals.
Now the server can spawn a goose orchestrator as a persistent ACP
subprocess, creating the wall file, tracking the session, and wiring
up SSE events automatically. The UI (or curl) just POSTs a prompt to
/api/launch and everything connects.
Key additions:
- AcpClient: async JSON-RPC 2.0 client over stdio for goose acp
- /api/launch: spawn orchestrator, create wall, track session
- /api/launch/status: check if orchestrator is running/exited
- /api/launch/stop: gracefully terminate the orchestrator
- /api/prompt: send follow-up messages to running orchestrator
- find_children: now discovers ACP-launched sub_agent sessions
- wall_watcher: tracks config changes when launch creates new wall
- positions_watcher: emits wall_read events from .positions/ dir
- wall_post: auto-nudges ACP orchestrator when human posts
- CLI: clean-start mode (no --session/--wall required)
- CSP: allow unsafe-inline for importmap script tags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Adds the ability to launch and manage a persistent goose orchestrator directly from the goosetown-ui server via the Agent Client Protocol (ACP).
Why ACP?
Previously, running a goosetown session required:
--walland--sessionflags--sessionand--wallto point at the running processThis was fragile and required multiple terminals just to see goose in action. With ACP, the server can spawn a goose orchestrator as a persistent subprocess over stdio JSON-RPC — creating the wall file, tracking the session ID, and wiring up SSE events automatically. A single
curlor UI button press starts everything.What's added
AcpClient(~130 lines): Async JSON-RPC 2.0 client over stdio forgoose acp. Handles initialize handshake, session creation, prompt streaming, and graceful shutdown./api/launch: Spawn an orchestrator with a prompt. Creates a fresh wall file, tracks the session, returns PID + session ID./api/launch/status: Check if orchestrator is running, exited, or idle./api/launch/stop: Gracefully terminate the running orchestrator./api/prompt: Send follow-up messages to a running orchestrator.find_children: Now discoverssub_agentsessions launched via ACP (not justgoose runstyle "Task X started in background").wall_watcher: Tracks config changes when launch creates a new wall file. Useswall_generationto discard stale reads during transitions.positions_watcher: Emitswall_readevents from.positions/directory for goose read-position tracking.--session/--wall— just launch and use/api/launch.unsafe-inlineinscript-srcfor importmap support (needed by the upcoming 3D town view).Part of a split
This is part of splitting PR #3 into smaller reviewable pieces:
ui/town/)How to test locally
1. Start the server (clean mode — no args needed):
./scripts/goosetown-ui # Should print: 🧹 Starting clean — use Launch Orchestrator to begin2. Launch an orchestrator via curl:
Expected: JSON with
ok,pid,wall_file,session_id3. Check status:
curl -s localhost:4242/api/launch/status | python3 -m json.toolExpected:
"status": "running"with PID and elapsed time4. Send a follow-up prompt:
5. Verify SSE events are flowing:
curl -s localhost:4242/events | head -20Expected:
bootstrapevent with session tree data, thenwallevents as messages appear6. Open the existing 2D dashboard:
Expected: Dashboard shows the ACP-launched orchestrator and its delegates
7. Stop the orchestrator:
8. Verify it exited cleanly:
curl -s localhost:4242/api/launch/status | python3 -m json.toolExpected:
"status": "exited"with exit code9. Test with existing wall (backwards compat):
Expected: Works exactly as before — explicit args still honored
Test plan checklist
./scripts/goosetown-uiwith no args) prints clean-start message/api/launchreturns success with pid, session_id, wall_file/api/launch/statusshowsrunningwhile orchestrator is alive/api/promptsends follow-up to running orchestrator/api/launch/stopterminates orchestrator gracefully/api/launch/statusshowsexitedafter stop--sessionand--wallflags still work🤖 Generated with Claude Code