Agent harness cheat sheet: components, files, problems and a launch checklist
An agent harness consists of five subsystems: instructions, tools, environment, state and feedback. The minimal set of files is an AGENTS.md as a short router, a check script (make check, verify.sh), a progress file and a feature list with statuses; the readiness status is set by a script, not by the agent.
Five harness subsystems
| Subsystem | What it is | Artifacts | Symptom of breakdown |
|---|---|---|---|
| Instructions | What the agent must know about the project | AGENTS.md / CLAUDE.md, skills, docs/, ADRs | Breaks known conventions |
| Tools | What the agent can do | shell, tests, linter, browser, MCP servers | "Wants to, but cannot" |
| Environment | Where the agent works | lock files, Docker/devcontainer, git worktree, sandbox, init.sh | The session starts with fixing the environment |
| State | What survives a restart | PROGRESS.md, DECISIONS.md, feature_list.json, commits | A new session does not know where things stopped |
| Feedback | How the agent learns about a mistake | make check, E2E, hooks, arch-check, evaluator | "Done", but it does not work |
Order for building from scratch: feedback → instructions → state → environment → tools.
Harness files
| File | Purpose | Rule |
|---|---|---|
| AGENTS.md / CLAUDE.md | Entry point: what the project is, how to run it, how to check it | A short router (about 80 lines), links to docs with the condition "when to read" |
| docs/*.md | Details by topic | Read on demand, not in full |
| .claude/skills/*/SKILL.md | Repeatable procedures (deploy, review) | Loaded when the task matches the description |
| PROGRESS.md | State, what is done, blockers, next steps | Update at the end of every session |
| DECISIONS.md | Decision, reason, rejected options | Record the path, not only the conclusion |
| feature_list.json | Features: behavior, verification, state | Exactly one feature active (WIP=1) |
| scripts/verify.sh | Checks a feature and moves it to passing | The only one who sets passing, with the commit SHA |
| scripts/arch-check.sh | Architectural boundaries | Exit code 1 + WHY and FIX in the output |
| scripts/init.sh | Environment check before work | Environment, clean git, green make check, an active feature |
| sprint contract | A contract for a feature before the code | In scope / out of scope / open questions |
| .claude/settings.json | Claude Code permissions and hooks | Checks on events, not in the agent's memory |
AGENTS.md skeleton
# Project: payment backend (FastAPI, PostgreSQL)
## Run
docker compose up -d && ./scripts/init.sh
## Check
make check # lint, types, unit, arch-check
make e2e # end-to-end scenarios
## Definition of Done
- make check and make e2e — exit code 0
- feature moved to passing by the scripts/verify.sh script
- PROGRESS.md updated
## MUST
- database queries only through repositories
- secrets only from environment variables
## Documents
- docs/payments.md — when the task touches payments and refunds
- docs/migrations.md — when the database schema changes
Feature states
| State | Meaning | Who changes it |
|---|---|---|
| pending | In the queue | Planner |
| active | In progress (only one) | Agent at start |
| passing | Check passed | Only verify.sh |
| blocked | Needs a human decision | Agent with a description of the reason |
Verification levels
| Level | What | When |
|---|---|---|
| 1 | Lint, types | Always |
| 2 | Unit and integration tests | Always |
| 3 | E2E | A change spanning more than one layer; before "done" |
| 4 | arch-check | New cross-layer imports |
The right to say "done" comes only after the top level. Green unit tests are not readiness.
Making rules mechanical
| Level | Tool | Cost |
|---|---|---|
| grep guard | A script that searches for a pattern and prints WHY/FIX | Minutes |
| Linter rule | import-linter (Python), dependency-cruiser, eslint-plugin-boundaries (JS/TS) | An hour |
| Architecture test | A CI test that fails when layers are violated | More work, but visible in make check |
#!/usr/bin/env bash
fail=0
if grep -rn "from app.db" app/services/; then
echo "WHY: services do not access the database directly"
echo "FIX: use a repository from app/repositories/"
fail=1
fi
exit $fail
Common problems and fixes
| Problem | Subsystem | Fix |
|---|---|---|
| A rule in CLAUDE.md is not followed | Instructions | Shorten the file, turn the rule into a check or a hook |
| The agent cannot run the tests | Tools | Allow the command, install the dependencies in the image |
| Different behavior on different machines | Environment | Lock files, Docker/devcontainer, pinned runtime versions |
| Amnesia between sessions | State | PROGRESS.md, a session handoff, reading it at the start of the session |
| Three features started, none finished | State | WIP=1 in feature_list.json |
| "Done", but it does not work | Feedback | DoD, E2E, verify.sh, an independent evaluator |
| Tests are green, but the feature is broken | Feedback | E2E with a real database and configuration |
| The agent copies bad patterns | Feedback | arch-check from day one |
| Unclear what the agent did | State | Small commits, a report in PROGRESS.md, DECISIONS.md |
| The agent broke the environment overnight | Environment | Sandbox, git worktree, checkpoints, rollback via init.sh |
| The same review comment twice | Harness overall | Turn it into a check in make check, remove the text from the instructions |
Roles for long tasks
| Role | Does | Does not |
|---|---|---|
| Planner | Features with acceptance criteria | Does not write code |
| Generator | Implements one feature, runs the tests | Does not decide whether it is done |
| Evaluator | A verdict by rubric, with references to a file, a line or a log | Does not see the generator's reasoning |
| Merge | Commits when review == pass | This is code, not an agent |
Budget for autonomous work
- The goal is one sentence (for example, bring all features to passing).
- WIP=1, a time and attempt limit per feature.
- The metric grows monotonically; a regression means an immediate rollback.
- Migrations, infrastructure, money — escalate to a human.
- After several failed reviews, start the feature with a clean context.
Agent launch checklist
- There is an AGENTS.md: stack, how to run, the check command, DoD.
- make check passes on a clean clone.
- The environment is reproducible: lock files, Docker or devcontainer.
- The agent has the commands it needs; dangerous ones are forbidden or sandboxed.
- There is an E2E test for at least the main scenario.
- There is a PROGRESS.md and a rule to read it at the start of the session.
- Features are in a list with statuses, exactly one active.
- The passing status is set by a script.
- Check messages contain WHY and FIX.
- The task is formulated with acceptance criteria and a scope boundary.
- It is defined what requires a human decision.
- The verification gap is measured before the changes, to have a baseline for comparison.
Harness metrics
| Metric | How to count |
|---|---|
| Verification gap | Share of "done" claims not confirmed by a check, over 10 tasks |
| MTTR | Time from breakdown to restoring a working state |
| Cold start | Whether a new session answers "where are we, what is next" without guessing |
| Ablation | Drop when one subsystem is disabled on a fixed set of tasks |
In short
The harness is a loop, not a file: instructions, tools, environment, state and feedback. Start with checks, keep AGENTS.md short, give the readiness status to a script and review the harness regularly. All of this is assembled as a whole on an end-to-end project in the harness engineering course.
FAQ
How is AGENTS.md different from CLAUDE.md?
In purpose they are the same thing: an instructions file for the agent. CLAUDE.md is read by Claude Code, AGENTS.md is a common format for different agents; in CLAUDE.md you can simply reference AGENTS.md.
How many lines should AGENTS.md have?
There is no strict limit, but keep the entry file short — around a hundred lines, like a table of contents. Details are moved into separate documents.
Do I need feature_list.json for a small project?
Not for one-off edits. It pays off when the agent works on several features in a row or across several sessions.
Where should I keep secrets the agent needs access to?
In environment variables or a secrets manager, not in instruction files and not in code. The agent is given access to the environment, not to the values written in the text.
This topic is covered in depth with practice in the course “Harness Engineering: Engineering Reliability for AI Agents”.
- What an AI Agent Harness Is Made Of: Instructions, Tools, Environment, State, Feedback Loops
- Building an AI Agent Harness From Scratch: AGENTS.md, feature_list.json, verify.sh and an Autonomous Loop