Status: Accepted
Date: 2026-05-01
Hub subcommand clicks from the TUI dialog were submitting directly to session.command() or session.prompt(), causing a 3+ minute LLM inference wait before any feedback to the user.
Subcommand clicks will:
- Show a toast notification instantly (pure TUI rendering, zero latency)
- Use
appendPrompt()to pre-fill the prompt bar with the command text - NOT call
session.command(),session.prompt(), or any LLM-involved API
The user then presses Enter when ready, which triggers the normal LLM pipeline.
- Instant feedback for the click action
- User controls when the 90-second LLM wait starts
- No way to bypass LLM inference in the current SDK — this is the best achievable UX
appendPrompt()may not work visually in all OpenCode versions- The 90+ second LLM wait is still unavoidable when the user presses Enter
- A proper fix requires an SDK-level API for tool/command execution without AI
- session.command(): Still calls LLM, 3+ minute wait
- session.prompt(): Still calls LLM, 3+ minute wait
- Pre-warming sessions: Doesn't help with cloud API cold-start
- Plugin hook short-circuit:
command.execute.beforecannot skip execution
Status: Accepted
Date: 2026-05-04
The vectorize-context skill required manual invocation (node vectorize.mjs) to index .opencode/context/ files into sqlite-vec. Users had to remember to trigger it, and the DB could get stale between runs.
Vector indexing uses lazy freshness — ensureIndexed() is called automatically on every queryChunks() call. It stats all files, re-indexes only stale ones, and returns instantly if nothing changed. The ML model (~200MB) only loads when there's actual indexing work.
- Users never need to remember to index
- Fast path (no changes) costs only filesystem stats (~8-20ms)
- Write operations (hub context saves, direct edits, file deletions) all get picked up automatically on next query
- The common case (no change) is nearly free
skills/vectorize-context/scripts/veclib.mjs— shared library exportingensureIndexed(),queryChunks(),getIndexStats()- CLI scripts became thin wrappers
- File paths stored as relative paths in DB for cross-project portability
- Deleted files have their chunks cleaned up automatically
Status: Accepted
Date: 2026-05-04
When a user types /orchestrate fix this bug without specifying a subcommand, there was no mechanism to route them to deep or remediate. Same for /ideation and /harvest-context.
Create intent-detecting router scripts that classify user requests across multi-dimensional profiles and score against subcommand profiles. Each profile covers 5-8 dimensions with normalized 0-1 scores.
- Subcommand profiles as data make adding new subcommands trivial
- Multi-dimensional scoring handles ambiguous inputs naturally
- Anti-keywords prevent false positives
- stderr/stdout separation (diagnostics vs machine output) lets CLI and agents use the same scripts
skills/orchestrate-router/scripts/route-orchestrate.mjs— 27 subcommandsskills/orchestrate-router/scripts/route-ideation.mjs— 21 subcommandsskills/orchestrate-router/scripts/route-harvest.mjs— 13 subcommands + auto-vectorize
Status: Accepted
Date: 2026-05-04
OpenCode has a plugin system with 10 hook types, 2 independent context injection mechanisms, and stateful patterns — but no consolidated skill existed to guide users through plugin creation.
Create opencode-plugin-creator skill with:
- Hook API reference extracted from
plugins/hubs-plugin.ts(the production plugin) - Templates for minimal hook, stateful, and TUI plugins
- Documentation of the two distinct context injection mechanisms
OpenCode has two independent context injection mechanisms:
experimental.chat.system.transform— injected into system prompt every turn viaoutput.system[]. RequiresqueueContextMessage()/consumeContextMessages()async pattern.experimental.session.compacting— survives context window compression viaoutput.context[](plain markdown). Both mechanisms can be used in the same plugin and serve different purposes.
Status: Accepted
Date: 2026-05-04
Existing skills cover specific creation tasks (agent-creator, skill-creator, command-creator, plugin-creator) but there was no holistic config management skill for validation, inspection, cross-surface integration, and project .opencode/ setup.
Create opencode-configure as a coordinator skill that covers all 8 config surfaces. It delegates to existing creator skills for focused tasks and provides:
- 20-item validation checklist covering JSONC, paths, frontmatter, plugins, MCP, gitignore
- Config inspection and repair workflows
- Project
.opencode/directory structure setup - Cross-surface integration verification
Single-creation skills (agent, skill, command, plugin) are well-covered by existing creators. What was missing was the holistic view — someone who says "fix my config" or "set up a project .opencode/" needs to touch multiple surfaces at once.
Status: Accepted
Date: 2026-06-08
The existing model lineup lacked a model specialized for agent orchestration and long-running agent workflows. Available models were either general-purpose, fast-reasoning, or extended-context, but none specifically targeted multi-step agentic loops with tool calling at scale.
Add nemotron-3-ultra:cloud (NVIDIA Nemotron 3 Ultra) as an available Ollama cloud model with:
- 256K context window / 131K output limit
- Best For: agent orchestration, long-running agents, deep research
- 550B parameters (55B active per token) — efficient for its class
- Built for long-running agents — tuned for orchestration, coding agents, and complex enterprise workflows
- 1M token native context (cloud version limited to 256K)
- Optimized for tool calling across hundreds of steps — directly relevant to Hubs orchestration patterns
- The existing model mix (pro/flash/glm/kimi/minimax/qwen) had no specific "agent orchestration" specialist
- Users can now select a model optimized for
/orchestrateworkloads - 256K context is smaller than the pro/flash 1M models, but output of 131K matches flash
- Model is listed prominently as the third entry (after flash) in the AGENTS.md table
Status: Proposed — Design Analysis Complete
Date: 2026-06-09
Current agent orchestration patterns treat agents as "ant-agents" — single-purpose workers that execute a task, then pass their raw output to a separate reviewer agent. This creates high overhead: 2+ handoffs per quality cycle, context serialization between agents, and a reviewer bottleneck when many agents produce output simultaneously.
The biological analogy is instructive: ants do not self-preserve or self-critique; they follow their assignment unquestioningly. Humans in skilled roles internalize quality standards and self-correct before presenting work.
A design analysis was conducted (via deep-thinker agent) evaluating whether a "craftsman agent" pattern — where each agent carries an internal self-critique loop — is theoretically sound and feasible.
-
The pattern is sound as a component, not a standalone replacement. Self-critique improves quality per agent, but external verification is still required for convergence guarantees.
-
"Incentivization" is achievable through structured prompt sequencing, not true internal motivation. Five levers exist: role-identity framing, accountability hooks, structured generation protocols, contrastive examples, and orchestrator-level meta-incentives.
-
Composition is key — the craftsman pattern nests inside existing patterns:
ralph + craftsman: outer loop guarantees convergence, inner loop polishes each submissionultrawork + craftsman: each parallel lane self-polishes independentlyteam + craftsman: reviewer focuses on composition, not individual quality
-
Risks are manageable: over-engineering (cap iterations), under-critique (require written critique), same-model blind spots (externally-authored checklists), false quality (never skip external verification for critical tasks).
craftsman — one word, self-evident in software engineering, pairs naturally with existing patterns.
If adopted: implement as an orchestration pattern option that injects a self-critique quality charter into each agent's context, with configurable max_inner_iterations and an externally-authored checklist.
Status: Accepted Date: 2026-06-12
The opencode.jsonc templates and provision script were injecting invalid top-level keys (agents: { paths: [...] }, commands: { paths: [...] }, agentPaths: [...]) that are not part of the OpenCode config schema. These caused OpenCode's config loader to reject the file, preventing OpenCode from running in projects initialized with /init-project.
Remove all invalid top-level keys from templates and generation code. Agents, commands, tools, and rules are auto-discovered from their respective .opencode/ subdirectories — no config registration needed. The only valid key for pointing to additional directories is skills: { paths: [...] }.
- The official schema at
https://opencode.ai/config.jsonhasadditionalProperties: falseon the Config object — any unrecognized key causes rejection - OpenCode auto-discovers agents from
agents/, commands fromcommands/, tools fromtools/, rules fromrules/— no config needed - The
skillskey is the exception because skill directories can be at arbitrary paths
- Fixed in:
03-configuration.mdtemplate,opencode.jsonc.template,provision.mjsPhase 6,provision/SKILL.md, and 3.documentation/files - Created
config-syncskill to prevent future drift — fetches schema fromopencode.ai/config.jsonand validates
Status: Accepted Date: 2026-06-12
10 of 29 agent definition files used plain markdown without the <Agent_Prompt> XML wrapper convention. This created an inconsistency where some agents had structured prompt sections (<Role>, <Constraints>, <Success_Criteria>) and others had free-form text. The non-compliant agents were: code-reviewer, code-simplifier, commit-drafter, config-orchestrator, deep-thinker, effort-estimator, prompt-simplifier, refactoring, requirements-analyzer, skill-creator.
All 29 agents must use the <Agent_Prompt> wrapper with <Role> sub-tag. Created agent-format-enforcer skill with check-agent-format.mjs script that validates compliance and can auto-fix.
- Consistent structure ensures all agents load correctly into OpenCode's agent system
- The
<Agent_Prompt>wrapper is the documented convention — non-compliance was an oversight - Automated enforcement prevents future drift
- 10 agents wrapped in
<Agent_Prompt>tags agent-format-enforcerskill created with validation scriptpackage.jsonscripts added:check-agents,fix-agents
Status: Accepted Date: 2026-06-12
The ~/.config/opencode/ directory IS the global OpenCode config directory. Having a .opencode/ subdirectory inside it with duplicate config files (opencode.json, package.json, tui.json, node_modules/) was conceptually wrong — .opencode/ is a project-scoped pattern, not something that should nest inside the global config.
Remove all redundant config files from .opencode/:
opencode.json— redundant with rootopencode.jsoncpackage.json+package-lock.json— redundant with rootpackage.jsontui.json— redundant with roottui.jsonnode_modules/— redundant with rootnode_modules/
Keep only: context/, state/, CHANGELOG.md, AGENTS.md, .vector/, .gitignore
- Eliminates duplicate version pinning (root had
@opencode-ai/plugin@1.14.30,.opencode/had1.14.25) - Removes conceptual confusion about where config lives
- Saves 58MB of duplicated
node_modules/
.opencode/now serves as a pure durable knowledge store (context + changelog + state).opencode/.gitignoreupdated to only ignorestate/and.vector/init-projectscaffold now adds.opencode/node_modules/to project.gitignore
Status: Accepted Date: 2026-06-12
When given raw text with multiple work items (numbered lists, "and" clauses, compound requests), the Hubs agent was serial-executing them itself instead of decomposing and dispatching to parallel subagents. This violated the core "orchestrate, don't execute" principle and made multi-item tasks take much longer than necessary.
Added a <Critical_Behavior> section to the Hubs agent prompt that mandates:
- Raw text with 3+ implicit work items → ALWAYS decompose and parallelize
- Numbered lists, "and" clauses, compound requests → extract N discrete work items
- Dispatch each item to its own subagent via concurrent
task()calls - No serial self-execution for multi-item tasks
- The orchestrator's job is to dispatch, monitor, and integrate — not to implement
- Parallel dispatch reduces wall-clock time for N items from O(N) to O(max(N))
- The existing
ultraworkandteampatterns already support this — the gap was in the Hubs prompt itself
agents/hubs.mdupdated with<Critical_Behavior>section- Multi-Item Batch pattern added to
<Orchestration_Patterns> - Workflow step 2 hardened: "if 3+ implicit work items, ALWAYS decompose and parallelize"
Status: Accepted
Date: 2026-06-10
The /ideation hub had no dedicated method for breaking a complex task into smaller, actionable subtasks. Users had to use "top-down" or "plan" to approximate this, but neither is optimized for pure work breakdown with dependencies and acceptance criteria.
Add "decomposition" as the 3rd menu option in /ideation (after brainstorm, before refine), implemented as an inline subcommand.
- Decomposition is a distinct cognitive operation from planning (which is interview-driven) and refining (which is diverge/converge)
- Inline execution is appropriate — no separate skill file needed since the workflow is straightforward: accept task → break down → output ordered subtasks with dependencies and criteria
- Positioning as 3rd option puts it early in the menu where users expect fundamental task-analysis tools
- hubMenu.ts: entry added at index 51 with
inline: true - ideation/SKILL.md: method documented under new section between brainstorm and refine
- route-ideation.mjs: profile added for intent-based routing with decomposition-specific keywords
- Users who type /ideation decompose or "break down this task" will now route correctly
Status: Accepted Date: 2026-06-14
Context files saved to .opencode/context/ are committed to git and accumulate across sessions. There was no mechanism to prevent secrets, API keys, PII, or privacy-compromising content from being committed as durable context. The existing .gitignore only covered .opencode/state/ — not session transcripts, chat history, or dynamically-identified sensitive files.
Implement a two-pronged approach:
-
Preventive
.gitignoreentries: Add.opencode/state/sessions/,.opencode/chat-history/, and.opencode/chat/to.gitignorein both the global config and project.opencode/directories. -
Dynamic privacy scan: Create a
privacy-scanskill with ascan-privacy.mjsscript that:- Scans content for API keys, tokens, passwords, private keys, connection strings, PII, and session/chat indicators
- Classifies risk as HIGH/MEDIUM/LOW/UNCERTAIN
- Distinguishes derived knowledge (ADRs, patterns, decisions — safe to commit) from raw data (session transcripts, logs, config dumps — may contain secrets)
- Routes HIGH risk →
.gitignore+.opencode/state/, MEDIUM/UNCERTAIN →.opencode/state/for review, LOW →.opencode/context/as normal
- Static
.gitignoreentries alone are insufficient — new types of sensitive content can appear dynamically - The derived-vs-raw distinction prevents false positives on legitimate context files (ADRs, patterns, lessons)
- The scan is integrated into both
init-project(setup/refresh) andharvest-context(before saving) for comprehensive coverage
init-projectPhase 3 now adds 4 gitignore entries + runs privacy scan during setup/refreshinit-projectPhase 8 verifies gitignore entries existharvest-contextruns privacy scan before saving any file to.opencode/context/harvest-context sweepscans existing context files for privacy issuesrules/context-strategy.mdupdated with privacy scan documentation- New skill:
skills/privacy-scan/with SKILL.md and scan-privacy.mjs script
Status: Accepted Date: 2026-06-14
The project was originally branded "JOC" (Joint Operations Center) — a military metaphor. Over time, the project was renamed to "OpenCode Hubs" with a hub-and-spoke metaphor. However, 35+ references to the old branding remained scattered across the codebase in comments, documentation, config files, templates, scripts, and lockfiles, creating confusion and an inconsistent identity.
Remove all JOC branding references from the codebase and replace with "OpenCode" or "OpenCode Hubs" as appropriate:
| Location | Change |
|---|---|
opencode.jsonc |
Remove .joc/** legacy permission entry |
init-project template |
joc-plugin.ts → hubs-plugin.ts |
veclib.mjs |
"JOC context" → "OpenCode context" |
state/.gitignore |
"JOC State" → "State" |
installation.md |
5 URL changes + subtitle fix |
README.md |
Title + origin story update |
hubs-teams/SKILL.md |
joc team → opencode team (14 occurrences) |
hubs-reference/SKILL.md |
joc → opencode (2 occurrences) |
hub-doctor/SKILL.md |
"Joint Operations Center" → "Hub-driven" |
route-harvest.mjs |
"JOC install layout" → "install layout" |
| PSM files | repo/alias reference fixes |
hubs-tui/bun.lock |
package name fix |
- Consistent branding across all documentation, code, and configuration
- Eliminates confusion for new users encountering the old name
- Removes dead code path (
.joc/**permission no longer referenced anywhere) - The hub-and-spoke metaphor better reflects the architecture
- All legacy
jocreferences removed from tracked files - Some
jocreferences may remain in git history — they're inert - The
opencode teamCLI command is the correct invocation going forward
Status: Proposed Date: 2026-06-14
The global configuration (~/.config/opencode/) serves as a runtime engine with 29 agents, 67 skills, 10 tools, and 11 rules. However, every project has unique domain language, architecture patterns, coding conventions, testing practices, and external dependencies. Users currently must manually decompose their project architecture and wrestle with domain jargon before they can productively use AI assistance. There is no mechanism for /init-project setup --full to:
- Auto-analyze a project's domain language, architecture, and conventions
- Research detected dependencies via Context7 MCP and synthesize structured knowledge
- Generate project-specific agents, rules, commands, tools, and skills
- Vectorize synthesized context for semantic retrieval
Adopt a self-deploying agentic configuration architecture where /init-project setup --full becomes a zero-to-context pipeline:
- Global (
~/.config/opencode/): The compiler — generic agents, skills, commands, tools, rules. Never bloated with project-specific artifacts. - Per-Repo (
./.opencode/): The compiled binary — project-specific agents, rules, commands, tools, skills, context, and vector index. Deployed fresh for each project.
- Phase 0: Verify Global Engine — Check
~/.config/opencode/is healthy - Phase 1: Deep Codebase Scan — 6-pass scanner: file enumeration, language detection, framework detection, architecture detection, domain extraction, pattern extraction
- Phase 2: Architecture Analysis — Delegate to
@architectfor dependency mapping, boundary detection, and pattern classification - Phase 3: Context Research — Fetch docs for every detected dependency via Context7 MCP
- Phase 4: Context Synthesis — Combine analysis + research into frameworks/, patterns/, decisions.md, theory.md
- Phase 5: Agent Generation — Generate project-aware agent wrappers in
.opencode/agents/ - Phase 6: Rule Generation — Generate project-specific rules in
.opencode/rules/ - Phase 7: Tool + Command Generation — Generate project-specific tools and commands
- Phase 8: Skill Generation — Generate project-specific reusable skills
- Phase 9: Verification — Validate all artifacts, compile tools, index vector DB
- Eliminates global config bloat — each project gets exactly what it needs
- Zero manual decomposition — project mechanics are analyzed automatically
- Agents understand domain language from codebase analysis, not manual glossaries
- Vector-accelerated retrieval makes agents dramatically more effective for niche projects
- Language- and framework-agnostic — works for any project type
- Incrementally deployable — each phase adds capability without breaking existing workflows
- New sub-skills needed:
context-research,context-synthesize,deep-scanner - Enhanced
provision.mjsfor project-specific artifact generation init-projectPhase 1-5 enhancements in 03-configuration.md, phases/*.md- Framework document created:
context/frameworks/per-repo-deployment-architecture.md - Migration path: 5 phases over multiple iterations, each deployed incrementally
.opencode/context/frameworks/per-repo-deployment-architecture.md— Full architecture document
Status: Accepted Date: 2026-06-14
The previous "continue" plugin pattern sent context-on-nudges on every tool call and every chat message without discriminating between active work, slow operations, or genuine stalls. This created three problems:
- Subagent spam: Context messages were queued into every LLM turn, consuming tokens and forcing agents to process irrelevant nudges while they were actively working
- No stall detection: The system could not distinguish between "agent is working" (tool calls happening) and "agent is stuck" (no tool calls for minutes)
- Network reset blind: If a session disconnected and reconnected, orphaned mode states persisted with no recovery mechanism
Implement a heartbeat-based stall detection system with 5-tier classification:
Every tool.execute.after call records a heartbeat entry to .opencode/state/sessions/{session-id}/heartbeat.json containing:
lastToolCalltimestamplastToolName- Recent tool history (last 5 tools)
- Todo progress snapshot
| Tier | Window | Criteria | Action |
|---|---|---|---|
ACTIVE |
< 15s since last tool call | Tools are firing | Nothing |
SLOW_POSSIBLE |
15-60s | No tool calls but could be a long build | Wait, extend threshold |
STALLED_SOFT |
60-120s + no todo progress | No tool calls, no progress | Single gentle nudge (max 1) |
STALLED_HARD |
> 120s | No activity whatsoever | Stronger nudge + state summary |
SESSION_RESET |
Session restarts with orphaned mode | Pre-existing active state but no heartbeat | Recovery context block, don't auto-restart |
- Nudge cooldown: minimum 90s between nudges
- Max 1 soft nudge per stall period
- Max 3 hard nudges per session, then offer cancel
- Silent during known long ops (build, test, deploy, install)
- Never inject empty context messages
On session.created, scan for orphaned mode states (active true, no recent heartbeat). Inject a single <session-recovery> block with state summary. Do NOT auto-restart modes.
- Heartbeat-based detection is cheap (write a small JSON file per tool call) and reliable
- The 5-tier classification prevents nudging agents that are simply running long operations
- Session recovery without auto-restart prevents infinite loops on reconnection
- Anti-spam safeguards ensure the system gets quieter as it detects less progress, not louder
hubs-plugin.tsupdated with heartbeat recording, stall classification, and recovery logic- Framework document created:
context/frameworks/stall-detection-and-recovery.md - ADR entry documenting the design and rationale
- Redundant "continue" plugin can be removed once this is deployed
.opencode/context/frameworks/stall-detection-and-recovery.md— Full architecture document
Status: Proposed Date: 2026-06-14
The per-repo deployment architecture (ADR June 14) defines the high-level pipeline but lacks the specific mechanisms, reliability guarantees, and multifaceted approaches needed to make /init-project setup --full robust enough for diverse, niche, and highly specific projects. Users cannot be expected to decompose their project mechanics, translate jargon, or manually verify generated artifacts.
Adopt an 11-approach architecture for the per-repo customization engine, each approach addressing a specific gap:
| # | Approach | Addresses |
|---|---|---|
| A1 | Multi-Pass Codebase Scanner (6 passes) | Shallow detection → deep project profile |
| A2 | Dependency Graph + Version-Specific Research | Generic docs → exact-version context |
| A3 | Heuristic Convention Detector | Template rules → codebase-accurate rules |
| A4 | Domain Language Extraction (NLP-Lite) | Generic agents → domain-speaking agents |
| A5 | Architecture Pattern Classification | Flat prompts → architecture-aware prompts |
| A6 | Bootstrap Agent Generator | Manual agent creation → zero-shot agents |
| A7 | Checkpointed Multi-Stage Pipeline | Full re-runs → resume from any phase |
| A8 | Cross-Phase Consistency Verification | Blind generation → verified artifacts |
| A9 | Lazy Vector Index with Auto-Merge | Single-file retrieval → cross-file synthesis |
| A10 | Provision Dry-Run + Diff Review | Trust-the-process → preview-then-approve |
| A11 | Post-Production Feedback Loop | One-time generation → self-healing context |
- Each approach is independently shippable — incremental deployment without breaking existing workflows
- Combined, they address every failure mode: partial completion, broken references, stale context, wrong assumptions, missing docs, domain ignorance
- Priority tiers (P0-P4) let implementation start with the highest-value foundations (scanner + checkpoints + architecture detection) and iterate toward polish (dry-run + feedback loop)
- Framework document:
.opencode/context/frameworks/per-repo-customization-engine.md(full design) - Implementation priority: P0 (scanner + checkpoints) → P1 (architecture + conventions + verification) → P2 (research + vector) → P3 (domain language + agents) → P4 (dry-run + feedback)
- Estimated total effort: 15-25 days for complete implementation
.opencode/context/frameworks/per-repo-customization-engine.md— Full 11-approach design document.opencode/context/frameworks/per-repo-deployment-architecture.md— Parent architecture proposal
Status: Accepted Date: 2026-06-14
When the LLM is actively working (tool calls happening, todos advancing), any prompt the user types is submitted immediately — interrupting the current task mid-stream. If the user types multiple prompts while waiting, only the last one is processed. The stall detection system (ADR June 14) handles the "LLM is stuck" case but does nothing for the "LLM is busy, user has more to say" case.
Implement a smart prompt queue that:
- Queues substantive user prompts when the LLM is busy (heartbeat shows activity within 15-60s)
- Does NOT queue continuation signals ("...", "continue", "go on") — those are handled by stall detection
- Auto-submits the next queued prompt when the current task completes (no tool calls in 120s+ AND all todos done)
- Persists the queue to
.opencode/state/sessions/{id}/prompt-queue.jsonacross sessions - Injects queue context into the LLM's system prompt so it knows more prompts are waiting
- Preserves user intent across task boundaries without interrupting active work
- Complements stall detection without overlapping (stall = stuck, queue = busy)
- No synthetic prompts — only what the user actually typed
- Survives context compression and session restarts
hubs-plugin.tsupdated with queue storage, enqueue/dequeue, completion detectiontui.prompt.appendhook intercepts prompts when LLM is busytool.execute.afterchecks for task completion and auto-submits next promptexperimental.chat.system.transforminjects queue status into LLM contextexperimental.session.compactingpreserves queue state- Framework document:
context/frameworks/smart-prompt-queue.md
.opencode/context/frameworks/smart-prompt-queue.md— Full design document.opencode/context/frameworks/stall-detection-and-recovery.md— Complementary stall detection
Status: Accepted
Date: 2026-07-03
The Hubs system dispatches subagents via OpenCode's Task tool, which calls an LLM API for each invocation. While the existing multi-tier cache (tool, mcp, llm, agent, session, stable, context7, file) handles exact-repeat work well, two significant inefficiencies remained:
-
Near-repeat tasks miss the cache — The agent output cache uses SHA-256 hashing of the task prompt + file contents. Rephrasing the same task (e.g., "fix button styling" vs "update button CSS") produces a different hash and a full cache miss, requiring a fresh LLM call. This is the single largest source of redundant API requests.
-
Subagent prompts are bloated — Every
Taskdispatch carries the full agent prompt template, all loaded rules, full file contents, and full skill dumps — even when only a small fraction is relevant to the task. This inflates per-request token consumption by an estimated 40-60%.
Add a semantic cache layer alongside the existing exact-match SHA-256 agent cache:
- Embedding model:
ollama/mxbai-embed-large(335M params, ~500MB RAM, runs on CPU/GPU via local Ollama). Replacednomic-embed-textfor better retrieval quality on code/technical content. 768-dim vectors, well-understood cosine similarity behavior. - Storage: Flat JSON index in
.opencode/cache/semantic/— a simple array of{ hash, vector, output, timestamp }objects scannable by cosine similarity. At our scale (hundreds, not millions of entries), a full vector DB is overkill. - Similarity threshold: 0.92 cosine similarity — tuned to catch paraphrased instructions without false positives on genuinely different tasks.
- Two-tier lookup: Exact SHA-256 match first (fast path, O(1)) → semantic fallback (O(n) cosine scan) → fresh dispatch.
- File-hash verification: On semantic hit, verify cached file hashes match current file state before returning (same as existing agent cache).
- TTL: 24 hours (matching the
stablecache namespace), with file-change invalidation. - No degradation: On miss, falls through to existing exact-match cache → fresh dispatch. Best-effort improvement, never worse than baseline.
Add a pre-dispatch prompt compilation step that strips redundant boilerplate and scopes context to only what's needed:
-
What it strips:
- Role definitions and agent catalog sections that overlap with the target agent's built-in instructions — the subagent already knows who it is
- Rules that duplicate the agent's base instructions (checked against a known-overlap table)
- File content outside the relevant scope — function/class-level slices instead of full files
- Narrative instructions converted to structured YAML bullet points (~30% fewer tokens)
-
What it preserves:
- All security rules — never strip security context
- All task-specific instructions verbatim
- All rule references that are relevant to the specific task
-
No budget enforcement: The compiler is a pure quality optimization — it strips waste without imposing token budgets, caps, or size limits. If the compiled prompt is larger than the raw prompt (edge cases), it passes through unchanged.
The existing loadSkill tool gains two optional parameters:
section: already exists, returns only the requested sectioncompress: true: converts markdown workflow steps to compact YAML bullet lists
The prompt compiler calls loadSkill(name, section, { compress: true }) when assembling context for a subagent dispatch. This covers skill compression without any separate infrastructure.
Add a cross-encoder reranker stage between embedding retrieval and context injection:
- Reranker model:
ollama/hans-tech/bge-reranker-v2-m3:260522(BAAI bge-reranker-v2-m3, 0.6B params, multilingual, Apache-2.0). Runs via Ollama's/api/rerankendpoint — same local infra as the embedding model. - Pipeline: Embedding model retrieves top-50 candidates → reranker scores each (query, doc) pair → top-5 injected into prompt.
- Tool:
tools/rerank.ts— wraps Ollama/api/rerank, returns scored+ranked results with original text attached. - CUDA support: Ollama auto-detects GPU. CPU/RADEON fallback transparent — same commands, no code changes.
- Latency budget: ~50-200ms on GPU, ~200-1000ms on CPU for 50 candidates at 512 tokens each. Quality improvement 20-40% better retrieval precision.
- No embedding model change needed: Reranker scores text pairs directly — no vector compatibility concerns. Works with any embedding model.
Two changes to reduce per-step verify overhead in iterative patterns:
- Self-verify mode — The executor agent runs its own verification (lint, test, typecheck) and only escalates to
@verifieron failure. Built into theralphandhardenpatterns as an optional flag. - Batch verification gate — In pipeline patterns, collect 3-5 changes before a single
@verifierpass instead of verify-after-every-change.
- Semantic cache catches 80% of near-repeat tasks that miss the exact-match cache. Combined with the prompt compiler, this eliminates an estimated 40-50% of subagent dispatches entirely for iterative workflows (ralph loops, review cycles, test-fix cycles).
- mxbai-embed-large replaces nomic-embed-text for better retrieval quality on code/technical content. Same Ollama infra, same API, just better embeddings. 335M params vs 137M, still far smaller than the session model.
- Prompt compiler reduces per-dispatch token consumption by 40-60% without changing the LLM's output quality — it only removes what the agent already knows or doesn't need.
- No budget enforcement avoids the complexity of context window management and the risk of silently dropping critical context. The compiler is a filter, not a constraint.
- Verification consolidation directly reduces the dominant cost in iterative patterns (the verify loop) by 2-3x.
- Semantic cache: Cosine scan over a flat JSON index is O(n) — acceptable at current scale (~hundreds of entries per project) but would need a proper vector index (HNSW, IVF) if it grows to thousands+. Monitor cache hit performance and migrate if scan time exceeds 100ms.
- Prompt compiler: Stripping boilerplate requires knowing which rules overlap with the agent's built-in instructions. This overlap table must be maintained as agents evolve. A validation check in the
agent-format-enforcerskill or ahub-doctordiagnostic can flag out-of-date entries. - Verification consolidation: Self-verification relies on the executor agent correctly running its own checks. For critical paths (deploy, security-sensitive changes), external
@verifierreview should remain the default — self-verify is an optimization for non-critical iteration loops.
- ADR (this document) — architecture decisions recorded
tools/prompt-compiler.ts— prompt compilation + skill compression integrationtools/semantic-cache.ts— embedding-based cache layerplugins/core/hooks.ts— integrate both into the pre-dispatch pipeline- Verification consolidation — update ralph/harden skill files
- Two new tools:
prompt-compiler.tsandsemantic-cache.ts - Modified:
plugins/core/hooks.ts(pre-dispatch hook),tools/loadSkill.ts(compress mode),skills/ralph/SKILL.md(self-verify flag) mxbai-embed-largeandhans-tech/bge-reranker-v2-m3:260522become required Ollama models — auto-pull in init-project setup- ADR linked from global config README documentation table
- No change to the existing exact-match agent cache — it remains as the fast path O(1) lookup
.opencode/context/frameworks/inference-optimization.md(if created — full design details)tools/prompt-compiler.ts— Implementationtools/semantic-cache.ts— Implementationtools/cache-utils.ts— Existing multi-tier cache infrastructuretools/agent-cache.ts— Existing exact-match agent output cacheplugins/core/hooks.ts— Hook integration (Tier 4 cache + pre-dispatch)
Status: Accepted Date: 2026-07-03
Hub subcommand invocations were producing giant prompts — the entire SKILL.md file (200-700 lines) was being dumped into the LLM context. The init-project/SKILL.md file never had this issue.
Strip YAML frontmatter (---\nname: ...\n---) from all 5 hub SKILL.md files (ideation, orchestrate, project, harvest-context, init-project). Hub SKILL.md files are routing manifests, not skill prompts — they must never have frontmatter.
OpenCode loads files with YAML frontmatter as skill context, injecting the entire file content into the prompt. Files without frontmatter are not auto-loaded. init-project/SKILL.md never had frontmatter and worked correctly — confirming frontmatter was the root cause, not the routing logic.
- Hub subcommand invocations now produce appropriately-sized prompts
- All 5 hub SKILL.md files start with
# Headinginstead of YAML frontmatter - Convention documented in
rules/hub-description-directive.mdandcontext/patterns/hub-skill-conventions.md
Status: Accepted Date: 2026-07-03
TUI dialogs have limited horizontal space (~80 chars). Long descriptions get truncated mid-sentence and become unintelligible. The hub name isn't visually present in the flat subcommand list, so descriptions must be self-contained.
Hub subcommand specs use two description fields:
description(≤80 chars, no tools/buzzwords, self-contained) — TUI menu displaydetailedDescription(unlimited, can include tools/methodology/steps) — route payload only
The two purposes have conflicting requirements. TUI needs short, distinctive, self-contained labels. Routing needs detailed workflows with tool names and methodology. A single field can't serve both without either truncating in TUI or being too sparse for routing.
- Rewrote
rules/hub-description-directive.mdfor two-tier clarity - Shortened all 154 subcommand spec
descriptionfields to ≤78 chars - Shortened all 5 hub TUI description lists in
plugins/hubs-tui/src/tui.tsx - TUI dist rebuilt (16.82 KB)
Status: Accepted Date: 2026-07-03
Hub SKILL.md files used individual ### /hub X — Y subsections with --- dividers. This caused agents to regurgitate content from multiple sections when loaded, inflating token consumption.
Replace individual subsections with a single compact markdown table: Subcommand | Skill/Delegate | What It Does. Terse reminders moved to a separate table. Shared lifecycle steps preserved but stripped of per-subcommand verbosity.
init-project/SKILL.md already used this format and worked well. Compact tables are more parseable, reduce token consumption, and prevent agents from pulling content across multiple sections.
- ideation: 476 → 236 lines
- orchestrate: 187 → 148 lines
- project: 387 → 117 lines (−70%)
- harvest-context: 698 → 207 lines (−70%)
- Verification: no-arg lists match spec labels, routing table row counts match spec counts
Status: Accepted Date: 2026-07-03
The tool-scaffolder only supported TypeScript tool generation. Python and Bash scripts needed different output paths since OpenCode auto-discovers tools only from tools/ / .opencode/tools/ (TypeScript only).
TypeScript tools go to tools/ (global) or .opencode/tools/ (project). Python and Bash scripts go to skills/<name>/scripts/ (global) or .opencode/skills/<name>/scripts/ (project). The language parameter (typescript | python | bash) controls output path and code generation.
Python/Bash scripts are skill-bundled automation, not standalone tools registered with OpenCode. Placing them in skills/<name>/scripts/ follows the artifact-placement rule and ensures they're discovered as skill scripts, not misinterpreted as OpenCode tools.
tools/tool-scaffolder.tsextended withgeneratePython(),generateBash(),validatePython(),validateBash()skills/tool-creator/SKILL.mdupdated with multi-language documentation, scope rules, parameter type mappings- Five bash escaping bugs fixed during testing (documented in
context/patterns/template-literal-bash-generation.md)