For most of this year I built Vist with one expensive model doing everything. Planning a feature, writing the specs, renaming a variable, fixing a typo in a migration. Every task went to the same frontier model at the same frontier price.
That works fine. The bill is less fine when you're a solo founder paying it yourself.
So I rebuilt my setup around one rule: pick the model for the job. Planning gets the expensive model. Everything else gets something cheaper. In my corporate setup, a lot of the actual code even gets written by a model running on my laptop. It costs a lot less. It's also slower, so this post covers both parts: the tiered model setup in OpenCode, and the git worktrees plus herdr workflow I use to get the time back.
The problem with one model for everything
Most of what a coding agent does isn't hard. It reads files, greps, writes a spec, runs it, watches it fail, writes the code, runs it again. The hard part is deciding what to build and how it fits into the rest of the app, and that's maybe 10 percent of the tokens.
If one frontier model does all of it, you pay frontier prices for the other 90 percent.
My tiered OpenCode setup
I do most of this in OpenCode because every agent in it can run on a different model from a different provider, including a local one. I still use Claude Code too (you can see it in its own tab in the screenshot further down), but the tiered pipeline lives in OpenCode.
I run two versions of the same pipeline. At my day job I have a GitHub Copilot subscription, which gives me models from several providers, and I add a local model on top. For Vist, where I'm a solo founder paying my own bills, I keep it simple and stay within the Claude family.
| Role | Corporate setup (Copilot) | Vist solo founder setup | What it does |
|---|---|---|---|
| Planner | Claude Opus | Claude Opus | Architecture, trade-offs, breaking a feature into tasks |
| Plan writer | Gemini Flash | Claude Haiku | Writes the planner's decisions out as a detailed plan file |
| Orchestrator | Gemini Flash | Claude Haiku | Hands tasks to implementers, reads their reports, keeps the ledger |
| Implementer, first choice | GLM-4.7-Flash (local) | Claude Haiku | Bounded, well-specified tasks |
| Implementer, broader work | GPT Luna | Claude Sonnet | Tasks that span more of the codebase |
| Implementer, escalation | Gemini Flash | Claude Sonnet | Takes over when a lower tier reports it's stuck |
| Reviewer | Gemini Flash | Claude Sonnet | Reviews each task's diff for simplicity and maintainability |
The exact models matter less than the shape: one expensive seat for thinking, cheap seats for the volume work, and a clear route upwards when a cheap seat gets stuck.
The planner
The planner gets the feature request and the relevant context. Its output is a plan: which files change, in what order, what the specs should prove, and where the risks are. It can read the whole codebase but it can't edit source files. It's only allowed to write under .superpowers/, where the plans live.
This is the one seat where I don't economise. Every cheaper model downstream will execute the plan exactly as written, so a bad plan just means paying less per token to build the wrong thing.
The planner also doesn't type out the full plan itself. It decides, then hands an outline to a plan writer on a cheaper model, which turns it into the long version with exact file paths, code snippets and a verify command per task. Writing that document is a lot of tokens and very little judgement.
The orchestrator
The orchestrator takes the plan file and works through it task by task. For each one it writes a short brief, sends it to an implementer, reads the report, sends the diff to the reviewer, and moves on. It reads a lot and decides little, which is what a fast, cheap model with a big context window is good at.
It also can't write code. Its edit permission is denied everywhere except its own ledger folder. I did that on purpose: if the orchestrator can edit files, sooner or later it will "just quickly fix" something itself on the wrong model.
The implementers
Bounded tasks go to the cheapest implementer first. In the corporate setup that's GLM-4.7-Flash, running locally through Ollama on my MacBook Pro (M2 Pro, 32 GB). For Vist it's Haiku. Most tasks are routine: write the failing RSpec example, make it pass, clean up. A small model handles that fine when the brief is specific.
When an implementer can't finish, it reports BLOCKED or NEEDS_CONTEXT instead of guessing, and the orchestrator re-dispatches the task one rung up. The fix loop is capped at five rounds. I'd rather have a stronger model look at it than burn a tenth retry on the same one.
This is why strict TDD matters more here than it did when I used one big model. A red-green loop gives a cheap model a clear signal. "Make this spec pass" is something a small model can do. "Implement search filters nicely" isn't.
What this looks like in OpenCode
A few things I only found out by getting them wrong:
- An unpinned subagent inherits the caller's model. OpenCode's subagent tool has no model parameter, so if you don't set
modelon a subagent, it quietly runs on whatever the parent runs on. For me that was Opus. Model choice is agent choice: you declare one named agent per role and model. - Cap the context on the Ollama side. OpenCode's context limit is only a client-side budget. Pointed at the plain GLM tag, Ollama loaded the model with its full native context: 30 GB, spilling off the GPU. A two-line Modelfile with
PARAMETER num_ctx 65536gives you a tag that loads at 22 GB, fully on the GPU.
Here's the local implementer from my corporate config, trimmed. This is the OpenCode V2 format; check the agents docs for your version, because the shape changed between V1 and V2.
"impl-local": {
"description": "FIRST-CHOICE IMPLEMENTER. Executes ONE bounded, well-specified task on the local GLM-4.7-Flash model. Never dispatches subagents.",
"mode": "subagent",
"model": "ollama/glm-4.7-flash:q4_K_M-65k",
"system": "{file:./prompts/implementer.md}",
"permissions": [
{ "action": "shell", "resource": "git*", "effect": "deny" },
{ "action": "shell", "resource": "git diff*", "effect": "allow" },
{ "action": "shell", "resource": "git status*", "effect": "allow" },
{ "action": "subagent", "resource": "*", "effect": "deny" }
]
}
Permissions are an ordered list and the last match wins, so the broad deny goes first and the exceptions after it. The local implementer can look at git but not commit. The orchestrator commits once the reviewer is happy.
The catch: it's slower
This costs less money and more time.
GLM-4.7-Flash decodes at around 50 tokens a second on my machine, which is fine, but slower than a hosted frontier model. Every handoff between planner, orchestrator, implementer and reviewer adds latency. An escalation means a task ran once on the wrong tier before it ran on the right one. A feature that used to be one long session now takes noticeably longer from start to finish.
For a while I sat and watched it work, which is a poor use of my evenings. So I stopped running one feature at a time.
Winning the time back with git worktrees
If each run is slower, run more of them. The problem is that two agents in the same checkout trample each other's files, branches and test runs.
Git worktrees fix that. A worktree is an extra working directory attached to the same repository, each on its own branch. No second clone, shared history, separate files.
# one worktree per task, each on its own branch
git worktree add ../vist-wt/search-filters -b feat/search-filters
git worktree add ../vist-wt/mcp-headers -b fix/mcp-headers
# see what's running where
git worktree list
# clean up after merging
git worktree remove ../vist-wt/search-filters
Each worktree gets its own OpenCode session with its own planner, orchestrator and implementers. One agent team per branch.
If it's a Rails app, a few things to sort out:
- Test databases collide. Two worktrees running specs against the same test database give you failures that make no sense. Give each worktree its own, for example with a suffix from an environment variable in
database.yml. - Ports collide too. If agents boot a dev server, give each worktree its own port.
- Keep tasks independent. Two worktrees editing the same model means a merge conflict later. Pick work in different parts of the codebase.
- There's one local model. If you run one, three worktrees hitting Ollama at once means three queued requests on one machine. In practice one or two worktrees are planning or waiting for me while the others implement, so it evens out.
Keeping track of it all with herdr
Three or four worktrees, an OpenCode session in each, plus a shell each for specs and git. That's a lot of panes, and the only question that matters at any given moment is: which agent is waiting for me?
I use herdr for that. It's a terminal multiplexer like tmux, written in Rust, that knows about coding agents. It tracks whether each OpenCode, Claude Code or Codex session is working, blocked on input, done or idle, and shows that per pane.

