Courses / GenAI and Agents Fast Track

Session 7 of 8

Coding with an AI agent: the first session

Overview

Chapter 7 — Coding with an AI Agent: The First Session

Course: GenAI and Agents Fast Track Prerequisites: basic Python and running tests with pytest; the idea of an agent that loops through tools (read, act, check, repeat); a repository to work in (this unit uses a small Python repository with an MCP notes server and a pytest suite); git basics (seeing what changed).

What the reader can do after this unit:

  • Write a short context file (AGENTS.md, or CLAUDE.md for the same purpose) that tells a coding agent the commands, conventions and working rules of a repository
  • Ask a coding agent for a plan, edit the plan, then have it implement the work in small steps, each with a test it runs
  • Review a diff line by line, and reject or correct a change that touches the wrong files, edits a test to make it pass, or breaks a repository rule

Core question this unit answers: How do you add a feature to a real codebase with a coding agent and still own the result?

Connections:

  • Builds on: an MCP notes server with tests, and the habit of giving an agent tools and a way to check its work
  • Leads into: choosing a capstone project and building it with the same workflow: context file, plan, small steps with tests, and review of every change

Notes

Student Notes — Chapter 7: Coding with an AI Agent: The First Session

GenAI and Agents Fast Track · Chapter 7

Before you start

You need the repository you have been building (Python 3, with pytest and anyio installed), git, and a terminal. To follow along with a real coding agent you also need one installed. The in-depth example is Claude Code: its installation steps are in the tool’s official quickstart, and signing in needs a Claude subscription (Pro, Max, Team or Enterprise), a Claude Console account, or access through a supported cloud provider. Other coding agents work for the project too, because the habits in this chapter (a context file, a plan, small steps with tests, and a review of every change) do not belong to one tool. If you have no agent, you can still read the chapter and write the context file in the project’s first task by hand.

Summary

A coding agent reads your repository, edits files and runs commands, so you can hand it a task in plain English, but the result is yours the moment you keep it. This chapter teaches the difference between vibe coding, where generated code is accepted without a thorough review, and engineering with an agent, where you give it context, make it prove its work with tests, and read every change. You write a repository context file (AGENTS.md, or CLAUDE.md for the same purpose) that carries the commands and rules the agent cannot guess. You then work in the order plan, small step, test, review, using a real feature added to the notes server as the running example. By the end you can run a first session with a coding agent and say what you checked before you kept each change.

Key concepts

Term Definition
Coding agent A program that uses a model to work on code: it reads your repository, edits files and runs commands such as tests, checking its own results and repeating until the task is done.
Vibe coding Building software by describing what you want and accepting the generated code, often without a thorough review of it, guiding changes only with follow-up requests.
Context file A markdown file in the repository, such as AGENTS.md or CLAUDE.md, that the coding agent reads at the start of a session. It holds the commands, conventions and rules the agent cannot work out from the code.
AGENTS.md A plain-markdown context file in an open format, described as a README for agents, that several different coding tools read.
Plan mode A setting in which the agent reads files and proposes a plan but makes no edits to your source files until you approve.
Plan A written list of the files to change, the steps in order, the test for each step and what is out of scope, which you read and edit before any code changes.
Small step One change that adds one behaviour and has one test, small enough that its diff can be read in one sitting without losing track.
Verification A check the agent can run and read, such as the test suite, that returns pass or fail. Without one, “looks done” is the only signal.
Diff The list of lines added and removed by a change, shown side by side with the old version.
Diff review Reading every line of a diff and asking whether it matches the plan, touches only the intended files, keeps the tests honest and obeys the repository’s rules.
Permission mode A session setting that decides which actions the agent may take without asking you first, such as editing files or running commands.
Checkpoint A snapshot of files taken before the agent edits them, so file changes can be undone. It is separate from git.

Explanations

1. Vibe coding or engineering with an agent

