Reframe M1-6: AI drives git, lesson=theory, de-slop + issue fixes (#92)
Sync course wiki / sync-wiki (push) Successful in 4s

Co-authored-by: claude <claude@jpaul.io>
Co-committed-by: claude <claude@jpaul.io>
This commit was merged in pull request #92.
This commit is contained in:
2026-06-22 21:41:31 -04:00
committed by Claude (agent)
parent 2467f25901
commit a29823f4b3
8 changed files with 578 additions and 481 deletions
+120 -83
View File
@@ -1,7 +1,7 @@
# Module 5 — Commit the AI's Config, Not Just the Code
> **The instructions you give the model are as worth versioning as the code it writes.** Write your
> project's conventions down once, commit them, and every teammate and every agent inherits the
> project's conventions down once, commit them, and every teammate (and every agent) inherits the
> same setup instead of each of you hand-tuning your own and quietly drifting apart.
---
@@ -22,8 +22,8 @@
By the end of this module you can:
1. Identify the repo-level instructions file your agentic tool reads, and explain what belongs in it.
2. Write an instructions file for a real project conventions, build/test commands, coding
standards, off-limits files, house style that an AI will actually act on.
2. Write an instructions file for a real project (conventions, build/test commands, coding
standards, off-limits files, house style) that an AI will actually act on.
3. Commit that file so the configuration travels with the repo, not with one person's machine.
4. Demonstrate the AI obeying the committed instructions, and changing its behavior when you change
the file.
@@ -65,7 +65,7 @@ a briefing for an agent that will edit this code. Keep it to what changes the AI
`python cli.py <command>`. Run tests with `python -m unittest`. Don't claim a change works until
the tests pass." This single line stops the AI from inventing a test runner you don't use.
- **Coding standards** — formatting, typing, error handling, the libraries you do and don't want.
"Use the standard library only no third-party packages. Type-hint public functions."
"Use the standard library only, no third-party packages. Type-hint public functions."
- **"Don't touch these files."** — the off-limits list. Generated files, vendored code, secrets,
anything the AI should read but never rewrite. "Never edit `tasks.json` by hand; it's generated."
- **House style** — the taste calls that otherwise come back wrong every time. "Keep functions
@@ -73,7 +73,7 @@ a briefing for an agent that will edit this code. Keep it to what changes the AI
cleverness."
The test of a good line: would you otherwise have to say it again next session? If yes, it belongs in
the file. If the AI already gets it right without being told, leave it out bloat dilutes the
the file. If the AI already gets it right without being told, leave it out; bloat dilutes the
signal (see *Where it breaks*).
### Why commit it instead of keeping it in your head (or your settings)
@@ -83,50 +83,77 @@ useful for personal preferences, but it's the wrong home for project knowledge,
lives: on *your* laptop, invisible to everyone else.
Picture a two-person project with no committed instructions file. You've trained your local setup to
run `python -m unittest` and avoid `tasks.json`. Your teammate's setup hasn't their agent reformats whole files
run `python -m unittest` and avoid `tasks.json`. Your teammate's setup hasn't, so their agent reformats whole files
and hand-edits the generated JSON. You're both "using AI on the same repo," but you're getting
different behavior, and neither of you can see the other's configuration. That's **drift**: the same
codebase, diverging because the rules live in two heads instead of one file.
Commit the file and that collapses. The configuration is now part of the repo. Clone the repo, get
the rules. A new teammate or a brand-new agent that's never seen the project is configured
the rules. A new teammate (or a brand-new agent that's never seen the project) is configured
correctly on the first run, because the setup travels *with the code* instead of with whoever set it
up. This is the same move as Module 2's "the repo is durable memory the AI can read," aimed one level
up: not just the code's history, but the instructions for working on it.
### The real unlock: AI behavior becomes reviewable
### Shared config vs. personal config
The instructions file is the main thing worth committing, but it's not the only AI config a tool drops
in a repo. Those files split cleanly into *shared* (belongs in the repo, so every collaborator and
every agent inherits it) and *personal* (your machine, your keys, your taste, kept out). Take Claude
Code as the concrete case (sub your own agent's filenames):
| File | Shared or personal |
| --- | --- |
| `CLAUDE.md` (the instructions file) | **Shared** — the whole point of this module |
| `.claude/settings.json` (project settings: permissions, hooks config) | **Shared** — the team runs the same setup |
| `.claude/settings.local.json` (your personal overrides) | **Personal** — gitignored for you |
| `.mcp.json` (the MCP servers the project uses) | **Shared if the project relies on them** |
| `.claude/commands/`, `.claude/agents/`, `.claude/hooks/` | **Shared if the project uses them** |
The principle is tool-agnostic. This very repo commits an `AGENTS.md` instead of a `CLAUDE.md` (same
job, vendor-neutral name) and keeps personal settings out. The line to hold: anything that defines
*how this project is worked on* is shared; anything that's your own machine or your secrets is not.
Rather than guess the split yourself, you can ask the agent which of its config files belong in the
repo. The lab does exactly that.
### AI behavior becomes reviewable
Here's the part that makes this more than a convenience. Once the instructions live in the repo, **a
change to how the AI works on this project is a change to a tracked file** so it shows up exactly
like a code change does:
change to how the AI works on this project is a change to a tracked file**, so it shows up exactly
like a code change. Tighten "keep functions small" into "no function over 30 lines" and `git diff`
reports it the same way it reports an edit to `tasks.py`:
```bash
git diff
```diff
## House style
-- Keep functions small and single-purpose.
+- No function over 30 lines; split anything longer.
```
When someone tightens "keep functions small" into "no function over 30 lines," or adds
`infra/` to the don't-touch list, that decision arrives as a *diff* you can read, question, and
accept or reject. It's no longer an invisible tweak in one person's settings that silently changes
what the AI does for everyone. The way your team works with AI becomes a reviewable artifact with a
history — you can `git log` it and see *why* a rule exists and when it was added.
That decision arrives as a *diff* you can read, question, and accept or reject. It's no longer an
invisible tweak in one person's settings that silently changes what the AI does for everyone. The way
your team works with AI becomes a reviewable artifact with a history: `git log` shows *why* a rule
exists and when it was added.
The full version of this lands in **Module 10**, where that diff becomes a pull request someone
actually reviews before it merges, and **Module 8**, where a shared remote means the file reaches the
whole team. You don't have those yet so for now the payoff is local: the file is committed, the
whole team. You don't have those yet, so for now the payoff is local: the file is committed, the
behavior is recorded, and `git diff` already shows changes to it as plainly as changes to any code.
The habit starts now; the team-scale payoff arrives on schedule.
### This course commits its own
You don't have to take this on faith this repo does exactly what the module teaches. At the root of
*The Workflow* is an `AGENTS.md` file: the committed instructions for the agents that help author the
course. It states what the repo is, the core promises (model-agnostic, GitHub-as-default-not-
requirement, the load-bearing dependency chain), the voice, the lab conventions, and a flat "Don't"
list. Open it:
You don't have to take this on faith: this repo does exactly what the module teaches. At the root of
*The Workflow* is an `AGENTS.md` file, the committed instructions for the agents that help author the
course. (Claude Code reads `CLAUDE.md` by default; `AGENTS.md` is the same job under a vendor-neutral
name, and most tools can be pointed at it.) It states what the repo is, the core promises
(model-agnostic, GitHub-as-default-not-requirement, the load-bearing dependency chain), the voice, the
lab conventions, and a flat "Don't" list. Because it's committed, its history reads like a changelog
of how agents work here:
```bash
git show HEAD:AGENTS.md # or just open AGENTS.md in your editor
git log --oneline AGENTS.md # its history — every change to how agents work on this repo
```text
$ git log --oneline AGENTS.md
4bd586b Tighten the no-slop voice rule; thin em-dashes
ced344d Add the git-reframe section (AI drives git from Module 4)
9e9bb51 Initial commit
```
That file is why every module in this course sounds like one course instead of twenty-seven
@@ -137,8 +164,8 @@ tutorials. It's the worked example for everything below.
A committed instructions file is the lightweight foundation. It says *how this project works* in
general — always-on context the AI reads every session. When you find yourself wanting to capture a
*specific repeatable procedure* ("here's exactly how we cut a release," "here's our playbook for
adding a new CLI command"), that's the structured big sibling: **Skills (Module 21)**. Same instinct
write the knowledge down, commit it, let the AI execute it your way but packaged as reusable
adding a new CLI command"), that's the structured big sibling: **Skills (Module 21)**. Same instinct
(write the knowledge down, commit it, let the AI execute it your way) but packaged as reusable
playbooks instead of a single always-on briefing. Start with the instructions file; graduate to
skills when a procedure earns its own page.
@@ -147,21 +174,21 @@ skills when a procedure earns its own page.
## The AI angle
This is the course thesis applied to your own configuration. **The model is the cheap, swappable
part; the setup you build around it is the durable artifact.** When you swap models next quarter
and you will your committed instructions file carries over unchanged. The new model reads the same
part; the setup you build around it is the durable artifact.** When you swap models next quarter (and
you will), your committed instructions file carries over unchanged. The new model reads the same
conventions, the same test command, the same don't-touch list, and behaves consistently on day one.
You configured the *project*, not the model.
Three things make this specifically an AI problem, not a generic config chore:
- **AI has no memory across sessions, but it reads files.** A committed instructions file is the
cleanest way to give an ephemeral agent durable, project-specific context written once, read
cleanest way to give an ephemeral agent durable, project-specific context: written once, read
every session, by every model.
- **AI is confidently inconsistent without a spec.** Unprompted, it'll pick a test runner, a
formatting style, a place to put new code and pick differently next time. The instructions file
formatting style, a place to put new code, and pick differently next time. The instructions file
is how you make "the way we do it here" the default instead of a coin flip.
- **AI behavior is otherwise invisible.** A teammate's hand-tuned local rules silently change what
the AI does. Committing the rules drags that into the open where it can be reviewed which is the
the AI does. Committing the rules drags that into the open where it can be reviewed, which is the
whole reason this audience trusts version control in the first place.
---
@@ -179,42 +206,53 @@ editor-integrated AI (Module 4) for the part where the AI obeys the file.
- Optionally, a test command for the AI to honor — Python's built-in `python -m unittest` works with
nothing to install (you'll write a real suite in Module 13; until then it simply reports no tests).
### Part A — Write the instructions file
### Part A — Write the instructions file and let the AI commit the config
1. Look up the instructions filename your tool reads. Copy this module's starter,
`lab/instructions-file-starter.md`, to that filename at the **root of your `tasks-app` repo**.
(If your tool reads several names, copy it to each, or symlink them.)
1. Look up the instructions filename your tool reads (Claude Code uses `CLAUDE.md`; sub your own).
Open an AI session in the `tasks-app` repo and direct it to create that file from this module's
starter, made true for the project:
```bash
cd ~/ai-workflow-course/tasks-app
# replace <YOUR_TOOL_FILE> with the name your tool actually reads:
cp /path/to/modules/05-commit-the-ai-config/lab/instructions-file-starter.md <YOUR_TOOL_FILE>
```
> *"Read `~/ai-workflow-course/modules/05-commit-the-ai-config/lab/instructions-file-starter.md`.
> Create my tool's instructions file at the root of this repo seeded from it, and adjust every line
> so it's accurate for this tasks-app. Don't commit yet — I want to review it first."*
2. Open it in your editor and make it true for *your* project. The starter is filled in for the
`tasks-app`, but read every line and confirm it matches reality — wrong instructions are worse
than none. At minimum, set the real test command (or delete the line if you don't have tests
yet).
You're handing the AI the file creation and placement. You keep the judgment over *content*: a
wrong instruction is worse than none.
3. Commit it. This is the point of the whole module:
2. Read what it produced, line by line. The starter is filled in for `tasks-app`, but confirm it
matches reality. At minimum, check the test command is real (or have it drop the line if you don't
have tests yet). Fix anything off before it gets committed.
```bash
git add <YOUR_TOOL_FILE>
git commit -m "Add committed AI instructions for tasks-app"
```
3. Now ask the AI which config should travel with the repo, then let it stage and commit:
The configuration now travels with the repo.
> *"Which of the AI config files in this repo should be committed so a teammate gets the same setup,
> and which are personal to my machine? Stage the shared ones and commit them with a clear message."*
A good answer separates *shared* from *personal*. For Claude Code that means commit `CLAUDE.md` and
`.claude/settings.json`; leave `.claude/settings.local.json` out (gitignored personal overrides);
commit `.mcp.json` and anything under `.claude/commands/`, `.claude/agents/`, or `.claude/hooks/`
*if the project uses them*. For a fresh `tasks-app` that's usually just the instructions file.
Letting the agent stage and commit is the point: from here on you direct the git work and check the
result.
4. Verify it landed the way you wanted:
> *"Show me what you just committed."*
Confirm the commit contains the instructions file and only the files you meant to share (no
`settings.local.json`, no secrets). This commit is the point of the whole module: the configuration
now travels with the repo.
### Part B — Watch the AI obey it
4. Start a **fresh** AI session in your editor (so it picks up the file cleanly) and give it a task
5. Start a **fresh** AI session in your editor (so it picks up the file cleanly) and give it a task
that the instructions constrain. Pick a command your app doesn't have yet (so this is a real
feature, not a re-add) — for example:
> *"Add a `search <term>` command that lists only the tasks whose title contains `term`. Then
> confirm it works."*
5. Watch for the file taking effect. A correctly-configured agent should, without you saying any of
6. Watch for the file taking effect. A correctly-configured agent should, without you saying any of
it this time:
- put the logic where your conventions said it goes (core in `tasks.py`, CLI wiring in `cli.py`);
- **not** hand-edit `tasks.json` (you marked it off-limits);
@@ -224,40 +262,38 @@ editor-integrated AI (Module 4) for the part where the AI obeys the file.
You're checking that behavior you'd normally have to *dictate every session* now happens by
default. That delta is the file working.
6. If it ignored a rule, that's signal too tighten the wording, commit the change, and try again.
7. If it ignored a rule, that's signal too: tighten the wording, commit the change, and try again.
Vague instructions get vague compliance; specific, imperative lines ("Never edit `tasks.json` by
hand it is generated") land far better than soft ones ("try to avoid editing generated files").
hand; it is generated") land far better than soft ones ("try to avoid editing generated files").
### Part C — Make a behavior change reviewable
7. Now change *how the AI works* and watch it show up as a diff. Add a house-style rule to the file —
say, a hard line length:
8. Now change *how the AI works* and watch it show up as a diff. Direct the AI to add a house-style
rule to the instructions file, say a hard line length:
> Add to the instructions file: `Keep functions under 20 lines; split anything longer.`
> *"Add this line to the instructions file under house style: `Keep functions under 20 lines; split
> anything longer.` Don't commit yet — I'll review the diff first."*
8. Before committing, read the change exactly as a reviewer would:
9. Before anything gets committed, read the change exactly as a reviewer would. This is your
verification step, so run it yourself:
```bash
git diff
```
That diff *is* the change to your AI workflow readable, attributable, revertable. Commit it:
That diff *is* the change to your AI workflow: readable, attributable, revertable. When it's right,
direct the AI to record it:
```bash
git add <YOUR_TOOL_FILE>
git commit -m "Require functions under 20 lines"
```
> *"Commit that with a message describing the rule."*
9. Look at the history of just this file:
10. Confirm the history. Ask the AI to surface it (or read it yourself):
```bash
git log --oneline <YOUR_TOOL_FILE>
```
> *"Show me the commit history of the instructions file."*
Every line is a decision about how the AI behaves on this project recorded, not lost in someone's
local settings. (In Module 8 this file reaches your whole team via a remote; in Module 10 that diff
becomes a PR someone reviews before it lands. The habit you just built is what those modules turn
into a team workflow.)
Every line is a decision about how the AI behaves on this project, recorded rather than lost in
someone's local settings. (In Module 8 this file reaches your whole team via a remote; in Module 10
that diff becomes a PR someone reviews before it lands. The habit you just built is what those
modules turn into a team workflow.)
---
@@ -267,22 +303,23 @@ Be honest about what a committed instructions file does and doesn't buy you:
- **It's guidance, not a guarantee.** The file biases the model strongly; it does not bind it. An AI
can still ignore a line, especially a vague one, especially deep in a long session. The enforcement
that *can't* be ignored tests that fail the build, scans that block a merge is **CI
that *can't* be ignored (tests that fail the build, scans that block a merge) is **CI
(Module 14)** and **security scanning (Module 15)**. The instructions file reduces how often the AI
goes wrong; it doesn't replace the gates that catch it when it does.
- **Bloat kills it.** A 300-line instructions file is read the way *you* read a 300-line terms-of-
service: not really. Every line you add dilutes the rest. Keep it to what actually changes behavior,
and prune lines the model already honors without being told.
- **Stale instructions are worse than none.** A file that says "run the tests with `python -m
unittest`" after you've switched to a different runner will actively misdirect the AI. The file is code-adjacent — it has to be
maintained like code, and reviewed like code. That's exactly why committing it (so changes are
unittest`" after you've switched to a different runner will actively misdirect the AI. The file is
code-adjacent: it has to be maintained like code, and reviewed like code. That's exactly why
committing it (so changes are
visible) matters.
- **The team payoff isn't here yet.** On a solo local repo, the "no more drift between teammates"
argument is theoretical there's only you. The full value lands with a shared remote
argument is theoretical: there's only you. The full value lands with a shared remote
(**Module 8**) and review (**Module 10**). What you get *now* is the habit and the local history;
don't oversell the team benefit until the team can actually pull the file.
- **It is not a security control.** Telling an agent "don't touch `secrets.env`" is a convention, not
a permission boundary a sufficiently confused or adversarial agent can still read or write it.
a permission boundary: a sufficiently confused or adversarial agent can still read or write it.
Real isolation and least-privilege for agents come later (**Modules 16 and 22**). The instructions
file expresses intent; it doesn't enforce it.
@@ -294,14 +331,14 @@ Be honest about what a committed instructions file does and doesn't buy you:
- Your `tasks-app` repo has a committed instructions file at the root, filled in to match the actual
project, and `git log` shows the commit that added it.
- You've watched a fresh AI session honor a rule from the file placing code where your conventions
said, respecting the don't-touch list, or running your stated test command *without you saying it
- You've watched a fresh AI session honor a rule from the file (placing code where your conventions
said, respecting the don't-touch list, or running your stated test command) *without you saying it
that session*.
- You've changed a behavior rule, read the change with `git diff`, and committed it so a change to
- You've changed a behavior rule, read the change with `git diff`, and committed it, so a change to
how the AI works is now a reviewable diff with a history.
- You can explain, in one sentence, why committing the file beats each teammate hand-tuning their own
setup: the configuration travels with the repo, so nobody drifts.
When the AI behaves like it already knows your project the moment you open it and you didn't say a
word this session the file is doing its job. Module 6 takes the safety net further: branches, so the
When the AI behaves like it already knows your project the moment you open it, and you didn't say a
word this session, the file is doing its job. Module 6 takes the safety net further: branches, so the
AI can try something wild in a sandbox you can throw away.