A Headless Two-Agent Coding Loop With OpenCode and Ollama
How to split planning and review between two agents in OpenCode with Ollama, with permissions, skills, redaction rules, screenshots and human-only commits.
This article is published in English.
Sources: Ollama on Steroids with OpenCode: A Headless Multi Agent Coding Workflow
Most AI coding demos impress right up to the moment someone asks a dull engineering question: what exactly happened, who reviewed it, which tests ran, and can the whole thing be reproduced tomorrow?
The workflow below tries to answer that. Instead of a chat window that now and then produces a good patch, it treats AI coding as a small engineering loop:
- one agent plans and implements
- a second agent reviews and signs off
- each prompt gets its own local session folder
- each run leaves a trail of logs and proof that tests ran
- a human, never an agent, decides when code is committed or pushed
- private prompts and session output stay private
The division of labour: MiniMax drafts plans and writes code, GLM reviews and approves, OpenCode drives the workflow and Ollama routes requests to the models. What comes out isn't magic autonomy. It's a repeatable loop that produces plans, reviews, tests, screenshots, security checks and commits a person controls.
On the tooling side, OpenCode offers a non-interactive opencode run, named agents, model selection, a --dir flag, and the ability to attach a run to a headless opencode serve instance. Sessions can be exported with --sanitize. Ollama documents an OpenCode integration via ollama launch opencode, and OpenCode reads project-level config, agents, permissions, skills and MCP servers.
The sample config names its Ollama Cloud models minimax-m3:cloud and glm-5.1:cloud, with MiniMax positioned for coding and agentic work and GLM described as a flagship for agentic engineering. The pattern itself doesn't depend on those exact models. Treat the model names as examples and check the current Ollama catalogue before copying them. Raw prompts, session output, local paths, keys and screenshots from the original project aren't shared here, only the method.
Stop treating AI coding as one chat
A lone coding agent shares a weakness with a solo developer under pressure: it can talk itself into believing it's finished. Asking the same model again doesn't fix that. A process does:
Prompt -> Plan -> Review -> Implement -> Test -> Review -> Fix -> Signoff -> Human commit
The layout looks like this:
control-workspace/
AGENTS.md
opencode.json
.opencode/
agents/
minimax-builder.md
glm-reviewer.md
skills/
opencode-ollama-agent-guardrails/
SKILL.md
agent-sessions/
project-slug/
promptNN/
PROMPTNN_CODER.md
PROMPTNN_REVIEWER.md
PROMPTNN_PLAN.md
PROMPTNN_PLAN_REVIEW.md
PROMPTNN_IMPLEMENTATION.md
PROMPTNN_TEST_RESULTS.md
PROMPTNN_IMPLEMENTATION_REVIEW.md
PROMPTNN_SIGNOFF.md
redacted logs
screenshot references
product-repo/
Why start from a parent control workspace? Inside the product repo alone, the agent may be unable to see prompt files, session files, shared rules or the wider workflow. Absolute paths, meanwhile, can carry machine-specific details into logs. Hence the rule: launch OpenCode from the parent, use relative paths, keep product edits in the product repo and session output outside it. It sounds dull, which is exactly why it works.
Two agents with separate duties
The key design choice isn't the exact model. It's the separation of duties.
The builder
minimax-builder may plan, edit code, run commands and write implementation notes. Its responsibilities are to read the prompt and AGENTS.md, draft a plan, apply the reviewer's feedback, implement only the approved scope, run validation, record what changed and what failed, and stop for human approval of any commit. Off limits: committing, pushing, rebasing, force-pushing, moving on to the next prompt, softening tests and editing files reserved for the reviewer.
The reviewer
glm-reviewer is strict by design. Its checklist: does the plan fit the prompt, did the implementation stay in scope, are the tests meaningful, were generated files changed on purpose, do browser screenshots back up the claim, is secret handling sane, and is the builder overstating its results?
Its decision vocabulary is kept tiny:
APPROVED
CHANGES_REQUESTED
SIGNED_OFF
NOT_SIGNED_OFF
A small vocabulary leaves little room to wriggle. "Looks good overall" isn't a signoff.
The OpenCode config
Here's the shape of the configuration:
{
"$schema": "https://opencode.ai/config.json",
"model": "ollama/minimax-m3:cloud",
"default_agent": "minimax-builder",
"share": "disabled",
"instructions": ["AGENTS.md"],
"enabled_providers": ["ollama"],
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow"
},
"glob": "allow",
"grep": "allow",
"webfetch": "ask",
"websearch": "ask",
"external_directory": "deny",
"skill": {
"*": "allow"
}
},
"agent": {
"minimax-builder": {
"description": "Main planning and implementation agent.",
"mode": "primary",
"model": "ollama/minimax-m3:cloud",
"temperature": 0.2,
"permission": {
"edit": {
"*": "deny",
"product-repo/**": "allow",
"agent-sessions/project-slug/**": "allow"
},
"bash": {
"*": "ask",
"cd product-repo && *": "ask",
"git status *": "allow",
"git diff *": "allow",
"git log *": "allow",
"git commit *": "deny",
"git push *": "deny",
"git rebase *": "deny",
"rm *": "deny"
}
}
},
"glm-reviewer": {
"description": "Strict reviewer. Must not edit product code.",
"mode": "primary",
"model": "ollama/glm-5.1:cloud",
"temperature": 0.1,
"permission": {
"edit": {
"*": "deny",
"agent-sessions/project-slug/**": "allow"
},
"bash": {
"*": "ask",
"git status *": "allow",
"git diff *": "allow",
"git log *": "allow",
"grep *": "allow",
"rg *": "allow",
"git commit *": "deny",
"git push *": "deny",
"git rebase *": "deny",
"rm *": "deny"
},
"task": "deny"
}
}
}
}
Two details deserve attention. Sharing is disabled by default, and since OpenCode has a share option, setting it to "disabled" shuts one route for accidental leaks. The reviewer also lacks broad edit rights: it can write review and signoff files into the session folder but shouldn't change production code. OpenCode has fine-grained permission rules for edit, bash, read, grep, glob, skill and more, so the config itself should enforce the workflow.
Adjust the paths for your own repository. The principle stays fixed:
builder can edit product code;
reviewer can write review notes;
neither agent can commit or push;
external directories are denied;
dangerous shell commands ask or deny.
Skills as a portable guardrail
The most reusable piece isn't only the config file. It's the skill. OpenCode skills are reusable SKILL.md definitions kept under project or global skill folders. The canonical project-level location is:
.opencode/skills/<skill-name>/SKILL.md
Claude-compatible and agent-compatible skill paths exist too, but for this workflow keeping it simple is sensible. Put the guardrail skill here:
.opencode/
skills/
opencode-ollama-agent-guardrails/
SKILL.md
Every SKILL.md must carry frontmatter with a name and a description at minimum. The name has to be lowercase, hyphen-separated and identical to the folder name. A guardrail skill can tell agents rules such as:
- Do not publish raw prompts.
- Do not publish raw session logs.
- Do not use absolute local paths.
- Do not edit outside the approved product directory.
- Do not claim success without test output.
- Do not weaken tests to make validation pass.
- Do not commit, push, rebase, or force-push.
- Store review notes separately from production code.
- Treat screenshots as sensitive evidence.
- Stop for human approval after signoff.
The rules look elementary, but they stopped real mistakes. If they sit only in one repository's AGENTS.md, they stay there. Packaged as a skill, they travel with you.
Headless mode makes it repeatable
Interactive coding suits exploration. Headless mode is better for repeatable runs. The builder pass looks like this:
opencode run \
--model ollama/minimax-m3:cloud \
--agent minimax-builder \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_CODER.md)"
And the reviewer pass:
opencode run \
--model ollama/glm-5.1:cloud \
--agent glm-reviewer \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_REVIEWER.md)"
For heavier setups with MCP servers, start a local OpenCode server once and attach later runs to it, avoiding repeated cold starts:
opencode serve --hostname 127.0.0.1 --port 4096
opencode run \
--attach http://localhost:4096 \
--agent minimax-builder \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_CODER.md)"
Bind the server to 127.0.0.1. Anyone who exposes it to another machine should set OPENCODE_SERVER_PASSWORD and run it like a genuine development service, since the CLI docs describe HTTP basic auth through that variable. The model didn't get smarter. The workflow just became harder to fool.
Keep prompts and output without leaking them
Storing prompt files and session output locally is worthwhile for debugging agent behaviour. Publishing raw prompts or raw exports isn't. Logs from agents may hold local paths, shell prompts, branch names, internal TODOs, implementation secrets, environment names, screenshot paths, stray credentials and prompt wording you'd rather reuse in private.
The rule: store everything locally and publish only redacted summaries and reusable templates. OpenCode's opencode export [sessionID] with --sanitize helps with internal review, but treat it as a first pass and not a publish button. Anything public should pass a second redaction review.
For a public repository, commit these:
AGENTS.md
opencode.json
.opencode/agents/*.md
.opencode/skills/*/SKILL.md
templates/*.md
scripts/*.zsh
scripts/redact_sessions.py
docs/publication-redaction-checklist.md
and gitignore these:
agent-sessions/**
screenshots/**
.env
project.local.env
*.raw.log
*.events.jsonl
opencode-session-*.json
The result is shareable reports without turning the repository into a leak.
Where MCP tools helped
Models are only part of the system, and the tool surface matters a great deal. A useful way to see MCPs and built-in tools is as specialised senses and hands:
| Workflow stage | Useful tool or MCP category | What it helped with |
| ---------------- | ------------------------------------------------------- | -------------------------------------------------- |
| Planning | repo search, docs lookup, issue/context reader | understand current architecture before changing it |
| Coding | filesystem, shell, language server, package manager | edit code, inspect symbols, run targeted commands |
| Review | git diff, grep, test reports, generated artifact reader | catch scope creep and weak tests |
| Unit tests | test runner, coverage | prove the patch did not only compile |
| Browser tests | Playwright/browser automation | validate real UI routes and flows |
| Security tests | secret scan, dependency audit, SAST | catch obvious unsafe output before publish |
| Docs/site checks | static-site build, route checks, smoke tests | catch generated-output drift |
The best MCP setup doesn't enable everything. It gives the agent the few tools it needs and makes risky ones ask first. OpenCode defines MCP servers under the mcp key in opencode.json and has CLI commands to manage them. Treat these definitions like production dependencies: pin them, review them and remove the unused ones.
Why screenshots earned a place
Browser tests return pass or fail. Screenshots give visual evidence. They helped the reviewer catch what unit tests miss: a broken layout after a clean build, wrong content on a route, empty generated pages, navigation regressions, an error banner no test asserted on, and proof that a static-site route exists and renders.
They carry risk too: browser profile names, private tabs, localhost paths, issue titles, URL tokens and devtools output can all end up in the frame. The policy is to take screenshots only of localhost UI, crop tightly, review before publishing, and never capture auth pages, production dashboards, private tabs or terminals that display environment values. A screenshot is evidence and doesn't count as a public artefact by default.
A case study on a private wiki project
The author applied this to a private LLM wiki and static-site project and published only a sanitised write-up. Its final validation notes recorded 977 Python tests passing, a static-site rebuild with refresh, smoke-site and domain validation, a docs build, route checks and 150 Playwright tests passing. For the completed, scoped features the author's own confidence was high, roughly 8 to 9 out of 10, backed by repeatable tests, generated-site checks, route checks and browser validation. That score is subjective and shouldn't be generalised beyond that project.
The weak spot wasn't the product code. One headless automation script failed because agent names were wired wrongly. It used generic names:
planner
coder
tester
reviewer
while the configured agents were actually:
minimax-builder
glm-reviewer
The mismatch made the run fall back to the wrong behaviour, so the intended multi-agent signoff didn't complete. The failure was useful, since it showed the value of plain names, exact config, relative paths and checking the session folder. The corrected pattern looks like this:
opencode run \
--model ollama/minimax-m3:cloud \
--agent minimax-builder \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_CODER.md)"
opencode run \
--model ollama/glm-5.1:cloud \
--agent glm-reviewer \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_REVIEWER.md)"
That means no absolute paths, no made-up agent names, and no prompt files hidden beyond the working scope.
How close to a frontier workflow?
This is where it's easy to oversell. A MiniMax plus GLM setup on OpenCode and Ollama isn't the same as running the best frontier coding model directly. Frontier models still have stronger raw reasoning, better long-context behaviour and better default instruction following, so comparing model for model wouldn't be fair. The comparison that matters is workflow quality: planning, review, tests, screenshots, security checks and human approval.
Workflow carries a lot of weight. On scoped tasks backed by good tests, the setup can feel not far from a strong frontier-style one, since it layers in separate roles, up-front planning, reviews on both sides of implementation, mandatory validation gates, local session memory, screenshot evidence, security checks and commits a human controls.
It got close on deterministic feature work, static-site generation, retrieval and search plumbing, test-heavy tasks, reviewing generated output, catching scope creep and forcing agents to document failures. Frontier models still win on ambiguous architecture calls, deep refactors across poorly tested code, taste and product judgement, long-horizon self-correction, needing fewer retries, following instructions by default and reasoning over complex screenshots.
Threat model
Several familiar AI-coding hazards shrink under this workflow: unsupported claims of success, builders wandering outside the intended repo, reviewers turning into implementers, raw prompts reaching public repos, logs exposing paths or secrets, screenshots revealing private tabs or tokens, silent changes to generated files, and agents committing or pushing before anyone has looked.
Human review remains necessary. Full autonomy isn't the target. A tighter loop, where each claim comes with evidence and each risky action has a limit, is.
Pros and cons
Pros
- Reproducibility. Prompts get folders, runs leave notes and signoffs can be traced back.
- Governance. The builder can't quietly skip tests if the reviewer must block signoff without validation evidence.
- Model flexibility. You can swap models as Ollama and OpenCode support evolves, and the process outlasts the churn.
- Velocity. Once prompts and scripts exist, running the next scoped task is quick.
Cons
- More ceremony. It's heavier than one chat prompt, and that's the trade.
- Enforcement needs config. Telling the reviewer not to edit production code is weaker than enforcing it with permissions and CI checks.
- Bad prompts still produce bad work. The loop reduces chaos but doesn't replace a clear scope.
- Permissions need care. MCP servers and shell access are powerful, so treat them like production access.
- Logs are sensitive. The richer your logs, the more careful the redaction must be.
The claim that holds up
The setup won't make MiniMax or GLM into a top-tier frontier model. What it does is make cheaper, Ollama-routed agentic coding more disciplined, auditable and useful for scoped engineering. That's the only claim it can honestly make.