{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreigmltbxaiatcg6tsilcemqt55gi6klaj5jbas5kesqzzbirrxkxfu",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mps6gja2y5f2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreifjd4hldhmmvte5dxe77hgkcnon7un2d35u4nylnplbq6ikbvywtq"
    },
    "mimeType": "image/webp",
    "size": 137678
  },
  "path": "/wolfejam/agentsmd-hands-on-build-one-step-by-step-and-watch-an-agent-use-it-3g27",
  "publishedAt": "2026-07-04T03:31:12.000Z",
  "site": "https://dev.to",
  "tags": [
    "ai",
    "agents",
    "programming",
    "tutorial",
    "the field guide"
  ],
  "textContent": "In the field guide I covered what an AGENTS.md is and what belongs in it. This is the hands-on follow-up: we'll build a complete AGENTS.md for a real project, one section at a time, then point an AI coding agent at it and watch the difference it makes. By the end you'll have a working file — and you'll have seen it pay off.\n\n_New to AGENTS.md? It's a single Markdown file at the root of your repo that tells AI coding agents how to work in it — build steps, tests, conventions, guardrails. The \"why\" behind each section is in the field guide._\n\n##  The project we'll use\n\nWe'll write the AGENTS.md for a small but real service: a **URL shortener API in Python** — FastAPI, SQLite, pytest. A couple of endpoints, a thin data layer, a test suite. Follow along with this, or swap in your own repo — the steps are identical.\n\nIts shape:\n\n\n\n    linkshort/\n      app/\n        main.py        # FastAPI routes\n        db.py          # SQLite access\n        models.py      # Pydantic models\n      migrations/      # generated SQL — not hand-edited\n      tests/\n      requirements.txt\n\n\n##  Step 0 — Start with an empty file\n\nAt the repo root:\n\n\n\n    touch AGENTS.md\n\n\nThat's the whole step. We'll fill it in one section at a time, building toward a file an agent can read in thirty seconds.\n\n##  Step 1 — Orientation: one line\n\nTell the agent what it's looking at. Add:\n\n\n\n    # AGENTS.md\n\n    A URL shortener API in Python — FastAPI, SQLite, pytest.\n\n\nOne sentence sets the agent's priors: it knows the language, framework, and storage before it reads a single line of code.\n\n##  Step 2 — Setup and run\n\nThe agent can't help if it can't start the project. Add the real, copy-pasteable commands:\n\n\n\n    ## Setup\n    python -m venv .venv && source .venv/bin/activate\n    pip install -r requirements.txt\n\n    ## Run\n    uvicorn app.main:app --reload   # http://localhost:8000\n\n\nUse the commands that actually work in your repo — no placeholders.\n\n##  Step 3 — Tests: the agent's feedback loop\n\nThis is the most important section, because tests are how the agent checks its own work. Add:\n\n\n\n    ## Test — all must pass before a change is done\n    pytest\n    ruff check .\n    mypy app\n\n\nNow the agent knows how to verify a change _and_ the bar it has to clear. An agent that knows `pytest` will run it; one that doesn't hands you a broken branch.\n\n##  Step 4 — The map: where things live\n\nA short map so the agent finds its way without spelunking the whole tree:\n\n\n\n    ## Structure\n    - app/main.py    route handlers\n    - app/db.py      SQLite access (parameterized queries only, never string-built SQL)\n    - app/models.py  Pydantic request/response models\n    - migrations/    generated SQL — do not hand-edit\n    - tests/         pytest, mirroring app/\n\n\nNotice we're already slipping a convention (\"parameterized queries only\") and a guardrail (\"do not hand-edit\") in right where they're relevant.\n\n##  Step 5 — Conventions: the house style\n\nThe patterns you want followed. Be specific — vague rules are noise:\n\n\n\n    ## Conventions\n    - Validate all input with Pydantic models at the route boundary.\n    - Raise HTTPException for client errors; never return raw dicts on failure.\n    - Type everything; mypy must stay clean.\n    - Match the style of the surrounding file.\n\n\n\"Type everything; mypy must stay clean\" tells the agent exactly what to do. \"Write good code\" wouldn't.\n\n##  Step 6 — Commits and PRs\n\nIf your agent opens PRs, give it the house rules:\n\n\n\n    ## Commits & PRs\n    - Conventional Commits (feat:, fix:, chore:).\n    - One logical change per PR; update CHANGELOG.md.\n\n\n##  Step 7 — Guardrails: the landmines\n\nThe \"don'ts\" that prevent expensive mistakes:\n\n\n\n    ## Don't\n    - Don't hand-edit migrations/ — they're generated.\n    - Don't commit directly to main — branch and open a PR.\n    - Never run the seed script against a non-local database.\n\n\n##  Your finished AGENTS.md\n\nPut it together and you have a complete, copy-pasteable file:\n\n\n\n    # AGENTS.md\n\n    A URL shortener API in Python — FastAPI, SQLite, pytest.\n\n    ## Setup\n    python -m venv .venv && source .venv/bin/activate\n    pip install -r requirements.txt\n\n    ## Run\n    uvicorn app.main:app --reload   # http://localhost:8000\n\n    ## Test — all must pass before a change is done\n    pytest\n    ruff check .\n    mypy app\n\n    ## Structure\n    - app/main.py    route handlers\n    - app/db.py      SQLite access (parameterized queries only, never string-built SQL)\n    - app/models.py  Pydantic request/response models\n    - migrations/    generated SQL — do not hand-edit\n    - tests/         pytest, mirroring app/\n\n    ## Conventions\n    - Validate all input with Pydantic models at the route boundary.\n    - Raise HTTPException for client errors; never return raw dicts on failure.\n    - Type everything; mypy must stay clean.\n    - Match the style of the surrounding file.\n\n    ## Commits & PRs\n    - Conventional Commits (feat:, fix:, chore:).\n    - One logical change per PR; update CHANGELOG.md.\n\n    ## Don't\n    - Don't hand-edit migrations/ — they're generated.\n    - Don't commit directly to main — branch and open a PR.\n    - Never run the seed script against a non-local database.\n\n\nThirty seconds to read. Now let's see if it works.\n\n##  Step 8 — Prove it: point an agent at it\n\nThis is the part that matters. Open your repo in an AI coding agent — Claude Code, Cursor, Codex, whatever you use — and give it a real task:\n\n> \"Add a `DELETE /links/{code}` endpoint that removes a link, with a test.\"\n\nWatch what it does **with the AGENTS.md in place:**\n\n  * It reads the file first — it knows the stack and where routes live.\n  * It adds the handler in `app/main.py`, validating input the way your conventions require.\n  * It writes a `pytest` test in `tests/`, mirroring the structure.\n  * It runs `pytest`, `ruff`, and `mypy` — because you told it that's the bar — and fixes what fails.\n  * It **doesn't** touch `migrations/`, and it **doesn't** commit to main — it opens a branch.\n\n\n\nNow picture the same task **without** the file. The agent has to guess: Which test runner? Where do routes go? Is there a lint step? So it asks you, or it guesses wrong, or it edits a generated file you'll have to revert. The AGENTS.md is the difference between an agent that interrupts you and one that just ships.\n\nThat's the whole payoff — and you can watch it happen in real time.\n\n##  Keep it alive\n\nOne habit before you go: treat the file like code. When the test command changes, or you add a directory, or you catch yourself telling the agent the same thing twice — update AGENTS.md in the same breath. A stale file is worse than none, because the agent trusts it.\n\n##  That's the loop\n\nYou started with an empty file, added eight short sections, and watched an agent use every one of them to land a correct, tested change without hand-holding. Write it once, and every agent that walks into your repo gets the same briefing.\n\n_This was the hands-on build. For the principles behind each section — what belongs, the anti-patterns, why short beats complete — see the field guide._",
  "title": "AGENTS.md, Hands-On: Build One Step by Step (and Watch an Agent Use It)"
}