5 min read
ai developer-tools

My Opencode Setup: Guardrails, Intelligence, and Skill-Driven AI Workflows

The Philosophy

AI coding assistants are powerful but chaotic. Give one access to 80 tools and a large context window, and it will happily flood that window with raw JSON, grep output, and full file dumps before writing a single line of useful code. Without guardrails, they waste context, break code blindly, and freestyle their way into inconsistent results.

I’ve spent months tuning my Opencode setup to eliminate these failure modes. The result is a configuration built around three problems:

ProblemWhat Happens
Context bloatTool outputs flood the context window, eating capacity before any real work happens
Blind editingChanges break things you didn’t know depended on the code you touched
Chaotic workflowsWithout enforced processes, results vary wildly between sessions

Each problem has a dedicated solution in my stack. Each solution is configured once in AGENTS.md and enforced automatically — the AI doesn’t get to opt out.

A good Opencode setup isn’t about having the most tools. It’s about building guardrails and automation so the AI works predictably within a system. This article walks through my setup layer by layer, starting with the most fundamental: making sure the AI always works with current information.

Layer 1 — RAG for Current Docs

The biggest risk with AI coding assistants isn’t that they write bad code — it’s that they write code based on outdated documentation. A model trained 6 months ago doesn’t know about the breaking change in Astro 6 or the new API surface in Tailwind v4. It hallucinates confidently.

Context7 solves this by providing a retrieval layer over live library documentation. The AI resolves a library ID, then queries up-to-date docs on demand. No stale training data, no guessing.

This is the first layer because it affects everything else. Without current docs, every subsequent layer — skills, context engineering, code intelligence — operates on potentially wrong assumptions. The AI needs accurate information before it can do anything useful.

Installation

Install the CLI globally with bun:

Terminal window
bun i -g ctx7

Then run the setup wizard — it gives two integration options:

Terminal window
ctx setup
OptionWhat It Does
MCPRegisters Context7 as an MCP server in your config
SkillsInstalls a find-docs skill that teaches the AI the correct lookup flow

I choose Skills. It’s more discoverable — the AI sees the skill and knows when to use it, without needing an extra MCP server in the config. The skill drops a rule into the right directory automatically.

Finally, log in to your Context7 account (free signup at context7.com):

Terminal window
ctx login

Logged-in users get higher API quotas than anonymous access. If you hit a quota error, this is why.

How It Works

The find-docs skill teaches the AI a two-step process: resolve the library ID first, then query the docs. Without the skill, the AI often tries to query directly without resolving, which fails silently. With it, every documentation lookup follows the correct flow:

  1. context7_resolve-library-id({libraryName: "react", query: "useEffect cleanup"}) — find the right library
  2. context7_query-docs({libraryId: "/facebook/react", query: "useEffect cleanup"}) — get current docs

The result: accurate code that works against the version you’re actually using, not the version the model was trained on.

Layer 2 — Prompt Engineering with Skill-Driven Workflows

With accurate docs available, the next problem is process. Without enforced workflows, the AI improvises. Sometimes it writes tests first, sometimes it doesn’t. Sometimes it plans, sometimes it dives straight in. The results are inconsistent, and you end up baby-sitting the session instead of getting work done.

Superpowers is a plugin that provides structured skills — reusable workflows the AI must invoke before acting. Systematic debugging before any fix. TDD before any implementation. Writing-plans before any multi-step task. The AI doesn’t get to skip steps; the skills enforce the process.

Installation

Open OpenCode and paste this line:

Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md

This will make OpenCode install the Superpowers skillset and plugin automatically. Restart OpenCode after installation.

Skills follow a priority hierarchy. Process skills fire first because they determine how to approach the task. Implementation skills guide execution. Review skills ensure quality:

  1. Process skills — brainstorming, systematic-debugging, TDD, writing-plans. These determine HOW to approach the task.
  2. Implementation skills — frontend-design, find-docs, accessibility-a11y. These guide execution.
  3. Review skills — verification-before-completion, requesting-code-review. These ensure quality.

