# v2.0 — BooCoder task breakdown ## Phase 0 — Prep (before any code) - [ ] Clone lift sources: `agent-hub`, `plandex`, `opencode` to `/opt/forks/` - [ ] Read agent-hub's schema + dispatcher pattern (Apache-2.0) - [ ] Read plandex's pending-changes + diff/apply/rewind flow (MIT) - [ ] Read opencode's `permission/evaluate.ts` for write-gate patterns (MIT) - [ ] Install ACP SDK: `pnpm add @zed-industries/agent-client-protocol` - [ ] Verify `opencode acp` and `goose acp` are available on the host - [ ] Write `openspec/changes/v2.0-boocoder/design.md` with finalized decisions ## v2.0.0 — Schema + Path A (native write tools + pending-changes + diff UI) ### Infra - [ ] Create `apps/coder/` directory skeleton (Fastify server, mirroring `apps/server/` structure) - [ ] Create `apps/coder/Dockerfile` (Node 20 bookworm-slim, `/opt:/opt:rw` mount) - [ ] Add `boocoder` service to `docker-compose.yml` (port 9502, boocode_net) - [ ] Add Caddy route: `coder.indifferentketchup.com` → boocoder:9502 - [ ] DB rename: `boocode_db` → `boochat_db` (one-time ALTER DATABASE + docker-compose volume rename) - [ ] Schema migration: CREATE TABLE `pending_changes`, `tasks`, `available_agents`; CREATE VIEW `human_inbox` - [ ] Container guidance: `BOOCODER.md` (bind-mounted at `/app/BOOCODER.md`) ### Write tools - [ ] `apps/coder/src/services/write_guard.ts` — `resolveWritePath(projectRoot, filePath)` (resolve + prefix-check, no realpath since file may not exist) - [ ] `apps/coder/src/services/pending_changes.ts` — queue, apply, reject, revert operations - [ ] Tool: `edit_file` — takes `{file_path, old_string, new_string}`, computes unified diff, queues in `pending_changes` - [ ] Tool: `create_file` — takes `{file_path, content}`, queues as `operation='create'` - [ ] Tool: `delete_file` — takes `{file_path}`, queues as `operation='delete'` - [ ] Tool: `apply_pending` — flushes pending changes to disk (re-validates write_guard before each write) - [ ] Tool: `rewind` — reverts applied changes by inverse-diff ### Inference loop - [ ] Port the v1.14 outer loop from `apps/server/` into `apps/coder/` (or share via workspace package) - [ ] Register write tools in the coder's tool registry (alongside all read tools from BooChat) - [ ] Permission gate: write tools require `pending_changes` queue (can't bypass to direct disk write) ### Frontend (diff pane) - [ ] Create `apps/coder/web/` SPA (React + Vite, same stack as BooChat's `apps/web/`) - [ ] Diff pane component: shows pending changes with syntax-highlighted diffs - [ ] Approve / Reject per change, Approve All / Reject All buttons - [ ] Workspace splitter integration (chat pane + diff pane side by side) ### Verification - [ ] `pnpm -C apps/coder build` clean - [ ] Write path-guard fuzz tests (traversal patterns, symlinks, non-existent paths, `.env` deny) - [ ] `docker compose up --build -d` — boocoder container starts, healthcheck passes - [ ] Smoke: send a chat requesting a file edit → see it queued in diff pane → approve → file written ## v2.0.1 — Path B (ACP dispatch + PTY fallback + worktrees) ### ACP client - [ ] `apps/coder/src/services/acp-client.ts` — spawn `opencode acp` / `goose acp` via `@zed-industries/agent-client-protocol` StdioTransport - [ ] Event mapping: ACP `file_operation` → `tool_call` part, `terminal_output` → BooTerm route, `permission_request` → pause - [ ] Session lifecycle: start, mid-session model switch, end - [ ] MCP auto-forward: pass BooCoder's `context_servers` config to the ACP session ### PTY fallback - [ ] `apps/coder/src/services/pty-dispatch.ts` — spawn `claude` / `pi` / `smallcode` via `node-pty` - [ ] Capture stdout/stderr/exit-code into parts (less structured than ACP) - [ ] Worktree setup: `git worktree add /tmp/booworktrees/ -b task- HEAD` - [ ] On completion: diff worktree vs HEAD → queue into `pending_changes` ### Dispatcher - [ ] `apps/coder/src/services/dispatcher.ts` — polls `tasks` WHERE `state='pending'`, picks by priority + creation order - [ ] Transport selection: check `available_agents.supports_acp` at dispatch time - [ ] On failure: mark `state='failed'`, surface in `human_inbox` - [ ] On completion: mark `state='completed'`, queue diff if Path B ### Agent probing - [ ] Startup probe: `which opencode && opencode --version`, `which goose`, `which claude`, `which pi` - [ ] Populate `available_agents` table with version + ACP support ### Verification - [ ] Smoke: dispatch a task to `opencode` via ACP → task completes → diff queued - [ ] Smoke: dispatch to `claude` via PTY fallback → captures output → diff from worktree - [ ] Worktree cleanup after task completion ## v2.0.2 — BooCoder MCP server ### Implementation - [ ] `apps/coder/src/services/mcp-server.ts` — register 6 tools as MCP tool handlers - [ ] Stdio transport (use `@modelcontextprotocol/sdk` server-side, same SDK as client) - [ ] Tools: `boocoder.create_task`, `boocoder.list_pending_changes`, `boocoder.apply`, `boocoder.reject`, `boocoder.dispatch_external_agent`, `boocoder.list_worktrees` - [ ] Each tool maps to a DB operation or service call ### Eval - [ ] Write 10-question eval per `anthropics/skills/mcp-builder` framework - [ ] Run eval against the MCP server — all 10 must pass before shipping - [ ] Document eval results in openspec ### Verification - [ ] From a terminal: `echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | boocoder --mcp` → returns 6 tools - [ ] From opencode: configure BooCoder as an MCP server in `~/.opencode/config.json`, verify tool calls work ## v2.0.3 — Polish ### CLI client - [ ] `apps/coder/src/cli.ts` — thin WebSocket/HTTP client against BooCoder API - [ ] Verbs: `boocode run `, `boocode ls`, `boocode attach `, `boocode send ` - [ ] Mirrors Paseo's UX, license-clean implementation ### Human inbox UI - [ ] Frontend route showing tasks in `blocked`/`failed` state - [ ] Per-task: view output, retry, cancel, reassign to different agent ### Cost tracking - [ ] `tasks.cost_tokens` populated from inference usage - [ ] Summary view: per-project, per-agent, per-day token spend ### Verification - [ ] `boocode run "add a health endpoint"` from terminal → task appears in UI → completes → diff in pane - [ ] `boocode ls` shows running/completed/failed tasks