Start-here doc for a fresh session. The migration itself (phases 0–5) is code-complete
on branch feature/opencode-v2; what remains is the owner-gated E2E pass and the two
SSE captures that could not be taken from a scratch server.
- Status: captures done (2026-09-18, commit d24917f); owner E2E checklist §3 remains the gate. §5 decisions still awaiting the owner.
- Related: opencode-v2-migration.md (verified endpoint/event map — read §1.1 first) · ../../AGENTS.md
- Branch stack (pushed to
originon 2026-09-18, in merge order):fix/post-audit-gaps→feature/circulo-general-frame→feature/reasoning-and-mode→feature/opencode-v2(HEAD). Canonical repo:github.com/soycanopa/circulo. - CI-lite green at HEAD (
go test ./...+pnpm vitest20/20 + tsc). - The app currently runs against opencode v2.0.8 via
CIRCULOGO_OPENCODE_BIN=$HOME/.local/opencode-v2/node_modules/@opencode/cli-darwin-arm64/bin/opencode. - Environment: global
opencodeCLI is still v1.18.31 (npmopencode-ai) — untouched on purpose. v2 lives side-by-side at~/.local/opencode-v2/…(npm@opencode/cli@2.0.8). - Provider credentials (v2 server): Z.AI Coding Plan, MiniMax, DeepSeek, xAI ✅ —
opencode gateway NOT configured (models under the
opencodeprovider fail withlogin fail … X-Api-Key; that error is correct behavior, not a bug).
pnpm --dir frontend build
go build -o build/bin/circulo .
CIRCULOGO_OPENCODE_BIN="$HOME/.local/opencode-v2/node_modules/@opencode/cli-darwin-arm64/bin/opencode" \
./build/bin/circuloThe managed v2 server prints server password <random> and listens on a random loopback
port; both live only in the app process (in-memory ring buffer), see §4 for capture options.
- Fresh temp project (
mkdir /tmp/e2e-v2 && cd /tmp/e2e-v2 && git init) → add in-app. - Prompt "list the files, then reply DONE" → tool card runs, text streams, usage footer.
- Prompt "create notes.txt with 'hi'" → expect a permission card (if the server auto-approves, capture §4-A first with a config that asks).
- Abort mid-turn → partial content stays, status idle.
- Kill the managed server externally → project error state → recovers on retry.
- Quit →
pgrep -fl "opencode serve"empty (no orphans). - Reopen → sessions hydrate. NOTE: sessions created under v1 may not exist for v2
(different storage);
GET /api/experimental/migration/v1can import them — owner decision.
Record every deviation; the translator has best-effort handling for permission and execution-failure events that still needs live confirmation.
Both shapes were captured from a standalone 2.0.8 server and are now real fixtures with translator coverage (commit d24917f):
- Permission ask/reply → event name is
permission.asked(data = the spec'sPermission.Request:{id, sessionID, action, resources, save, metadata, source}), and after the reply POST the server broadcastspermission.replied({sessionID, requestID, reply}). Fixture:internal/opencode/testdata/v2-permission-roundtrip.sse; translator emits the existing neutralpermission.request/permission.resolvedevents, soprotocol.tsneeded no changes. session.execution.failed→ data{sessionID, error:{type, message}}(statusonly for HTTP-backed errors; live example:provider.no-routefrom a bad model pin, fires promptly on a fresh session). Fixture:internal/opencode/testdata/v2-execution-failed.sse.
Phase 0 finding closed: the "auto-approve" repro was config placement — a project
opencode.json with the v2 permissions ruleset asks as documented
(opencode.ai/v2/docs/permissions: rules {action, resource, effect}, action shell
replaces v1 bash, unmatched tools default to ask, reject cascades to the session's
pending asks). The legacy permission:{edit,bash} object still loads (server normalizes
it to the ruleset — verified via GET /api/config).
Status as of 2026-09-29 (see the version-audit amendment in implement.md):
Done — rewritten for v2 on branchAGENTS.mdOpenCode-traps section describes v1.docs/agent-rules-sync, along with the dependency diagram and project map that still omittedinternal/omp.SIGTERM/SIGINT handler soDone — the original claim here was right and the retraction in this file was wrong. Wails does install a default handler whose routing does reachkillroutes through graceful shutdown.ServiceShutdown(); what fails is that the graceful teardown does not finish before the process exits. Measured twice on 2026-09-29 against opencode 2.0.18: after SIGTERM the app was gone andopencode servewas still listening on its port.main.gonow installsshutdownOnSignal, which stops the adapters synchronously and then exits; SIGTERM and SIGINT were both re-measured with no orphans afterwards.- Import v1 sessions (
/api/experimental/migration/v1) or start clean. Switch the global CLI to v2.Moot — the globalopencodeis already v2 (2.0.18 as of 2026-09-29); the 2.0.8 side-by-side install is stale.Merge the branch stack toDone — merged, including the omp adapter.main.
- E2E checklist §3 passes with no translator deviations. ← pending (owner)
- Both captures taken, fixtures + translator + tests updated, CI-lite green. ← ✅ done (d24917f)
- Docs updated (TRD already pinned to 2.0.8; implement.md E2E note; this doc closed). ← migration doc + this doc updated; implement.md note pending the checklist result.