First, a failure (an invented example). A learner writes to a coding agent: “add a limit to the search tool in the notes server”. Nothing else: no plan, no tests, no repository rules. The agent adds a limit argument with no default value, adds a print("searching...") line for debugging, and reports “done”. The learner skims the message, sees the word done and keeps the change. Next morning the research helper from the previous unit fails on every search. The tool now requires limit, and the toolkit rejects calls that leave it out. And because the notes server speaks through its standard output, the stray print line is read by the client as a broken message. Two mistakes, both in a diff of ten lines that nobody read.

That is vibe coding. The term was coined in February 2025 by the computer scientist Andrej Karpathy, who described coding where you “fully give in to the vibes” and forget that the code exists. In its common definition, vibe coding may involve accepting AI-generated code without thorough review, relying on results and follow-up prompts to guide changes. Two pictures help:

  • An autopilot with the pilot’s eyes closed. The plane flies itself, and works fine in clear weather. The pilot is still responsible when it does not.
  • A kitchen that sends dishes out without tasting. Most plates are fine. The ones that are not reach a customer.

Simon Willison, quoted in reporting on the practice, put the limit this way: vibe coding your way to a production codebase is clearly risky, because most of the work of software engineers is evolving existing systems, where the quality and understandability of the code is crucial. A real repository is exactly that. So this chapter teaches the other way: engineering with an agent, in which the agent does the typing and you stay responsible for the result. It has three habits:

  1. Give context. The agent starts each session knowing nothing about your repository’s rules. A context file tells it.
  2. Make it prove its work. Give it a check it can run, so that “done” means “the tests pass”, not “it looks right”.
  3. Review. You read the diff before the change is kept.

What a coding agent does. Think of a capable contractor who can read the plans, use the tools and test the work. Claude Code, the agent used as the in-depth example, is described by its documentation as an agentic assistant that runs in your terminal. When you give it a task it works through three phases that blend together: it gathers context, takes action and verifies results. Its tools fall into groups: file operations (read and edit files), search, execution (run shell commands, start servers, run tests, use git), the web, and code intelligence through plugins. You are part of the loop: you can interrupt at any point to steer it. This is the agent loop you built by hand, aimed at code: the model decides, tools act, results come back. The difference is that your repository is the environment, and your tests are how it learns what happened.

2. The repository context file: AGENTS.md or CLAUDE.md

Think of the letter you would leave for a new colleague starting on Monday: how to run the tests, which rules the team follows, which mistakes to avoid. A coding agent starts every session as that new colleague: each session begins with a fresh context window. A context file is that letter, kept in the repository where every session finds it. Another picture: the sign on a workshop door that lists the safety rules; you do not need to remember them each time, because the door reminds you.

Two names matter. AGENTS.md is an open, plain-markdown format that its site describes as a README for agents: the extra, sometimes detailed context that coding agents need, such as build steps, tests and conventions, which might clutter a README or not matter to human contributors. It has no required format; you can use any headings. CLAUDE.md is the file Claude Code has long used for the same job. They are one idea with two file names, so write the content once. How Claude Code treats them:

Your repository has Claude Code reads
An AGENTS.md and no CLAUDE.md The AGENTS.md
Both an AGENTS.md and a CLAUDE.md The CLAUDE.md only
A CLAUDE.md whose first line is @AGENTS.md The CLAUDE.md, with AGENTS.md included through the import

So a team that uses several tools keeps one AGENTS.md, and adds a short CLAUDE.md that imports it only when it needs a Claude-specific instruction. Running /init in Claude Code generates a starting file by looking at your codebase; you then edit it. The file is loaded into context every session, which is why it must be short: the guidance is to keep a file under about 200 lines, because longer files use more context and reduce how well the agent follows them. The documentation also says Claude treats these files as context, not enforced configuration: a rule in the file is a strong hint, and a check that must hold every time belongs somewhere that enforces it, such as a test.

Here is the context file for the notes repository, AGENTS.md at the repository root:

# AGENTS.md

