Started: Feb 5, 2026 Source: /tmp/opencode (anomalyco/opencode, dev branch) Comparison: /tmp/claude-code-vs-opencode-comparison.md
- Not started
- [~] In progress
- Complete
- [-] Blocked/Deferred
- Run existing test suite, confirm all pass
- Understand build system (bun, turbo)
- Create working branch for changes
- Research: read
session/compaction.ts, server endpoint, TUI command - Implement: add optional
instructionsparam to/compactcommand - Implement: pass instructions through to compaction prompt
- Test: unit tests (schema, storage) + integration test (real LLM via Claude Max OAuth)
- Verify: 891 pass, 0 fail
- Files changed:
src/session/compaction.ts-instructionsinprocess()andcreate()src/session/message-v2.ts-instructionsinCompactionPartschemasrc/session/prompt.ts- passtask.instructionstoprocess()src/server/routes/session.ts-instructionsin/summarizeendpointsrc/cli/cmd/tui/component/prompt/index.tsx- handle/compact [text]in promptpackages/sdk/js/src/v2/gen/sdk.gen.ts-instructionsinsummarize()methodtest/session/compaction.test.ts- 3 new schema teststest/server/session-summarize.test.ts- 6 new endpoint + storage tests
- Complexity: Low
- Notes: Verified end-to-end: instructions stored in compaction part AND influenced LLM summary output
- [-] Deferred: user uses Gitea/GitLab, not GitHub
- Notes: Would need Gitea/GitLab API support instead of
ghCLI
- [-] Deferred: user uses Gitea/GitLab, not GitHub
- Notes: Would need Gitea/GitLab API support
- [-] Skipped: OpenCode already supports this via its existing subagent/task system
- Notes: Different mechanism than Claude Code's
context: forkfrontmatter, but same result. Commands supportsubtask: truefor subagent execution.
- Research: read editor/prompt components, understand how responses complete
- Design: background LLM call using small/fast model after agent finishes
- Implement:
SessionSuggestionmodule withgenerate()usingProvider.getSmallModel() - Implement: Bus event
session.suggestion→ SSE → client store → placeholder text - Implement: Tab to accept into input, Enter to accept+submit, grayed-out display
- Implement:
experimental.suggestionsconfig flag (opt-out) - Test: unit tests (891 pass), type check clean, integration test (real LLM via Google OAuth)
- Verify: end-to-end SSE event received by client
- Files changed:
src/session/suggest.ts- NEW - generates suggestions via small model (e.g.gemini-3-flash,claude-haiku-4.5)src/session/prompt.ts- callsSessionSuggestion.generate()at loop exit (fire-and-forget)src/config/config.ts-suggestions: z.boolean().optional()inexperimentalschemasrc/cli/cmd/tui/context/sync.tsx-session_suggestionstore + SSE event handler + clear on busysrc/cli/cmd/tui/component/prompt/index.tsx-suggestionmemo, placeholder display, Tab/Enter handlerspackages/sdk/js/src/v2/gen/types.gen.ts-EventSessionSuggestiontype inEventunion
- Complexity: Medium
- Notes: Uses
Provider.getSmallModel()(same as title generation) for cost/speed. Silently skips if model returns empty or session goes busy. Subtask sessions excluded.
- Research: Claude Code backgrounds individual bash commands, not whole sessions
- Design: Approach A - background individual bash tool calls (matches Claude Code behavior)
- Study: PR #9681 (4,878 lines, unmerged) - adapted cleaner version without persistence
- Implement:
src/task/events.ts- Bus events (task.created, task.output, task.completed, task.killed) - Implement:
src/task/index.ts- In-memory TaskManager (adopt, list, get, kill, read, tail, remove) - Implement:
src/tool/bash.ts- Foreground process registry +migrateToBackground()function - Implement:
src/tool/process-query.ts- LLM tool for agents to check on background tasks - Implement:
src/server/routes/task.ts- REST API (list, get, output, tail, kill, migrate, foreground) - Implement: TUI Ctrl+B keybind (context-sensitive: only when session is busy + bash running)
- Implement:
/taskscommand + DialogTasks (list, kill, view output) - Implement: Toast notification on background task completion
- Test: type check clean, 887 unit tests pass, integration test verified full flow
- Files changed:
src/task/events.ts- NEW - Bus event definitionssrc/task/index.ts- NEW - TaskManager (in-memory, cleaned up on exit)src/tool/bash.ts- Foreground process registry, migration support, callID in metadatasrc/tool/process-query.ts- NEW - LLM tool (list, status, read_output, read_last_n, search)src/tool/registry.ts- Register ProcessQueryToolsrc/server/routes/task.ts- NEW - Task REST APIsrc/server/server.ts- Mount TaskRoutes at /tasksrc/cli/cmd/tui/app.tsx- /tasks command, toast on task.completedsrc/cli/cmd/tui/component/dialog-tasks.tsx- NEW - Tasks dialog with kill/viewsrc/cli/cmd/tui/routes/session/index.tsx- Ctrl+B handler
- Complexity: Medium
- Notes: No persistence (matches Claude Code - tasks die with server). ~500 lines total vs PR #9681's 4,878. Ctrl+B is context-sensitive: only triggers when session busy + bash running, otherwise acts as cursor-left.
- Research: OpenCode already has AGENTS.md/CLAUDE.md loading, global instructions, contextual loading via resolve()
- Part A:
/memorycommand - dialog to list/create/edit memory files in $EDITOR - Part B:
.opencode/rules/*.mdwith path-scoping (like Claude Code's.claude/rules/*.md) - Implement: scan
.opencode/rules/**/*.mdand.claude/rules/**/*.mdwithgray-matterfrontmatter parsing - Implement: unconditional rules (no
pathsfrontmatter) loaded in system prompt alongside AGENTS.md - Implement: path-scoped rules (
pathsfrontmatter with glob patterns) loaded contextually via resolve() when matching files are read - Implement: rules cached per-instance, claimed per-message (no duplicate injection)
- Test: 11 new unit tests (unconditional loading, frontmatter stripping, path matching, claiming, compatibility)
- Verify: 922 pass, 0 fail, type check clean
- Files changed:
src/session/instruction.ts-RuleFiletype,scanRules(),getRules()cache, rules insystem()andresolve()src/cli/cmd/tui/component/dialog-memory.tsx- NEW - Memory file browser with $EDITOR supportsrc/cli/cmd/tui/app.tsx-/memorycommand registrationtest/session/instruction-rules.test.ts- NEW - 11 tests for rules loading
- Complexity: Medium
- Notes: Supports both
.opencode/rules/(native) and.claude/rules/(compatibility). YAML frontmatter withpathsfield for glob-based scoping. Unconditional rules go in system prompt, path-scoped rules injected as<system-reminder>when agent reads matching files.
- Research: OpenCode todo system (4-field flat list), Claude Code Tasks (full deps), 7 related issues
- Fix #5612: Changed
statusfromz.string()toz.enum(["pending","in_progress","completed","cancelled","blocked"]),prioritytoz.enum(["high","medium","low"]) - Implement:
depends_onoptional field (array of todo IDs) inTodo.Infoschema - Implement:
blockedstatus — auto-set when deps are incomplete, auto-unblocked when deps complete - Implement: dependency validation — circular dep detection (DFS), strip refs to non-existent IDs, auto-resolve on update
- Implement: TodoItem UI —
⊘icon for blocked tasks, red color for blocked state - Fix #5934: Inject incomplete todos into compaction prompt so they survive context compaction
- Update:
todowrite.txtprompt with dependency instructions + example - Test: 14 new unit tests (schema validation, auto-block, auto-unblock, chain deps, multiple deps, invalid refs)
- Verify: 936 pass, 0 fail, type check clean
- Files changed:
src/session/todo.ts-StatusandPriorityenums,depends_onfield,resolveDependencies(),hasCircularDeps(),hasUnresolvedDeps()src/session/compaction.ts- Inject incomplete todos into compaction prompt contextsrc/tool/todowrite.txt- Dependency documentation and examplesrc/cli/cmd/tui/component/todo-item.tsx-statusIcon()function, blocked/cancelled renderingtest/session/todo.test.ts- NEW - 14 tests
- Complexity: Medium
- Notes: Also fixes issues #5612 (status validation) and #5934 (todos lost after compaction). Dependency resolution uses AND logic (all deps must complete). Circular deps are warned but not blocked to avoid breaking the LLM flow.
- Research: Studied OpenClaw's memory system (vector search, session-memory hooks, pre-compaction memory flush, memory_search/memory_get tools)
- Design: Conservative approach —
memory_savetool the LLM calls when user explicitly asks to remember something - Implement:
MemorySaveTool— writes facts to.opencode/rules/memory.mdwith timestamps - Implement: Auto-inject via existing rules loading system (#7) — no new code needed, facts load in future sessions automatically
- Also fixed: Todo list now injected into system prompt via
Todo.systemContext()for reliable persistence across compaction (simpler than compaction prompt hack) - Test: 5 new unit tests (create file, append, date inclusion, directory creation, instruction system integration)
- Verify: 944 pass, 0 fail, type check clean
- Files created:
src/tool/memory-save.ts- NEW -MemorySaveTooltool definitionsrc/tool/memory-save.txt- NEW - Conservative usage instructionstest/tool/memory-save.test.ts- NEW - 5 tests
- Files changed:
src/tool/registry.ts- RegisterMemorySaveToolsrc/session/todo.ts- AddedTodo.systemContext()for system prompt injectionsrc/session/prompt.ts- Inject todos into system prompt every turnsrc/session/compaction.ts- Removed compaction prompt hack (replaced by system prompt injection)
- Complexity: Low (conservative approach leverages existing rules infrastructure)
- Notes: OpenClaw has much more sophisticated memory (embeddings, SQLite vector search, pre-compaction flush). Can layer those on later. Current approach: LLM writes to
.opencode/rules/memory.md, rules system loads it automatically.
- Research: read
textarea-keybindings.ts, understand input handling - Implement: mode state (normal/insert)
- Implement: normal mode motions (h/j/k/l, w/e/b, 0/$, gg/G, f/F/t/T)
- Implement: operators (d/c/y) with motions and text objects
- Implement: visual indicator of current mode
- Test: write tests
- Verify: run test suite
- Files likely touched:
cli/cmd/tui/component/textarea-keybindings.ts, prompt component - Complexity: Medium-High (mechanical but lots of cases)
- Notes:
- Implement: partial compaction with
boundaryMessageID("summarize before X") - Implement: validation that
boundaryMessageIDexists in message list, fallback to full compaction - Verify: type check clean, integrated with
/compactcommand - Files changed:
src/session/compaction.ts-boundaryMessageIDparam inprocess()andcreate()
- Complexity: Low (extension of #1)
- Notes: Allows targeting specific conversation ranges for compaction
- Design: file-locked JSON state per team under
.opencode/teams/<name>/ - Design:
TeamMemberschema (name, sessionID, agent, status, model, planApproval) - Design:
TeamTaskschema (id, content, status, priority, assignee, depends_on) - Implement:
src/team/index.ts-Teamnamespace: create, get, list, addMember, removeMember, setMemberStatus, setMemberPlanApproval, setDelegate, findBySession, cleanup.TeamTasks: list, update, add, claim, complete, resolveDependencies. File locking viaLock.write(). - Implement:
src/team/events.ts- 10 Bus events (Created, MemberSpawned, MemberStatusChanged, Message, Broadcast, TaskUpdated, TaskClaimed, PlanApproval, ShutdownRequest, Cleaned) - Implement:
src/team/messaging.ts-TeamMessaging.send()andbroadcast()inject synthetic user messages into recipient sessions - Test: 12 server route tests pass via
bun test - Verify: 1030 pass, 0 fail
- Files created:
src/team/index.ts- NEW - Team and TeamTasks namespacessrc/team/events.ts- NEW - Schemas and Bus event definitionssrc/team/messaging.ts- NEW - Cross-session messagingsrc/server/routes/team.ts- NEW - REST API (list, get, tasks, by-session, delegate toggle)test/server/team-routes.test.ts- NEW - 12 route tests
- Complexity: High
- Implement: 9 team tools (team_create, team_spawn, team_message, team_broadcast, team_tasks, team_claim, team_approve_plan, team_shutdown, team_cleanup) behind
OPENCODE_EXPERIMENTAL_AGENT_TEAMSflag - Implement:
team_createwith delegate mode (restricts lead to coordination-only by denying bash/write/edit/apply_patch) - Implement:
team_spawn— spawns teammate as child session, startsSessionPrompt.loop()in background, auto-claims task - Implement: Plan approval (
require_plan_approval: true) — teammate starts in read-only mode with write tools denied; lead usesteam_approve_planto grant access - Implement: Multi-model support —
team_spawnacceptsmodelparam inprovider/modelformat (e.g.anthropic/claude-sonnet-4-20250514,google/gemini-2.5-pro), validated viaProvider.getModel()with fuzzy suggestions on error - Implement: Model resolution priority: explicit param > agent.model > lead's current model > Provider.defaultModel()
- Implement:
team_shutdownwith negotiation (teammate can approve/reject) - Implement: Child session permission rules (deny team management tools, deny todowrite/todoread)
- Implement: Idle notification when teammate loop finishes
- Implement:
POST /session/:sessionID/team-messageroute (followsshell()pattern) - Implement:
SessionPrompt.teamMessage()function - Test: team e2e, scenarios, edge cases, integration tests
- Verify: 1030 pass, 0 fail
- Files created:
src/tool/team.ts- NEW - 9 team tool definitions (~650 lines)
- Files changed:
src/tool/registry.ts- Register team tools behind flagsrc/flag/flag.ts-OPENCODE_EXPERIMENTAL_AGENT_TEAMSdynamic gettersrc/session/prompt.ts-teamMessage()functionsrc/server/routes/session.ts-POST /session/:sessionID/team-messagesrc/config/config.ts-max_turns,max_budget_usdexperimental config
- Complexity: High
- Implement:
dialog-team.tsx— team dialog with member list (status icons), shared tasks, Enter to navigate,mfor message,lto go to lead - Implement:
TeamBadge— compact: "Team: name (N active, N idle, N total)" or "memberName @teamName" - Implement:
TeamStatusBar— per-member: status icon, model label, plan approval state, current task (truncated), task progress, delegate indicator - Implement: Shift+Up/Down teammate selection with "Messaging: @name" indicator bar
- Implement:
@teammateautocomplete with plan approval state and model in description - Implement: Prompt submit interception — when teammate selected, routes through
POST /session/:sessionID/team-message - Implement:
<leader>j/<leader>kteammate navigation,<leader>wteam dialog,<leader>ddelegate toggle - Implement:
/teamslash command,/delegateslash command - Implement: Team event toasts (member status, task claimed, cleanup)
- Implement: SSE handlers for all team events + session.suggestion in sync.tsx
- Test: 11 PTY smoke tests + 10 PTY live tests (all pass)
- Verify: type check clean, all tests pass
- Files created:
src/cli/cmd/tui/component/dialog-team.tsx- NEW - Team management dialogtest/tui/pty-harness.ts- NEW - Reusable PTY test harness (bun-pty)test/tui/tui-smoke.ts- NEW - 11 PTY smoke teststest/tui/tui-live.ts- NEW - 10 PTY live tests (real Anthropic OAuth)
- Files changed:
src/cli/cmd/tui/app.tsx- Team commands, toasts, session.limit handlersrc/cli/cmd/tui/context/sync.tsx- Team store type (with model field), SSE handlerssrc/cli/cmd/tui/routes/session/header.tsx- TeamBadge, TeamStatusBarsrc/cli/cmd/tui/routes/session/index.tsx- Teammate selection, messaging bar, keybindssrc/cli/cmd/tui/component/prompt/index.tsx- Tab-to-accept suggestions, team message routingsrc/cli/cmd/tui/component/prompt/autocomplete.tsx- @teammate autocomplete with model infosrc/config/config.ts- Keybinds: team_show, team_next, team_previous, team_delegate
- Complexity: Medium-High
- Implement:
max_turnsandmax_budget_usdin experimental config - Implement: Toast notifications when limits are reached (via
session.limitBus event) - Implement: 80% budget warning (fires once per session via
budgetWarnedSet) - Implement:
LimitEventBusEvent definition in prompt.ts - Implement: TUI handler in app.tsx — "Budget Warning" / "Limit Reached" toasts
- Verify: type check clean, 1030 tests pass
- Files changed:
src/session/prompt.ts-LimitEvent,budgetWarned, guard logic with Bus.publishsrc/cli/cmd/tui/app.tsx-session.limitSSE event handlersrc/config/config.ts-max_turns(int),max_budget_usd(number) in experimental schema
- Complexity: Low
- Notes: Novel feature — Claude Code doesn't have per-session turn/budget limits. Our implementation: silent loop break + toast notification + server-side log.
- Chrome integration (separate product)
- Sandboxing (design doc at
opencode-sandbox-integration.md, pending implementation) - Reverse search (low value)
- Status line (low value)
| Date | Session | Work done | Issues |
|---|---|---|---|
| Feb 5, 2026 | 1 | Comparison sheet created, tracker created | Wasted time on wrong Go repo |
| Feb 5, 2026 | 1 | Compact with instructions: implemented, tested (unit + integration with real LLM) | Server endpoint tests need Instance cache handling |
| Feb 5, 2026 | 2 | Prompt suggestions: implemented server-side generation, SSE plumbing, TUI display + accept | Initial test showed empty suggestion (trivial prompt); fixed by using small model |
| Feb 5, 2026 | 3 | Prompt suggestions: debugged integration test, switched to small model, verified e2e | Flash model returns short suggestions for trivial convos (acceptable) |
| Feb 5, 2026 | 4 | Background tasks: studied PR #9681, designed leaner approach, implemented full feature | Ctrl+B is context-sensitive (only when session busy). stdin pipe broke cat test (fixed). Route ordering mattered for /foreground vs /:taskId. |
| Feb 5, 2026 | 5 | Persistent memory: /memory command + .opencode/rules/*.md with path-scoping. Fixed compact test on wrong branch. Investigated 200K token limit (Claude Max OAuth restriction, not OpenCode). | context-1m beta header not available on Claude Max subscription. |
| Feb 5, 2026 | 5 | Task dependencies: depends_on field, blocked status, auto-resolve, circular dep detection. Fixed #5612 (enum validation) + #5934 (todos lost after compaction). | Researched Claude Code's new Tasks system (addBlockedBy/addBlocks) and 7 related OpenCode issues. |
| Feb 5, 2026 | 6 | Auto-memory: memory_save tool + todo system prompt injection. Studied OpenClaw's memory system. | Replaced compaction prompt hack with simpler Todo.systemContext() in system prompt. |