Overview
Right model for the job
Architecture on Opus. Routing on DeepSeek Flash. A README scaffold on a free model. Most workflows use one model for everything. You pay premium rates for autocomplete. oowl routes each task to the cheapest model that can actually do the work. The savings fund the runs that actually need a frontier model.
Docs before code
Architect writes design.md. Planner writes
implementation.md. Both live in
docs/specs/ and need your sign-off before anything
gets built. Agents can't skip straight to editing files.
You approve every gate
Two hard stops in every substantial workflow: design approval and plan approval. Nothing moves to implementation without your explicit sign-off. Trivial fixes skip the ceremony entirely.
No faking done
Agents must return test output, lint results, or build logs
alongside TASK_COMPLETE. File paths are declared
upfront and locked. Protected spec files are tracked and must
remain intact.
The backstory
Claude Code and its proprietary models are great tools. They unblock developers and accelerate real work. But they've become expensive and increasingly restricted. Token limits. Session limits. Rate limits.
I started looking for alternatives. A lot of open-weight models match proprietary ones on SWE-Bench. DeepSeek Pro at 1M tokens costs $0.10. GPT-4 costs $10. Two orders of magnitude.
Then I found OpenCode. It's model-agnostic, connects to anything. OpenCode Go gives you roughly 16,000 requests/month for $5 on request-based pricing. GitHub Copilot caps at 1,500 for more money. The math was obvious.
Once model-switching was available, the real problem came into focus: same model for everything. You're paying Opus rates to write a test scaffold or a routing comment. The solution was to route different agents to different cost tiers: cheap models for cheap work, stronger models only where the quality delta matters.
oowl is the workflow layer that makes that practical. Role-specific agents, cost-tiered profiles, a structured design → plan → review process built on top of Superpowers, with Caveman-Lite keeping inter-agent chatter token-efficient.
Quick start
Prerequisites: OpenCode installed and configured, Node.js 18+.
Install the framework
npx @jimzandueta/oowl init
The wizard asks where to install (local project or global), whether you have an OpenCode Go subscription, and which models to use for each cost tier.
Open OpenCode
opencode
Launch from your project root. OpenCode picks up
opencode.jsonc and the agents in
.opencode/.
Talk to dispatcher
Type your request. The dispatcher routes it: trivial fixes go straight to one implementer, substantial work flows through design → plan → implementation → review with your approvals at each gate.
The three commands
npx @jimzandueta/oowl init # first-time setup wizard
npx @jimzandueta/oowl profile # switch model profiles interactively
npx @jimzandueta/oowl update # update framework files with conflict detection
Install globally with
npm install -g @jimzandueta/oowl to drop the
npx prefix.
What you get
| Feature | Details |
|---|---|
| 23 role-specific agents | Orchestration, design, implementation, review, escalation, low-tier bounded work |
| 23 slash commands | Workflow phases, domain specialists, escalation, low-tier workers |
| Two approval gates | Design approval and plan approval before any implementation begins |
| File locks | Every implementation task declares exact paths; parallel tasks are collision-checked |
| Protected artifacts |
design.md, implementation.md,
review.md under docs/specs/
|
| Verification evidence | No proof, no TASK_COMPLETE |
| Sensitive-area safeguards | Auth, IAM, payments, PII, secrets, production config require explicit approval |
| Switchable profiles |
low, balanced, high,
custom (from your connected models)
|
| Superpowers methodology | TDD, brainstorming, writing plans, debugging, review discipline |
| Caveman-Lite | Terse, token-efficient agent handoffs |
How it works
Why this instead of one big agent
| One mega-agent | oowl |
|---|---|
| Edits unrelated files | File locks constrain every task |
| Design lives in chat history |
design.md, plan, review live in docs/specs/
|
| "Looks done" is enough | Verification evidence required |
| Model choice is manual | Profiles assign cheap/mid/premium by role |
| Security review if remembered | Sensitive areas trigger approval + escalation |
| Agent handoffs are verbose | Caveman-Lite keeps runtime summaries concise |
Trivial-fix fast path
A request skips the full workflow when all of these are true:
- Under ~20 lines, under 3 files
- No auth, IAM, payments, PII, secrets, or production config touched
- No new dependency introduced
- No architectural decision required
Trivial work goes directly to one implementation agent with a complete task prompt and verification requirements. You can also tell dispatcher explicitly: "this is a trivial fix, skip the design phase."
Protocol signals
Agents don't pass work through freeform chat. Every handoff is a named, structured block with required fields. That's what keeps the workflow machine-readable and stops agents from going off-script.
How signals flow
Signal reference
TRIVIAL_FIX_DISPATCH (dispatcher → implementer)
dispatcher sends this when a request qualifies
for the fast path. Design, planning, and review are skipped. The
implementer gets a complete task prompt and must return
TASK_COMPLETE.
TRIVIAL_FIX_DISPATCH
Justification:
- under ~20 lines and under 3 files
- no sensitive area touched
- no new dependencies
- no architectural decision required
Target agent: <agent-name>
Task prompt: |
<complete prompt>
Files: <expected files>
Verification: <required checks>
PHASE_COMPLETE (architect / designer / planner / reviewer →
dispatcher)
Marks a workflow phase as complete. Used after design, UI spec, build, and review. Includes the artifact list and the next phase for dispatcher to move to.
PHASE_COMPLETE
Phase: <design | implementation-spec | build | review | ui-spec>
Summary: <summary>
Artifacts:
- <file created or modified>
Next phase: <user-design-approval | user-implementation-approval | plan-reviewer | build | review | done>
Risks: <remaining risks>
Verification:
- <checks performed or required>
PLAN_APPROVED /
PLAN_REJECTED (plan-reviewer → dispatcher)
plan-reviewer returns exactly one of these.
PLAN_APPROVED moves to the user approval gate.
PLAN_REJECTED sends the plan back to
planner with specific required changes. A new
version must be approved before the workflow continues.
PLAN_APPROVED
Summary: <why this plan is executable>
Next phase: user-implementation-approval
Risks: <remaining risks>
Verification: <expected verification>
PLAN_REJECTED
Issues:
- <BLOCKER or WARNING>: <issue>
Required changes:
- <specific fix>
Return to: planner
REQUEST_CONSULT (builder → dispatcher)
Builder sends this to hand a single task to dispatcher: full prompt, file locks, and verification checks included. Dispatcher forwards it unchanged.
REQUEST_CONSULT
Target agent: <agent-name>
Task ID: <task id, if any>
File locks:
- <path>
Task prompt: |
<complete prompt dispatcher should send directly>
Expected output: <expected result>
Verification requirements:
- <check>
Subagent summary: <current state>
REQUEST_CONSULT_BATCH (builder → dispatcher)
Builder sends this to dispatch 2–3 agents in the same assistant message. File locks must not overlap across tasks. Issuing them one at a time when a valid batch is possible is a protocol violation.
REQUEST_CONSULT_BATCH
Max parallel: 3
Wave: <wave id>
Parallel group: <group id>
Atomic dispatch required: yes
Tasks:
- Target agent: <agent-name>
Task ID: <task id>
File locks:
- <path>
Task prompt: |
<complete prompt>
Expected output: <expected result>
Verification requirements:
- <check>
Reason parallel-safe: <reason>
Subagent summary: <why this batch is safe>
TASK_COMPLETE (implementer → builder / dispatcher)
An implementer's success signal. Must include verification
evidence (test output, lint result, build output) and confirm
protected artifacts under docs/specs/** are still
present. No evidence, no completion.
TASK_COMPLETE
Task ID: <task id>
Files changed:
- <file>
Verification:
- <command/result>
Risks:
- <risk or none>
Notes:
- <brief note>
Protected artifacts:
- confirmed docs/specs/** unchanged and present
NEEDS_USER_INPUT (any agent → user via dispatcher)
Any agent that hits a sensitive area, an ambiguity, or a decision it can't make on its own sends this and stops. The workflow waits. Includes a safe default so the user knows what happens if they don't respond.
NEEDS_USER_INPUT
Question: <one clear question>
Why needed: <brief reason>
Default if unanswered: <safe default>
Subagent summary: <brief summary>
ESCALATION_REQUEST (low-tier agent → dispatcher)
Low-tier agents (low-engineer,
low-task-worker, low-architect,
low-designer) stop and send this when a task turns
out to need more than their tier allows: sensitive areas,
security implications, architectural decisions. They don't
attempt it. Dispatcher upgrades to the right agent.
ESCALATION_REQUEST
Target agent: <high-engineer | high-architect | high-designer | security-auditor>
Why cheaper agents are insufficient: <reason>
What was attempted: <summary>
Specific output needed: <decision or deliverable>
Risk if wrong: <impact>
ESCALATION_COMPLETE (high-tier agent → dispatcher)
Sent by escalation agents (high-engineer,
high-architect, high-designer,
security-auditor) when escalated work is done.
ESCALATION_COMPLETE
Reason escalation was justified: <reason>
Result: <summary>
Files changed or decisions made:
- <item>
Verification:
- <command/result or recommended check>
Remaining risks:
- <risk or none>
REVIEW_COMPLETE (reviewer → dispatcher)
End of review. Lists findings by severity, any blocking issues, and gaps in verification coverage.
REVIEW_COMPLETE
Summary: <summary>
Findings:
- <finding count by severity>
Blocking issues: <yes/no>
Verification gaps:
- <gap or none>
PARALLEL_DISPATCH_FAILED (dispatcher → builder)
Dispatcher couldn't send a REQUEST_CONSULT_BATCH as
one atomic message, usually context pressure. Builder responds
with a fallback: run serially, split the batch, or hand the
decision to the user.
PARALLEL_DISPATCH_FAILED
Reason: <why concurrent dispatch was not possible>
Fallback proposed: <serial execution | smaller batch | user decision>
PROTECTED_ARTIFACT_MISSING (any agent → dispatcher)
An agent found that a protected file under
docs/specs/** is gone.
Stop everything and restore it from Git before
continuing.
PROTECTED_ARTIFACT_MISSING
Missing:
- <path>
Last task or batch: <summary>
Required action: restore from git or snapshot before continuing
git checkout -- docs/specs/<feature>/design.md
Agents
23 agents across 6 classes. All files live in
framework/agents/ and are copied to
.opencode/agents/ on install.
Orchestration
dispatcher classifies requests and routes them. Only dispatcher may invoke implementation agents via Task. builder is scheduler-only: no file edits, no shell, no Task calls.
Artifact owners
Implementation
Review
Escalation
Low-tier bounded
Model profiles
Profiles assign models to agent tiers. Switch anytime with
oowl profile.
Bundled profiles (OpenCode Go)
| Profile | Purpose |
|---|---|
low |
Cost-first for long sessions and routine development |
balanced |
Daily fullstack. Stronger models where quality pays off. |
high |
Quality-first for higher-stakes or shorter sessions |
Custom profile (no OpenCode Go needed)
oowl init and oowl profile → custom scan
your connected OpenCode models and let you assign them to
cheap/mid/premium tiers. If fewer than 3 models are detected, you
can enter model IDs manually.
Balanced profile: current mapping
| Agents | Model |
|---|---|
dispatcher, builder,
low-engineer, low-task-worker
|
opencode-go/deepseek-v4-flash |
architect, planner,
plan-reviewer, backend-engineer,
database-engineer, code-reviewer
|
opencode-go/minimax-m2.5 |
reviewer, designer,
frontend-engineer, test-engineer,
security-reviewer, low-architect,
low-designer
|
opencode-go/qwen3.5-plus |
frontend-polisher |
opencode-go/kimi-k2.6 |
cloud-architect |
opencode-go/deepseek-v4-pro |
security-auditor |
opencode-go/glm-5.1 |
high-engineer |
github-copilot/gpt-5.5 |
high-architect |
github-copilot/claude-sonnet-4.6 |
high-designer |
github-copilot/claude-opus-4.7 |
Model availability changes. Profiles are editable defaults, not permanent benchmarks.
Plugins
opencode.jsonc loads two plugins out of the box:
"plugin": [
"superpowers@git+https://github.com/obra/superpowers.git",
"caveman@git+https://github.com/juliusbrussee/caveman.git"
]
| Plugin | Role |
|---|---|
| obra/superpowers | Skills for TDD, brainstorming, planning, systematic debugging, and review discipline. Agents load them on demand. |
| juliusbrussee/caveman | Keeps agent handoffs short and signal-dense. Applied to routing summaries and completion signals , never to artifacts, code, or security findings. |
Install
oowl init
npx @jimzandueta/oowl init
Prompts for install location, model setup, and conflict handling.
Local installs write opencode.jsonc and
AGENTS.md to your project root. Global installs use
~/.config/opencode/.
oowl profile
oowl profile
Updates model assignments across all 23 agent files,
opencode.jsonc, and profile-models.json.
oowl update
oowl update
Updates framework files to the latest package version. Files you haven't modified update silently. Modified files show a unified diff. Keep yours or accept the update, per file.
Uninstall
# local install
rm -rf .opencode opencode.jsonc AGENTS.md .oowl.json
# global install
rm -rf ~/.config/opencode ~/.oowl.json
Customizing
Edit an agent prompt
Agent files live in .opencode/agents/ (local) or
~/.config/opencode/agents/ (global). Edit directly for
immediate effect. When oowl update runs and detects the
change, choose "keep mine" to preserve it.
Add an agent
-
Add a
.mdfile under the right class inframework/agents/ -
Add the agent to every profile JSON under
agent_orderandagents - Update
framework/agents/README.md -
Add a command file in
framework/commands/if needed -
Run
oowl profileto verify it appears in the model strategy
Change workflow rules
| File | Controls |
|---|---|
framework/prompts/shared/routing.md |
Trivial vs substantial thresholds |
framework/prompts/shared/protocols.md |
Core protocol blocks and agent communication |
framework/prompts/shared/sensitive-data.md |
Sensitive-area triggers and escalation rules |
framework/prompts/shared/protected-artifacts.md
|
Artifact ownership and protection rules |
Add a custom profile
cp framework/model-profiles/balanced.json framework/model-profiles/my-profile.json
# edit my-profile.json with your model assignments
bash scripts/apply-profile-models.sh framework/model-profiles/my-profile.json
Common issues
Agents aren't showing up in OpenCode
OpenCode must be launched from the directory containing
opencode.jsonc. For a local install, that's your
project root.
ls .opencode/agents # should list agent subdirs
ls opencode.jsonc # should exist
If either is missing, re-run oowl init from your
project root.
oowl command not found after npm install -g
Your global npm bin directory may not be on PATH.
npm bin -g # shows the path to add
Alternatively, keep using npx @jimzandueta/oowl,
which doesn't require a global install.
Wrong model after switching profiles
Use oowl profile: it updates agent frontmatter,
opencode.jsonc, and
profile-models.json as one atomic operation. The
legacy shell script doesn't update
opencode.jsonc unless you pass the project root
as a second argument.
Fewer than 3 models found during init
oowl needs at least one model per tier (cheap, mid, premium).
Connect more providers in OpenCode's settings, then run
oowl init again, or choose "enter manually" to
type model IDs directly.
oowl update shows everything as modified
.oowl.json is missing or predates checksum
tracking. Run oowl init (choose "skip existing
files") to regenerate it. Future updates will detect changes
correctly.
Protected artifact disappeared mid-workflow
Restore from Git:
git checkout -- docs/specs/<feature>/design.md
To protect against this, commit approved specs before implementation starts:
git add docs/specs
git commit -m "chore: preserve approved specs for <feature>"
Caveman-Lite not activating
The Caveman plugin is loaded via opencode.jsonc.
Make sure OpenCode is running from the correct directory so it
picks up the config. Check that the plugin URL is reachable
from your network.
The workflow feels like too much ceremony
Tell dispatcher explicitly: "this is a trivial fix, skip the design phase."
Or adjust the routing thresholds directly in
framework/prompts/shared/routing.md. The rules
are yours to tune.
Contributing
Before opening a PR, run:
# Node tests
npm test
# CLI smoke tests
node bin/oowl.js --help
node bin/oowl.js foobar; echo "exit: $?" # should exit 1
# Profile JSON validation
for f in framework/model-profiles/*.json framework/profile-models.json; do
node -e "JSON.parse(require('fs').readFileSync('$f','utf8'))" && echo "OK: $f"
done
# npm pack check
npm pack --dry-run
Keep these intact:
dispatcherowns dispatch: only it invokes Task-
builderschedules only: no file edits, no shell, no Task - Protected artifacts remain owner-controlled
- Implementation tasks require file locks
-
Verification evidence required before
TASK_COMPLETE - Sensitive flows require explicit approval and stricter routing
- Caveman-Lite stays limited to runtime communication, not artifacts or code
See CONTRIBUTING.md for the full process.