### What this repository is
A teaching repository for GenAI work in Python: model calls, a PDF question-answering
assistant, an agent loop and an MCP notes server. Code is in `app/`; tests are in `tests/`.

### Commands
- Run all tests: `python -m pytest -q`
- Run one test file: `python -m pytest tests/test_mcp_server.py -q`
- The tests replace the model client with a fake: they need no key and no network.

### Conventions
- Python 3.11, with type hints on all functions.
- An MCP tool is one function with a docstring that tells a model when to use it.
- A failing MCP tool raises `ToolError` instead of returning an error sentence.
- No `print()` under `app/mcp_server/`: standard output is the protocol channel. Use `logging`.
- Settings come from `LLM_BASE_URL`, `LLM_API_KEY` and `LLM_MODEL`. Keep keys and model ids out of code.

### Working rules
- Add or change a test with each change in behaviour, and run the whole suite before saying a task is done.
- Do not edit an existing test to make it pass. If one looks wrong, say so and stop.
- Ask before adding a dependency or touching files outside the task.

Read it as the failure from section 1, fixed in advance. The print() rule would have stopped the debug line. The ToolError rule and the testing rule shape how errors and tests are written. The command lines let the agent run the tests itself, and the AGENTS.md site says coding agents will attempt to run the relevant checks listed in the file and fix failures before finishing.

What belongs in it, and what does not. Ask of each line: “Would removing this cause the agent to make mistakes?” If not, cut it. A bloated file makes the agent ignore your real instructions. The official guidance gives a clear split:

Include Leave out
Commands the agent cannot guess Anything the agent can work out by reading the code
Style rules that differ from the defaults Standard language conventions it already knows
How to run the tests, and which runner Detailed API documentation (link to it instead)
Rules that came from a past mistake Information that changes often
Environment quirks, such as required settings Long explanations and file-by-file tours

Other agents, briefly. The same idea exists across tools, and the file names differ:

Agent Context file it reads Worth knowing
Claude Code CLAUDE.md; reads AGENTS.md when there is no CLAUDE.md /init drafts a file; @AGENTS.md imports one
Codex (command-line agent) AGENTS.md Combines files from the repository root down to your current folder; files nearer your folder come later and override earlier ones; the combined size is capped at 32 KiB by default
Gemini CLI GEMINI.md by default A setting named context.fileName accepts a list of names, such as AGENTS.md, CONTEXT.md and GEMINI.md

The AGENTS.md site also notes that in a large repository you can place nested AGENTS.md files in sub-folders, and that the closest file to the edited file wins when instructions conflict. A prompt you type in the chat overrides the file.

3. Plan first: ask for a plan, read it, change it

Picture an architect’s drawing before the builders arrive. Changing a line on paper costs a pencil stroke; changing a wall after it is built means pulling it down. Or picture a trip itinerary you check before you book: you spot that the train leaves from the wrong station while it is still free to change. A plan is the same for code: a written list of the files to change, the steps in order, the test for each step and what is out of scope.

Official guidance for Claude Code recommends separating research and planning from implementation, to avoid solving the wrong problem. Its plan mode lets the agent read files and propose changes without editing your source files; edits stay blocked until you approve the plan. You start it in one of two ways: begin the session with claude --permission-mode plan, or press Shift+Tab during a session until the status bar shows plan mode. When the plan is ready, the agent shows it and gives you three choices: approve it and have each edit asked about individually (“Yes, manually approve edits”), approve it and let the agent continue with fewer prompts, or keep planning (“No, keep planning”) and tell it what to change. You can also press Ctrl+G to open the plan in your text editor and edit it yourself before the agent proceeds. Other tools have their own commands for this; what matters is the habit of asking for a plan and reading it before approving.

Here is a prompt for the running example, adding a list_notes tool to the notes server:

Read app/mcp_server/server.py and tests/test_mcp_server.py. I want a new MCP tool,
list_notes, that returns one line per note in the form "id: title", where the title is
the text before the first colon. Make a plan: the files to change, the steps in order,
the test for each step, and what is out of scope. Do not edit any file yet.

