SnackOnAI Engineering | Senior AI Systems Researcher | Technical Deep Dive | November 14, 2026
Oversells, because one of the providers in its V2 core is Claude Code itself, run through Anthropic's Claude Agent SDK as if it were just another model. It also quietly renames any tool call named bash to shell, since that's what models trained on other agents keep asking for.
What actually makes OpenCode different is control. Every agent (Build, Plan, Explore, General, even the hidden one that writes session titles) is a list of permission rules, evaluated by one line: the last matching rule wins, and if nothing matches, ask.
The promise: by the end you'll know how OpenCode V2 is put together, from the background server to agents, permissions, compaction and providers, what it does better than a closed agent, and what its own code says is still unfinished.
The fence: we read the anomalyco/opencode monorepo at f7a0684 (November 9, 2026, dev branch, V2, latest release v2.2.5 on October 30): the agent definitions, the permission engine, Plan mode, session compaction, the provider plugins including Claude Agent, the server's event feed, the edit tool, and the changelog. The repo holds about 1.29 million lines of TypeScript across 40+ packages, so we read the core paths, not everything. The opencode.ai docs weren't reachable from this environment, so community numbers come from secondary reporting. We didn't run it.
What It Actually Does
OpenCode is an MIT-licensed AI coding agent from Anomaly, the team behind SST: Jay V, Frank Wang, Dax Raad and Adam Elmore. It reads and edits code, runs shell commands, searches the web, delegates to subagents, and works with nearly any model provider.
Runtime |
|
Stack | TypeScript on Bun, Effect for services and errors, SQLite via Drizzle, generated typed client |
Agents | Build (default, primary), Plan (read-only primary), General and Explore (subagents), plus hidden Compaction, Title and Summary agents |
Tools | read, write, edit, patch, glob, grep, shell, webfetch, websearch, subagent, todo, question, skill, schedule, MCP resources, artifacts, image generation |
Providers | ~25 dedicated provider plugins (Anthropic via Claude Agent, OpenAI, Bedrock, Vertex, Azure, OpenRouter, Ollama, LM Studio, vLLM, NVIDIA, xAI…) plus the models.dev catalog. Docs claim 75+ providers |
Extensibility | Plugins (agents, tools, hooks on tool execution and session context), MCP servers, custom commands, skills |
Community | ~204K GitHub stars and ~26.6K forks (September 2026), 900+ contributors. Anomaly claims 7.5M monthly developers |
Business | Free core. Zen (pay-per-token curated models) and Go ($10/month for hosted open-weight models) |
Think of the difference between a game console and a game server. Claude Code is a console: one box with its controller built in. OpenCode is a server you run yourself, which any number of controllers (terminal, desktop, browser, your own scripts) can connect to, and which can plug in whatever engine you choose, including the console's.
The Architecture, Unpacked

