The Minimal Agent Workbench
The smallest useful workbench is three files: a root router, a state file, and a task board. Everything else layers on top. If a repo can't carry these three, no model will save it.
Learning Objectives
- Define the three files that form the minimum viable workbench.
- Explain why a short root router beats a long monolithic `AGENTS.md`.
- Build a state file the agent can read at every turn and write at the end.
- Build a task board that survives multi-session work without chat history.
The Problem
Most teams reach for a workbench by writing a 3000-line AGENTS.md and calling it done. The model loads it, ignores the parts it cannot summarize, and still fails on the same surfaces it failed on before.
The fix is the opposite shape. A tiny root file routes the agent into deeper files only when they're relevant. Durable state gets read before acting and written after. A task board says what is in flight, what is blocked, and what is up next.
That's three files, each with one job, and each machine-readable enough to grow into a real system later.
The Concept
A minimal agent workbench is three files in a repo: a short AGENTS.md that routes the agent to everything else, an agent_state.json that records where the work stands, and a task_board.json that queues what is left. Each one is covered below.
AGENTS.md is a router, not a manual
A router is a short root file that points the agent at what it needs and nothing more. A good AGENTS.md points at:
- The state file (where you are).
- The task board (what is left).
- The deeper rules (under
docs/agent-rules.md). - The verification command (how to know it works).
Anything longer goes in deeper docs, loaded only when needed. Long manuals get ignored, while short routers get followed.
agent_state.json is the system of record
The system of record is the file the workbench treats as authoritative once chat is gone. Here that file carries the active task id, the touched files, the assumptions made, the blockers, and the next action. The agent reads it at every turn, and the next session reads it instead of replaying chat.
State lives in a file because chat history is unreliable. Sessions die and conversations get trimmed. The file doesn't.
task_board.json is the queue
The task board holds every task with a status of todo | in_progress | done | blocked. The agent pulls from it when state is empty, and you read it when you want to know whether the agent is on track.
A task has an id, a goal, an owner (builder, reviewer, or human), and acceptance criteria. The board is small on purpose: when it grows past a screen, you have a planning problem, not a board problem.
Three files is the floor, not the ceiling
Later lessons add scope contracts, feedback runners, verification gates, reviewer checklists, and handoff packets. All of them assume these three files exist.
Build It
code/main.py writes the minimal workbench into an empty repo and runs a single agent turn that:
- Reads
agent_state.json. - Pulls the next task from
task_board.jsonif state is empty. - Marks it
in_progressand sets the next action. - Writes back updated state.
Run it:
python3 code/main.py
The script creates workdir/ next to itself, lays down the three files, runs one turn, and prints the diff. Run it again and the second turn picks up where the first left off.
Use It
The same three roles show up inside production agent products under different names. This mapping is illustrative, not a full account of each product:
- Claude Code:
CLAUDE.md(or a symlink toAGENTS.md) is the router. For state and the board, keepagent_state.jsonandtask_board.jsonin the repo and point the router at them. - Codex / Cursor: workspace rules or
AGENTS.mdare the router. State and board are again files you add and reference from it. Each product also has its own session memory or task list, which fill similar roles but live outside your repo. - Custom Python agent: the same files you just wrote.
The names change. The shape doesn't.
Production patterns in the wild
The minimum workbench holds up in real monorepos once three patterns are layered on top. They're independent, so pick the ones your repo needs.
Nested AGENTS.md with nearest-wins precedence. OpenAI ships 88 AGENTS.md files across its main repo, one per subcomponent. Tools that read AGENTS.md natively, such as Codex and Cursor, walk from the working file toward the repo root and concatenate every AGENTS.md they find on the way, so sub-directory files extend the root file. Claude Code reads CLAUDE.md instead, which is why the symlink below exists. Codex adds AGENTS.override.md to replace rather than extend. That mechanism is Codex-specific, so avoid it for cross-tool work. Augment Code's measurement is the line that matters: the best AGENTS.md files give a quality jump equivalent to upgrading from Haiku to Opus, and the worst ones make output worse than no file at all.
Anti-patterns to refuse, even when they look like coverage.
- Conflicting instructions silently drop the agent from interactive to greedy mode (ICLR 2026 AMBIG-SWE: 48.8% → 28% resolve rate). Give the rules ranked numbers so the agent knows which one wins when, say, "ask before editing" collides with "don't interrupt me", instead of stacking them flat.
- Unverifiable style rules ("follow the Google Python Style Guide") with no enforcement command let the agent invent compliance. Pair every style rule with the exact lint command.
- Leading with style instead of commands buries the verification path. Put commands first and style last.
- Writing for humans instead of agents wastes context budget. Terseness is a feature.
Cross-tool symlinks. One root file plus symlinks (ln -s AGENTS.md CLAUDE.md, ln -s AGENTS.md .github/copilot-instructions.md, ln -s AGENTS.md .cursorrules) keeps every coding agent on the same source of truth. Nx's nx ai-setup automates this across Claude Code, Cursor, Copilot, Gemini, Codex, and OpenCode from a single config.
Ship It
outputs/skill-minimal-workbench.md generates the three-file workbench for any new repo: an AGENTS.md router tuned to the project, an agent_state.json with the right keys, and a task_board.json seeded with the current backlog.
I treat the router as the file to protect. The failure this lesson opens with is a 3000-line AGENTS.md that the model loads and then ignores the parts it cannot summarize. The fix it gives is a short file that points elsewhere. So when a new rule wants to live in the root, I'd put it in docs/agent-rules.md and leave a pointer behind. My bet is that a root file short enough to lint (exercise 4 caps it at 80 lines) stays a router, and once it starts reading like a manual it has stopped doing the job.
Exercises
- Add a
last_runtimestamp toagent_state.json. Refuse to run if the file is older than 24 hours unless an operator confirms. - Add a
priorityfield to the task board and change the puller to always pick the highest prioritytodo. - Migrate
task_board.jsonto JSON Lines so each task is a line and diffs are clean in version control. - Write a
lint_workbench.pythat fails ifAGENTS.mdis over 80 lines or references a file that does not exist. - Decide which one of the three files would hurt the most to lose. Defend it.
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| Router | "The instructions file" | Short root file that points the agent at deeper docs and files |
| State file | "The notes" | Machine-readable record of where the agent is, written every turn |
| Task board | "The backlog" | JSON queue of work with status, owner, acceptance |
| System of record | "Source of truth" | The file the workbench treats as authoritative when chat is gone |
Further Reading
- agents.md: the open spec: adopted by Cursor, Codex, Claude Code, Copilot, Gemini, OpenCode
- Augment Code, A good AGENTS.md is a model upgrade. A bad one is worse than no docs at all: measured quality jumps
- Blake Crosley, AGENTS.md Patterns: What Actually Changes Agent Behavior: what works empirically, what does not
- Datadog Frontend, Steering AI Agents in Monorepos with AGENTS.md: nested precedence in practice
- Nx Blog, Teach Your AI Agent How to Work in a Monorepo: single-source generation across six tools
- The Prompt Shelf, AGENTS.md Best Practices: Structure, Scope, and Real Examples: section ordering that survives review
- Anthropic, Claude Code subagents and session store: how Claude Code handles subagents and sessions
- Phase 14 · 31: the failure modes this minimum absorbs
- Phase 14 · 34: the durable state schema this lesson previews
Code
- main.py (python, 156 lines)