A good plan for this task names two files (app/mcp_server/server.py and a new tests/test_list_notes.py), lists the steps in order, gives each step a test, and says what is not being touched. A weak plan says “update the server and add tests” and touches nine files. The same guidance adds that a good written spec names the files and interfaces it touches, says what is left out, and finishes with a check that shows the feature works from end to end. Read the plan with these questions: Is every file in it one I expect? Is anything in it that I did not ask for? Does each step have a test? Then edit what is wrong. If the agent proposes a refactor you did not request, cross the line out before you approve.

Planning has a cost. For a task where the scope is clear and the fix small (a typo, a log line, a renamed variable), ask for the change directly. The guidance gives a rule of thumb: when the whole diff fits in one sentence, skip the plan. Plan when you are unsure of the approach, when the change touches several files, or when you do not know the code.

4. Implement in small steps, with a test for each

Think of laying bricks. A bricklayer sets a few bricks, checks them with a level, and carries on; a wall built in one go and checked at the end may lean the whole way up. Another picture: proofreading a page at a time instead of a whole book at the end. A small step is one change that adds one behaviour and has one test, small enough that you can read its diff in one sitting without losing track.

The reason for the test is a central point in the official guidance: give the agent a way to verify its work. Without a check it can run, “looks done” is the only signal available, and you become the verification loop, so every mistake waits for you to notice it. With a test suite, the agent runs the check, reads the result and iterates until it passes. The guidance contrasts a vague request (“implement a function that validates email addresses”) with one that includes example cases and says to run the tests. Our rule in this chapter follows from it: every prompt that asks for code also asks for a test and asks the agent to run the whole suite and show you the output.

Step 1 of the running example is the list_notes tool. The implementation, added next to search_notes in app/mcp_server/server.py, is short:

@mcp.tool()
def list_notes() -> str:
    """List every note as 'id: title', where the title is the text before the first colon."""
    return "\n".join(f"{i}: {t.split(':', 1)[0]}" for i, t in NOTES.items())

and its test, in tests/test_list_notes.py, uses the in-memory client you met with the notes server:

import pytest
from mcp import Client

from app.mcp_server.server import mcp


@pytest.fixture
def anyio_backend():
    return "asyncio"


@pytest.mark.anyio
async def test_list_notes_gives_one_title_per_note():
    async with Client(mcp, raise_exceptions=True) as client:
        result = await client.call_tool("list_notes", {})
    lines = result.content[0].text.splitlines()
    assert lines == ["n1: Remote work", "n2: Travel", "n3: Expenses"]

The test fixes the behaviour: three notes, three lines, the title before the first colon. Run it before the change and it fails (there is no list_notes tool); run it after and it passes. Watching it fail first proves the test can fail, which makes its later pass mean something. Ask the agent to do that: write the test, run it and show the failure, make the change, run it again.

Step 2 is a change to an existing tool, search_notes: add an optional limit argument that defaults to 5 and returns at most that many lines, and make a limit below 1 a tool error:

@mcp.tool()
def search_notes(query: str, limit: int = 5) -> str:
    """Find notes containing every word of the query. One 'id: text' line per note, at most limit lines."""
    if limit < 1:
        raise ToolError("limit must be at least 1")
    log.info("search_notes %r limit=%d", query, limit)
    words = query.lower().split()
    hits = [f"{i}: {t}" for i, t in NOTES.items() if all(w in t.lower() for w in words)]
    return "\n".join(hits[:limit]) or "No notes match."

with two tests in tests/test_search_limit.py:

@pytest.mark.anyio
async def test_limit_caps_the_number_of_results():
    async with Client(mcp, raise_exceptions=True) as client:
        result = await client.call_tool("search_notes", {"query": "a", "limit": 2})
    assert len(result.content[0].text.splitlines()) == 2