What to notice: agents, Plan mode and subagent limits aren't separate code paths. They're rows in the same permission table, checked at the same choke point before any tool runs.
Four decisions define OpenCode V2.
One: the agent is a server, not an app. A single background service per machine owns sessions, terminals and state. Clients attach over HTTP with a private local credential and stream events over SSE. Desktop terminals now "survive server restarts with their scrollback" (v2.2.4), because they belong to the session, not the window.
Two: agents are data. Build, Plan, Explore and General are records with a name, a mode (primary or subagent), an optional system prompt, and a permission list. A plugin can add, edit or remove any of them through the same editor API.
Three: one permission evaluator for everything. File edits, shell, web access, subagent spawning, even asking the user a question are all actions checked against rules with wildcard matching.
Four: providers behind the AI SDK. Each provider is a plugin that hands the session a language model. That's general enough that the Claude Agent plugin wraps a whole other agent, Claude Code, as a model.
The Code, Annotated
Snippet one: the entire permission decision (from packages/core/src/permission.ts, our comments marked // SnackOnAI:).
export function evaluate(action: string, resource: string, ...rulesets: Permission.Ruleset[]): Permission.Rule {
return (
rulesets
.flat() // SnackOnAI: agent rules + config rules, in order
.findLast((rule) => Wildcard.match(action, rule.action) && Wildcard.match(resource, rule.resource)) ?? {
action, // ← THIS is the trick: the LAST match wins, so
resource: "*", // later, more specific rules override earlier ones
effect: "ask", // SnackOnAI: and anything unmatched becomes a prompt,
} // not a silent allow
)
}
Last-match-wins makes rule order the policy. Put a broad allow after a narrow deny and the deny vanishes. The upside is that agents read like layered overrides.
Snippet two: the Explore subagent as a ruleset (from packages/core/src/plugin/agent.ts).
editor.update(Agent.ID.make("explore"), (item) => {
item.system = PROMPT_EXPLORE // SnackOnAI: "You MUST NOT create, modify, delete... files"
item.mode = "subagent"
item.permissions.push(
{ action: "*", resource: "*", effect: "deny" }, // SnackOnAI: start from nothing
{ action: "shell", resource: "*", effect: "allow" }, // SnackOnAI: shell is allowed; "read-only" is only
{ action: "grep", resource: "*", effect: "allow" }, // enforced by the prompt for shell commands
{ action: "read", resource: "*", effect: "allow" },
{ action: "read", resource: "*.env", effect: "ask" }, // ← THIS is the trick: secrets need a human...
{ action: "read", resource: "*.env.*", effect: "ask" },
{ action: "read", resource: "*.env.example", effect: "allow" }, // ...except the example file, listed LAST
{ action: "subagent", resource: "*", effect: "deny" }, // SnackOnAI: subagents can't spawn subagents
)
})
Explore is read-only for file tools by permission, but its shell access is "read-only" only because the system prompt says so. That's the gap any coding agent with a shell has, and OpenCode makes it visible.
Snippet three: Plan mode, keeping the cache warm (from packages/core/src/plugin/plan.ts).
item.permissions.push({ action: "edit", resource: "*", effect: "deny" })
item.permissions.push({ action: "edit", resource: path.join(directory, "*"), effect: "allow" }) // plan files only
// Compaction and committed reverts can strip reminders while the session's agent stays
// put. Reconcile per request, appending near the tail so the cached prefix stays warm.
yield* ctx.session.hook("context", (event) => {
const reminder = lastReminder(event.messages, enterReminder)
const missing = event.agent === plan && reminder !== enterReminder
const stale = event.agent !== plan && reminder === enterReminder // SnackOnAI: also tells the model
const text = missing ? enterReminder : stale ? leave : undefined // when Plan mode has ENDED
...
event.messages.splice(at, 0, Message.user(text)) // ← THIS is the trick: inject near the end, never edit the
}) // prefix, so the provider's prompt cache keeps hitting
Mode switches are delivered as reminder messages, not by rewriting the system prompt. Rewriting the prompt would invalidate the prompt cache, the biggest cost lever in long agent sessions.
Snippet four: compaction thresholds (from packages/core/src/session/compaction.ts).
/** After each "too long" rejection, the next attempt aims at this share of the first rejected request's size. */
const SHRINK_STEPS = [0.85, 0.7, 0.5, 0.35]
const RESERVE_MIN = 16_000
/** ... Single steps grew by up to ~22k tokens at p99 in real sessions. */
const RESERVE_SHARE = 0.15 // ← THIS is the trick: the margin is sized from measured step growth,
const UNKNOWN_WINDOW = 200_000 // so one big tool output can't push the next request over the limit
const SUMMARY_OUTPUT_FLOOR = 32_000 // SnackOnAI: the summary always gets room to be written
The p99 step-growth comment is the most production-grade line in the file: the compaction margin comes from real session telemetry, not a guess.
It In Action
Input: a long refactoring session on a 200K-token model, using the Build agent. The Explore subagent is asked to inventory config files.
Step one, permissions. Explore wants to read .env.example, .env.local and config.env, then edit README.md:
Request | Matching rules (in order) | Last match | Result |
|---|---|---|---|
read |
|
| allow |
read |
|
| ask the user |
read |
|
| ask the user |
edit |
|
| deny |
Step two, context grows. Reserve = max(16,000, 15% × 200,000) = 30,000 tokens, so automatic compaction triggers once a request would exceed about 170,000 tokens. A background summary starts as the session nears that point, so the swap is instant.
Step three, a provider rejects anyway. If a request of 180,000 tokens comes back "too long," retries aim at 153K, 126K, 90K, then 63K (85%, 70%, 50%, 35%).
Step four, Plan mode. Switching to Plan appends one reminder message near the tail. The cached prefix stays the same, and edits outside ~/.opencode/plan/ now return a clear tool error instead of a generic denial.
Output:
context budget on a 200K window (our arithmetic from compaction.ts)
used before compaction ██████████████████████████████████ 170K
reserve (15%, ≥16K) ██████ 30K
p99 single-step growth ████▌ ~22K ← why the reserve isn't 10K
OpenCode's context management is policy written from telemetry: the reserve exceeds the largest step it has measured, and overflow retries shrink geometrically.
Why This Design Works (and what it trades away)
It works because state lives in one place. A single service owns sessions, PTYs and the database. Closing the TUI doesn't kill the work, a desktop window and a terminal see the same session, and the SDK can drive it headlessly.
It works because policy is data. Agents as permission lists make the system auditable. You can read exactly what Explore may do, and a plugin can tighten or loosen it without forking.
It works because it absorbs other ecosystems. The bash → shell alias, the Claude Agent provider and MCP support all meet models and users where they already are.
It trades away simplicity. 1.29M lines of TypeScript, Effect services everywhere, a background daemon, pairing and credentials. Users report the TUI can use 1 GB+ of RAM. Claude Code is one process.
It trades away stability. V2 replaced V1's architecture. The September reporting flagged migration risk from the 2.0 beta, and V2 has shipped multiple releases a week.
It trades away safe defaults. Unmatched requests ask, but Build's defaults are broad. Two January 2026 advisories (a critical 9.4 involving the web UI and local command execution, and a high-severity unauthenticated local HTTP server) show what a local agent server exposes. Both are patched.
Technical Moats
Community scale. ~204K stars, ~26.6K forks and 900+ contributors produce a provider and plugin surface no single vendor matches, along with ~4,200 open issues to triage.
Distribution economics. The free agent feeds Zen and Go, Anomaly's paid model gateways, reportedly a multi-million-dollar annualized business. The open agent is the funnel.
Operational detail. Compaction margins from p99 telemetry, cache-preserving reminders, overflow shrink steps, MCP messages over 10 MiB. This kind of tuning only comes from many real sessions.
Not the agent loop. Prompt, model, tools, repeat is common knowledge. Anyone can build that part.
Contrarian Insights
One: the "LSP integration" headline isn't in the V2 core we read. The configuration schema accepts lsp entries and there's an LSP event type. But the V2 edit tool states it plainly: // TODO: Add LSP notification and diagnostics after LSP runtime exists. The same block defers watcher events and "snapshots / undo after design exists." V1 users had LSP diagnostics after edits. If that feedback loop matters to your workflow (type errors surfacing right after an edit), check whether your V2 build has it before migrating.
Two: "provider-agnostic" now includes the vendor it's an alternative to, and the defaults decide your privacy. OpenCode V2 ships a Claude Agent provider that runs Claude Code underneath, and v2.2.4 added guided setup for it. That's pragmatic, since many users have Claude subscriptions, but it means "open alternative to Claude Code" can mean "a UI on top of Claude Code." Meanwhile, hidden helper agents (Title, Summary, Compaction) also call models. One developer found V1's title generation sending prompts to a free hosted model by default even when everything else was local. Self-hosting means configuring every agent, including the hidden ones.
Surprising Takeaway
OpenCode's entire safety model reduces to findLast(...) ?? ask. Every agent's personality, from read-only Explore to file-restricted Plan to subagents that can't spawn subagents, is an ordered list of (action, resource, effect) rows, and the last matching row wins. It's the most portable idea in the codebase: you could implement the same policy engine in any agent framework in an afternoon, and audit it in one.
TL;DR For Engineers
OpenCode V2 is a background server (HTTP + SSE) with TUI, desktop, web and SDK clients. Sessions, PTYs and state survive closing any client.
Agents are permission lists. Evaluation is last-match-wins with a default of "ask." Rule order is your policy, so put narrow overrides last.
Compaction keeps 15% (minimum 16K) of the window free, sized from p99 step growth of ~22K, and shrinks to 85/70/50/35% on overflow.
~25 provider plugins plus models.dev, including Claude Code via the Claude Agent SDK. Configure the hidden title and summary agents too if you need local-only.
In the V2 code we read, LSP diagnostics after edits are still a TODO. Check before relying on them.
Explain It Like I'm New
AI coding assistants can now do real work in a codebase: read files, make changes, run tests, and try again when something fails. The best-known ones come from AI companies and work best, or only, with that company's models.
OpenCode is an open-source version that lets you pick the AI model, whether from Anthropic, OpenAI, Google, or one running on your own computer. You keep the same tool and switch the engine.
It's built differently, too. Instead of being one program in your terminal, it runs quietly in the background like a small server, and different screens connect to it: a terminal interface, a desktop app, a web page, or your own scripts. If you close one, the work keeps going.
Safety comes from a simple rulebook. Each assistant mode has a list of what it may do, like "may read files but not edit them" or "must ask before reading password files." When the AI tries something, OpenCode checks the list and either allows it, blocks it, or asks you.
As AI coding becomes part of everyday software work, tools that let teams choose their own models and set their own rules will matter as much as the models themselves.
See It In Action
OpenCode on GitHub, Anomaly. Read the README and releases. Installation for every platform, plus a detailed changelog where each V2 release describes behavior changes, the best record of how the agent actually evolves.
OpenCode deep dive, Ry Walker. Read the research note. Team, business model, Zen and Go pricing, and the trade-offs users report, including memory use and permission defaults.
OpenCode hit GitHub trending, but its real test is control, remio. Read the analysis. Repository health at 200K+ stars, the January security advisories, and why local agent servers need careful exposure.
We couldn't verify an official video walkthrough of V2 from this environment. The opencode.ai site wasn't reachable.
Community Conversation
Sophie Larsen, remio, analysis. Frames OpenCode's challenge as governance, not popularity: about 4,200 open issues and 1,500 PRs, plugin trust, inconsistent provider behavior, and migration risk from the 2.0 beta.
Ry Walker, research note. Collects Hacker News criticism (1 GB+ TUI memory, features breaking between releases, a learning curve steeper than Claude Code) alongside the business picture: Zen is reported at several million dollars in annualized revenue.
Never Code Alone, OpenCode for vibe coding. A practitioner view from German-speaking consulting work, positioning OpenCode as the model-agnostic default for teams that want to switch providers freely.
Anomaly team, V2 changelog. The changelog itself is the most candid source. It's where
bashcalls being renamed toshell, LiteLLM context errors triggering compaction, and 10 MiB MCP messages show up.
Conclusion: The Agent Is Infrastructure Now, So Read the Rulebook
OpenCode V2 gets the big decisions right. The agent is a long-lived server with many clients. Every agent is a readable permission list. Context management is tuned from real telemetry, and the provider layer is so open it can run its main competitor as a model. The costs are complexity (1.29M lines, a daemon, Effect everywhere), a fast-moving V2 whose own code marks LSP diagnostics and undo as unfinished, and defaults you need to audit, including the hidden helper agents. Adopt it if you want to own your coding-agent infrastructure and choose your models. Before you deploy it for a team, read your agents' permission rules top to bottom, remembering the last match wins.
References
SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering, Yang et al. The case that tool and interface design, which OpenCode makes configurable, drives agent performance.
OpenHands: An Open Platform for AI Software Developers as Generalist Agents, Wang et al. The other major open coding-agent platform, sandbox-first where OpenCode is server-first.
ReAct: Synergizing Reasoning and Acting in Language Models, Yao et al. The think, act, observe loop under every coding agent's session runner.
Lost in the Middle: How Language Models Use Long Contexts, Liu et al. Why compaction and tail-placed reminders matter for long sessions.
OpenCode V2 is an MIT-licensed coding agent built as a background server, with every agent defined as a permission list evaluated last-match-wins with a default of "ask." It manages long sessions with telemetry-sized compaction and supports ~25 provider plugins, including Claude Code itself. Its own code marks LSP diagnostics after edits as not yet implemented.
Sponsored Ad If you enjoy practical AI insights, check out SnackOnAI and support the newsletter by subscribing, sharing, and exploring our sponsored ad—it helps us keep building and delivering value 🚀
Frontier models perform better in Attio’s agent harness.
We gave GPT-6 Astra the same job twice: analyze 100 sales calls and draft the follow-ups, once in Ask Attio and once in ChatGPT.
Ask Attio finished in 4 minutes 49 seconds. ChatGPT took 26 minutes 11 seconds, about 5.4 times as long.
The most ambitious GTM work requires more than frontier intelligence. It requires architecture that can put that intelligence to work at scale.



