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:
| Problem | What Happens |
|---|---|
| Context bloat | Tool outputs flood the context window, eating capacity before any real work happens |
| Blind editing | Changes break things you didn’t know depended on the code you touched |
| Chaotic workflows | Without 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:
bun i -g ctx7Then run the setup wizard — it gives two integration options:
ctx setup| Option | What It Does |
|---|---|
| MCP | Registers Context7 as an MCP server in your config |
| Skills | Installs 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):
ctx loginLogged-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:
context7_resolve-library-id({libraryName: "react", query: "useEffect cleanup"})— find the right librarycontext7_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.mdThis 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:
- Process skills — brainstorming, systematic-debugging, TDD, writing-plans. These determine HOW to approach the task.
- Implementation skills — frontend-design, find-docs, accessibility-a11y. These guide execution.
- Review skills — verification-before-completion, requesting-code-review. These ensure quality.
The full development pipeline chains these together in sequence:
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.
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:
| Path | How It Works | When to Use |
|---|---|---|
| Subagents | Dispatches independent tasks as parallel agents, each in its own context | 3+ tasks with no sequential dependencies |
| Current session | Executes tasks sequentially in the current thread | Tight 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:
| Aspect | Greenfield | Brownfield |
|---|---|---|
| First step | Define requirements | Understand existing code |
| Before editing | No existing deps | MUST run gitnexus_impact |
| Risk | LOW | HIGH |
| Debugging | Rarely needed | Primary concern |
| Refactoring | Minimal | Critical for safety |
In practice, you rarely invoke skills in isolation. They chain together based on the scenario:
| Scenario | Skill/Tool Chain |
|---|---|
| Debug UI screenshot | diagnose_error_screenshot → systematic-debugging |
| Build from design | ui_to_artifact → frontend-design → TDD |
| Research library | Context7 → web_search_prime → zread_search_doc |
| Safe refactor | gitnexus_impact → gitnexus_rename → gitnexus_detect_changes |
| Explore codebase | gitnexus-exploring → gitnexus_query → gitnexus_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 Reference | OpenCode Equivalent |
|---|---|
TodoWrite | todowrite |
Task with subagents | @mention syntax |
Skill tool | OpenCode’s native skill tool |
| File operations | Native 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:
bun i -g context-modeBun blocks postinstall scripts by default, so trust the package:
bun pm -g trust --allThen run the diagnostics to check everything works:
context-mode doctorThis 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:
context-mode upgradeThis 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:
| Check | Status | Notes |
|---|---|---|
| Server test | PASS | MCP subprocess starts correctly |
| Plugin registration | PASS | Found in opencode.json plugin array |
| Hook script | PASS | PreToolUse hook exists and is executable |
| FTS5 / SQLite | PASS | Native module compiled and working |
| Plugin enabled | PASS | Plugin array includes context-mode |
| SessionStart hook | FAIL | OpenCode 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:
(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:
| Rule | What’s Blocked | What You Use Instead |
|---|---|---|
| curl/wget | Shell HTTP calls | ctx_fetch_and_index or ctx_execute |
| Inline HTTP | fetch(), requests.get() in shell | ctx_execute sandbox |
| Shell >20 lines | Raw command output in context | ctx_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:
- 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. - FOLLOW-UP:
ctx_search— query previously indexed content with natural language. - PROCESSING:
ctx_execute/ctx_execute_file— run code in a sandboxed subprocess. Only stdout enters context. - WEB:
ctx_fetch_and_index— fetch a URL, convert to markdown, chunk, index, then query. Raw HTML never touches context. - 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 bashset -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:
gitnexus analyzeThe 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_impactbefore editing any symbol - MUST run
gitnexus_detect_changesbefore 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_renameinstead
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:
| Question | Tool | What It Returns |
|---|---|---|
| ”How does auth work?” | gitnexus_query | Execution flows ranked by relevance |
| ”Who calls this function?” | gitnexus_context | 360° view: callers, callees, processes |
| ”What breaks if I change this?” | gitnexus_impact | Blast radius by depth (d=1, d=2, d=3) |
| “Did my changes affect anything unexpected?” | gitnexus_detect_changes | Changed symbols + affected processes |
The impact tool returns results grouped by depth, where each level carries a clear action:
| Depth | Meaning | Action |
|---|---|---|
| d=1 | WILL BREAK — direct callers | MUST update these |
| d=2 | LIKELY AFFECTED — indirect deps | Should test |
| d=3 | MAY NEED TESTING — transitive | Test 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:
bun i -g agent-browserThen install the Chrome component (this downloads Chromium to ~/.agent-browser/):
agent-browser installIf 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:
npx skills add https://github.com/vercel-labs/agent-browser --skill agent-browser -y -gThe 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:
agent-browsertakes a screenshot of the pagezai-mcp-serveranalyzes 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.
bunx @z_ai/coding-helperWithin the tool here’s what I do:
- Register my Coding Plan key
- Register z.ai provider on opencode
- Register all MCPs on opencode
I made some changes.
Models
Two models, two slots, each optimized for a different job:
| Slot | Model | Use Case |
|---|---|---|
model | glm-5-turbo | Main reasoning, code generation, complex tasks |
small_model | glm-4.5-air | Fast, 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:
| Tool | What It Does |
|---|---|
zai-mcp-server | Vision: screenshot-to-code, OCR, error diagnosis, diagram reading, UI diff |
web-search-prime | Web search with Chinese and international coverage |
web-reader | Fetch any URL and convert to clean markdown |
zread | Search 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.
| Category | Skills |
|---|---|
| Review & Quality | web-design-reviewer |
| Frontend | daisyui, tailwindcss-fundamentals-v4, tailwindcss-advanced-layouts, tailwind-design-system, astro, accessibility-a11y |
| Backend | golang, golang-architect, golang-documentation |
| Research | find-skills, tavily-search, tavily-extract |
| Infrastructure | bun, openapi-spec-generation |
| Content | technical-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:
Context7fetches current Tailwind v4 docs — the AI works with the real API, not a hallucinated one.- The
brainstormingskill activates — it asks clarifying questions one at a time instead of guessing my intent. context-modehandles the research phase —ctx_batch_executeruns commands in a sandbox whilectx_searchqueries the indexed results. No context bloat.GitNexusexplores the codebase —gitnexus_queryfinds relevant code,gitnexus_contextshows what depends on what.GitNexusruns the safety check —gitnexus_impactshows the blast radius before any edit happens. I see exactly what will break.- The
TDDskill drives implementation — test first, then code. The AI can’t skip it. verificationkicks in —gitnexus_detect_changesconfirms the scope, tests pass, lint passes.finishinghandles 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.
| Key | Action |
|---|---|
ctrl+x | Leader (prefix for commands) |
ctrl+x n | New session |
ctrl+x l | Session list |
ctrl+x g | Session timeline |
ctrl+x c | Compact session |
ctrl+x x | Export session |
F2 | Cycle recent models |
Tab | Cycle agents |
ctrl+p | Command 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.
| Tool | Author | What It Does |
|---|---|---|
| OpenCode | Anomaly | The AI coding assistant this entire setup runs on |
| Context7 | Context7 | Live library documentation retrieval |
| Superpowers | obra | Plugin that provides skill-driven workflows and process enforcement |
| context-mode | mksglu | MCP plugin that protects the context window from tool output bloat |
| GitNexus | mikenye | Code intelligence — knowledge graph, blast radius analysis, safe refactoring |
| agent-browser | Vercel | Browser automation for AI agents |
| Z.ai MCP Server | Z.ai | Vision, web search, web reader, GitHub integration |
This article was written by opencode (GLM-5-Turbo | Z.AI Coding Plan).