@pytest.mark.anyio
async def test_limit_below_one_is_a_tool_error():
    async with Client(mcp, raise_exceptions=True) as client:
        result = await client.call_tool("search_notes", {"query": "a", "limit": 0})
    assert result.is_error is True
    assert "limit" in result.content[0].text

Look at the default value limit: int = 5. It is the difference between the change in section 1 that broke the research helper and one that does not: old calls that leave limit out still work. The existing test from the notes server, test_search_finds_the_expense_note, is the guard that proves it.

When the agent drifts. The agent’s context fills up as a session grows, and its performance drops as it fills, so keep sessions focused. Press Esc to stop it mid-action; your context is preserved so you can redirect. If you have had to correct it three times or more about one problem in a single session, the conversation is full of failed attempts: run /clear and start again with a more specific prompt that includes what you learned. A session that mixes unrelated tasks is a “kitchen sink” session; clear the context between unrelated tasks. A checkpoint lets you undo the agent’s file changes, but checkpoints only cover changes made through its file-editing tools and are not a replacement for git: commit each step once you have reviewed it.

5. Review every diff before it is kept

Picture a building inspector. The builder says the wall is finished; the inspector does not take that on trust but looks at the work against the drawing. Or picture a proofreader who reads the printed page, not the author’s summary of it. A diff is the printed page: the list of lines added and removed. Diff review is reading it with the plan beside it. The official guidance names the trap: the agent produces a plausible-looking implementation that does not handle edge cases, and the fix is always to provide verification, because if you cannot verify it, do not ship it.

After each step run git status to list the files the agent touched, git diff to read its changes to existing files, and open any new file directly, since a new file does not appear in git diff until it is added. Then ask five questions:

  1. Does it match the plan? Every changed file should be one the plan named.
  2. Is anything outside the plan? A refactor, a renamed function, a new dependency. Stop and ask why.
  3. Did an existing test change? A test edited in the same change as the code it checks is the most important line in the diff. If an existing assertion was changed to make a failure go away, reject it and restore the test.
  4. Do the tests test the behaviour? A test that repeats the code’s own logic proves nothing. Read each assertion and ask what mistake it would catch.
  5. Does it obey the rules in AGENTS.md? A print() under app/mcp_server/, an error sentence returned instead of a raised ToolError, a key or model id in code.

Then run the whole suite yourself. The agent’s report that tests passed is a claim; your own run is evidence. Here is a diff worth rejecting, in the style of the failure from section 1 (an invented first draft of step 2):

 @mcp.tool()
-def search_notes(query: str) -> str:
+def search_notes(query: str, limit: int) -> str:
+    print("searching", query)
     ...
-    assert result.content[0].text.startswith("n3")
+    assert "n3" in result.content[0].text or True

Three defects in six lines: limit has no default, so old calls fail; a print() under the server folder breaks the protocol channel; and an existing assertion was weakened until it cannot fail. Reject the diff, tell the agent which rule each line broke, and ask for a corrected step.

A second opinion. Review is stronger with fresh eyes. The official guidance suggests a Writer and Reviewer pattern: one session writes, another session with a clean context reviews, because a fresh context improves review since the reviewer is not biased toward code it just wrote. You can ask it, for example: “Review the uncommitted changes against plan.md. Report only gaps that affect correctness or the stated requirements: anything outside the plan, any changed existing test, and any rule in AGENTS.md that the change breaks.” Tell the reviewer to flag only real gaps, because a reviewer that is asked to look for gaps tends to report some even when the work is fine, and acting on every finding leads to over-engineering. The second opinion helps; it does not replace your own reading.

Safe settings for a first session. The agent can edit files and run commands, so its permission mode matters. In Manual mode it asks before file edits and shell commands; in Accept edits mode it edits files and runs common filesystem commands without asking but still asks for other commands; in Plan mode it explores and proposes without editing source files. Press Shift+Tab to cycle the modes. The documentation also describes an Auto mode, in which a separate classifier reviews most actions instead of you, and says it is the starting mode for interactive sessions in recent versions, so look at the status bar when a session opens. For your first sessions, use Plan mode for planning and Manual for implementing, so that every edit is shown to you before it happens.