The full development pipeline chains these together in sequence:

flowchart LR A[brainstorming] --> B[writing-plans] B --> C[implementation-plan] C --> D[TDD] D --> E[build] E --> F[verification] F --> G[finish]

Every step is enforced. The AI can’t jump ahead.

The Workflow in Practice

Everything starts with brainstorming. I type /brainstorming followed by a basic idea — something like “add a dark mode toggle to the blog” or “build a search page for the docs”. From there, the skill takes over.

flowchart TD A["/brainstorming [basic idea]"] --> B["Q&A Phase
Clarifying questions"] B --> C{Building UI?} C -->|Yes| D["Ask user to set up
prototyping web"] D --> E["User provides
design reference"] C -->|No| F["Define requirements
and constraints"] E --> F F --> G["writing-plans
Auto-generate implementation plan"] G --> H{Execution method?} H -->|Subagents| I["Dispatch parallel agents
Independent tasks in isolation"] H -->|Current session| J["Execute sequentially
Single thread"] I --> K["TDD per task"] J --> K K --> L["verification
Tests, lint, impact check"] L --> M["finishing
Review, commit, merge"]

The Q&A phase is the key differentiator. Instead of the AI guessing what I want, it asks one question at a time — scope, constraints, tech preferences, edge cases. Each answer narrows the design space. By the time the questions stop, the requirements are clear enough that the plan almost writes itself.

For UI work, the skill asks you to set up a prototyping web page — a live Figma mockup, a reference site, or even a rough HTML sketch. This becomes the design contract. The AI can then use the vision pipeline (Layer 5 — agent-browser + zai-mcp-server) to compare its output against the reference during verification.

Once requirements are locked, writing-plans generates a structured implementation plan — ordered tasks with acceptance criteria, file targets, and dependency mapping. No ambiguity about what to build or in what order.

Then comes the execution choice. The skill offers two paths:

PathHow It WorksWhen to Use
SubagentsDispatches independent tasks as parallel agents, each in its own context3+ tasks with no sequential dependencies
Current sessionExecutes tasks sequentially in the current threadTight dependencies between tasks, or quick jobs

I always pick subagents. Parallel execution means three tasks finish in the time of one, and each agent gets a clean context — no pollution from the other tasks. The tradeoff is that you need enough tasks that benefit from parallelism; for a two-step sequential fix, the overhead isn’t worth it.

After execution, verification-before-completion runs automatically — tests, lint, and gitnexus_detect_changes to confirm nothing unexpected was affected. Finally, finishing handles review, commit, and merge.

This pipeline looks different depending on whether you’re starting from scratch or working in an existing codebase. The key difference is risk:

AspectGreenfieldBrownfield
First stepDefine requirementsUnderstand existing code
Before editingNo existing depsMUST run gitnexus_impact
RiskLOWHIGH
DebuggingRarely neededPrimary concern
RefactoringMinimalCritical for safety

In practice, you rarely invoke skills in isolation. They chain together based on the scenario:

ScenarioSkill/Tool Chain
Debug UI screenshotdiagnose_error_screenshotsystematic-debugging
Build from designui_to_artifactfrontend-designTDD
Research libraryContext7web_search_primezread_search_doc
Safe refactorgitnexus_impactgitnexus_renamegitnexus_detect_changes
Explore codebasegitnexus-exploringgitnexus_querygitnexus_context

That last row is where layers 3 and 4 work together. GitNexus gives you the intelligence; Superpowers gives you the process. Without both, you’re either guessing what to change (no intelligence) or guessing how to change it (no process).

OpenCode Tool Mappings

Superpowers was originally built for Claude Code, so some tool references differ in OpenCode. The plugin handles this automatically, but it’s useful to know the mapping:

Superpowers ReferenceOpenCode Equivalent
TodoWritetodowrite
Task with subagents@mention syntax
Skill toolOpenCode’s native skill tool
File operationsNative read/edit/write tools

You can verify the plugin is loaded and skills are discovered by asking: “List your skills” or using OpenCode’s native skill tool directly.

Layer 3 — Context Engineering

Now the AI has current docs and enforced processes. The next problem is capacity. Raw MCP tool outputs dump directly into context. A single Playwright snapshot is 56 KB. Five of those and you’ve burned your session — the AI has no room left to reason about your actual code.

How OpenCode plugins work: OpenCode plugins are JavaScript/TypeScript modules that hook into events like tool.execute.before and tool.execute.after. They can intercept tool calls, modify behavior, inject context, and add custom tools. Plugins are loaded from npm packages (specified in opencode.json under plugin) or local files in .opencode/plugins/. See the OpenCode plugin docs for details.

The fix is context-mode, an MCP plugin that intercepts tool outputs and routes them through an isolated subprocess. Only a condensed summary enters the context window. The full data stays in a searchable FTS5 database, available on demand through query tools.

Installation

Install globally with bun:

Terminal window
bun i -g context-mode

Bun blocks postinstall scripts by default, so trust the package:

Terminal window
bun pm -g trust --all

Then run the diagnostics to check everything works:

Terminal window
context-mode doctor

This checks your platform, runtimes, FTS5/SQLite native module, plugin registration, and hook configuration. On Node 25, you may hit a better-sqlite3 build error — the doctor output will suggest rebuilding the native module manually inside bun’s global package directory. Follow the suggestion, then run doctor again.

Finally, register the plugin and hooks:

Terminal window
context-mode upgrade

This automatically adds context-mode to your opencode.json plugin array and sets up hook scripts. Here’s the expected doctor output after a clean install:

CheckStatusNotes
Server testPASSMCP subprocess starts correctly
Plugin registrationPASSFound in opencode.json plugin array
Hook scriptPASSPreToolUse hook exists and is executable
FTS5 / SQLitePASSNative module compiled and working
Plugin enabledPASSPlugin array includes context-mode
SessionStart hookFAILOpenCode doesn’t support SessionStart yet (#14808)

The SessionStart hook failure is a known OpenCode limitation, not a setup problem. Everything else should pass.

How It Works

Once installed, context-mode sits between the AI agent and every tool call. Raw data never enters the context window — it stays in an isolated subprocess, gets summarized or indexed, and only the relevant parts come through. Here’s what that looks like:

flowchart LR A["AI Agent
(200K context)"] --> B["context-mode MCP"] B --> C["Isolated Subprocess"] C --> D["Summary only"] D --> A

The plugin alone isn’t enough. The real enforcement comes from routing rules written into AGENTS.md — instructions the AI must follow on every session:

RuleWhat’s BlockedWhat You Use Instead
curl/wgetShell HTTP callsctx_fetch_and_index or ctx_execute
Inline HTTPfetch(), requests.get() in shellctx_execute sandbox
Shell >20 linesRaw command output in contextctx_batch_execute or ctx_execute

These rules are backed by a five-level tool hierarchy. The AI reaches for the highest-level tool first and only drops down when necessary:

  1. GATHER: ctx_batch_execute — run multiple commands and search indexed output in a single call. This is the primary tool. One call replaces 30+ individual tool invocations.
  2. FOLLOW-UP: ctx_search — query previously indexed content with natural language.
  3. PROCESSING: ctx_execute / ctx_execute_file — run code in a sandboxed subprocess. Only stdout enters context.
  4. WEB: ctx_fetch_and_index — fetch a URL, convert to markdown, chunk, index, then query. Raw HTML never touches context.
  5. INDEX: ctx_index — store arbitrary content in the FTS5 knowledge base for later retrieval.

Since adding context-mode, my context usage has dropped significantly. Sessions that used to die after a few heavy tool calls now sustain full development workflows. The raw data stays out of my context window, and I only get what I actually need — when I need it.

For the deep dive on how context-mode works, see my earlier article.

Layer 4 — Code Intelligence

With docs, processes, and context protection in place, the AI can work safely. But in a brownfield project, editing a function without knowing what calls it is Russian roulette. You fix one thing and break three others. The larger the codebase, the worse the odds.

GitNexus solves this by building a knowledge graph of your codebase from git history and AST analysis. Functions, classes, imports, call chains — everything becomes a queryable graph. Instead of grepping for callers and hoping you found them all, you ask the graph and get an exact answer with blast radius estimates.

Installation

GitNexus has a Node 22 requirement (see my deep dive for the full version analysis). I isolate it using an nvm wrapper script at ~/.local/bin/gitnexus:

#!/usr/bin/env bash
set -euo pipefail
export NVM_DIR="${NVM_DIR:-$HOME/.config/nvm}"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
NODE_VERSION="22"
if ! nvm ls "$NODE_VERSION" | grep -q "$NODE_VERSION"; then
echo "Node $NODE_VERSION not found. Installing..." >&2
nvm install "$NODE_VERSION"
fi
nvm exec "$NODE_VERSION" npx -y gitnexus@latest "$@"

Then configure the MCP server in opencode.json pointing to the wrapper:

{
"mcp": {
"gitnexus": {
"type": "local",
"enabled": true,
"command": ["/home/youruser/.local/bin/gitnexus", "mcp"]
}
}
}

Then index your project:

Terminal window
gitnexus analyze

The config is trivial. The enforcement is what matters. I write these rules into AGENTS.md at the project level, where the AI must follow them:

  • MUST run gitnexus_impact before editing any symbol
  • MUST run gitnexus_detect_changes before committing
  • MUST warn if impact analysis returns HIGH or CRITICAL risk
  • NEVER edit a function, class, or method without impact analysis first
  • NEVER rename symbols with find-and-replace — use gitnexus_rename instead

These aren’t suggestions. They’re checked before every edit and every commit. The AI can’t skip them.

Here’s how the tools map to real questions:

QuestionToolWhat It Returns
”How does auth work?”gitnexus_queryExecution flows ranked by relevance
”Who calls this function?”gitnexus_context360° view: callers, callees, processes
”What breaks if I change this?”gitnexus_impactBlast radius by depth (d=1, d=2, d=3)
“Did my changes affect anything unexpected?”gitnexus_detect_changesChanged symbols + affected processes

The impact tool returns results grouped by depth, where each level carries a clear action:

DepthMeaningAction
d=1WILL BREAK — direct callersMUST update these
d=2LIKELY AFFECTED — indirect depsShould test
d=3MAY NEED TESTING — transitiveTest if critical path

A d=1 result means you have direct callers that will break. A d=2 means the blast radius extends further. A d=3 means transitive dependencies might be affected — test them if they’re on a critical path.

One practical detail: after you commit code, the GitNexus index goes stale. Run gitnexus analyze to refresh it. If the index previously included embeddings, add --embeddings to preserve them. I keep this in AGENTS.md so the AI handles it automatically.

Layer 5 — Give Vision

A terminal-based AI assistant is powerful, but it’s blind. It can read files and run commands, but it can’t see what a user sees — a broken layout, a misaligned button, an error screenshot. You end up pasting descriptions into the chat and hoping the AI understands.

agent-browser solves this by giving the AI a real browser. It can navigate pages, click buttons, fill forms, take screenshots, and extract data — all programmatically. No more guessing what the UI looks like from HTML alone.

Installation

Install globally with bun:

Terminal window
bun i -g agent-browser

Then install the Chrome component (this downloads Chromium to ~/.agent-browser/):

Terminal window
agent-browser install

If you see “shared library” errors on Linux, use agent-browser install --with-deps to install system dependencies.

Finally, add the skill so the AI knows when and how to use it:

Terminal window
npx skills add https://github.com/vercel-labs/agent-browser --skill agent-browser -y -g

The skill installs universally — it works with OpenCode, Claude Code, Cline, Gemini CLI, and other supported agents.

Combined with Vision MCP

agent-browser captures what’s on screen, but the AI still needs to understand what it’s seeing. That’s where zai-mcp-server comes in — it’s a vision MCP server that decodes and analyzes images. Together they form a two-stage pipeline:

  1. agent-browser takes a screenshot of the page
  2. zai-mcp-server analyzes the image — reads UI layouts, diagnoses errors from screenshots, extracts text via OCR, understands diagrams

This combination is particularly powerful for debugging. Instead of describing an error dialog (“there’s a red box with some text”), the AI sees it directly and can diagnose the actual problem.

Layer 6 — The Z.ai Stack

Every layer so far has been about tooling and guardrails. This layer is about the model provider itself. I’m using Z.ai Coding Plan — not because I did an exhaustive comparison of every provider, but because it’s what I have access to. It covers both the AI models and several MCP tools, so it keeps things simple. The layers above work regardless of provider; this is just the one I’m running.

Let’s use the installation tool provided by z.ai.

Terminal window
bunx @z_ai/coding-helper

Within the tool here’s what I do:

  1. Register my Coding Plan key
  2. Register z.ai provider on opencode
  3. Register all MCPs on opencode

I made some changes.

Models

Two models, two slots, each optimized for a different job:

SlotModelUse Case
modelglm-5-turboMain reasoning, code generation, complex tasks
small_modelglm-4.5-airFast, cheap tasks: summarization, classification, routing

The dual-model setup matters. Most of what the AI does — routing tool calls, classifying input, summarizing output — doesn’t need a frontier model. glm-4.5-air handles these at a fraction of the cost and latency. glm-5-turbo only fires when actual reasoning or code generation is needed.

I already tested glm-5, glm-5-turbo, and glm-5.1 for coding and I found out that for my use case and behavior glm-5-turbo performance is the best.

MCP Servers

Three Z.ai MCP servers handle the work that goes beyond code:

ToolWhat It Does
zai-mcp-serverVision: screenshot-to-code, OCR, error diagnosis, diagram reading, UI diff
web-search-primeWeb search with Chinese and international coverage
web-readerFetch any URL and convert to clean markdown
zreadSearch GitHub repos — docs, issues, commits, and file contents

zai-mcp-server is the most impactful. It gives the AI eyes — it can analyze screenshots, decode error dialogs, understand diagrams, and compare two UI states. Combined with agent-browser (Layer 5), it forms a complete vision pipeline.

web-search-prime and web-reader handle general web research. zread is specialized for GitHub — the AI can search issues, read files, and explore repos without ever leaving the session.

Configuration

{
"provider": {
"zai-coding-plan": {
"options": {
"apiKey": "your-api-key-here"
}
}
},
"mcp": {
"zai-mcp-server": {
"type": "local",
"command": ["npx", "-y", "@z_ai/mcp-server"],
"environment": {
"Z_AI_MODE": "ZAI",
"Z_AI_API_KEY": "your-api-key-here"
}
},
"web-search-prime": {
"type": "remote",
"url": "https://api.z.ai/api/mcp/web_search_prime/mcp",
"headers": {
"Authorization": "Bearer your-api-key-here"
}
},
"web-reader": {
"type": "remote",
"url": "https://api.z.ai/api/mcp/web_reader/mcp",
"headers": {
"Authorization": "Bearer your-api-key-here"
}
},
"zread": {
"type": "remote",
"url": "https://api.z.ai/api/mcp/zread/mcp",
"headers": {
"Authorization": "Bearer your-api-key-here"
}
}
},
"model": "zai-coding-plan/glm-5",
"small_model": "zai-coding-plan/glm-4.5-air"
}

Layer 7 — On-Demand Knowledge

Beyond the core layers, I have additional skills and MCP servers that are only activated when needed. These sit idle most of the time and don’t consume resources until you flip them on.

Skills

Beyond Superpowers and the agent-browser skill, I have additional skills in ~/.agents/skills/ for niche workflows and specific frameworks. Superpowers activates these when the context matches.

CategorySkills
Review & Qualityweb-design-reviewer
Frontenddaisyui, tailwindcss-fundamentals-v4, tailwindcss-advanced-layouts, tailwind-design-system, astro, accessibility-a11y
Backendgolang, golang-architect, golang-documentation
Researchfind-skills, tavily-search, tavily-extract
Infrastructurebun, openapi-spec-generation
Contenttechnical-blog-writing, writing-skills

Each one fills a gap — a specific framework or niche workflow that Superpowers doesn’t cover. They’re installed individually using npx skills add.

MCP Servers

Three additional MCP servers sit in the config but are disabled — Astro docs, bearnie, and shadcnVue. They’re marked "enabled": false so they don’t consume resources while idle. Flip the flag when you need them, leave them off when you don’t. No teardown, no cold starts, no wasted context.

How It All Fits Together

Here’s what happens when I ask the AI to add a dark mode toggle:

  1. Context7 fetches current Tailwind v4 docs — the AI works with the real API, not a hallucinated one.
  2. The brainstorming skill activates — it asks clarifying questions one at a time instead of guessing my intent.
  3. context-mode handles the research phase — ctx_batch_execute runs commands in a sandbox while ctx_search queries the indexed results. No context bloat.
  4. GitNexus explores the codebase — gitnexus_query finds relevant code, gitnexus_context shows what depends on what.
  5. GitNexus runs the safety check — gitnexus_impact shows the blast radius before any edit happens. I see exactly what will break.
  6. The TDD skill drives implementation — test first, then code. The AI can’t skip it.
  7. verification kicks in — gitnexus_detect_changes confirms the scope, tests pass, lint passes.
  8. finishing handles the close — review, commit, merge. The AI knows which skill to invoke based on where we are in the pipeline.

Every layer activates automatically. No manual orchestration, no prompting the AI to “be careful” or “check dependencies first.” The guardrails are baked in.

This setup evolved over months. Don’t try to copy everything at once — start with whatever solves your biggest pain point (Context7 for doc accuracy, context-mode for context bloat, or GitNexus for code intelligence), then add layers as you feel the need. The config files live at ~/.config/opencode/ and are just JSON and markdown. Nothing here is magic — it’s deliberate automation of things you’d otherwise do manually.

The Interface

My tui.json rebinds the interface around an Emacs-style leader key (ctrl+x) and vim-style input motions. The input field supports standard readline-like navigation: ctrl+b/ctrl+f for character movement, alt+b/alt+f for word jumps, ctrl+a/ctrl+e for line home and end.

KeyAction
ctrl+xLeader (prefix for commands)
ctrl+x nNew session
ctrl+x lSession list
ctrl+x gSession timeline
ctrl+x cCompact session
ctrl+x xExport session
F2Cycle recent models
TabCycle agents
ctrl+pCommand palette

Model cycling is on F2 / Shift+F2 — no leader prefix needed because switching models is a frequent operation that should be instant. Agent cycling uses Tab / Shift+Tab for the same reason. Theme switching is ctrl+x then t, under the leader because you don’t change themes mid-workflow. Scroll acceleration is enabled at speed 3, making long outputs comfortable to read.

References

This setup wouldn’t exist without the tools and projects listed below. Each one solves a real problem, and together they make AI-assisted development something I actually enjoy using.

ToolAuthorWhat It Does
OpenCodeAnomalyThe AI coding assistant this entire setup runs on
Context7Context7Live library documentation retrieval
SuperpowersobraPlugin that provides skill-driven workflows and process enforcement
context-modemksgluMCP plugin that protects the context window from tool output bloat
GitNexusmikenyeCode intelligence — knowledge graph, blast radius analysis, safe refactoring
agent-browserVercelBrowser automation for AI agents
Z.ai MCP ServerZ.aiVision, web search, web reader, GitHub integration

This article was written by opencode (GLM-5-Turbo | Z.AI Coding Plan).