The all-in-one OpenCode plugin for autonomous development workflows.
Iterative loops · Multi-agent orchestration · Code graph · Sandboxed execution · Smart harness
opencode-forgecode is a single plugin for OpenCode that gives your AI agents the ability to plan, execute, review, and iterate — autonomously. It combines two systems into one cohesive runtime:
| Forge | Iterative development loops with git worktree isolation, session-scoped plans, code-graph indexing, Docker/Firejail/Bubblewrap sandboxing, background tasks, and a TUI sidebar |
| Harness | Summary-frame compaction, output truncation, doom-loop detection, pending-todo reminders, undo snapshots, and the multi-agent system (9 specialized agents) |
Both systems share the same plugin entrypoint — no conflicts over hooks, no duplicate compaction, no fighting for tool.execute.*.
npm add opencode-forgecodeopencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-forgecode@latest"],
"compaction": { "auto": true, "prune": true },
"agent": {
"forge": { "model": "anthropic/claude-opus-4.7" },
"muse": { "model": "openai/gpt-5.4" },
"sage": { "model": "openai/gpt-5.4-mini" }
}
}~/.config/opencode/tui.json:
{
"$schema": "https://opencode.ai/tui.json",
"plugin": ["opencode-forgecode@latest"]
}On first run the plugin auto-creates ~/.config/opencode/forge-config.jsonc with sensible defaults. Run oc-forgecode doctor to verify everything is wired correctly.
The plugin ships 9 specialized agents, all registered automatically on load:
| Agent | Role | Mode | Description |
|---|---|---|---|
| forge | Coder | primary | Graph-first code discovery, read/write/bash access, harness-aware. The workhorse. |
| muse | Planner | primary | Strategic planning with KV-backed plan store. All file edits denied. Two-step approval flow before any execution. |
| sage | Reviewer | subagent | Dual-mode: code review on diffs/PRs or deep research on architecture. Read-only, temp 0.0. |
| Agent | Role | Description |
|---|---|---|
| explore | Explorer | Parallel codebase discovery — optimized for broad, open-ended questions |
| oracle | Q&A | Short, precise answers to specific codebase questions |
| librarian | Researcher | Information retrieval using read-only tools |
| prometheus | Generator | Scaffolding, boilerplate, migrations, templates |
| metis | Meta-agent | Analyzes context and recommends which agent to use next |
| caveman | Efficiency mode | Cuts ~75% output tokens while keeping technical substance |
Agents can call each other via bg_spawn (Sisyphus-style delegation) or the tool_supported agent-as-tool pattern.
| Tool | Description |
|---|---|
plan-write |
Store a plan skeleton (auto-keyed to plan:{sessionID}, 7-day TTL, 8 KB soft cap) |
plan-append |
Append a section to the stored plan (for incremental, timeout-safe writes) |
plan-edit |
Find-and-replace within the stored plan (supports replace_all / occurrence) |
plan-read |
Retrieve plan with pagination and pattern search |
plan-execute |
Launch plan execution as a new forge session |
review-write |
Store review findings (file, line, severity, description) |
review-read |
Query findings by file path or regex |
review-delete |
Remove a finding by file and line |
| Tool | Description |
|---|---|
loop |
Run an iterative dev loop. worktree: true for git worktree isolation |
loop-status |
List active loops or get details by name. restart to resume |
loop-cancel |
Cancel a running loop |
| Tool | Description |
|---|---|
graph-status |
Check indexing status or trigger a re-scan |
graph-query |
File-level: top_files, file_deps, file_dependents, cochanges, blast_radius, packages, file_symbols |
graph-symbols |
Symbol-level: find, search, signature, callers, callees, blast_radius, call_cycles |
graph-analyze |
Quality: unused_exports, duplication, near_duplicates |
| Tool | Description |
|---|---|
patch |
Hash-anchored LINE#HASH replacements — resilient to concurrent edits |
multi_patch |
Atomic multi-replacement on a single file (tempfile + rename) |
fs_undo |
Restore from automatic pre-edit snapshots |
| Tool | Description |
|---|---|
lsp_diagnostics |
Fetch diagnostics from language servers |
lsp_hover |
Get type info and docs for a symbol |
lsp_references |
Find all references to a symbol |
lsp_definition |
Jump to definition |
lsp_code_actions |
Get available code actions |
lsp_rename |
Rename a symbol across the project |
ast_search |
Structural code search via ast-grep patterns |
ast_rewrite |
Structural code rewrites via ast-grep |
sem_search |
Semantic search with embeddings (OpenAI / fastembed / Voyage) |
code-stats |
Language / LOC summary via tokei → scc → rg fallback |
| Tool | Description |
|---|---|
bg_spawn |
Launch an agent as a background task |
bg_status |
Check status of background tasks |
bg_wait |
Wait for a background task to complete |
bg_cancel |
Cancel a running background task |
| Command | Description | Agent |
|---|---|---|
/review |
Run a code review on current changes | sage |
/loop |
Start an iterative development loop | forge |
/loop-status |
Check status of all active loops | forge |
/loop-cancel |
Cancel the active loop | forge |
oc-forgecode <command> [options]| Command | Description |
|---|---|
doctor |
Validate config, DB, sandbox, and runtime health |
upgrade |
Check for and install plugin updates |
stats |
Display session and loop statistics |
status [name] |
Detailed loop status (iterations, tokens, phase) |
cancel <name> |
Cancel and clean up a worktree loop |
restart <name> |
Resume a cancelled/failed loop |
graph status |
Show graph indexing state |
graph scan |
Trigger a full graph re-scan |
graph list |
List all cached graph indexes |
graph remove <target> |
Remove a specific graph cache |
graph cleanup --days <n> |
Clean up caches older than N days |
ci |
Headless loop execution for CI/CD pipelines |
mcp |
MCP server management |
Global flags: --project, -p <name> · --dir, -d <path> · --db-path <path> · --help, -h
┌──────────────────────────────────────────────────────────┐
│ OpenCode Host │
│ │
│ opencode.json ──► plugin: ["opencode-forgecode@latest"] │
└──────────────┬───────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────┐
│ opencode-forgecode plugin │
│ │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ 9 Agents │ │ Hooks Pipeline │ │
│ │ forge·muse·sage │ │ chat.message │ │
│ │ explore·oracle │ │ tool.execute.before/after │ │
│ │ librarian │ │ event │ │
│ │ prometheus │ │ permission.ask │ │
│ │ metis·caveman │ │ session.compacting │ │
│ └──────────────────┘ │ messages.transform │ │
│ └──────────────────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ Services │ │ Runtime │ │
│ │ KV Store │ │ Budget Enforcer │ │
│ │ Loop Service │ │ Session Recovery │ │
│ │ Graph Service │ │ Telemetry Collector │ │
│ │ Sandbox Manager │ │ Intent Router │ │
│ │ LSP Pool │ │ Restricted Shell │ │
│ │ Background Mgr │ │ Skill Loader │ │
│ │ MCP Registry │ │ Context Injection │ │
│ │ Host Tools (rg) │ │ Search Renderer │ │
│ └──────────────────┘ └──────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Storage: SQLite (KV + Graph + Telemetry) │ │
│ │ ~/.local/share/opencode/forge/ │ │
│ └────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────┘
- Leader/Follower graph — Multiple plugin instances (e.g., across worktrees) coordinate via a lock file + Unix domain socket IPC. Only the leader writes; followers read over RPC.
- Soft-fail everywhere — If the DB can't open, the plugin falls back to in-memory KV. If the graph can't initialize, tools gracefully report "unavailable". Nothing crashes the session.
- Per-agent budgets —
AgentBudgetEnforcertracks turns, tokens, requests, and tool failures per agent with configurablewarn→stoppolicies. - Session recovery —
SessionRecoveryManagerhandles context-overflow, timeouts, and overload errors with automatic retry and model fallback chains. - Host-side fast tools — When
rg(ripgrep) is available,grep/globtool calls are intercepted before reaching the sandbox and served via ripgrep with submatch-windowed, grouped output — reducing token usage and latency.
The plugin config lives at ~/.config/opencode/forge-config.jsonc (JSONC format — comments allowed).
Per-agent budgets
{
"agents": {
"forge": {
"budget": {
"maxTurns": 50,
"maxTokensPerSession": 500000,
"maxToolFailuresPerTurn": 5,
},
},
},
}Fallback models
{
"agents": {
"forge": {
"fallbackModels": [
{ "provider": "anthropic", "model": "claude-sonnet-4" },
{ "provider": "openai", "model": "gpt-5.4-mini" },
],
},
},
}Restricted shell
{
"restrictedShell": {
"enabled": true,
"dangerousPatterns": ["rm -rf /", ":(){ :|:& };:"],
"allowlist": ["npm test", "bun test", "make"],
},
}Context injection
{
"contextInjection": {
"enabled": true,
"rules": [
{
"pattern": "**/*.test.ts",
"content": "Follow the testing conventions in TESTING.md",
"priority": 10,
},
],
},
}Skill loader
{
"skills": {
"enabled": true,
"directories": [".opencode/skills", "~/.config/opencode/skills"],
},
}LSP integration
{
"lsp": {
"enabled": true,
"servers": {
"typescript": { "command": "typescript-language-server", "args": ["--stdio"] },
"python": { "command": "pylsp" },
},
},
}Host-side fast tools (ripgrep)
{
"host": {
// When true and `rg` is on PATH, intercept grep/glob tool calls
// and serve them via ripgrep with grouped, submatch-windowed output.
// Defaults to true.
"fastGrep": true,
},
}Background tasks
{
"background": {
"enabled": true,
"maxConcurrent": 5,
"perModelLimit": 2,
"pollIntervalMs": 3000,
"idleTimeoutMs": 10000,
},
}Telemetry (local-only, opt-in)
{
"telemetry": {
"enabled": true, // SQLite-backed, never leaves your machine
},
}Built-in MCPs
{
"mcp": {
"websearch": { "provider": "tavily", "apiKey": "tvly-..." },
"context7": { "apiKey": "..." },
"grepApp": { "enabled": true },
},
}| Section | Key | Default | Description |
|---|---|---|---|
| — | dataDir |
~/.local/share/opencode/forge |
Plugin data directory |
| — | defaultKvTtlMs |
604800000 (7d) |
Default TTL for KV entries |
logging |
enabled / debug / file |
false / false / auto |
File-based logging |
graph |
enabled / autoScan / watch / debounceMs |
true / true / true / 100 |
Code graph indexing |
loop |
enabled / defaultMaxIterations / defaultAudit / cleanupWorktree / stallTimeoutMs / minAudits |
true / 15 / true / false / 60000 / 1 |
Loop execution |
sandbox |
mode / image |
"off" / "oc-forge-sandbox:latest" |
Sandboxed execution |
harness |
enabled / doomLoopThreshold / pendingTodosReminder / snapshots / compaction / hashAnchoredPatch |
true / 3 / true / true / true / true |
Harness runtime |
harness.truncation |
enabled |
true |
Output truncation (shell 200+200 lines @ 500 chars/line, search 200 lines @ 400 chars/line, fetch 40K chars) |
compaction |
customPrompt / maxContextTokens |
true / 0 |
Summary-frame compaction fallback |
messagesTransform |
enabled / debug |
true / false |
Message pipeline |
host |
fastGrep |
true |
Intercept grep/glob via ripgrep when rg is on PATH |
Tracks tool call signatures per session. When it detects 3+ consecutive identical or cyclic patterns, it injects a reminder via tui.appendPrompt asking the agent to change strategy.
Automatically trims long tool output in tool.execute.after:
- Shell/bash: 200 lines head + 200 lines tail, 500 chars/line max
- Search/grep: 200 lines max, 400 chars/line max (with per-file match distribution banner)
- Web fetch: 40,000 chars max
Overrides experimental.session.compacting with an intelligent summary frame that preserves key context, decisions, and in-progress state. Falls back to a custom compaction prompt when no cached messages are available.
Before every write / edit / multi_patch / patch, the harness snapshots the file at:
<dataDir>/snapshots/<sessionId>/<timestamp>-<fileTag>.bak
Restore with:
fs_undo file="src/foo.ts" # latest snapshot
fs_undo file="src/foo.ts" steps=3 # 3 versions back
Tracks todo.updated events. When a session goes idle with pending or in-progress todos, appends a reminder with the outstanding items.
When rg (ripgrep) is on PATH, the plugin intercepts grep and glob tool calls before they reach the sandbox and serves them via ripgrep. This provides:
- Submatch-windowed output — only ±30 chars around each match are returned, dramatically reducing token consumption on large files
- Grouped results — matches are grouped by file with a per-file match distribution banner
- Automatic fallback — if
rgisn't available or a sandbox is active, calls pass through to the default implementation
Disable with "host": { "fastGrep": false } in forge-config.jsonc.
| Plugin | Status | Notes |
|---|---|---|
opencode-forgecode |
✅ This plugin | Owns compaction, hooks, agents, tools |
@plannotator/opencode |
✅ Compatible | Planning layer complements forge plans |
opencode-forge (upstream) |
❌ Do not stack | Already included — running both doubles hooks and graph scans |
@tarquinen/opencode-dcp |
Safe as upstream pruning layer. Let forgecode own final compaction |
Rule of thumb: opencode-forgecode must own the final experimental.session.compacting prompt. If using DCP, treat it as proactive pruning only.
Use the built-in CI mode for headless loop execution in pipelines:
- name: Run forge loop
run: npx oc-forgecode ci --task "Fix failing tests" --output jsonSupports --output json|markdown|text and automatic PR comment posting.
bun install
bun run typecheck # TypeScript type checking
bun run lint # Linting
bun test # 756+ tests
bun run build # Emit dist/MIT
{ // Storage (empty = ~/.local/share/opencode/forge) "dataDir": "", // Logging "logging": { "enabled": false, "debug": false }, // Graph indexing "graph": { "enabled": true, "autoScan": true, // Scan on startup "watch": true, // Watch for file changes "debounceMs": 100, }, // Iterative loops "loop": { "enabled": true, "defaultMaxIterations": 15, "defaultAudit": true, "cleanupWorktree": false, "stallTimeoutMs": 60000, }, // Sandbox (off | docker | sandbox-exec | bubblewrap | firejail) "sandbox": { "mode": "off", "image": "oc-forge-sandbox:latest" }, // Harness (doom-loop, truncation, snapshots, compaction) "harness": { "enabled": true, "doomLoopThreshold": 3, "pendingTodosReminder": true, "snapshots": true, "compaction": true, "hashAnchoredPatch": true, "truncation": { "enabled": true }, }, }