6. Your first session, start to finish

Put the habits in order. Open a terminal in the repository root and run git status to confirm you are starting clean. Check that AGENTS.md is in the root. Start the agent with claude (or claude --permission-mode plan for the planning step). Then:

  1. Plan. Use the planning prompt from section 3. Read the plan, cut anything out of scope, and save the approved plan as plan.md.
  2. Step 1. Prompt: “Implement step 1 of the plan: add the list_notes tool to app/mcp_server/server.py and a test in tests/test_list_notes.py. Show me the test failing first, then passing, then run the whole suite and show me the output.”
  3. Review step 1. git status and git diff, the new test file, the five questions, then your own python -m pytest -q. Commit when it is clean.
  4. Step 2. Prompt: “Step 2: give search_notes an optional limit argument that defaults to 5 and returns at most that many lines. A limit below 1 must be a tool error. Add tests in tests/test_search_limit.py, run the whole suite and show me the output.”
  5. Review step 2 with the same five questions, and ask a fresh session for a second opinion.
  6. Finish. Run the whole suite one last time and commit. The feature is two small commits you have read, not one large change you hoped was right.

The new files on top of the earlier repository are AGENTS.md, tests/test_list_notes.py and tests/test_search_limit.py, plus the two edits to app/mcp_server/server.py.

Flashcards

Say the answer aloud before revealing it. Speaking is a different skill from reading; practise both.

  1. What is vibe coding, and what is the risk?

    • Building software by describing what you want and accepting the generated code, often without a thorough review of it. The risk is that mistakes in code nobody read reach a real codebase, where quality and understandability of the code matter.
  2. What are the three habits of engineering with an agent?

    • Give it context with a context file, make it prove its work with a check it can run such as tests, and review the diff before the change is kept. You stay responsible for the result.
  3. What is a context file, and why does the agent need one?

    • A markdown file in the repository, such as AGENTS.md or CLAUDE.md, that holds the commands, conventions and rules the agent cannot guess. Each session starts with a fresh context window, so the file is how the rules reach the agent every time.
  4. What is the relationship between AGENTS.md and CLAUDE.md in Claude Code?

    • They serve the same purpose. With an AGENTS.md and no CLAUDE.md, Claude Code reads AGENTS.md; with both it reads CLAUDE.md only; a CLAUDE.md that starts with an @AGENTS.md import includes the shared file.
  5. How do you decide whether a line belongs in a context file?

    • Ask whether removing it would cause the agent to make mistakes. If not, cut it. Include commands it cannot guess and rules that came from past mistakes; leave out what it can read from the code.
  6. Why should a context file stay short?

    • It is loaded into context every session, and a longer file uses more context and reduces how well the agent follows it. The guidance is to stay under about 200 lines.
  7. What is plan mode, and what do you do with the plan?

    • A mode in which the agent reads files and proposes a plan but makes no edits until you approve. You read the plan, cut anything out of scope, edit it, and only then approve it.
  8. When can you skip the plan?

    • When the scope is clear and the fix is small: if you could describe the diff in one sentence, ask for the change directly. Plan when you are unsure of the approach or the change touches several files.
  9. Why give the agent a check it can run?

    • Without a check, “looks done” is the only signal and you become the verification loop. With tests it can run, read and fix against, “done” means the checks pass.
  10. What should you do after correcting the agent more than twice on the same problem?

    • Run /clear and start again with a more specific prompt that includes what you learned. The context is full of failed approaches, and the guidance says a clean session with a better prompt almost always outperforms a long one full of corrections.
  11. What five questions do you ask when you read a diff?

    • Does it match the plan, is anything outside the plan, did an existing test change, do the tests test the behaviour, and does it obey the rules in the context file.
  12. Why is an edited existing test the most important line in a diff?

    • A test changed in the same change as the code it checks may have been weakened to hide a failure. Reject it and restore the original, then fix the code.

