
Morph published a head-to-head between OpenCode and Claude Code. Good piece. Numbers, prompt extracts, the January 2026 OAuth block. Two tools, two philosophies.
It left a third one out.
This is the three-way. Every SoulForge claim below is verified against the source tree (paths cited inline). The other two columns come from Morph's piece and the public docs of each tool.
Table of contents
- The verdict
- Legend
- The 30-second version
- Foundations
- How the agent edits your file
- Codebase intelligence
- Agent architecture
- Context and compaction
- Permissions and safety
- MCP
- Remote and mobile
- Headless
- Themes
- Memory across sessions
- Pricing
- Bench numbers
- When to pick which
The verdict
Who wins between Claude Code and OpenCode? Look at the numbers Morph published. Claude Code finished every task in under half the time. Cross-file refactor 2m 15s vs 4m 20s. Bug fix 1m 45s vs 3m 10s. Total 9m 9s vs 16m 20s. OpenCode also reformatted code it shouldn't have on every model tested.
On raw speed and harness reliability, Claude Code wins that fight. OpenCode wins on cost, provider choice, and remote control. Different axes, different answers.
Here's the punchline though.
On the SoulForge bench, with Claude Opus 4.6 driving both tools on the same repo with the same prompt, SoulForge finished a bug fix in 6m 22s for $1.70. OpenCode took 11m 18s and $3.52. The audit task was sharper: 2m 00s, $0.84, 7-out-of-7 correct findings, zero false alarms. OpenCode: 5m 56s, $2.61, 4-out-of-7, three false alarms, one wrong claim.
Same model. Same code. Same prompt. Half the time. Half the cost. Better accuracy.
The gap isn't model magic, it's harness design. AST editing instead of string replace. A live codebase graph instead of grep. Symbol-level reads instead of file dumps. Zero-LLM compaction instead of summarization round-trips. Per-task model routing so Haiku does exploration while Sonnet writes code.
You don't pick the agent. You pick the harness that lets the agent do less work.

