Skip to content

It's all a Yoke to you, isn't it?

Or: How to put your agents to work and actually trust the results

A yoke is the wooden beam that connects draft animals to the plow. It doesn’t make the ox weaker. It makes the ox useful. Without it, you’ve got a very powerful animal wandering around your field eating your crops.

And let’s be honest about what’s happening here. The agents are already doing the heavy lifting. The grunt work. The “write 400 lines of test scaffolding” work. The “implement this CRUD endpoint for the seventh time this week” work. They’re the ones pulling the plow through the dirt at 3 AM while you sleep.

What you need to do is give them a proper harness so they don’t plow straight through your neighbor’s fence.

Yes, “yoke” rhymes with “joke.” No, that wasn’t an accident. The joke is giving six agents commit access to your repo. The yoke is what keeps that from being a horror story.


The Gap Between “Steering” and “Shipping”

Section titled “The Gap Between “Steering” and “Shipping””

The first post in this series laid out the approach: AGENTS.md for master instructions, skill files for task-specific procedures, automated quality gates for enforcement. Later posts showed how to scale that to parallel agents with git worktrees, and the inner/outer loop model formalized where agents end and humans begin.

But there was a gap. A pretty big one, actually.

Setting all of that up by hand is a lot of work. You need the config file, the completion checker, the plan-first hook, the grind loop implementation (different for every agent tool), the commands, the code reviewer, the documentation structure, the CI workflows, the enforcement scripts. And they all need to reference each other correctly, use the right test commands for your toolchain, and not have any typos in the shell scripts that silently break everything at 2 AM.

I built this harness incrementally over several weeks in a single repo. It worked great. But “just copy these 30 files and manually adjust all the paths and commands” is not a viable distribution strategy.

So I built Yoke: a portable, run-once bootstrap that sets up the entire harness in any Git repository. Point your agent at a spec file, answer two questions, get the whole thing.


You: "Read YOKE_SPEC.md and set up the agentic harness for this repository"
Agent: "Which profile?
- minimal: Core quality gates
- standard: Full knowledge layer + commands
- full: Parallel orchestration"
You: "standard"
Agent: "Which agent tools? Claude Code, OpenCode, Codex, Kiro?"
You: "claude and opencode"
Agent: *sets up your entire harness in 5-10 minutes*

The agent reads the spec, runs the scaffolding script, detects your toolchain (Python/uv? TypeScript/npm? Rust/cargo? Go?), fills in templates, generates tool-native components, analyzes your codebase, and validates everything. You answer two questions and go make coffee.

After setup, the repo owns everything. No daemon. No SaaS. No subscription. Just files in your repo that you can read, modify, and commit. Yoke lays the foundation, then gets out of the way.


If you read the previous posts, you know the three-layer model. Here’s how Yoke implements it concretely — the parts that are new, not the philosophy you’ve already heard.

The core. Install nothing else if you want, but install this.

Grind Loop — The completion checker runs after each agent turn and produces structured JSON:

{
"complete": false,
"iteration": 2,
"max_iterations": 5,
"checks": {
"tests_pass": false,
"review_clean": true,
"scratchpad_done": false
},
"followup_prompt": "Tests are still failing. Fix these:\n\nFAILED test_momentum_strategy..."
}

If incomplete, the agent gets a targeted follow-up. If stuck on the same thing for three iterations, it gets an escalation: “Try a different approach.” If it hits the iteration cap, it stops gracefully instead of spiraling.

Without iteration control, agents will happily spend four hours on a problem that needed a five-minute workaround. The grind loop is a leash, not a cage.

Every agent tool — Claude, OpenCode, Kiro, bash wrapper — calls the same check-completion.sh. The iteration mechanics are tool-native (because Claude’s hook model and OpenCode’s plugin model are architecturally different), but the evaluation is shared. One source of truth for “are we done yet.”

Plan-First Enforcement — A pre-write hook blocks code changes until a plan file exists in docs/plans/. Sounds draconian. Is draconian. Also the single most effective quality gate in the entire harness. Agents that plan before coding produce dramatically better results. Almost like thinking before acting is a good idea.

Shared Config — One YAML file, parseable by both shell scripts and structured parsers:

grind_loop:
max_iterations: 5
stall_timeout_seconds: 300
idle_timeout_seconds: 120

Layer 2 keeps agents from going off the rails. Layer 3 makes them good at their job.

Yoke generates all of this from your actual codebase — not empty scaffolds:

  • AGENTS.md from your architecture, toolchain, and detected patterns
  • Four commands (/plan-feature, /start-issue, /create-pr, /fix-issue) with your actual test/lint/typecheck commands baked in
  • Skills detected from codebase patterns (Pydantic models? You get a skill for that. Strategy pattern? Skill. API routes? Skill.)
  • Documentation — architecture overview, testing guide, debugging guide, principles derived from your linter and CI config
  • Code reviewer agent definition parameterized with your tech stack

The issue-decomposition skill is always included. It teaches agents how to break features into the right-sized chunks: one issue = one agent session = one worktree. With dependency ordering, parallel safety rules, and acceptance criteria that are actually testable. “Implement the feature” is not an acceptance criterion. It’s a wish.

This is where the yoke metaphor gets literal. Multiple agents, pulling together.

