OpenCode Deep Dive Knowledge Base
A structured knowledge base for understanding OpenCode as a local-first AI coding assistant: architecture, agents, sessions, tools, permissions, database, server design, testing, and extensibility.
How to Use This Knowledge Base
Use this document as a reference when you need to understand:
- How OpenCode is architected internally.
- How agents, sub-agents, sessions, tools, and permissions work together.
- What infrastructure OpenCode uses and deliberately avoids.
- Where the system can be generalised beyond coding workflows.
- Which parts are strong, risky, or missing.
Knowledge Base Map
| Area | Best starting section |
|---|---|
| Product overview | 1. Product Summary |
| Repository layout | 2. Repository & Package Structure |
| Architecture | 3. Core Architecture |
| LLM orchestration | 4. LLM Integration & Orchestration |
| Agents | 5. Agent System |
| Sub-agents | 6. Sub-Agent Orchestration |
| Tools | 7. Tool System |
| Concurrency | 8. Parallelism & Resource Model |
| Human approval | 9. Human-in-the-Loop Systems |
| Sessions | 10. Session Management |
| Database | 11. SQLite Database Design |
| Auth | 12. Authentication |
| Server | 13. Server Architecture |
| Build and testing | 14. Build System, 15. Testing Strategy |
| Security | 16. Security Model |
| Missing features | 17. Explicit Non-Goals / Missing Capabilities |
| Design philosophy | 18. Design Philosophy |
| Generalisation | 19. Generalising Beyond Coding |
Executive Summary
OpenCode is a local-first AI coding assistant for developers. It provides a terminal, web, and desktop interface over a custom agent orchestration system that can inspect code, edit files, run shell commands, call tools, spawn sub-agents, and persist conversation state locally.
The system is notable because its core orchestration is custom-built rather than being based on frameworks such as LangChain, CrewAI, AutoGen, or Vercel AI SDK as the central orchestration layer. External libraries are used for infrastructure and provider transport, but the core model of sessions, agents, tools, permissions, and sub-agent spawning is implemented inside OpenCode.
At a high level:
User Interface
-> Session
-> Agent
-> LLM Provider
-> Tool Calls
-> Permission / Question Systems
-> SQLite Persistence
-> Events / UI UpdatesKey conclusions
- OpenCode is designed for single-user local development, not multi-tenant production orchestration.
- The most important abstraction is the session, which isolates conversations, sub-agents, permissions, messages, and state.
- The most important safety mechanism is permission inheritance, especially for sub-agents.
- Concurrency uses Effect fibers, not OS-level worker threads.
- Tool execution and agent orchestration are extensible and domain-agnostic.
- The coding-specific parts are mostly tools, prompts, agent configurations, and permission names.
Glossary
| Term | Meaning |
|---|---|
| Agent | A configured AI role with a prompt, model settings, mode, and permission rules. |
| Primary agent | A user-facing agent, such as build, plan, or general. |
| Sub-agent | A helper agent spawned by a parent agent through the task tool. |
| Session | A conversation unit with its own state, message history, permissions, runner, and optional parent session. |
| Tool | A callable capability exposed to an agent, such as file read, edit, grep, shell, web fetch, or task spawning. |
| MCP | Model Context Protocol, used to connect external tools/providers. |
| Effect | The functional programming runtime used for services, dependency injection, structured concurrency, and typed effects. |
| Fiber | Lightweight Effect concurrency primitive running on Node.js's single event loop. |
| Permission ruleset | A rule structure controlling which tools are allowed, denied, or require user approval. |
| Human-in-the-loop | Mechanisms that pause execution for user approvals or structured answers. |
1. Product Summary
What OpenCode Is
OpenCode is an AI-powered coding assistant for local development. It runs on the developer's machine and gives the LLM access to local codebase context through controlled tools.
Primary Use Cases
- Codebase exploration and understanding.
- Writing, editing, and refactoring code.
- Automating development tasks via shell commands.
- Planning and architectural reasoning.
- Delegating exploration or research tasks to sub-agents.
- Pair programming through terminal, web, or desktop UI.
Target Users
OpenCode is primarily built for:
- Full-stack developers.
- Backend engineers.
- Frontend engineers.
- DevOps and infrastructure engineers.
- Open-source contributors.
- Developers who want AI assistance with local control and permission-based safety.
2. Repository & Package Structure
OpenCode is organised as a monorepo with packages for the core application, shared libraries, SDKs, UI, desktop app, documentation, plugins, and admin console.
opencode/
├── packages/
│ ├── opencode/ # Core business logic, CLI, server
│ │ ├── src/
│ │ │ ├── agent/ # Agent definitions, permissions
│ │ │ ├── session/ # Session management, LLM loop
│ │ │ ├── tool/ # Built-in tool implementations
│ │ │ ├── config/ # Configuration loading
│ │ │ ├── auth/ # Authentication
│ │ │ ├── server/ # HTTP API + WebSocket server
│ │ │ ├── mcp/ # MCP client integration
│ │ │ ├── storage/ # Drizzle ORM + SQLite schemas
│ │ │ ├── permission/ # Permission evaluation engine
│ │ │ ├── question/ # Human-in-loop question system
│ │ │ ├── background/ # Background job system
│ │ │ └── effect/ # Effect utilities
│ │ ├── core/ # Shared utilities
│ │ ├── llm/ # LLM provider abstraction + tool runtime
│ │ ├── sdk/ # JavaScript/TypeScript SDK
│ │ ├── plugin/ # Plugin system
│ │ ├── app/ # Shared SolidJS UI components
│ │ ├── desktop/ # Electron desktop app
│ │ ├── ui/ # UI component library
│ │ ├── web/ # Documentation site
│ │ └── console/ # Admin console
├── script/ # Build scripts and release automation
└── migration/ # SQLite migration filesImportant Package Roles
| Package / folder | Role |
|---|---|
packages/opencode | Core application logic, CLI, server, sessions, tools, auth, config, permissions. |
packages/core | Shared utilities such as logging, filesystem helpers, and schemas. |
packages/llm | LLM provider abstraction, route system, and tool runtime. |
packages/sdk | API client for consumers of the HTTP server. |
packages/plugin | Plugin support and extensibility. |
packages/app, packages/ui | Shared UI components. |
packages/desktop | Electron desktop application. |
packages/web | Documentation website. |
migration | SQLite schema migrations. |
3. Core Architecture
Architectural Pattern
OpenCode uses a service-oriented architecture built on Effect.
Each feature is modelled as a service with:
| Part | Purpose |
|---|---|
| Interface | Defines what the service can do. |
| Implementation | Defines how the service behaves. |
| Layer | Defines how dependencies are injected. |
This makes the system modular, testable, and dependency-injectable.
Core Services
| Service | Responsibility |
|---|---|
| Session | Manages AI conversations, message history, and state. |
| Agent | Defines AI personalities, modes, prompts, and permissions. |
| Config | Loads settings from files, environment variables, and remote configuration. |
| Auth | Manages API keys, OAuth, and provider credentials. |
| Provider | Connects to LLM providers. |
| Tool | Exposes file, shell, web, orchestration, and utility capabilities. |
| Server | Provides HTTP API and WebSocket transport. |
| Permission | Evaluates and enforces tool access rules. |
| Question | Handles structured human-in-the-loop prompts. |
| Background | Manages background jobs and task execution. |
Main Data Flow
User input
-> CLI / TUI / Web / Desktop UI
-> Config loading
-> Session creation or lookup
-> Agent selection
-> LLM call through provider layer
-> Tool execution when requested
-> Permission and question checks as needed
-> Results persisted in SQLite
-> Events emitted to UI and API consumersKey Technologies
| Layer | Technology |
|---|---|
| Language | TypeScript |
| Functional runtime | Effect |
| Validation | Effect Schema |
| UI | SolidJS |
| ORM | Drizzle ORM |
| Database | SQLite |
| Runtime and build | Bun |
4. LLM Integration & Orchestration
Core Insight
OpenCode uses a custom orchestration layer.
The following are implemented internally:
- Agent management and hierarchy.
- Session creation and parent-child session relationships.
- Permission derivation and composition.
- Sub-agent spawning through the
tasktool. - Tool registry and execution orchestration.
- LLM route system.
- Session processor for LLM events, tool calls, and results.
What External Libraries Do
External libraries are used for infrastructure rather than core orchestration.
| Library | Role |
|---|---|
| Effect | Functional runtime, structured concurrency, dependency injection, typed effects. |
| Vercel AI SDK | Optional provider transport adapter. |
| Drizzle | ORM and persistence layer. |
Route-Based LLM Abstraction
Location:
packages/llm/src/route/Conceptual route shape:
Route.make({
protocol: Protocol, // API contract, such as OpenAI or Anthropic
endpoint: Endpoint, // URL construction
auth: Auth, // Bearer tokens, headers, signing
framing: Framing // Stream parsing, SSE, event-stream
})This allows one protocol abstraction to work across multiple providers.
Tool Runtime
Location:
packages/llm/src/tool-runtime.tsResponsibilities:
- Executes model-requested tool calls.
- Handles tool results.
- Handles tool errors.
- Integrates tool execution with the route system and session processor.
Tool Definition Pattern
Tool.define(id, Effect.succeed({
description: string,
parameters: Schema,
execute: (args, ctx) => Effect.Effect<ExecuteResult>
}))Tool Calling Flow
LLM request
-> Route.compile
-> Provider API
-> Tool call event detected
-> ToolRuntime.execute
-> Tool.execute through Effect
-> Tool result returned to session loop
-> Result fed back to LLMRuntime Selection
Location:
packages/opencode/src/session/llm.tsThe session layer decides per request between:
| Runtime | Role |
|---|---|
| Native route runtime | Custom Effect-based runtime. |
| AI SDK runtime | Vercel AI SDK-based provider adapter. |
5. Agent System
Agent Shape
Agents are configured with a name, mode, permissions, prompt, model, and generation settings.
{
name: "explore",
mode: "subagent",
permission: {
"*": "deny",
grep: "allow",
glob: "allow",
read: "allow"
},
prompt: "You are a fast exploration agent...",
model: { ... },
temperature: 0.0
}Agent Modes
| Mode | Meaning |
|---|---|
primary | User-facing agent. |
subagent | Helper agent that can only be invoked by another agent. |
Built-In Agents
| Agent | Mode | Purpose | Typical tools |
|---|---|---|---|
build | Primary | Default execution agent. | Broad permitted tool set. |
plan | Primary | Planning mode. | No edit tools. |
general | Primary | Multi-step, parallel work. | Broad tool set. |
explore | Sub-agent | Fast codebase exploration. | grep, glob, read. |
scout | Sub-agent | External docs and dependency research. | webfetch, websearch. |
compaction | Sub-agent | Context compaction. | read. |
title | Sub-agent | Generate session titles. | None. |
summary | Sub-agent | Summarise sessions. | read. |
Agent Selection Flow
User input
-> Session processor
-> Agent selected from request/config
-> Agent prompt + available tools prepared
-> LLM called6. Sub-Agent Orchestration
How Sub-Agents Are Spawned
Sub-agents are not automatically picked from a worker queue. A parent agent explicitly creates one by calling the task tool.
Example:
task({
description: "Explore codebase",
prompt: "Find all API endpoints",
subagent_type: "explore"
})This creates a new independent child session.
sessions.create({
parentID: ctx.sessionID,
title: description + " (@explore subagent)",
permission: derivedPermissions
})Sub-Agent Lifecycle
Parent agent calls task tool
-> New child session is created
-> Permissions are derived from parent and sub-agent config
-> Sub-agent processes its prompt independently
-> Result is returned to parent as text
-> Parent may continue, spawn more sub-agents, or resume by task_idPermission Derivation
Permission inheritance is the critical safety layer.
Location:
packages/opencode/src/agent/subagent-permissions.tsPermissions are merged roughly as:
Parent agent edit denies
+ Parent session denies
+ Parent external_directory rules
+ Default denies
= Effective sub-agent permissionsImportant default denies include todowrite and task unless explicitly allowed.
Safety Rule
A sub-agent should not gain more permissions than its parent.
This prevents permission escalation when an agent delegates work.
Execution Modes
| Mode | Behaviour |
|---|---|
| Synchronous | Parent waits until the sub-agent finishes. |
| Background | Sub-agent runs asynchronously and parent continues. |
| Resume | Parent passes task_id to continue an existing sub-agent session. |
Limits
There is no hard-coded sub-agent limit in the analysed design. Practical limits come from:
- LLM provider rate limits.
- Prompt instructions, such as "launch up to 3 explore agents".
- User approval prompts.
- Local system memory and network capacity.
7. Tool System
Tool Sources
OpenCode combines tools from multiple registries.
const tools = yield* Effect.all({
builtIn: ToolRegistry.builtIn(),
plugin: ToolRegistry.plugin(),
skill: ToolRegistry.skill()
})| Source | Meaning |
|---|---|
| Built-in tools | Core OpenCode tools. |
| Plugin tools | External tools, including MCP integrations. |
| Skill tools | User-defined skill tools. |
Core Built-In Tools
File Operations
| Tool | Purpose |
|---|---|
read | Read file contents with offset and limit. |
write | Write or create files. |
edit | Edit files with diff application. |
apply_patch | Apply git-style patches. |
Search
| Tool | Purpose |
|---|---|
grep | Search file contents, typically using ripgrep. |
glob | Find files by pattern. |
repo_overview | Retrieve repository structure. |
Shell
| Tool | Purpose |
|---|---|
shell / bash | Execute shell commands. |
repo_clone | Clone Git repositories. |
Web
| Tool | Purpose |
|---|---|
websearch | Search the web via MCP providers. |
webfetch | Fetch URLs and convert pages into markdown, text, or HTML. |
Agent Orchestration
| Tool | Purpose |
|---|---|
task | Spawn sub-agent sessions. |
task_status | Check sub-agent status. |
plan | Enter or exit planning mode. |
Interaction
| Tool | Purpose |
|---|---|
question | Ask the user structured questions. |
todo | Read task lists. |
todowrite | Write todo items. |
Language Server
| Tool | Purpose |
|---|---|
lsp | Language Server Protocol operations, such as diagnostics or go-to-definition. |
Utilities
| Tool | Purpose |
|---|---|
external_directory | Access directories outside the current project. |
skill | Execute user-defined skills. |
invalid | Handle invalid tool calls. |
Web Search
Two MCP-based providers are described:
| Provider | MCP URL | API key |
|---|---|---|
| Exa | https://mcp.exa.ai/mcp | EXA_API_KEY |
| Parallel | https://search.parallel.ai/mcp | PARALLEL_API_KEY |
Selection can be controlled by:
OPENCODE_WEBSEARCH_PROVIDER- Flags
- Hash-based random selection using session ID checksum
Default behaviour:
| Setting | Value |
|---|---|
| Results | 8 |
| Live crawl | Fallback |
| Timeout | 25 seconds |
Web Fetch
Web fetch is implemented through HTTP requests via Effect's HttpClient, not through a headless browser.
Capabilities include:
- HTML to Markdown conversion via
turndown. - HTML parsing via
htmlparser2. - Cloudflare bot detection retry using honest user-agent fallback.
- Base64 image attachments.
- 5 MB response size limit.
- 30 second default timeout.
- 120 second maximum timeout.
- Output formats:
markdown,text,html.
Headless Browser Support
OpenCode core does not include Puppeteer, Playwright, or another headless browser.
To add browser automation, use one of:
- MCP server.
- Custom tool.
- Skill plugin.
8. Parallelism & Resource Model
Concurrency Model
OpenCode uses Effect fibers on top of the Node.js event loop.
Node.js event loop
-> Effect fiber 1
-> Effect fiber 2
-> Effect fiber 3Fibers are lightweight concurrency units. They are not OS threads.
Fibers Compared with async/await
| Capability | async/await | Effect fibers |
|---|---|---|
| Scoped cleanup | Manual | Built in |
| Interruption | Limited | Built in |
| Controlled concurrency | Manual | Built in |
| Background jobs | Manual | Built in |
| Structured hierarchy | Limited | Built in |
Example Concurrency Patterns
yield* Effect.all([task1, task2, task3], {
concurrency: "unbounded"
})yield* Effect.forEach(tasks, runTask, {
concurrency: 8
})CPU Core Usage
Effect fibers do not automatically use more CPU cores. They run on Node.js's single-threaded event loop.
This model is suitable because most OpenCode work is I/O-bound:
- HTTP calls to LLM providers.
- File reads.
- Network fetches.
- Tool orchestration.
CPU cores would matter more if OpenCode used:
- Worker threads.
- Child processes for CPU-bound work.
- Native parallel execution.
Concurrency Limits
| Operation | Concurrency |
|---|---|
| Tool calls | Unbounded |
| File reads | 8 |
| Grep operations | 16 |
| Network fetches | 4 |
| Sequential operations | 1 |
Background Job System
Location:
packages/opencode/src/background/job.tsConceptual usage:
yield* background.start({
id: "task-123",
type: "task",
run: subagentTask()
})
yield* background.wait({
id: "task-123"
})
yield* background.cancel("task-123")Jobs are stored in an in-memory Map, not Redis or a durable queue.
Resource Allocation
OpenCode does not implement explicit resource quotas for sub-agents.
No built-in quota exists for:
- CPU.
- Memory.
- Network.
- Maximum concurrent sub-agents.
- Maximum tool calls.
Practical constraints come from:
| Constraint source | Example |
|---|---|
| Provider | API rate limits. |
| User | Permission approval prompts. |
| Permission system | Denied tools or denied directories. |
| Local machine | Memory, network, and process limits. |
Heavy Sub-Agent Scenario
If a user spawns many heavy sub-agents:
- Permission checks may deny unsafe tools.
- User approval prompts may multiply.
- LLM providers may rate-limit requests.
- The local machine may run out of memory or become unstable.
OpenCode is therefore better understood as a local developer assistant than a hardened multi-tenant agent platform.
9. Human-in-the-Loop Systems
OpenCode has two distinct human-in-the-loop systems:
- Permission approvals.
- Structured questions.
9.1 Permission System
The permission system asks the user to approve or reject tool operations.
Conceptual example:
yield* permission.ask({
permission: "bash",
patterns: ["*"],
metadata: {
command: "rm -rf /"
}
})Possible outcomes:
| Outcome | Meaning |
|---|---|
once | Allow this single call. |
always | Allow future matching calls and persist the approval. |
reject | Deny the call and reject pending requests for the session. |
Permission Rule Examples
{
bash: "ask",
edit: "allow",
task: "deny",
read: {
"*.env": "ask",
"*": "allow"
}
}| Rule | Meaning |
|---|---|
ask | Pause and request approval. |
allow | Execute without asking. |
deny | Block execution. |
| Patterned rule | Apply different rules by path or pattern. |
Blocking Mechanism
Permission prompts use Effect-based deferred promises.
This means tool execution pauses until the user responds, reducing race conditions and preventing bypass during the blocked state.
9.2 Question System
The question system lets the LLM ask the user structured questions.
Example:
yield* question.ask({
questions: [{
question: "Which framework should we use?",
options: [
{ label: "React", description: "Facebook's library" },
{ label: "Vue", description: "Progressive framework" }
],
multiple: false,
custom: true
}]
})Flow:
LLM calls question tool
-> UI displays dialog
-> User responds
-> Answer is returned to LLM
-> LLM continuesReliability Assessment
Overall reliability: 7 / 10
Strengths
- Blocking via Effect deferred is reliable.
alwaysapprovals are persisted in SQLite.- Session rejection cascades across pending requests.
- Permission rules can be defined per agent and pattern.
Weaknesses
- No timeout for abandoned approval prompts.
- No dedicated permission revocation UI.
- No "deny forever" option for specific patterns.
- Complex sub-agent permission inheritance can be hard to audit.
- No rate limiting on approval prompt spam.
10. Session Management
Location:
packages/opencode/src/session/Session Responsibilities
Sessions manage:
- Multi-turn conversation state.
- Message and part storage.
- Token usage.
- Cost calculation.
- Session forking.
- Parent-child session hierarchy for sub-agents.
- Event emission.
Session States
| State | Meaning |
|---|---|
busy | The LLM or tool loop is processing. |
idle | The session is waiting for input. |
Stored Token Metrics
Sessions track:
- Input tokens.
- Output tokens.
- Reasoning tokens.
- Cache read tokens.
- Cache write tokens.
Event Types
Common emitted events include:
CreatedUpdatedDeletedDiffError
Session Independence
Starting a new chat does not automatically cancel existing running sessions.
Each session can have its own runner and may remain busy until it completes or is explicitly cancelled.
Cancellation endpoint:
POST /session/{sessionID}/abort11. SQLite Database Design
Database Model
OpenCode uses one SQLite database per project.
Typical location:
~/.config/opencode/projects/{projectID}/db.sqliteThere is no Redis, external database, or distributed persistence layer in the core design.
Storage Hierarchy
Session
-> Message
-> Part
-> TodoTables
Session Table
Stores chat/session metadata.
Key columns:
| Column | Purpose |
|---|---|
id | Session ID. |
project_id | Project association. |
parent_id | Parent session for sub-agent hierarchy. |
title | Session title. |
agent | Agent name. |
model | Model metadata. |
cost | Cost tracking. |
tokens_* | Token metrics. |
permission | JSON permission rules. |
revert | JSON revert information. |
| timestamps | Creation/update tracking. |
Indexes:
project_idworkspace_idparent_id
Message Table
Stores user and assistant turns.
Key columns:
| Column | Purpose |
|---|---|
id | Message ID. |
session_id | Parent session. |
time_created | Timeline ordering. |
data | Full JSON message payload. |
Primary query optimisation:
(session_id, time_created, id)Part Table
Stores components of messages.
Part types include:
- Text.
- Tool call.
- Tool result.
- Reasoning.
- Error.
Key columns:
| Column | Purpose |
|---|---|
id | Part ID. |
message_id | Parent message. |
session_id | Parent session. |
data | JSON part payload. |
Indexes:
(message_id, id)session_id
Todo Table
Stores ordered tasks.
Primary key:
(session_id, position)Columns include:
- Content.
- Status.
- Priority.
- Position.
- Timestamps.
Project Table
Stores project metadata:
- ID.
- Worktree.
- Version control system.
- Name.
- Icons.
- Sandboxes.
- Commands.
- Timestamps.
Permission Table
Stores project-level permission rules.
- Primary key:
project_id. - Rules stored as JSON.
Workspace Table
Stores workspace metadata:
- ID.
- Type.
- Name.
- Branch.
- Directory.
- Extra JSON.
- Project association.
- Last-used time.
Account and Account State Tables
Store authentication information:
- OAuth tokens.
- Refresh tokens.
- Expiry.
- Active account or organisation state.
Session Share Table
Stores session sharing metadata:
- Share URL.
- Share ID.
- Secret.
Event Tables
Event-sourcing support:
| Table | Purpose |
|---|---|
event_sequence | Tracks aggregate sequence numbers. |
event | Stores typed events with aggregate ID, sequence, type, and JSON data. |
Database Optimisations
| Technique | Benefit |
|---|---|
| JSON-mode columns | Flexible typed payloads with automatic parsing. |
| Cascade deletes | Cleans up child records. |
| Integer timestamps | Compact and fast comparisons. |
| Text / ULID primary keys | Distributed-friendly IDs. |
| Composite indexes | Efficient timeline and lookup queries. |
| Foreign keys | Referential integrity. |
| Auto timestamps | Simpler lifecycle tracking. |
| Per-project DB | Simple local isolation. |
Optimised For
| Suitable | Not suitable |
|---|---|
| Single-user local development | Multi-user concurrent production use |
| Small-to-medium datasets | Millions of records |
| Read-heavy chat history | Complex analytical workloads |
| Session-based queries | Distributed locking or coordination |
12. Authentication
Location:
packages/opencode/src/auth/Supported Methods
- OAuth.
- API keys.
- Well-known auth discovery.
Storage
Credentials are stored in JSON files with 0o600 file permissions, meaning only the local user should be able to read and write them.
Provider-Specific Handling
Each LLM provider has its own auth handler.
This allows providers to differ in:
- Token format.
- API key location.
- OAuth flow.
- Refresh behaviour.
- Required headers.
13. Server Architecture
Location:
packages/opencode/src/server/Server Capabilities
- HTTP API.
- OpenAPI specification.
- WebSocket updates.
- mDNS local network discovery.
- Configurable CORS.
- Graceful shutdown.
Role in the System
The server enables headless operation.
The following clients can consume the same API:
- TUI.
- Web UI.
- Desktop UI.
- SDK users.
SDK Generation
The SDK in packages/sdk is generated from the OpenAPI specification, keeping API clients aligned with the server contract.
14. Build System
Tooling
OpenCode uses Bun for build and runtime tasks.
Targets
Build output covers 12 platform/architecture combinations:
Linux / macOS / Windows
x
arm64 / x64
x
glibc / musl where applicableBuild Features
- Cross-platform binary generation.
- Embedded web UI bundling.
- Embedded SQLite migrations.
- Optional source maps.
- Smoke testing for the current platform.
- Release automation with GitHub uploads.
15. Testing Strategy
Test Framework
OpenCode uses Bun test.
Test Types
- Unit tests.
- Integration tests.
- CLI tests.
- HTTP API tests.
- Effect-specific tests through a
testEffecthelper. - Snapshot tests.
Fixtures and Test Utilities
- Temporary directories.
- Test providers.
- Mock services.
- Stable snapshot outputs.
Testing Guidance
Documented testing practices include:
- Avoid arbitrary
sleepcalls for readiness. - Prefer Effect synchronisation primitives.
- Use dedicated test guides such as:
test/AGENTS.mdtest/EFFECT_TEST_MIGRATION.md
16. Security Model
Strengths
- Multiple authentication methods.
- Credentials stored with restricted file permissions.
- Default-deny permission posture.
- Per-agent permission isolation.
- Session-level rejection cascades.
- Schema-based input validation.
- Sub-agent permission inheritance.
Risks and Weaknesses
| Risk | Explanation |
|---|---|
| API keys in local JSON | File permissions help, but secrets still exist on disk. |
| No resource quotas | Sub-agents can consume excessive API/network/local resources. |
| No permission revocation UI | Users may need to edit config manually. |
| No approval timeout | Execution can hang forever if the user walks away. |
| Complex inheritance | Sub-agent permission logic may be hard to audit. |
| No approval spam guard | Many tool calls can create many permission prompts. |
Security Interpretation
OpenCode is designed for a trusted local developer environment.
It provides meaningful guardrails, especially around tools and permissions, but it is not a hardened multi-user sandbox or production agent execution platform.
17. Explicit Non-Goals / Missing Capabilities
| Capability | Status |
|---|---|
| Headless browser | Not included. |
| Redis / external cache | Not used. |
| Distributed locks | Not used. |
| Durable task queue | Not used; background jobs are in-memory. |
| Resource quotas for sub-agents | Not implemented. |
| Maximum sub-agent limit | No hard limit. |
| Permission revocation UI | Not included. |
| Approval timeout | Not included. |
| CPU / OS-thread parallelism | Not used for Effect fibers. |
| Core orchestration framework | Not based on LangChain, CrewAI, AutoGen, etc. |
18. Design Philosophy
1. Local-First and Single-User
OpenCode prioritises local control and developer ownership over multi-tenant cloud orchestration.
2. Trust the Developer
The system assumes the developer is the operator and provides permission controls rather than strict resource policing.
3. Service-Oriented with Effect
Each major capability is a service with interface, implementation, and dependency layer.
Effect provides:
- Typed error handling.
- Structured concurrency.
- Dependency injection.
- Interruption.
- Resource safety.
4. Protocol-Agnostic LLM Routing
The LLM layer separates protocol, endpoint, authentication, and stream framing so providers can vary without rewriting orchestration.
5. Tools Are the Extension Point
The orchestration layer is general. Domain-specific behaviour is mainly in:
- Tool implementations.
- Agent prompts.
- Agent configs.
- Permission rule names.
6. MCP for External Extensibility
MCP is used to connect external services and tools without embedding every capability into core.
7. Sessions Are the Unit of Isolation
Sessions isolate:
- Message history.
- Agent state.
- Parent-child relationships.
- Permission state.
- Running jobs.
8. Permission Inheritance Is the Safety Guarantee
Sub-agents inherit constraints from their parent so delegation does not become privilege escalation.
19. Generalising Beyond Coding
Core Claim
OpenCode's harness is mostly domain-agnostic.
The coding-specific parts are:
- Tool implementations.
- Agent configurations.
- Prompts.
- Permission names and rules.
The reusable parts are:
- Agent orchestration.
- Session management.
- Permission evaluation.
- Sub-agent spawning.
- Tool registry.
- Human-in-the-loop systems.
- Effect-based concurrency.
- MCP integration.
- Background jobs.
- HTTP server and SDK generation.
Domain Mapping Examples
| Domain | Custom tools | Custom agents |
|---|---|---|
| Research assistant | websearch, paper_fetch, citation_extract, summary_generate | researcher, writer, analyst |
| Financial analyst | stock_query, portfolio_analyze, trade_execute, report_generate | analyst, trader, risk_assessor |
| Healthcare workflows | patient_query, diagnosis_assist, treatment_plan | clinician, researcher, reviewer |
| Marketing | campaign_create, analytics_fetch, content_generate | strategist, copywriter, analyst |
Three Generalisation Strategies
1. Fork OpenCode
Keep the core and replace:
- Tools.
- Agents.
- Prompts.
- Domain-specific permissions.
Best when you want a fast domain-specific fork.
2. Extract a Core Library
Create something like:
@your-org/agent-harnessThen make OpenCode one implementation of that harness.
Best when you want multiple domain applications on the same orchestration core.
3. Template System
Use OpenCode as a scaffold that generates domain-specific configurations.
Best when you want repeatable setup for different teams or use cases.
20. Operational Checklists
Architecture Review Checklist
- Identify the session lifecycle.
- Identify primary and sub-agent modes.
- Review permission rules for each agent.
- Confirm sub-agents cannot exceed parent permissions.
- Review tool registry sources.
- Confirm which tools require user approval.
- Review database persistence paths.
- Confirm event flow from backend to UI.
- Check whether background jobs need durability.
- Check whether rate limits or quotas are needed.
Security Review Checklist
- Review credential storage paths and file permissions.
- Review default permission posture.
- Audit high-risk tools: shell, write, edit, external directory.
- Audit sub-agent permission inheritance.
- Check whether approval prompts can hang indefinitely.
- Check whether permission revocation is documented.
- Check whether prompt spam or tool spam can overwhelm users.
- Decide whether resource quotas are required for your use case.
Generalisation Checklist
- List domain-specific tools.
- List domain-specific agents.
- Define permission names and default policy.
- Decide which tools require human approval.
- Decide whether sessions remain the right isolation unit.
- Decide whether SQLite is sufficient.
- Decide whether background jobs need durable queues.
- Decide whether MCP integrations are enough.
- Define test fixtures for domain-specific workflows.
21. Frequently Asked Questions
Is OpenCode based on LangChain, CrewAI, AutoGen, or a similar orchestration framework?
No. The analysed design indicates that the orchestration layer is custom-built. External libraries are used for infrastructure, provider transport, validation, persistence, and runtime support.
Does OpenCode use a headless browser?
No. Core web fetching uses HTTP requests and parsing. Browser automation would need to be added through MCP, a custom tool, or a skill/plugin.
Do Effect fibers use multiple CPU cores?
No. Effect fibers run on Node.js's single-threaded event loop. They improve structured concurrency and I/O orchestration, but they are not OS threads.
Can sub-agents escalate permissions?
The intended safety model prevents this. Effective sub-agent permissions are derived from parent permissions and additional default denies.
Is the database suitable for production multi-user workloads?
Not as described. The database design is best suited for local, single-user, project-scoped workflows.
What is the most reusable part of OpenCode?
The session + agent + tool + permission harness is the most reusable part. The coding domain can be swapped out by replacing tools, prompts, and agent definitions.
22. Quick Reference
Most Important Concepts
| Concept | Why it matters |
|---|---|
| Session | Unit of state, isolation, persistence, and execution. |
| Agent | Defines role, tools, prompt, model, and permissions. |
| Tool | Primary extension mechanism. |
| Permission inheritance | Core safety model for sub-agent delegation. |
| Effect fibers | Structured concurrency model. |
| SQLite per project | Local persistence model. |
| MCP | External integration mechanism. |
Key Files / Areas to Inspect
| Area | Path |
|---|---|
| Agents | packages/opencode/src/agent/ |
| Sessions | packages/opencode/src/session/ |
| Tools | packages/opencode/src/tool/ |
| LLM routes | packages/llm/src/route/ |
| Tool runtime | packages/llm/src/tool-runtime.ts |
| Permissions | packages/opencode/src/permission/ |
| Sub-agent permissions | packages/opencode/src/agent/subagent-permissions.ts |
| Questions | packages/opencode/src/question/ |
| Background jobs | packages/opencode/src/background/ |
| Database schema | packages/opencode/src/storage/ |
| Server | packages/opencode/src/server/ |
| Migrations | migration/ |
23. Suggested Next Improvements for This Knowledge Base
- Add links to exact source files once repository URLs are available.
- Add architecture diagrams for:
- Session lifecycle.
- Tool calling loop.
- Sub-agent permission derivation.
- Database entity relationships.
- Add code snippets from actual implementation files.
- Add a risk register with severity and mitigation.
- Add a migration guide for extracting the harness into another domain.
- Add a comparison table against LangChain, CrewAI, AutoGen, and Claude Code-style local assistants.