Legend
| Symbol | Meaning |
|---|---|
| ✓ | Shipped, on by default |
| ◐ | Shipped, behind a flag or partial |
| ✗ | Not available |
| n | Numeric value from source |
path:line | Verifiable in the SoulForge repo |
The 30-second version
Claude Code wins if you want Anthropic's vertical stack with /goal autonomy and Agent View fleet management. Tight, polished, subscription-locked.
OpenCode wins if you want provider freedom across 75+ models, the Tauri desktop app, Scout for external docs research. MIT, open ecosystem.
SoulForge wins if you want the agent to understand your codebase as a graph before it touches anything. AST editing, live PageRank repo map, per-task model routing, zero-LLM compaction. BSL, BYOK. Same model as the others, finished in roughly half the time and half the cost on our bench.
Foundations
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| License | MIT | Proprietary | BSL 1.1 → Apache 2.0 (2030) |
| Runtime | Node.js | Node.js | Bun |
| UI | TUI + Tauri desktop | TUI + VS Code ext | TUI (OpenTUI) + embedded Neovim |
| GitHub stars (May 2026) | 161K | 124K | growing |
| Provider count | 75+ | Anthropic only | 21 built-in + custom |
| Local models | ✓ Ollama | ✗ | ✓ Ollama, LM Studio |
| Subscription required | optional | $20+/mo | none, BYOK |
SoulForge's 21 built-in providers verified at src/core/llm/providers/index.ts:49: Anthropic, OpenAI, Google, xAI, Groq, DeepSeek, Mistral, Bedrock, Fireworks, MiniMax, Codex, Copilot, GitHub Models, OpenRouter, OpenCode Zen, OpenCode Go, LLM Gateway, Vercel AI Gateway, Proxy, Ollama, LM Studio. Plus any OpenAI-compatible endpoint via providers[] array.
How the agent edits your file
This is the single biggest difference.
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Primary edit tool | edit (string replace) | Edit (string replace) | ast_edit (ts-morph) for TS/JS, line-anchored edit_file / multi_edit for the rest |
| Symbol-level ops | via MCP | via MCP | native: rename_symbol, move_symbol, refactor |
| LSP integration | ✓ default | ✓ since v2.1.121 | ✓ default, dual backend (Neovim + standalone) |
| LSP server installer | via Neovim | via Neovim | Mason inside the TUI, 576+ packages |
| Atomic multi-op | ✗ | ✗ | ✓ all-or-nothing rollback |
| Pre/post-edit diagnostics fed to agent | ✗ | partial | ✓ |
OpenCode and Claude Code both treat code as text. Match old_string, replace with new_string. When whitespace drifts, the match fails. Morph's own data: 35% of string-match edits fail on the first try, 70%+ on files with formatOnSave.
SoulForge picks ast_edit for .ts/.tsx/.js/.jsx/.mts/.cts/.mjs/.cjs automatically. It walks the TypeScript compiler API, mutates the node, serializes back. Whitespace drift can't fail something the tool doesn't read as text.
Want to make a function async, change its return type, add a parameter, and import the new type? One tool call, four operations, atomic:
ast_edit({
path: "src/api.ts",
operations: [
{ action: "set_async", target: "function", name: "fetchUser", value: "true" },
{ action: "set_return_type", target: "function", name: "fetchUser", value: "Promise<User>" },
{ action: "add_parameter", target: "function", name: "fetchUser", value: "cache: boolean" },
{ action: "add_named_import", value: "./types", newCode: "User" },
],
})If User doesn't exist in ./types, none of the four apply. No half-refactored file.
Codebase intelligence
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Live repo graph | ✗ | ✗ | Soul Map — SQLite, src/core/intelligence/repo-map.ts |
| Ranking | n/a | n/a | PageRank over import graph |
| Git-aware | ✗ | ✗ | co-change weighting |
| Blast radius per file | ✗ | ✗ | ✓ |
| Symbol-level reads | ✗ | ✗ | ✓ across 33 languages |
| External docs research | ◐ via WebFetch | ◐ via WebFetch | ◐ via web_search + soul_grep dep=npm-package |
| Scout-style dep cloning | ✓ Scout subagent | ✗ | ✗ |
SoulForge starts every session by parsing your codebase with tree-sitter, building a SQLite graph, and ranking files by PageRank over the import graph plus git co-change. The agent receives a ranked digest in its system prompt before the first turn.
Neither OpenCode nor Claude Code has anything equivalent. Both grep when they need to find something. SoulForge greps too, but only after the map fails.
OpenCode's Scout is the one place it leads on intelligence: it clones dependency repos into cache and inspects library source. SoulForge approaches the same problem with soul_grep dep="react" which searches inside node_modules directly, but Scout's full-clone model is more thorough.
Agent architecture
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Built-in subagents | General, Explore, Scout | Plan, Explore, Task | Spark (read-only), Ember (code), WebSearch |
| User-defined agents | ✓ .opencode/agents/*.md | ✓ .claude/agents/ + marketplace | per-task router slots |
| Fleet dashboard | ✗ | ✓ Agent View | per-tab dispatch view |
| Autonomous goal completion | ✗ | ✓ /goal with validator model | auto mode (no validator) |
| Background subagents | ✓ | ✓ --bg | dispatch only |
| Cross-tab file claims | ✗ | ✗ | ✓ 5 tabs, advisory warnings |
| Per-task model routing | one per agent | one per session | 8 task slots, different model each |
The router slots in SoulForge (src/core/agents/agent-runner.ts:33): spark, ember, webSearch, desloppify, verify, compact, semantic, default. Default concurrency: 3, max 8. You can run Haiku on explore, Sonnet on code, Flash on compaction, all in one session. Cheap work to cheap models, automatically.
Context and compaction
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Auto-compaction | ✓ v1.14+ | ✓ built-in | ✓ default |
| Strategy | LLM summary | LLM summary | V2 structural extraction, usually zero LLM tokens |
| Session persistence | server-side via Hono | background sessions + --bg | JSONL auto-save, crash-resilient |
| Checkpoints | session pinning | Esc×2 instant rewind | every prompt is a git-tagged checkpoint, per-tab, branchable |
| Context window | provider-dependent | 1M (Opus 4.7) | provider-dependent |
V2 compaction in SoulForge (src/core/compaction/working-state.ts) tracks structured state as the conversation runs: files touched, decisions, failures, tool results. When the context fills, that state is already built. No LLM round-trip. Old tool results prune to one-liners enriched with Soul Map symbols.
Permissions and safety
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Default posture | granular glob rules | ask by default | approval gates on destructive ops |
rm -rf detection | regex rule | heuristic | hardcoded denylist |
| Forbidden files | config | config | built-in blocks: .env, .pem, credentials, id_rsa, .npmrc, .netrc, shadow, passwd |
| Pre-commit gate | ✗ | ✗ | ✓ runs lint + typecheck before any commit |
| Hook system | per-agent frontmatter | plugin hooks | 13 events, wire-compatible with Claude Code |
SoulForge's hook events (src/core/hooks/types.ts:12): PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, Stop, StopFailure, SessionStart, SessionEnd, PreCompact, PostCompact, SubagentStart, SubagentStop, Notification. Reads from five config sources merged in order (src/core/hooks/loader.ts:21): ~/.claude/settings.json, .claude/settings.json, .claude/settings.local.json, ~/.soulforge/config.json, .soulforge/config.json. Your existing Claude Code hooks work without modification.
MCP
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Transports | stdio, HTTP | stdio, HTTP | stdio, streamable HTTP, SSE |
| Loading | declarative per-agent | eager (Tool Search lazy) | per-server config |
| Tool namespace | mymcp_* | mcp__server__tool | mcp__server__tool |
| Auto-restart on crash | ✓ | ✓ | ✓ stdio only |
| Bounded concurrency at startup | ✗ | ✗ | ✓ max 5 simultaneous, retry 3× exponential |
Verified at src/core/mcp/manager.ts:223. SoulForge supports the legacy SSE transport for older remote servers, which the other two have dropped.
Remote and mobile
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Remote control | ✓ HTTP API | ✗ | ✓ Hearth (experimental) |
| Mobile | via API | ✗ | Telegram + Discord |
| Code leaves your host | optional | no | no, ever |
| Approval prompts | API | n/a | inline buttons in chat |
| Secret redaction in logs | ✗ | ✗ | ✓ Telegram + Discord + JWT + PEM + AWS + GitHub + Stripe + Slack + Google + bearer + DB URL + basic auth |
Hearth runs as a daemon over a UNIX socket (mode 0600). Tokens stored in OS keychain, never in config. Destructive tool calls arrive as tap-to-approve buttons. Identity allowlist; unknown senders dropped silently. Path containment forces every daemon-managed file to live inside ~/.soulforge. Service install via launchd (macOS) or systemd (Linux).
Headless
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Headless mode | ✓ | ✓ -p | ✓ first-class |
| Event stream | partial | partial | typed JSONL union, 14 event types |
| Pipe from stdin | ✓ | ✓ | ✓ |
| Resume by short prefix | ✗ | ✗ | ✓ --session abc finds abc123... |
| Pre-load files | ✗ | ✗ | ✓ --include (repeatable) |
| Daemon-embeddable | ✗ | ✗ | ✓ via Hearth seam |
soulforge --headless "fix the auth bug"
soulforge --headless --events "refactor store" | jq -r 'select(.type=="tool-call").tool'
soulforge --headless --chat --session abc # resume by prefix
echo "list TODOs" | soulforge --headless # pipe from stdinExit codes: 0 success, 1 error, 2 timeout, 130 abort. SIGINT re-raised so parent shells see a true signal death.
Themes
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Built-in themes | a few | 1 | 36 |
| Custom themes | ✗ | ✗ | JSON files, hot-reload on save |
| Transparent backgrounds | ✗ | ✗ | ✓ with per-element opacity |
| Kitty inline images | ✗ | ✗ | ✓ |
Counted directly from src/core/theme/tokens.ts:1879. The list includes Catppuccin (Mocha, Frappé, Macchiato, Latte), Dracula, Gruvbox, Tokyo Night (+ Storm), Nord, Rose Pine, Kanagawa, Nightfox, Cyberdream, Oxocarbon, Sonokai, Moonfly, Melange, Solarized (Dark + Osaka), Bamboo, Nordic, Synthwave, Iceberg, Ember, Vesper, GitHub (Dark + Light), Everforest, Ayu, One Dark + Light, and three proxysoul themes.
Memory across sessions
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Cross-session memory | via files | CLAUDE.md + Skills | SQLite DB, project + global scopes |
| Auto-recall per turn | ✗ | ✗ | ✓ top-3 stubs from prompt + edited files |
| Inline hint footers | ✗ | ✗ | ✓ pinned, pref, gotcha, decision |
| Soft-delete (restorable) | n/a | n/a | ✓ forever |
| Embeddings | n/a | n/a | offline default, optional provider embedder |
When the agent learns something worth remembering ("we use bun, not npm", "JWT clock drift breaks prod auth"), it writes a memory. Next session, the relevant entries surface automatically from the prompt and the files you're editing. Two-DB layout: project-scoped per repo, global for cross-project preferences.
Pricing
| OpenCode | Claude Code | SoulForge | |
|---|---|---|---|
| Tool cost | free, MIT | free, proprietary | free, BSL personal/internal |
| Minimum to start | $0 (Ollama) | $20/mo Pro | $0 (Ollama / LM Studio) |
| Cheapest cloud tier | Go $10/mo (open-weight) | Pro $20/mo | BYOK, your account |
| Premium tier | Black $200/mo (sold out) | Max20x $200/mo | BYOK |
| Commercial use | permissive | per Anthropic ToS | commercial license for resale |
Bench numbers
Morph's own benchmark, Claude Opus 4.7, OpenCode vs Claude Code:
| Task | OpenCode | Claude Code |
|---|---|---|
| Cross-file refactor | ✓ 4m 20s | ✓ 2m 15s |
| Bug fix from error | ✓ 3m 10s | ✓ 1m 45s |
| Test generation | 94 tests, 8m 50s | 73 tests, 5m 9s |
| Reformatting bugs | yes (all 3 models) | no |
SoulForge bench, Claude Opus 4.6, same repo, SoulForge vs OpenCode:
| Bug fix | SoulForge | OpenCode |
|---|---|---|
| Time | 6m 22s | 11m 18s |
| Cost | $1.70 | $3.52 |
| Audit task | SoulForge | OpenCode |
|---|---|---|
| Time | 2m 00s | 5m 56s |
| Cost | $0.84 | $2.61 |
| Accuracy | 7/7 | 4/7 |
| False alarms | 0 | 3 |
Different harness, different model, not directly comparable to Morph's run. The cost gap is structural though, coming from V2 compaction and symbol-level reads instead of file dumps.
When to pick which
| Your priority | Pick |
|---|---|
| Anthropic vertical stack, fire-and-forget autonomy | Claude Code |
| Provider freedom, open-weight models, desktop app, $10/mo tier | OpenCode |
| Symbol-aware editing, codebase graph, per-task routing, multi-tab workflow, Neovim embed, headless CI, BYOK across 21 providers | SoulForge |
The three tools aren't really competing for the same thing. Claude Code optimizes for autonomous Anthropic-stack work. OpenCode optimizes for provider freedom and community surface area. SoulForge optimizes for what the agent understands before it acts.
If you've ever watched a string-matching agent burn three retries on whitespace, give SoulForge a try.
brew tap proxysoul/tap && brew install soulforge
soulforge --set-key llmgateway sk-... # or any of 20 other providers
soulforgeSources
- Morph: OpenCode vs Claude Code (2026)
- SoulForge docs · AST editing · Soul Map · Hearth
- SoulForge on GitHub
- OpenCode docs · Claude Code
- ProxySoul