Terminal window
# Dispatch all orchestrator-ready issues
scripts/orchestrate.sh --label orchestrator-ready
# Or be specific
scripts/orchestrate.sh --issues 101,102,103,104,105
# Peek at the plan without launching anything
scripts/orchestrate.sh --dry-run --label orchestrator-ready

The orchestrator discovers issues, resolves dependencies via topological sort, groups them into waves, and dispatches agents to isolated worktrees in parallel. Wave 1 (no dependencies) runs in parallel. When done, Wave 2 starts. Each agent gets its own git worktree, its own dependency install, its own .env. Complete isolation.

Stall detection kills agents that go silent. Auto-merge handles low-risk PRs. Issue preflight validates everything before an agent touches it. All using native git worktree — no third-party CLIs.


The design decision that makes Yoke work: a clean split between mechanical scaffolding and intelligent generation.

install.sh handles the boring stuff. Directory creation. Template files with {{placeholder}} markers. Gitignore entries. It’s a POSIX shell script. Idempotent (run it twice, same result). Safe (never overwrites existing files). Paranoid (32 automated self-test checks).

The agent handles the smart stuff. Toolchain detection. Placeholder substitution. Tool-native component generation. Codebase analysis. The spec (YOKE_SPEC.md) walks the agent through all of it step by step.

This split means install.sh is dead simple and testable, while the agent does what agents are good at: reading code and making decisions.

Every agent tool shares the same underlying scripts. But the iteration loop itself is tool-native. Because Claude Code’s hook-based model (Stop hook fires → output becomes next prompt → Claude re-enters automatically) is fundamentally different from OpenCode’s event-driven plugin model (session.idle → plugin calls checker → plugin sends new prompt via API).

Pretending these are the same thing would produce a worse result than acknowledging the difference. The shared contract is the JSON output from check-completion.sh. The loop mechanics are each tool’s business.

Share what can be shared, go native where it matters. Forced abstraction over genuinely different architectures is how you get leaky abstractions that nobody trusts.


The most impactful addition was also the last one built. The orchestrator needs well-formed GitHub issues. But where do those issues come from?

Before /plan-feature, the answer was “the developer writes them by hand.” Fine for three issues. Less fine for fifteen.

Developer: /plan-feature "Add backtesting support with historical data replay"
Agent: *reads AGENTS.md, architecture docs, scans codebase*
*decomposes into 7 issues across 3 waves*
"Here's the proposed breakdown into 7 issues across 3 waves.
Want me to:
1. Create all issues as-is
2. Modify the plan
3. Cancel"
Developer: "Merge issues 3 and 4, they're too small separately."
Agent: *adjusts, creates 6 issues with Agent Metadata tables*
"Created 6 issues. To run:
scripts/orchestrate.sh --issues 101,102,103,104,105,106"

The human-in-the-loop gate is non-negotiable. The agent proposes, the developer approves. No issues get created without explicit sign-off. This is where human judgment matters most — scoping, prioritization, and “actually, that’s way more complex than you think.”

The agent is good at decomposition. It’s terrible at knowing what matters. That’s still your job.

This closes the loop: idea → issues → dispatch → implementation → review → merge. You decide what to build. The agents handle the rest.


A real workflow from the project where Yoke was born:

9.00 am:
/plan-feature "Add sentiment analysis scanner with LLM-based scoring"
→ 5 issues created across 2 waves
scripts/orchestrate.sh --issues 201,202,203,204,205
9.40 am:
Wave 1 complete. Both PRs merged.
Wave 2 in progress. Agent on #203 hit a test failure,
grind loop re-prompted twice, fixed on iteration 3.
Agent on #204 completed first try.
10.30 am:
All 5 PRs merged. Feature complete.
Total human time: 2 minutes reviewing the plan,
5 minutes spot-checking the final PRs.

Five issues, three waves, two agents in parallel, one afternoon. The agents did the implementation. The harness did the quality enforcement. The human did the thinking.

That’s the yoke working. The agents pulled the plow. The harness kept them in the furrow. The farmer picked the field.


Terminal window
# Copy the two files into your repo
cp /path/to/yoke/{install.sh,YOKE_SPEC.md} .
# Point your agent at the spec
"Read YOKE_SPEC.md and set up the agentic harness for this repository"

Start with standard profile. Upgrade to full when you’re ready for parallel orchestration. Drop to minimal if you just want the grind loop and plan-first enforcement.

ProfileWhat You GetWhen to Use
minimalGrind loop, plan-first enforcement, shared configSolo dev, single agent
standard+ AGENTS.md, commands, skills, code reviewerMost projects
full+ Orchestrator, wave dispatch, stall detectionParallel agents at scale

Supports Python (uv/pip), TypeScript (npm/yarn/pnpm), Rust (cargo), and Go. Toolchain detection is automatic.


After setup, Yoke is done. No daemon. No version to update. The files are in your repo, committed to git, owned by your team.

Want to change the grind loop iterations? Edit .agents/config.yaml. Want a new skill? Create a file in .agents/skills/. Want to modify the completion checker? It’s a shell script. Read it. Change it. It’s yours.

If you can’t read it, you can’t trust it. And if you can’t trust it, you shouldn’t be letting it control your AI agents.


Yoke is open source. Because the only thing worse than an uncontrolled AI agent is a proprietary system controlling your AI agents.