This is what it looks like on a normal evening. On the far left are the spaces, one per branch I'm working on, and below them the agents list, sorted by priority, so whichever session needs me floats to the top. Each space has tabs: here opencode, claude and terminals. The file tree comes from the herdr-sidebar plugin, and the diff pane on the right is herdr-reviewr, which shows uncommitted changes without leaving the terminal. Under it is a plain shell for specs and commits.
When an agent finishes or gets stuck, it moves up the list and I switch to it. Sessions survive detaching, so I can close the laptop mid-feature and pick up where I left off.
Most of my time now goes into reviewing agents' work instead of watching them do it.
A typical day
- Pick two to four independent tasks from the backlog.
- Create a worktree per task and open a herdr space for it with an OpenCode session.
- Run the planner in each. Read every plan before anything gets built. These are the most important ten minutes of the day.
- Let the orchestrators and implementers run, and work on something else.
- When herdr shows a session as done or blocked, read the diff, answer the question or approve the escalation.
- Merge, remove the worktree, start the next task.
Before you copy this
- Context switching is real. Four parallel features means four things to keep in your head. Past three or four worktrees I start missing things in review.
- Plan quality is everything. Cheap implementers do exactly what the plan says. A vague plan gets you confident, wrong code.
- You need the hardware for local models. GLM-4.7-Flash needs about 22 GB, so 32 GB of unified memory is the realistic floor. If your machine can't run it, send the first tier to a cheap hosted model, like I do with Haiku for Vist. You keep most of the savings.
- You still have to review. More parallel output means more diffs to read. Skip that and you've built a faster way to ship bugs.
Where Vist fits
Running several agent sessions in parallel makes one problem worse: every session starts from zero. Each one needs to know the project conventions, the decisions already made and what the other branches are doing.
That's what I built Vist's MCP server for. Vist is connected to OpenCode as a remote MCP server, and every session starts by calling load_context: current project state, recent decisions, open tasks. When a planner settles an architectural question, it gets recorded, so the agent team in the next worktree doesn't argue it again an hour later. Finished plans get saved to Vist as notes too, so the plan outlives the worktree it was written in. You can see Claude Code reading one of those notes in the screenshot above.
If you're running agents in parallel and are tired of re-explaining your project to each of them, try Vist.
FAQ
Can OpenCode use a different model for each agent?
Yes. Each agent, primary or subagent, sets its own model. You can mix hosted providers and local models served through Ollama in the same session. Pin a model on every subagent, because an unpinned one inherits the model of the agent that called it.
Are local models good enough for coding?
For small, well-specified tasks with a spec to satisfy, GLM-4.7-Flash does most of the work well. For open-ended design or tricky debugging it falls short, which is why the setup escalates to a stronger hosted model when the local one reports it's stuck. If you'd rather not run anything locally, a small hosted model like Claude Haiku fills the same seat.
Why use git worktrees for AI coding agents?
Worktrees give each agent its own directory and branch within one repository. Agents can work in parallel without overwriting each other's files, and you don't have to maintain several full clones.
What is herdr?
Herdr is an open-source terminal multiplexer, similar to tmux, that understands coding agents. It shows whether each agent session is working, blocked, done or idle, which makes running several at once manageable.
Is a multi-model setup worth the extra complexity?
If you use coding agents every day and pay for tokens, yes, the savings add up quickly. If you use them now and then, one subscription is simpler. The complexity pays off once running things in parallel makes up for each run being slower.