Model answer

The core question this unit answers: “How do you add a feature to a real codebase with a coding agent and still own the result?”

Five beats a good answer covers; hit all five, in this order:

  1. Context — a context file carries the commands and rules the agent cannot guess
  2. Plan — ask for a plan, read it and cut it before any edit
  3. Steps — small steps, each with a test the agent runs
  4. Review — read every diff and run the whole suite yourself
  5. Ownership — you decide what is kept, because the result is yours

The full answer, said aloud:

(Context) “I start with a context file, AGENTS.md or CLAUDE.md, that holds the commands to run the tests and the rules the agent cannot guess, such as raising a tool error and never printing in a server that speaks over standard output.

(Plan) Then I ask for a plan before any edit: the files, the steps in order, a test for each step and what is out of scope. I read it, cut what I did not ask for and approve it.

(Steps) I work in small steps, one behaviour and one test each, and I ask the agent to show the test fail and then pass so it has a check it can run.

(Review) Before I keep a step I read the diff against the plan: only planned files, no existing test weakened, the repository rules obeyed. I run the whole suite myself, and sometimes ask a fresh session for a second opinion.

(Ownership) The agent does the typing, but I decide what is kept. The code is mine the moment it is committed.“

Skip any of these five and the answer is incomplete. An interviewer or reviewer who hears only “I ask the agent and check that the tests pass” will ask how you gave it the repository’s rules, how you kept the change small, and what you looked for in the diff. Practise until all five beats come out in order without notes.

Why this matters

On the job: if your team uses coding agents, what a reviewer needs from you is a change that can be reviewed. A short context file, a plan and a small diff are what make that possible.

In interviews and reviews: “how do you use AI to write code safely?” is a fair question for a reviewer or interviewer to ask. The five-beat answer above is built for it, and it applies to any agent, because the habits do not belong to one tool.

As a builder: a context file you keep current gives each new session the repository’s rules at the start, so you do not retype them, and a shared AGENTS.md can serve the other tools your teammates use.

After this unit

Hands-on project. Three tasks: (1) write an AGENTS.md for your repository by hand, from the facts in the brief; (2) plan, implement and review the list_notes feature with a coding agent, keeping the plan and your review notes; (3) optionally, add the limit argument in a second small step and review it. The full brief is in the project file.

What’s next. The capstone asks you to choose a project, build it with the workflow from this chapter, demo it, and review it against a checklist. Keep your AGENTS.md, your plan and your review notes: the capstone starts from them.

Project

Hands-on Project — Chapter 7: A Feature Added to a Real Repository, With Tests

Objective

Add a small feature to the repository you have been building, working the way the chapter teaches: a context file you wrote, a plan you read and edited, small steps each with a test, and a review of every diff before it is kept.

What you need: the repository (Python 3, pytest and anyio installed) with the notes server at app/mcp_server/server.py and its test file tests/test_mcp_server.py, plus git. Task 1 needs nothing else: no agent and no account. Tasks 2 and 3 need a coding agent. The chapter’s examples use Claude Code, which needs a Claude subscription, a Claude Console account or a supported cloud provider; another coding agent that reads AGENTS.md can be used instead. Before any task, run python -m pytest -q in the repository and note how many tests pass: you will compare against that number.

You write the context file yourself and you review every change yourself. This brief gives the facts and the checks; the finished files are not in it. Work through the tasks in order and check each output before moving on.

Facts about the repository, for Task 1.

  • Code is in app/ and tests are in tests/. All tests replace the model client with a fake, so they need no key and no network.
  • python -m pytest -q runs every test; python -m pytest tests/test_mcp_server.py -q runs one file.
  • The notes server is started as a program that speaks to its client through standard input and standard output. Anything printed to standard output by that program is read by the client as a protocol message.
  • A tool that returns an error sentence looks like a success to the model; a tool that raises ToolError is reported as an error.
  • Settings come from the names LLM_BASE_URL, LLM_API_KEY and LLM_MODEL.
  • The language is Python 3.11. Python files end in .py, and tests are named test_*.py.

