# Honker ACP Bridge — Implementation Plan ## Current State What's implemented today: - ✅ Initialize ACP connection to Goose (`goose acp` over stdio) - ✅ Create new sessions (one per Signal contact) - ✅ Send text prompts and collect text responses - ✅ Interactive permission requests over Signal (numbered options) - ✅ Signal-cli lifecycle management and socket communication --- ## Phase 1: Essential — Make the Bridge Robust ### 1.1 Terminal Execution (Client ← Agent) **Priority: HIGH — Goose cannot function without this** Goose's primary tool is running shell commands. The ACP protocol has the agent ask the *client* to execute commands via `create_terminal`, then polls output with `terminal_output` and `wait_for_terminal_exit`. Currently we return `None` for all terminal methods, which means Goose can't run any commands. We need to: - `create_terminal(command, args, cwd, env)` → spawn a real subprocess, return a `terminal_id` - `terminal_output(terminal_id)` → return accumulated stdout/stderr - `wait_for_terminal_exit(terminal_id)` → await process completion, return exit code - `release_terminal(terminal_id)` → clean up - `kill_terminal(terminal_id)` → kill the subprocess Implementation: a `TerminalManager` class that tracks running subprocesses keyed by terminal_id. ### 1.2 File System Operations (Client ← Agent) **Priority: HIGH — Goose cannot edit code without this** The agent asks the client to read/write files: - `read_text_file(path, line, limit)` → read from the local filesystem, return content - `write_text_file(path, content)` → write to the local filesystem Currently we return `None`, so Goose can't read or write files. These should be straightforward to implement against the local filesystem. We should also advertise these capabilities in `ClientCapabilities` during `initialize`: ```python ClientCapabilities( fs=FileSystemCapabilities(read_text_file=True, write_text_file=True), terminal=True, ) ``` ### 1.3 Cancellation **Priority: MEDIUM** Allow Signal users to cancel a running prompt. The user could send a special command (e.g. `/cancel`) while a prompt is in progress. We'd call `conn.cancel(session_id)` to tell Goose to stop. The `PromptResponse.stop_reason` already distinguishes `cancelled` from `end_turn`, `max_tokens`, `refusal`, and `max_turn_requests` — we should handle each appropriately in the reply. ### 1.4 Stop Reason Handling **Priority: MEDIUM** Currently we only look at the response text. We should handle all stop reasons: - `end_turn` — normal completion (current behavior) - `max_tokens` — context limit hit; notify user - `max_turn_requests` — agent hit its turn limit; notify user - `refusal` — agent refused the request; notify user - `cancelled` — user cancelled; acknowledge --- ## Phase 2: Enriched Feedback ### 2.1 Tool Call Notifications **Priority: MEDIUM** Forward tool activity as status messages so the Signal user knows what Goose is doing while working. On `ToolCallStart`, send a brief message like: "🔧 Running: `ls -la /src`" On `ToolCallProgress` with status updates, optionally send progress. We need to be careful not to spam — batch or throttle these. ### 2.2 Agent Thoughts **Priority: LOW-MEDIUM** `AgentThoughtChunk` contains the agent's chain-of-thought reasoning. Could forward these optionally (config flag) as italicized or prefixed messages. Useful for debugging but noisy for everyday use. ### 2.3 Plan Updates **Priority: LOW-MEDIUM** `AgentPlanUpdate` sends a structured plan with entries (content, priority, status). Could render as a checklist: ``` 📋 Plan: ✅ Read the project structure 🔄 Implement the new feature ⬚ Write tests ⬚ Update documentation ``` ### 2.4 Usage/Cost Updates **Priority: LOW** `UsageUpdate` reports token usage (size, used) and optional `Cost` (amount, currency). Could send periodic summaries or on-demand via a `/usage` command. --- ## Phase 3: Session Management ### 3.1 Session Persistence (Load/Resume) **Priority: MEDIUM** Goose supports `load_session` and `resume_session`. We could persist the session_id→contact mapping in SQLite (as the README mentions) and restore sessions across honker restarts. - `load_session(cwd, session_id)` — restore conversation history - `resume_session(cwd, session_id)` — resume an interrupted session - `list_sessions()` — list available sessions - `close_session(session_id)` — explicitly end a session User commands: `/sessions`, `/load `, `/new` (force new session) ### 3.2 Session Commands **Priority: MEDIUM** Signal user sends special commands (prefix with `/`): - `/new` — start a fresh session - `/sessions` — list previous sessions - `/load ` — resume a previous session - `/cancel` — cancel current prompt - `/mode ` — change session mode (via `set_session_mode`) - `/model ` — change model (via `set_session_model`) - `/usage` — show token usage / cost ### 3.3 Session Modes **Priority: LOW** Goose supports modes (e.g., "auto" vs "manual" approval). `set_session_mode` and `CurrentModeUpdate` notifications. Could expose via `/mode` command. ### 3.4 Session Configuration **Priority: LOW** `set_config_option` lets the client change boolean/select config options. `ConfigOptionUpdate` notifications report changes. Could expose via a `/config` command. --- ## Phase 4: Rich Content ### 4.1 Image Support (Input) **Priority: MEDIUM** Signal users can send images. signal-cli provides attachment data. ACP supports `ImageContentBlock` in prompts (with base64 `data` and `mime_type`). We could forward Signal image attachments to Goose as image content blocks. ### 4.2 Image Support (Output) **Priority: LOW** If Goose responds with `ImageContentBlock` in agent messages, we could send them as Signal attachments. Less common but possible. ### 4.3 File/Resource Content **Priority: LOW** `ResourceContentBlock` and `EmbeddedResourceContentBlock` in agent messages. Could send file contents as Signal attachments or inline code blocks. ### 4.4 Audio Support **Priority: LOW** ACP has `AudioContentBlock`. Signal supports voice messages. Theoretically bridgeable but Goose doesn't currently use audio. --- ## Phase 5: Advanced / Optional ### 5.1 Multi-User Concurrency **Priority: MEDIUM** Currently each contact gets their own session, and prompts run as async tasks. But there's no protection against a user sending a second message while the first is still processing. Options: - Queue messages per-user (process sequentially) - Allow concurrent prompts (may confuse Goose session state) - Tell the user "please wait" if a prompt is in progress ### 5.2 Group Messaging **Priority: LOW** Signal groups could map to shared Goose sessions. Would need the account number (already in config) for group message handling. signal-cli has different envelope structure for group messages. ### 5.3 Extension Methods **Priority: LOW** `ext_method` and `ext_notification` are catch-alls for custom protocol extensions. Log them for now; implement specific ones if Goose uses them. ### 5.4 MCP Server Configuration **Priority: LOW** `new_session` accepts `mcp_servers` to connect external tool servers. Could be configured per-contact or globally in honker config. --- ## Decisions Made 1. **Terminal execution**: Permission gate is enough. No additional sandboxing. 2. **Tool call notifications**: Light — send "🔧 Running: ..." on tool start. Goose already keeps extensive logs at `~/.local/state/goose/logs/`. 3. **Agent thoughts**: Opt-in via config flag (`forward_thoughts: true`). 4. **Cancellation UX**: `/cancel` plus general `/command` prefix convention. 5. **Multi-user concurrency**: "Please wait" — reject concurrent prompts per user. 6. **Image attachments**: Yes, wire up in Phase 1. 7. **Working directory**: Global config option (`working_directory`).