Reframe sweep M7-27 + capstone (AI drives git, lesson=theory, de-slop) (#93)
Sync course wiki / sync-wiki (push) Successful in 11s
Sync course wiki / sync-wiki (push) Successful in 11s
Co-authored-by: claude <claude@jpaul.io> Co-committed-by: claude <claude@jpaul.io>
This commit was merged in pull request #93.
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user