Capstone: Ship a Reusable Agent Workbench Pack
The mini-track ends with a directory you can drop into any repo. Eleven lessons of surfaces, compressed into something you `cp -r` so an agent is working reliably the next morning. This is the artifact the curriculum trades on.
Learning Objectives
- Package the seven workbench surfaces into one drop-in directory.
- Pin the schemas, scripts, and templates so a new repo gets a known-good baseline.
- Add a single installer script that lays down the pack idempotently.
- Decide what stays in the pack and what stays out, defending the cut for each.
The Problem
A workbench pack is a versioned directory that holds the seven surfaces (init script, scope contract, state, feedback runner, verification gate, reviewer, and handoff, built in Lessons 34 to 40 and listed in Lesson 41), the schemas, the scripts, and a one-command installer. Without one, the workbench lives in a Google Doc, a chat history, and three half-remembered scripts, and it gets rebuilt every quarter.
You will end this lesson with outputs/agent-workbench-pack/ shipped on disk and a bin/install.sh that drops it into any target repo.
The Concept
The pack layout
outputs/agent-workbench-pack/
├── AGENTS.md
├── docs/
│ ├── agent-rules.md
│ ├── reliability-policy.md
│ ├── handoff-protocol.md
│ └── reviewer-rubric.md
├── schemas/
│ ├── agent_state.schema.json
│ ├── task_board.schema.json
│ └── scope_contract.schema.json
├── scripts/
│ ├── init_agent.py
│ ├── run_with_feedback.py
│ ├── verify_agent.py
│ └── generate_handoff.py
├── bin/
│ └── install.sh
└── README.md
What stays in, what stays out
In:
- Surface schemas. They are the contract.
- The four scripts above. They are the runtime.
- The four docs. They are the rules and the rubric.
Out:
- Project-specific tasks. Those belong on the target repo's board, not in the pack.
- Vendor SDK calls. The pack is framework-agnostic.
- Onboarding prose. The pack sits next to the team's existing onboarding, not inside it.
The installer
A short bin/install.sh (or bin/install.py) does four things:
- Refuses to install over an existing pack without
--force. - Copies the pack into the target repo.
- Wires up CI if a
.github/workflows/exists. - Prints next steps: fill in the board, set acceptance commands, run the init script.
Versioning
The pack carries a VERSION file. A schema bump, or a script change that requires a migration, bumps the major. A change that only needs the checker re-run bumps the minor. A doc-only change bumps the patch. The target repo's agent_state.json records which pack version it was initialized against.
Build It
code/main.py assembles the pack into outputs/agent-workbench-pack/ next to the lesson. It seeds the pack with the schemas and scripts from the previous lessons in this mini-track, plus the docs you already wrote.
Run it:
python3 code/main.py
The script copies and pins the surfaces, writes the README, prints the pack tree, and exits zero. Re-running is idempotent.
Production patterns in the wild
A pack is only valuable if it survives forks, updates, and an unfriendly upstream. Four patterns make that work. The layout above is the minimal pack. A full version also ships VERSION, lint_pack.py, and uninstall.sh (Exercises 3 and 4 have you build the last two), and the installer writes .workbench-version into the target repo.
VERSION is the contract, not the marketing. Major bumps require a state migration. Minor bumps require a checker re-run. Patch bumps are doc-only. The installer writes .workbench-version into the target repo on every install, and lint_pack.py refuses to ship if the target's lock disagrees with the pack's VERSION. That is how npm, Cargo, and pyproject.toml survive 10 years of churn. Agents don't change the rules.
One source, every tool. Nx ships a single nx ai-setup that lays down AGENTS.md, CLAUDE.md, .cursor/rules/, .github/copilot-instructions.md, and an MCP server from one config. The pack should do the same. The installer emits the symlinks (ln -s AGENTS.md CLAUDE.md), so a single source of truth fans out to every coding agent. Forking the pack to support one tool over another is a failure mode.
An uninstall.sh that refuses on non-trivial state. Uninstalling must not delete the user's agent_state.json, task_board.json, or outputs/. The uninstaller removes the schemas, scripts, docs, and AGENTS.md (with a --keep-agents-md opt-out), and it refuses to proceed if any state file has uncommitted changes. State belongs to the user; the pack does not own it.
Publish it as a skill. The pack ships as a SkillKit skill: skillkit install agent-workbench-pack lays it down across 32 AI agents from a single source. The pack repo is the source of truth and SkillKit is the distribution channel. Vendor lock-in collapses, and the seven surfaces stay the same.
Use It
The pack ships three ways:
- As a directory you drop into a repo.
cp -r outputs/agent-workbench-pack /path/to/repo. - As a public template repo. Fork and customize, with
VERSIONcontrolling drift. - As a SkillKit skill. Wired into your agent product so a single command lays it down.
The pack is the recipe. Each install is a serving.
Ship It
outputs/skill-workbench-pack.md generates a project-tuned pack: rules sharpened to the team's history, scope globs matched to the repo, and the rubric extended with one domain-specific dimension.
My bet is that a pack gets judged on what it refuses to touch. I treat the out list as the design: tasks stay on the target repo's board, vendor SDK calls stay out, and the uninstaller leaves agent_state.json, task_board.json, and outputs/ alone. State belongs to the user; the pack does not own it, so I'd make the uninstaller refuse before it would ever guess. Keeping vendor SDK calls out is what keeps the pack framework-agnostic. Everything on the out list is a line I'd hold.
Exercises
- Decide which optional fifth doc deserves promotion into the canonical pack. Defend the cut.
- Rewrite the installer as Python with a
--dry-runflag. Compare its ergonomics against bash. - Add a
bin/uninstall.shthat safely removes the pack and refuses if state files have non-trivial history. What counts as non-trivial? - Add a
lint_pack.pythat fails when the pack drifts fromVERSION. Wire it into CI for the pack's own repo. - Author the migration runbook from a hand-rolled workbench to this pack. Which order of operations minimizes downtime?
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| Workbench pack | "The starter kit" | A versioned directory carrying all seven surfaces |
| Installer | "Setup script" | bin/install.sh that lays the pack down idempotently |
| Pack version | "VERSION" | Major bumps for schema/script changes, minor for checker re-runs, patch for doc-only |
| Drop-in pack | "cp -r and go" | Pack works without per-repo customization on day one |
| Forkable template | "GitHub template" | Public repo that GitHub's "Use this template" can clone from |
Further Reading
- Phases 14 · 31 to 14 · 41: every surface this pack bundles
- SkillKit: install this skill across 32 AI agents
- Nx Blog, Teach Your AI Agent How to Work in a Monorepo: single-source generator across six tools
- agents.md: the open spec: what your pack's router must implement
- HKUDS/OpenHarness: reference implementation of a pack-equivalent
- andrewgarst/agentic_harness: Redis-backed reference with eval suite
- Augment Code, A good AGENTS.md is a model upgrade: pack docs quality bar
- Anthropic, Effective harnesses for long-running agents
- Anthropic, Harness design for long-running application development
- Phase 14 · 30: eval-driven agent development that consumes the pack's verification gate
- Phase 14 · 41: the before/after benchmark this pack improves on
Code
- main.py (python, 622 lines)