Sets up the Cargo workspace (harness-core, harness-tools, harness-providers, harness-mcp, harness-lsp, harness-app, harness-tui) and the ten architecture docs under docs/. harness-core gets its foundational types (session/message/part/model ids), an in-process event bus, a table-driven permission evaluate function, and a SQLite-backed storage actor with schema and roundtrip coverage. Every crate compiles empty and a bin stub prints its version.
5.6 KiB
10 — Milestones, Testing, Risks
Milestones
Each milestone ends with a verifiable outcome (✅).
M0 — Scaffolding
Workspace + all crates compile empty; CI (fmt, clippy -D warnings, test). harness-core: id types, event bus, permission evaluate with table-driven tests, storage actor with roundtrip tests.
✅ cargo test green; a bin stub prints version.
M1 — Headless core loop + Anthropic
Anthropic codec + provider (against fixtures), config loading, Tool trait + read/bash/glob/grep/edit/write (edit replacers ported with opencode's test table), engine loop end-to-end with a MockProvider, permission service with an auto-approve stub frontend. Debug command harness run -p "<prompt>".
✅ Integration test: scripted MockProvider does text → tool call (read) → final text with correct parts persisted; harness run works against real Anthropic.
M2 — TUI
Event loop, chat viewport + markdown renderer + cache, input, streaming render, permission modal wired to the real oneshot path, session picker/resume, abort. ✅ Manually drive a multi-turn session with permission-gated edits; TestBackend snapshot tests pass.
M3 — All providers + auth
OpenAI (responses + chat codecs), Copilot (device-flow modal, token exchange with direct-Bearer fallback, /models routing to the three codecs), auth.json + token refresh, models.dev metadata + cost display, retry policy + doom-loop guard.
✅ The same session works on all three providers; device-flow login completes inside the TUI; costs shown.
M4 — Multiagent
Agent registry (bundled markdown + overrides), task tool foreground/background, JobBoard + persistence + injection, aliases/reuse, depth limits, permission intersection, jobs pane + subtask drill-in. ✅ An orchestrator session spawns a background explorer; the board appears in next-turn context (verify via request logging); reuse by alias continues the same child session.
M5 — MCP, LSP, commands/skills
rmcp integration + namespaced tools + permissions; LSP pool + diagnostics in edit/write output; markdown commands + skill tool.
✅ A config-declared MCP server's tool is callable with ask-permission; editing a broken .rs file surfaces rust-analyzer errors in the tool result; /mycommand works.
M6 — Polish
Auto-compaction (Compactor impl + overflow trigger), session title generation (small_model), tool-output spill dir, theming, syntax-highlighted code blocks, crash-resume hardening, streaming-render perf pass. ✅ A session driven past the context limit compacts and continues correctly.
Testing strategy
- Provider decoders: recorded SSE fixtures per codec (text-only, tool call, parallel tool calls, thinking, errors, mid-stream disconnect,
data:split across chunks) → assert exactVec<LlmEvent>viainstasnapshots. Request builders snapshot outgoing JSON (cache_control placement, tool schemas, header sets) withwiremock. - Auth: device-flow poll loop against wiremock (
authorization_pending → slow_down → success); token-exchange expiry + refresh single-flight. - Tools: tempdir-based unit tests; edit replacers get a direct port of opencode's
edit.test.tscase table; bash timeout/kill-process-group; truncation boundaries. - Engine integration (MockProvider): multi-step tool loop; permission ask/deny/reject via the real oneshot path; retry backoff (mock returns RateLimited twice); doom-loop trigger; cancellation mid-tool; task tool foreground + background with job-board assertions; depth-limit rejection; permission intersection.
- Permission engine: table-driven last-match-wins/wildcard tests mirroring opencode's semantics.
- TUI: ratatui
TestBackendsnapshots (empty session, streaming message, tool card, permission modal, jobs pane); input-handling unit tests onAppState. - Storage: actor roundtrips; resume-after-simulated-crash (unfinished assistant → aborted).
Top risks
- Copilot token exchange variance — opencode ships direct-Bearer; classic Copilot API wants the
copilot_internal/v2/tokenexchange. Mitigation: dual-pathtoken.rs, verify live early in M3. - SSE edge cases — events split across TCP chunks, keepalive comments, provider-specific mid-stream error events. Mitigation:
eventsource-stream+ adversarial fixtures. - Streaming markdown perf in ratatui — no incremental layout. Mitigation: per-part render cache + tail-only re-render + plain-text-tail fallback.
- Edit replacer fidelity — port the test suite, not just the code.
- Child-process lifecycle (MCP/LSP/bash) — zombies. Mitigation: process-group kills +
Dropguards + centralChildRegistry.
Key reference files
| What | Where |
|---|---|
| Inner stream state machine to mirror | ~/repos/opencode/packages/opencode/src/session/processor.ts |
| Outer loop semantics | ~/repos/opencode/packages/opencode/src/session/prompt.ts |
| Permission evaluate/ask semantics | ~/repos/opencode/packages/opencode/src/permission/index.ts |
| Edit replacer chain + tests (port verbatim) | ~/repos/opencode/packages/opencode/src/tool/edit.ts |
| Copilot auth/headers/model routing | ~/repos/opencode/packages/opencode/src/plugin/github-copilot/{copilot,models}.ts |
| Anthropic caching/beta headers | ~/repos/opencode/packages/opencode/src/provider/transform.ts |
| Retry policy details | ~/repos/opencode/packages/opencode/src/session/retry.ts |
| JobRecord, aliases, formatForPrompt | ~/repos/oh-my-opencode-slim/src/utils/background-job-board.ts |
| Session-reuse mechanics | ~/repos/oh-my-opencode-slim/src/hooks/task-session-manager/index.ts |
| Agent prompt content to port into markdown | ~/repos/oh-my-opencode-slim/src/agents/*.ts |