How to write the perfect AGENTS.md
A strong AGENTS.md is a short execution contract for contributors working on an agent-enabled repository. It should state the local operating rules, define w...
How to write the perfect AGENTS.md
A “perfect” AGENTS.md for this kind of repository is a clear one. The file should help someone act correctly inside the current system: what the agent is allowed to do, what layer owns which rules, how state is handled, and how to change behavior without breaking instruction composition.
For a repository like ZeroState, that means writing AGENTS.md as a local execution contract, not a general AI manifesto and not a duplicate of deeper system doctrine.
What do I need before I start?
Start with the documents that show how the repository operates today: the current AGENTS.md, any deeper guardrail document that owns broader orchestration or system doctrine, and the runtime or architecture material that describes current behavior rather than planned behavior.
If the repository already separates local rules from shared doctrine, keep that split. Do not use AGENTS.md to restate every architectural rule in full if another document already owns it.
Step 1: Define the job of AGENTS.md before you draft it
Start by writing one plain statement of purpose near the top of the file.
The purpose should say that AGENTS.md defines repository-specific operating rules for the coding agent. That framing matters because it keeps the file practical. A contributor reading it during active work should immediately understand that this is the contract for execution in this repo, not a loose style guide and not a theory document.
Expected result: The first paragraph answers, “What is this file for?” without explaining AI concepts, prompting theory, or team philosophy.
Step 2: Keep the file short and push deep doctrine down a layer
Next, decide what should stay in AGENTS.md and what should move to a deeper document.
AGENTS.md should stay focused on local operating rules. If the task touches orchestration, instruction layering, workflow composition, client interfaces, or broader architecture doctrine, point readers to the guardrail document that owns those rules instead of duplicating them.
A common failure mode is letting AGENTS.md absorb context that belongs in a deeper architectural document. That makes the file harder to use during real work.
Write short routing language such as:
- “Read the system guardrails first when the change affects orchestration or instruction layering.”
- “Keep AGENTS.md focused on local execution rules.”
- “Do not duplicate shared doctrine here.”
Expected result: A contributor can tell which document to read next when the task moves beyond local agent behavior.
Step 3: Encode the repository defaults that shape day-to-day work
After the purpose and scope are clear, add the default behavior rules. These are the practical defaults contributors should assume unless a more specific local contract overrides them.
Based on the repository guidance, good defaults include:
- Preserve the existing architecture.
- Make the smallest viable change.
- Keep agents thin.
- Keep contracts explicit.
- Keep outputs inspectable.
These defaults work because they shape decisions without turning the file into a giant checklist. They tell contributors how to behave when the task does not spell out every detail.
Make each default concrete. For example, “keep agents thin” is useful if you connect it to instruction ownership and workflow composition. “Keep contracts explicit” is useful if you tie it to local roles, state boundaries, and output expectations. “Keep outputs inspectable” is useful if you connect it to diagnostics and traceability.
Expected result: The file contains a short section of defaults that influences real implementation decisions, not just tone.
Step 4: Draw hard role boundaries
Now add the rules that prevent role drift.
A strong AGENTS.md should say, in plain language, that writers do not become fact-checkers, editors do not become planners, and image nodes do not alter article content. More generally, each agent should keep to its assigned role and output contract.
This matters because role drift creates conflicting instructions and makes workflows harder to debug. The problem is not only quality. It also becomes harder to trace why a workflow produced a given output.
Keep this section firm and specific. Avoid fuzzy wording like “agents should generally stay focused.” Say what they must not cross.
Expected result: A contributor can identify which work belongs to which agent without inferring it from scattered prompts.
Step 5: Name the instruction layers and where each kind of rule belongs
Once roles are clear, explain the instruction layers.
The repository guidance supports a pattern like this:
- Local behavior belongs in agent YAML or the local contract layer.
- Shared doctrine belongs in bundle assets or shared instruction assets.
- Orchestration rules belong in the core workflow engine.
This section is one of the most valuable parts of the file because it helps contributors change the right thing first. It also reduces duplicated doctrine and “prompt soup,” where similar rules appear in too many places with slight variations.
Do not describe these layers abstractly. State who owns what. If a contributor wants to change a shared writing doctrine, they should know not to patch AGENTS.md first. If they want to change the execution sequence, they should know that the workflow engine owns it.
Expected result: The file gives a reader a reliable map from requested behavior change to owning layer.
Step 6: Make state boundaries explicit
If the system uses distinct state types, name them directly in AGENTS.md.
The repository guidance points to four important boundaries:
- Immutable task state
- Instruction state
- Ephemeral working state
- Locked output state
You do not need to turn this into a long state-management essay. You do need to make the boundaries visible enough that contributors do not casually blur them.
For example, AGENTS.md can state that immutable task state is the source of truth for task constraints, ephemeral state is working context only, and locked output state should not be modified once finalized by the owning stage. The exact wording can stay short, but the separation should be unambiguous.
This helps contributors avoid changing behavior in ways that quietly break state pruning, execution traceability, or downstream stage assumptions.
Expected result: A contributor can see which state is stable, which state is temporary, and which state must not be overwritten casually.
Step 7: Document the preferred change pattern
After you define layers and boundaries, tell contributors how to make changes in the correct order.
The repository guidance supports a change pattern like this:
- Change the local contract first when the request is local.
- Change shared doctrine when the rule is shared across agents or workflows.
- Change instruction composition before changing agent code when the issue is really in prompting or layering.
- Run tests or diagnostics after the contract change.
This section should feel operational. The reader should know what to touch first, not just what exists.
If you skip this, contributors may edit the most visible file rather than the correct one. That usually leads to duplicated logic, unexplained overrides, or hidden orchestration changes.
Expected result: The file gives a believable sequence for implementing behavior changes without guessing.
Step 8: Protect observability and diagnostics
Add a short section that preserves inspectability.
The repository guidance emphasizes keeping traceability, prompt diagnostics, state reduction metrics, per-agent size diagnostics, and compact-versus-debug output separation intact. AGENTS.md should reflect that by telling contributors not to hide workflow behavior or remove useful diagnostics just to make prompts look cleaner.
This does not require a long monitoring section. A few direct rules are enough:
- Preserve traceability.
- Keep diagnostic surfaces intact.
- Do not collapse debug and compact outputs into one blurred mode.
- Do not hide instruction flow behind undocumented logic.
That language keeps the system reviewable. It also helps contributors understand that clean output is not the same thing as invisible execution.
Expected result: The file protects debugging and review surfaces instead of treating them as optional noise.
Step 9: Add a short red-flags section
Finish the main draft with the failure patterns contributors should avoid.
The repository research supports warning against:
- Prompt soup
- Bespoke agent sprawl
- Hidden orchestration logic
- Duplicated doctrine
- Context bloat without measurement
This section works best as a compact warning list, not a lecture. Its job is to stop mistakes early. If a contributor reads only one cautionary section before editing the system, this should be it.
Expected result: The file names concrete anti-patterns that a contributor can recognize during a change.
How do I verify it worked?
Use these checks after drafting or revising AGENTS.md:
- Read the first screenful only. You should be able to answer three questions immediately: what AGENTS.md is for, what it does not own, and where to look for deeper rules.
- Pick one sample change request. For example: “change a shared writing rule” or “change orchestration order.” The file should make it obvious which layer owns that change.
- Trace one role boundary. A writer, editor, or image node should each have a clearly limited job.
- Trace one state boundary. The draft should distinguish stable task constraints from temporary working context.
- Scan for duplication. If AGENTS.md repeats broad doctrine already owned by guardrails, cut it or replace it with a pointer.
- Scan for future-state language. The file should describe current runtime behavior and current constraints, not imply capabilities the system does not actually have.
- Check diagnostics language. The draft should preserve inspectability rather than encouraging hidden behavior.
If a contributor can route a behavior change correctly after a short read, the file is doing its job.
Common errors and gotchas
The file becomes a second architecture manual
Symptom: AGENTS.md grows into a long explanation of orchestration, shared doctrine, and workflow internals.
Cause: The file is trying to own global rules instead of local execution rules.
Fix: Keep AGENTS.md short. Move deeper architectural or orchestration doctrine into the guardrail document and leave a pointer in AGENTS.md.
The rules are clear, but nobody knows where to make changes
Symptom: Contributors understand the system in theory but still patch the wrong layer.
Cause: The file describes the architecture but does not map change requests to owning layers.
Fix: Add a routing section that distinguishes local contract changes, shared doctrine changes, and workflow-engine changes.
Agent roles start to blur
Symptom: Writers start validating facts, editors start planning, or downstream nodes alter content they should not own.
Cause: The file uses soft wording around role boundaries.
Fix: Rewrite role rules as hard boundaries. Say what each role must not do, not just what it usually does.
The file sounds impressive but is hard to use during active work
Symptom: The document reads like policy language instead of an operating contract.
Cause: Too much abstract explanation and not enough execution guidance.
Fix: Cut theory, keep defaults short, and make each section answer an action question: what does this rule control, and what should the contributor do?
Diagnostics get removed in the name of simplification
Symptom: A change reduces traceability or hides instruction flow.
Cause: Contributors treat observability as optional implementation detail.
Fix: State directly that inspectable outputs, prompt diagnostics, and traceability are part of the contract and should remain intact.
What should I do next?
Draft your AGENTS.md as a short local contract, then test it against one real change request to confirm the file routes that change to the right layer without guesswork.