Task 1 — Write the repository’s context file

Create AGENTS.md in the repository root, in your own words, for a coding agent that has never seen this repository. Use the facts above and choose what belongs in the file. Then create agents-why.txt with one line for every command, convention or rule in your file, naming the mistake an agent would make without that line.

Scope: two files, AGENTS.md of at most 40 lines and a short agents-why.txt. Stop once the checks hold.

Checks:

  • AGENTS.md has a section for commands, one for conventions and one for working rules.
  • The commands section gives a way to run the whole suite and a way to run one test file.
  • There are at least 3 conventions and at least 2 working rules, each specific to this repository.
  • agents-why.txt has one line for each command, convention and rule, and none of its lines is “it is good practice”.
  • You removed at least one fact from the list above because an agent could work it out from the code, and agents-why.txt ends with one sentence naming it.

Output: AGENTS.md and agents-why.txt.


Task 2 — Plan, build and review a list_notes tool

The feature: a new MCP tool named list_notes in app/mcp_server/server.py. It takes no arguments. It returns one line per note, in the order the notes are stored, in the form id: title, where the title is the text of the note before its first colon. It needs a test of its own in a new file, tests/test_list_notes.py.

  1. Start the coding agent in the repository root, in plan mode, with AGENTS.md in place. Ask it for a plan that gives the files to change, the steps in order, the test for each step and what is out of scope. It must not edit anything yet.
  2. Read the plan and edit it, or tell the agent to change it. Save the plan you approve as plan.md.
  3. Have the agent write the test first. Run it and save the failing output. Then have it make the change, and run the test again and save the passing output. Then run the whole suite.
  4. Review the result yourself: git status, git diff and the new test file. Write review.md with one answer for each of the five review questions in the notes, and the number of tests passing in your own run of the whole suite.

Scope: one tool and one new test file, not more. Stop once the checks hold.

Checks:

  • plan.md names at most 3 files and gives each step a test.
  • You edited the plan at least once, or review.md says in one sentence why no edit was needed.
  • The only files changed are app/mcp_server/server.py and tests/test_list_notes.py, and no existing test was changed.
  • task2-output.txt shows the new test failing before the change and passing after it.
  • The whole suite passes, and the number of passing tests is the starting number plus the tests you added.
  • review.md has 5 answers, each of one or two sentences.

Output: plan.md, task2-output.txt, review.md and the diff saved as task2.diff.


Task 3 — A limit on search_notes, with a second opinion (optional)

The feature: search_notes gets an optional limit argument. When it is left out, the tool must work exactly as before. A limit of 1 or more returns at most that many lines. A limit below 1 must come back as a tool error whose message contains the word limit. Tests go in a new file, tests/test_search_limit.py.

Work in a new agent session, with the same habits: a plan, the test first, the whole suite. Commit the change from Task 2 before you start so that this diff contains only the new work. Then open a second, fresh agent session and ask it to review the uncommitted changes against your plan, reporting only gaps that affect correctness or the stated requirements. Record the exact prompt you used.

Scope: one argument, one new test file and one reviewer session. Stop once the checks hold.

Checks:

  • The suite passes, and the old test that calls search_notes with only a query still passes unchanged.
  • The new tests cover a limit that caps the results and a limit below 1.
  • review2.md holds the reviewer prompt, each finding the reviewer reported, and for each finding “accepted” or “rejected” with one reason.
  • review2.md ends with a sentence saying whether the reviewer found anything you had missed in your own review.

Output: task3.diff and review2.md. The artifact the next unit starts from is your AGENTS.md from Task 1, so it stays in the repository root.

Keep AGENTS.md, plan.md, review.md and review2.md in the repository: the next unit asks you to choose a project and build it with the same workflow, and it starts from a context file like yours.

TechEazy Consulting training material — not affiliated with or endorsed by OpenAI, Anthropic or any other company named in this course.