Skip to content
cd ../blog

OpenCode vs Claude Code vs SoulForge: a real comparison

aisoulforgeopencodeclaude-codecomparisontooling

SoulForge in action

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

  1. The verdict
  2. Legend
  3. The 30-second version
  4. Foundations
  5. How the agent edits your file
  6. Codebase intelligence
  7. Agent architecture
  8. Context and compaction
  9. Permissions and safety
  10. MCP
  11. Remote and mobile
  12. Headless
  13. Themes
  14. Memory across sessions
  15. Pricing
  16. Bench numbers
  17. 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.

Same model, half the cost


Legend

SymbolMeaning
Shipped, on by default
Shipped, behind a flag or partial
Not available
nNumeric value from source
path:lineVerifiable 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

OpenCodeClaude CodeSoulForge
LicenseMITProprietaryBSL 1.1 → Apache 2.0 (2030)
RuntimeNode.jsNode.jsBun
UITUI + Tauri desktopTUI + VS Code extTUI (OpenTUI) + embedded Neovim
GitHub stars (May 2026)161K124Kgrowing
Provider count75+Anthropic only21 built-in + custom
Local models✓ Ollama✓ Ollama, LM Studio
Subscription requiredoptional$20+/monone, 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.

OpenCodeClaude CodeSoulForge
Primary edit tooledit (string replace)Edit (string replace)ast_edit (ts-morph) for TS/JS, line-anchored edit_file / multi_edit for the rest
Symbol-level opsvia MCPvia MCPnative: rename_symbol, move_symbol, refactor
LSP integration✓ default✓ since v2.1.121✓ default, dual backend (Neovim + standalone)
LSP server installervia Neovimvia NeovimMason inside the TUI, 576+ packages
Atomic multi-op✓ all-or-nothing rollback
Pre/post-edit diagnostics fed to agentpartial

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

OpenCodeClaude CodeSoulForge
Live repo graphSoul Map — SQLite, src/core/intelligence/repo-map.ts
Rankingn/an/aPageRank over import graph
Git-awareco-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

OpenCodeClaude CodeSoulForge
Built-in subagentsGeneral, Explore, ScoutPlan, Explore, TaskSpark (read-only), Ember (code), WebSearch
User-defined agents.opencode/agents/*.md.claude/agents/ + marketplaceper-task router slots
Fleet dashboard✓ Agent Viewper-tab dispatch view
Autonomous goal completion/goal with validator modelauto mode (no validator)
Background subagents--bgdispatch only
Cross-tab file claims✓ 5 tabs, advisory warnings
Per-task model routingone per agentone per session8 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

OpenCodeClaude CodeSoulForge
Auto-compaction✓ v1.14+✓ built-in✓ default
StrategyLLM summaryLLM summaryV2 structural extraction, usually zero LLM tokens
Session persistenceserver-side via Honobackground sessions + --bgJSONL auto-save, crash-resilient
Checkpointssession pinningEsc×2 instant rewindevery prompt is a git-tagged checkpoint, per-tab, branchable
Context windowprovider-dependent1M (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

OpenCodeClaude CodeSoulForge
Default posturegranular glob rulesask by defaultapproval gates on destructive ops
rm -rf detectionregex ruleheuristichardcoded denylist
Forbidden filesconfigconfigbuilt-in blocks: .env, .pem, credentials, id_rsa, .npmrc, .netrc, shadow, passwd
Pre-commit gate✓ runs lint + typecheck before any commit
Hook systemper-agent frontmatterplugin hooks13 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

OpenCodeClaude CodeSoulForge
Transportsstdio, HTTPstdio, HTTPstdio, streamable HTTP, SSE
Loadingdeclarative per-agenteager (Tool Search lazy)per-server config
Tool namespacemymcp_*mcp__server__toolmcp__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

OpenCodeClaude CodeSoulForge
Remote control✓ HTTP APIHearth (experimental)
Mobilevia APITelegram + Discord
Code leaves your hostoptionalnono, ever
Approval promptsAPIn/ainline 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

OpenCodeClaude CodeSoulForge
Headless mode-p✓ first-class
Event streampartialpartialtyped 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 stdin

Exit codes: 0 success, 1 error, 2 timeout, 130 abort. SIGINT re-raised so parent shells see a true signal death.


Themes

OpenCodeClaude CodeSoulForge
Built-in themesa few136
Custom themesJSON 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

OpenCodeClaude CodeSoulForge
Cross-session memoryvia filesCLAUDE.md + SkillsSQLite 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/an/a✓ forever
Embeddingsn/an/aoffline 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

OpenCodeClaude CodeSoulForge
Tool costfree, MITfree, proprietaryfree, BSL personal/internal
Minimum to start$0 (Ollama)$20/mo Pro$0 (Ollama / LM Studio)
Cheapest cloud tierGo $10/mo (open-weight)Pro $20/moBYOK, your account
Premium tierBlack $200/mo (sold out)Max20x $200/moBYOK
Commercial usepermissiveper Anthropic ToScommercial license for resale

Bench numbers

Morph's own benchmark, Claude Opus 4.7, OpenCode vs Claude Code:

TaskOpenCodeClaude Code
Cross-file refactor✓ 4m 20s✓ 2m 15s
Bug fix from error✓ 3m 10s✓ 1m 45s
Test generation94 tests, 8m 50s73 tests, 5m 9s
Reformatting bugsyes (all 3 models)no

SoulForge bench, Claude Opus 4.6, same repo, SoulForge vs OpenCode:

Bug fixSoulForgeOpenCode
Time6m 22s11m 18s
Cost$1.70$3.52
Audit taskSoulForgeOpenCode
Time2m 00s5m 56s
Cost$0.84$2.61
Accuracy7/74/7
False alarms03

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 priorityPick
Anthropic vertical stack, fire-and-forget autonomyClaude Code
Provider freedom, open-weight models, desktop app, $10/mo tierOpenCode
Symbol-aware editing, codebase graph, per-task routing, multi-tab workflow, Neovim embed, headless CI, BYOK across 21 providersSoulForge

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
soulforge

Sources

- ProxySoul