fix(M7-27+capstone): apply AI-drives-git reframe, lesson=theory, de-slop course-wide

Phase 2 sweep — all modules are post-pivot, so the learner directs the AI agent
(Claude Code as the worked example) to do the git/setup work and verifies, instead
of typing commands by hand; no re-teaching basics. Lesson sections are theory with
example output; all execution lives in the labs. De-slopped ("prose" etc. gone
course-wide, em-dash density thinned). /path/to placeholders -> ~/ai-workflow-course.

Every deliberate teaching device verified intact: M10 ai-change.patch trap,
M12 bad-clear-snippet, M13/M27 planted pending_count bug, M15 secret+typosquat+MD5,
M18 BREAK=1, M21 absent-.gitignore, M22 poisoned skill, M24 no-op patch, M25 --simulate.
Labs compile/parse (py/sh/yaml/json); no junk.

Closes #83
Closes #86
Closes #89

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT
This commit is contained in:
2026-06-22 21:58:17 -04:00
parent a29823f4b3
commit f925fd9645
38 changed files with 1735 additions and 1424 deletions
@@ -8,15 +8,15 @@
## Prerequisites
- **Module 6 — Branches** — you can create a branch, switch to it, merge it back, and resolve a
- **Module 6 — Branches.** You can create a branch, switch to it, merge it back, and resolve a
conflict. A worktree is the physical counterpart to the logical isolation a branch already gives
you, so this module makes no sense without it.
- **Module 4 — Getting the AI out of the browser** — the agents in this module edit real files in a
- **Module 4 — Getting the AI out of the browser.** The agents in this module edit real files in a
folder. You'll point an editor-integrated AI session at each worktree directory.
- **Module 2 — Version control** — the `tasks-app` is already a Git repo with commits, and you read
- **Module 2 — Version control.** The `tasks-app` is already a Git repo with commits, and you read
a project's state from `git status` / `git diff` / `git log`. Each worktree has its own answer to
those, which is the whole point.
- **Module 1 — the `tasks-app`** — the running example continues here.
- **Module 1 — the `tasks-app`.** The running example continues here.
If you parachuted in: you minimally need a Git repo with at least one commit and a working
understanding of branches.
@@ -80,8 +80,8 @@ destroy the work. But now you're stuck choosing between bad options:
- **Commit half-finished work** just to get it out of the way (pollutes history, and Agent B's
`remaining` command isn't done).
- **Stash it** (now Agent B's context lives in a stash you have to remember to pop, and Agent B a
long-running session that thinks its files are right there is now editing files that silently
- **Stash it** (now Agent B's context lives in a stash you have to remember to pop, and Agent B, a
long-running session that thinks its files are right there, is now editing files that silently
changed under it).
- **Run both agents on the same branch in the same folder** — and watch them overwrite each other's
edits, because they're both writing the same `cli.py` with no idea the other exists.
@@ -94,8 +94,10 @@ The branch was never the problem. The single working directory is. You need two
repository, each with its own checked-out branch.** One repo, many checkouts.
```bash
cd ~/ai-workflow-course/tasks-app # your existing repo from Module 2
git worktree add ../tasks-app-remaining -b feature/remaining
$ cd ~/ai-workflow-course/tasks-app # your existing repo from Module 2
$ git worktree add ../tasks-app-remaining -b feature/remaining
Preparing worktree (new branch 'feature/remaining')
HEAD is now at a1b2c3d Add done command
```
That command creates a brand-new folder, `~/ai-workflow-course/tasks-app-remaining`, containing a full
@@ -120,8 +122,8 @@ This is the distinction that makes the whole thing click:
> **A clone copies the history. A worktree copies the working files and shares the history.**
A clone is a second repository — separate objects, separate `.git`, you sync between them with
pull/push (Module 8). A worktree is the *same* repository wearing two outfits. A commit you make in
one worktree is instantly an object in the shared store — no pushing, no pulling, it's just *there*,
pull/push (Module 8). A worktree is one repository checked out in two places. A commit you make in
one worktree is instantly an object in the shared store. No pushing, no pulling; it's just *there*,
because there's only one store.
### The mental model: one history, many present moments
@@ -133,8 +135,8 @@ write to the same past (commits go to the shared store), but each lives in its o
files on disk).
That's why worktrees are the natural payoff of branches. A branch is a *logical* "what if." A
worktree makes that "what if" a *place you can stand* a folder you can open, run, and point an
agent at while every other "what if" stays open in its own folder at the same time.
worktree makes that "what if" a *place you can stand*: a folder you can open, run, and point an
agent at, while every other "what if" stays open in its own folder at the same time.
### The core commands
@@ -150,9 +152,9 @@ git worktree prune # forget worktrees whose folders were
```bash
$ git worktree list
/home/you/ai-workflow-course/tasks-app a1b2c3d [main]
/home/you/ai-workflow-course/tasks-app-remaining d4e5f6a [feature/remaining]
/home/you/ai-workflow-course/tasks-app-wipe 7g8h9i0 [feature/wipe]
~/ai-workflow-course/tasks-app a1b2c3d [main]
~/ai-workflow-course/tasks-app-remaining d4e5f6a [feature/remaining]
~/ai-workflow-course/tasks-app-wipe 7g8h9i0 [feature/wipe]
```
Three folders, one repo, three branches checked out simultaneously. No stashing, no switching, no
@@ -177,7 +179,7 @@ Give each agent its own worktree and every one of those collisions disappears *b
already in one repo. No syncing between copies.
So "run two agents at once" stops being a coordination nightmare and becomes "open two folders."
That's the local foundation; **doing this at scale many agents, split work, kept reviewable is
That's the local foundation; **doing this at scale (many agents, split work, kept reviewable) is
Module 26 (Orchestrating Multiple Agents).** Worktrees are the primitive that module is built on.
Learn the primitive here on two; the orchestration comes later.
@@ -205,7 +207,7 @@ AI-assisted work they're closer to essential, for a reason specific to how agent
review. That reviewability is what later lets agents run with less supervision (Unit 5).
You don't reach for worktrees because you read about them. You reach for them the first time you try
to run two agents and watch them eat each other's homework.
to run two agents and watch them overwrite each other's work.
---
@@ -228,15 +230,17 @@ the parallel isolation, not the commands.)
- **Two** editor-integrated AI sessions you can run at once (Module 4) — two editor windows, or two
terminal AI sessions. If you only have a browser chat, you can still do the lab; just treat each
worktree folder as a separate copy-paste context.
- The starter scripts and prompts in this module's `lab/` folder. As established in Module 4, the
course's lab scripts live in the course repo under `modules/NN/lab/`, while `tasks-app` is a
separate folder — so **copy the scripts into `tasks-app` and run them by name** (`bash
setup-worktrees.sh`), using your real course path in place of `/path/to/`.
- The starter scripts and prompts in this module's `lab/` folder, at
`~/ai-workflow-course/modules/07-worktrees-running-agents-in-parallel/lab/`. As established in
Module 4, the course's lab scripts live in the course repo while `tasks-app` is a separate folder.
Here the worktree git is the **AI's** job (the Module 4 pivot): you direct the coordinating session
to run the `git worktree` commands, or hand it `setup-worktrees.sh` / `cleanup-worktrees.sh` to
run, and you verify the result. You don't type the git by hand.
### Part A — Feel the collision (1 minute)
Before fixing it, reproduce the bottleneck from "Where branches alone run out." The wall only appears
when both branches touch the **same line** of `cli.py` one committed, one not so we make each
when both branches touch the **same line** of `cli.py` (one committed, one not), so we make each
branch edit the usage line. (The `sed … > tmp && mv` is just a portable, copy-pasteable stand-in for
the edit an agent would make.) In your `tasks-app`:
@@ -275,28 +279,25 @@ git branch -D feature/wipe feature/remaining # throw away the demo branches
### Part B — Create two worktrees
Copy the setup script into `tasks-app` (see *You'll need*), then run it from inside the repo (or run
the commands by hand):
```bash
cp /path/to/modules/07-worktrees-running-agents-in-parallel/lab/setup-worktrees.sh .
bash setup-worktrees.sh
```
It runs:
```bash
git worktree add ../tasks-app-wipe -b feature/wipe
git worktree add ../tasks-app-remaining -b feature/remaining
git worktree list
```
You now have three folders backed by one repo. Confirm:
An agent that lives *inside* a worktree can't create its own worktree, so the **coordinating
session** (the AI you already have pointed at `tasks-app` from Module 4) sets them up. That's Claude
Code in this example; sub your own agent. Tell it:
> *"From the `tasks-app` repo, create two linked worktrees as siblings of this folder: one at
> `../tasks-app-wipe` on a new branch `feature/wipe`, and one at `../tasks-app-remaining` on a new
> branch `feature/remaining`. Then show me `git worktree list`."*
It runs the `git worktree add` calls for you. (If you'd rather it run a script than type the commands,
hand it `lab/setup-worktrees.sh`, which does exactly this.) Then **verify** by hand:
```bash
cd ~/ai-workflow-course/tasks-app
git worktree list # should show main + feature/wipe + feature/remaining
```
Three folders backed by one repo, and you didn't type a git command. You directed, the agent did the
git, you confirmed.
### Part C — Run two AI sessions in parallel
This is the part to actually *do simultaneously*, not one then the other.
@@ -314,19 +315,24 @@ This is the part to actually *do simultaneously*, not one then the other.
cd ~/ai-workflow-course/tasks-app-remaining && python cli.py add "from worktree B" && python cli.py list
```
Each `list` shows only its own task worktree A never sees "from worktree B" and vice versa. Each
Each `list` shows only its own task: worktree A never sees "from worktree B" and vice versa. Each
worktree has its **own** `tasks.json` (gitignored runtime state, not shared history), so the two
running apps don't even share data. Separate files, separate state, while both agents work. Total
isolation.
running apps don't even share data. Separate files, separate state, while both agents work.
4. In each worktree, commit the agent's work on its own branch:
4. Review each agent's diff, then have **that worktree's own session** commit its work on its branch.
In the `tasks-app-wipe` session, read the diff and tell the agent:
> *"The diff looks right. Commit this on the branch with the message 'Add wipe command'."*
Do the same in the `tasks-app-remaining` session (message 'Add remaining command'). Each agent
stages and commits its own work; you verify each landed and left a clean tree:
```bash
cd ~/ai-workflow-course/tasks-app-wipe && git add . && git commit -m "Add wipe command"
cd ~/ai-workflow-course/tasks-app-remaining && git add . && git commit -m "Add remaining command"
cd ~/ai-workflow-course/tasks-app-wipe && git status && git log --oneline -1
cd ~/ai-workflow-course/tasks-app-remaining && git status && git log --oneline -1
```
Two agents, two commits, two branches neither ever saw the other's files.
Two agents, two commits, two branches, and neither ever saw the other's files.
5. *Now* the new commands exist — run each in its own worktree to watch it work:
@@ -335,38 +341,48 @@ This is the part to actually *do simultaneously*, not one then the other.
cd ~/ai-workflow-course/tasks-app-remaining && python cli.py remaining # agent B's new command
```
`remaining` counts a single pending task the one you added to worktree B in step 3 because B's
`tasks.json` is the only state it can see. The isolation, one last time.
`remaining` counts a single pending task, the one you added to worktree B in step 3, because B's
`tasks.json` is the only state it can see.
### Part D — Merge back and clean up
Bring both features home to `main` in your original worktree:
Both feature branches need to come home to `main`. Back in the **coordinating session** (the one on
`tasks-app`), direct the merges:
> *"On the `tasks-app` repo: switch to `main`, then merge `feature/wipe` and `feature/remaining` into
> it."*
Both commits are already in the shared object store, so there's nothing to fetch; the merges are
local and instant. The second merge **may** hit a small conflict in `cli.py` if both agents added
their `elif` branch in the same spot. That's expected, and it's a *merge-time* event, not a
parallel-work collision. When it happens, direct the agent to resolve it with the same conflict skill
from Module 6:
> *"`cli.py` has a merge conflict. I want the final file to keep BOTH the `wipe` and `remaining`
> commands. Resolve it and complete the merge."*
Then **verify** the result before you trust it, the same way you did in Module 6:
```bash
cd ~/ai-workflow-course/tasks-app
git switch main
git merge feature/wipe
git merge feature/remaining
git diff # no conflict markers remain
python cli.py list # the app still runs
python cli.py wipe # both new commands work
python cli.py remaining
```
Both commits are already in the shared object store, so there's nothing to fetch — the merges are
local and instant. The second merge **may** hit a small conflict in `cli.py` if both agents added
their `elif` branch in the same spot. That's expected, and it's a *merge-time* event, not a
parallel-work collision — resolve it with the exact skill from Module 6, then `python cli.py list`
to confirm both commands work.
Now tear down the worktrees. Direct the coordinating session:
Now tear down the worktrees (copy the cleanup script into `tasks-app` the same way, then run it from
inside the repo):
> *"Remove the `tasks-app-wipe` and `tasks-app-remaining` worktrees and prune any stale records."*
It runs `git worktree remove` on both folders and `git worktree prune`. (Hand it
`lab/cleanup-worktrees.sh` if you'd rather it run the script.) The branches are already merged into
`main`, so the work is safe. **Verify** only the main worktree is left:
```bash
cp /path/to/modules/07-worktrees-running-agents-in-parallel/lab/cleanup-worktrees.sh .
bash cleanup-worktrees.sh
git worktree list # only the main worktree remains
git worktree list # only the main worktree remains
```
The script runs `git worktree remove` on both folders and `git worktree prune` to clear any stale
records. The branches are already merged into `main`, so the work is safe.
---
## Where it breaks
@@ -407,7 +423,7 @@ Worktrees are sharp tools. The honest caveats:
- `git worktree list` showed three entries at once, and you ran the `tasks-app` from two different
worktree folders — adding a different task in each and watching each keep its own `tasks.json`.
- You ran two AI sessions in parallel each in its own worktree on its own branch and confirmed
- You ran two AI sessions in parallel, each in its own worktree on its own branch, and confirmed
neither touched the other's files (different folders, different `tasks.json`, different branch).
- You merged both feature branches back into `main` (resolving a conflict if one appeared) and the
app has both new commands.
@@ -12,4 +12,4 @@ Add a `wipe` command to this task app that removes **all** tasks.
`wiped all tasks`.
- After `wipe`, `python cli.py list` should print `(no tasks yet)`.
Make the change, then stop I'll review the diff and commit it myself.
Make the change, then stop. I'll review the diff, then have you commit it on this branch.
@@ -11,4 +11,4 @@ Add a `remaining` command to this task app that prints how many tasks are still
- Running `python cli.py remaining` should print something like `2 pending` (the number of tasks not
marked done).
Make the change, then stop I'll review the diff and commit it myself.
Make the change, then stop. I'll review the diff, then have you commit it on this branch.
@@ -1,9 +1,10 @@
#!/usr/bin/env bash
#
# Module 7 lab — tear down the two worktrees created by setup-worktrees.sh.
# Copy this into your tasks-app repo, then run it from inside:
# The tool the coordinating AI session runs to clean up. Hand it to your agent, or copy it into
# tasks-app and let the agent run it:
#
# cp /path/to/modules/07-worktrees-running-agents-in-parallel/lab/cleanup-worktrees.sh .
# cp ~/ai-workflow-course/modules/07-worktrees-running-agents-in-parallel/lab/cleanup-worktrees.sh .
# bash cleanup-worktrees.sh
#
# `git worktree remove` deletes the folder AND clears Git's record of it; `prune` mops up any
@@ -1,9 +1,10 @@
#!/usr/bin/env bash
#
# Module 7 lab — create two linked worktrees off the tasks-app repo, each on its own branch.
# Copy this into your tasks-app repo (the one you git-init'd in Module 2), then run it from inside:
# This is the tool the coordinating AI session (the one already pointed at tasks-app) can run to
# set up the worktrees. Hand it to your agent, or copy it into tasks-app and let the agent run it:
#
# cp /path/to/modules/07-worktrees-running-agents-in-parallel/lab/setup-worktrees.sh .
# cp ~/ai-workflow-course/modules/07-worktrees-running-agents-in-parallel/lab/setup-worktrees.sh .
# bash setup-worktrees.sh
#
# It places the new worktree folders next to the repo, so you end up with: