Based on deep analysis of sst/opencode internals. Prioritized by impact and effort.
Our setup is 80% optimized. Key gaps:
- No doom loop detection (agents can infinite loop)
- No streaming progress from tools
- Flat agent structure (no nesting)
- Missing abort signal handling in custom tools
- No output size limits in custom tools
What: Track repeated identical tool calls, break infinite loops.
Why: OpenCode detects when same tool+args called 3x and asks permission. We don't - agents can burn tokens forever.
Implementation:
// In swarm plugin or tool wrapper
const DOOM_LOOP_THRESHOLD = 3;
const recentCalls: Map<
string,
{ tool: string; args: string; count: number }[]
> = new Map();
function checkDoomLoop(sessionID: string, tool: string, args: any): boolean {
const key = `${tool}:${JSON.stringify(args)}`;
const calls = recentCalls.get(sessionID) || [];
const matching = calls.filter((c) => `${c.tool}:${c.args}` === key);
if (matching.length >= DOOM_LOOP_THRESHOLD) {
return true; // Doom loop detected
}
calls.push({ tool, args: JSON.stringify(args), count: 1 });
if (calls.length > 10) calls.shift(); // Keep last 10
recentCalls.set(sessionID, calls);
return false;
}Files: plugin/swarm.ts
What: Propagate cancellation to long-running operations.
Why: OpenCode tools all respect ctx.abort. Ours don't - cancelled operations keep running.
Implementation:
// In each tool's execute function
async execute(args, ctx) {
const controller = new AbortController();
ctx.abort?.addEventListener('abort', () => controller.abort());
// Pass to fetch, spawn, etc.
const result = await fetch(url, { signal: controller.signal });
}Files: All tools in tool/*.ts
What: Truncate tool outputs that exceed 30K chars.
Why: OpenCode caps at 30K. Large outputs blow context window.
Implementation:
const MAX_OUTPUT = 30_000;
function truncateOutput(output: string): string {
if (output.length <= MAX_OUTPUT) return output;
return (
output.slice(0, MAX_OUTPUT) +
`\n\n[Output truncated at ${MAX_OUTPUT} chars. ${output.length - MAX_OUTPUT} chars omitted.]`
);
}Files: Wrapper in tool/ or each tool individually
What: Fast codebase search specialist with no write permissions.
Why: OpenCode has explore agent that's read-only. Safer for quick searches.
Implementation:
# agent/explore.md
---
name: explore
description: Fast codebase exploration - read-only, no modifications
mode: subagent
tools:
edit: false
write: false
bash: false
permission:
bash:
"rg *": allow
"git log*": allow
"git show*": allow
"find * -type f*": allow
"*": deny
---
You are a read-only codebase explorer. Search, read, analyze - never modify.Files: agent/explore.md
What: Stream progress updates during tool execution.
Why: OpenCode tools call ctx.metadata({ output }) during execution. Users see real-time progress.
Current gap: Our tools return all-or-nothing. User sees nothing until complete.
Implementation: Requires OpenCode plugin API support for ctx.metadata(). Check if available.
What: Allow agent/swarm/planner.md → agent name swarm/planner.
Why: Better organization as agent count grows.
Implementation: Already supported by OpenCode! Just use nested paths:
agent/
swarm/
planner.md → "swarm/planner"
worker.md → "swarm/worker"
security/
auditor.md → "security/auditor"
Files: Reorganize agent/*.md into subdirectories
What: Sort search results by modification time (newest first).
Why: OpenCode's glob/grep tools do this. More relevant results surface first.
Implementation:
// In cass_search, grep results, etc.
results.sort((a, b) => b.mtime - a.mtime);Files: tool/cass.ts, any search tools
What: Track when beads were last read, detect concurrent modifications.
Why: OpenCode tracks file reads per session, prevents stale overwrites.
Implementation:
const beadReadTimes: Map<string, Map<string, Date>> = new Map();
function recordBeadRead(sessionID: string, beadID: string) {
if (!beadReadTimes.has(sessionID)) beadReadTimes.set(sessionID, new Map());
beadReadTimes.get(sessionID)!.set(beadID, new Date());
}
function assertBeadFresh(
sessionID: string,
beadID: string,
lastModified: Date,
) {
const readTime = beadReadTimes.get(sessionID)?.get(beadID);
if (!readTime) throw new Error(`Must read bead ${beadID} before modifying`);
if (lastModified > readTime)
throw new Error(`Bead ${beadID} modified since last read`);
}Files: plugin/swarm.ts or new tool/bead-time.ts
What: Pattern-based bash command permissions like OpenCode.
Why: Finer control than boolean allow/deny.
Example:
permission:
bash:
"git *": allow
"npm test*": allow
"rm -rf *": deny
"*": askStatus: May already be supported - check OpenCode docs.
What: Track parent-child relationships between swarm sessions.
Why: OpenCode tracks parentID for subagent sessions. Useful for debugging swarm lineage.
Implementation: Add parentSessionID to Agent Mail messages or bead metadata.
What: tool.execute.before and tool.execute.after hooks.
Why: Enables logging, metrics, input validation without modifying each tool.
Status: Requires OpenCode plugin API. Check if Plugin.trigger() is exposed.
These areas we're ahead of OpenCode:
- BeadTree decomposition - Structured task breakdown vs ad-hoc
- Agent Mail coordination - Explicit messaging vs implicit sessions
- File reservations - Pre-spawn conflict detection
- Learning system - Outcome tracking, pattern maturity
- UBS scanning - Auto bug scan on completion
- CASS history - Cross-agent session search
Hidden Features to Explore
From context analysis, OpenCode has features we might not be using:
- Session sharing -
share: "auto"in config - Session revert - Git snapshot rollback
- Doom loop permission -
permission.doom_loop: "ask" - Experimental flags:
OPENCODE_DISABLE_PRUNE- Keep all tool outputsOPENCODE_DISABLE_AUTOCOMPACT- Manual summarization onlyOPENCODE_EXPERIMENTAL_WATCHER- File change watching
Week 1: ✅ COMPLETE
[x] Doom loop detection (swarm plugin)
[x] Abort signal handling (all tools)
[x] Output size limits (tool-utils.ts)
[x] Explore agent (agent/explore.md)
[x] Repo tooling optimizations (caching, parallel, GitHub token)
Week 2:
[ ] Nested agent directories (reorganize)
[ ] mtime sorting (cass, search tools)
Week 3:
[ ] FileTime tracking for beads
[ ] Streaming metadata (if API available)
Backlog:
[ ] Permission wildcards
[ ] Session hierarchy
[ ] Plugin hooks
knowledge/opencode-plugins.md- Plugin system architectureknowledge/opencode-agents.md- Agent/subagent systemknowledge/opencode-tools.md- Built-in tool implementationsknowledge/opencode-context.md- Session/context management