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:
@@ -1,6 +1,6 @@
|
||||
# Module 11 — Collaboration: Humans and Agents on One Repo
|
||||
|
||||
> **You now have every piece — issues, branches, PRs, review. This module wires them into one loop,
|
||||
> **You now have every piece: issues, branches, PRs, review. This module wires them into one loop,
|
||||
> and points out that half your "teammates" might not be human.** Once the loop runs the same way no
|
||||
> matter who's pulling the work, an agent is just another contributor who needs a branch.
|
||||
|
||||
@@ -20,7 +20,7 @@ This is the synthesis module for Unit 2's collaboration arc. It assumes the whol
|
||||
- **Module 10** — pull/merge requests and the skill of reviewing a diff you didn't write.
|
||||
|
||||
Each of those taught one move. This module is the assembled motion. If you're missing one, the loop
|
||||
still works, but a step will feel like a black box — go back and fill it in.
|
||||
still works, but a step will feel like a black box, so go back and fill it in.
|
||||
|
||||
---
|
||||
|
||||
@@ -54,8 +54,8 @@ issue → branch → implementation → pull request → review → me
|
||||
(M9) (M6) (inner loop, M2) (M10) (M10) (this module)
|
||||
```
|
||||
|
||||
Everything you learned was a single station on this track. The reason to assemble them now — rather
|
||||
than keep treating issues, branches, and PRs as separate skills — is that the *handoffs between
|
||||
Everything you learned was a single station on this track. The reason to assemble them now, rather
|
||||
than keep treating issues, branches, and PRs as separate skills, is that the *handoffs between
|
||||
stations* are where collaboration actually happens, and where it breaks. The issue says what to do.
|
||||
The branch isolates the attempt. The PR makes the attempt reviewable. The review is the judgment.
|
||||
The merge is the commitment. Closing the issue is the receipt. Skip a handoff and you get the
|
||||
@@ -63,7 +63,7 @@ failure modes every team knows: work nobody asked for, changes that land straigh
|
||||
review, "done" issues for work that was never actually done.
|
||||
|
||||
The loop is worth internalizing as a loop because **it's the same loop regardless of who's doing the
|
||||
work** — and increasingly, some of the workers are agents. Hold that thought; it's the whole point of
|
||||
work**, and increasingly some of the workers are agents. Hold that thought; it's the whole point of
|
||||
the module, and we'll come back to it.
|
||||
|
||||
### The loop, step by step
|
||||
@@ -71,17 +71,18 @@ the module, and we'll come back to it.
|
||||
**1 — The issue (Module 9) is the contract.** Before any code, there's a statement of intent: a
|
||||
title, a description of the desired behavior, maybe acceptance criteria. It has a number (`#42`) that
|
||||
the rest of the loop will reference. The issue exists so that "what we're doing and why" lives
|
||||
somewhere durable and shared — not in one person's head or one chat session that'll evaporate
|
||||
somewhere durable and shared, not in one person's head or one chat session that'll evaporate
|
||||
(Module 1, Seam 2). Assign it to whoever's taking it: a person, or an agent.
|
||||
|
||||
**2 — The branch (Module 6) is the workspace.** You never implement on `main`. You cut a branch
|
||||
named for the work — convention is something traceable like `42-clear-done-command` (the issue
|
||||
named for the work. Convention is something traceable like `42-clear-done-command` (the issue
|
||||
number plus a slug). The name matters more than it looks: months later, `git branch` and the host's
|
||||
branch list become a map of "what's in flight," and the issue number ties each branch back to its
|
||||
contract.
|
||||
|
||||
```bash
|
||||
git switch -c 42-clear-done-command # branch off main and switch to it
|
||||
# Switched to a new branch '42-clear-done-command'
|
||||
```
|
||||
|
||||
**3 — Implementation is the inner loop (Module 2).** This is where the actual editing happens —
|
||||
@@ -91,6 +92,7 @@ untouched until the loop says otherwise.
|
||||
|
||||
```bash
|
||||
git push -u origin 42-clear-done-command # publish the branch so others (and the host) can see it
|
||||
# branch '42-clear-done-command' set up to track 'origin/42-clear-done-command'.
|
||||
```
|
||||
|
||||
**4 — The pull request (Module 10) makes it reviewable.** Opening a PR says "this branch is ready
|
||||
@@ -99,12 +101,12 @@ reviewable unit. Crucially, **this is where you link back to the issue** (next s
|
||||
can close itself.
|
||||
|
||||
**5 — Review (Module 10) is the judgment gate.** Someone who isn't the author reads the diff for
|
||||
correctness *and plausibility* — the skill Module 10 is built around. They approve, request changes,
|
||||
correctness *and plausibility*, the skill Module 10 is built around. They approve, request changes,
|
||||
or comment. For AI-generated diffs this gate is doing more work than it used to: the code compiles,
|
||||
reads cleanly, and is still wrong in a way only review catches.
|
||||
|
||||
**6 — Merge is the commitment.** Approved, the PR merges into `main`. Hosts offer a couple of merge
|
||||
styles — a squash or a merge commit; your team picks one and the effect is the same: the branch's work
|
||||
styles, a squash or a merge commit; your team picks one and the effect is the same: the branch's work
|
||||
is now part of the shared trunk. (You'll also see a *rebase-merge* option; it rewrites history and is
|
||||
out of scope here.) Delete the branch after; its job is done and its name lives on in the merge.
|
||||
|
||||
@@ -114,8 +116,8 @@ issue automatically. The receipt is written without anyone touching the issue. T
|
||||
|
||||
### Linking the PR to the issue (the auto-close)
|
||||
|
||||
The mechanic that makes step 7 free: put a **closing keyword** in the PR description. Most hosts —
|
||||
GitHub, GitLab, Gitea/Forgejo, Bitbucket — recognize a common set:
|
||||
The mechanic that makes step 7 free: put a **closing keyword** in the PR description. Most hosts
|
||||
(GitHub, GitLab, Gitea/Forgejo, Bitbucket) recognize a common set:
|
||||
|
||||
```
|
||||
Closes #42
|
||||
@@ -127,11 +129,11 @@ host closes the referenced issue and cross-links the two so each shows the other
|
||||
body buys you a self-closing loop and a permanent trail from "why we did this" (issue) to "what we
|
||||
did" (PR/diff) to "when it landed" (merge).
|
||||
|
||||
A plain mention without a keyword — just `#42` — *links* the two but does **not** close on merge.
|
||||
A plain mention without a keyword, just `#42`, *links* the two but does **not** close on merge.
|
||||
That's useful too (for "related to" references), but know the difference: the keyword is load-bearing.
|
||||
|
||||
> **The trail is the point.** Six months later, someone — possibly an agent reading the repo as
|
||||
> durable memory (Module 2) — asks "why does `clear-done` exist?" The answer is one click away:
|
||||
> **The trail is the point.** Six months later, someone (possibly an agent reading the repo as
|
||||
> durable memory, Module 2) asks "why does `clear-done` exist?" The answer is one click away:
|
||||
> issue → PR → diff → merge. You built that trail for free by linking one line.
|
||||
|
||||
### Branch vs. fork: it comes down to push access
|
||||
@@ -157,7 +159,7 @@ simple: **can you push to the repo?**
|
||||
```
|
||||
|
||||
For this audience, working mostly on repos you control, **branches are the default and forks are the
|
||||
exception** — you reach for a fork when contributing to something you don't own. The relevance to AI
|
||||
exception**: you reach for a fork when contributing to something you don't own. The relevance to AI
|
||||
work: an agent you run on your own repo branches like any teammate. An agent contributing to a
|
||||
project it doesn't own forks like any outside contributor. The rule doesn't change for machines.
|
||||
|
||||
@@ -167,10 +169,10 @@ project it doesn't own forks like any outside contributor. The rule doesn't chan
|
||||
*enforced* rule, and that enforcement is the other half of collaboration nobody mentions until it
|
||||
bites.
|
||||
|
||||
**Roles.** Hosts assign access in tiers — typically read (clone, comment), then write/develop (push
|
||||
**Roles.** Hosts assign access in tiers, typically read (clone, comment), then write/develop (push
|
||||
branches, open PRs), then maintain/admin (manage settings, force-merge, change protections). A
|
||||
contributor only needs *write* to do the whole loop above; admin is for the people running the repo.
|
||||
Give out the least that lets someone do their job — the same least-privilege instinct you already
|
||||
Give out the least that lets someone do their job, the same least-privilege instinct you already
|
||||
have for production systems.
|
||||
|
||||
**Protected branches.** This is the enforcement mechanism. You mark `main` (and any other shared
|
||||
@@ -183,38 +185,38 @@ can layer rules on top:
|
||||
|
||||
Turning these on converts "we agreed not to push to `main`" into "the server won't let you." For a
|
||||
solo learner this can feel like bureaucracy, but it's exactly the guardrail that makes it safe to add
|
||||
contributors you trust *less than fully* — including machine ones. (Required **status checks** —
|
||||
"CI must pass before merge" — are the same protected-branch feature, but they need CI to exist first;
|
||||
contributors you trust *less than fully*, including machine ones. (Required **status checks**,
|
||||
"CI must pass before merge", are the same protected-branch feature, but they need CI to exist first;
|
||||
that's Module 14. We'll come back and switch it on there.)
|
||||
|
||||
### The contributor who isn't human
|
||||
|
||||
Here's the synthesis the whole unit was building toward. Re-read the loop — issue, branch,
|
||||
implementation, PR, review, merge — and notice that **nothing in it specifies that the contributor is
|
||||
Here's the synthesis the whole unit was building toward. Re-read the loop (issue, branch,
|
||||
implementation, PR, review, merge) and notice that **nothing in it specifies that the contributor is
|
||||
a person.** That's not an accident; it's the most useful property of the whole system right now.
|
||||
|
||||
- **An agent is a contributor with a branch.** You hand an agent an issue (Module 9 already framed
|
||||
assignees as a mix of humans and agents). It cuts a branch, implements, and opens a PR — exactly
|
||||
assignees as a mix of humans and agents). It cuts a branch, implements, and opens a PR, exactly
|
||||
the loop above. A human reviews that PR on the same gate used for any teammate (Module 10). The
|
||||
agent never touches `main`; the protected-branch rules and the review gate apply to it identically.
|
||||
This is *why* the loop is worth assembling as a loop: it's the harness that lets you accept work
|
||||
from a contributor whose judgment you don't fully trust yet.
|
||||
|
||||
- **Two agents in parallel are just two contributors needing branches.** The moment you run more than
|
||||
one agent at once, you have the classic collaboration problem — two workers who must not edit the
|
||||
one agent at once, you have the classic collaboration problem: two workers who must not edit the
|
||||
same files in the same working directory. That's not a new problem, and it already has an answer:
|
||||
**worktrees (Module 7).** Each agent gets its own working directory and its own branch; they work
|
||||
simultaneously, each opens its own PR, and you review and merge them independently. Worktrees
|
||||
earned their module precisely so this case would already be solved by the time you got here.
|
||||
|
||||
- **The merge stays human (for now).** The agent can do every step *up to* merge. The merge — the
|
||||
commitment to shared `main` — is where a human stays in the loop, because review is judgment and
|
||||
- **The merge stays human (for now).** The agent can do every step *up to* merge. The merge, the
|
||||
commitment to shared `main`, is where a human stays in the loop, because review is judgment and
|
||||
judgment is the thing you haven't delegated yet. Unit 5 is about carefully, conditionally moving
|
||||
that line; this module is where you should be able to *picture* an agent doing the first five steps
|
||||
while you do the sixth.
|
||||
|
||||
The reframe to carry forward: **collaboration tooling was never really about humans.** It's about
|
||||
coordinating *contributors* — isolating their work, making it reviewable, controlling who can commit
|
||||
coordinating *contributors*: isolating their work, making it reviewable, controlling who can commit
|
||||
it to the trunk. Those guarantees are exactly what you need to safely let an agent contribute, which
|
||||
is why the team layer you just learned doubles as the agent-safety layer you'll lean on for the rest
|
||||
of the course.
|
||||
@@ -223,26 +225,26 @@ of the course.
|
||||
|
||||
## The AI angle
|
||||
|
||||
A generic "intro to team git" lesson ends at "branch, PR, review, merge — congrats, you can work on a
|
||||
A generic "intro to team git" lesson ends at "branch, PR, review, merge, congrats, you can work on a
|
||||
team." This module's reason to exist is that **the team you're coordinating now includes agents, and
|
||||
the loop is what makes that safe.**
|
||||
|
||||
- **The loop is the harness for untrusted contributors — and an agent is one.** Branch isolation,
|
||||
the PR boundary, mandatory review, protected `main` — every one of these was designed to let work
|
||||
- **The loop is the harness for untrusted contributors, and an agent is one.** Branch isolation,
|
||||
the PR boundary, mandatory review, protected `main`: every one of these was designed to let work
|
||||
flow from someone whose every change you don't personally vouch for. That's the exact profile of an
|
||||
agent. You don't need new tooling to put an agent to work; you need the tooling you just learned,
|
||||
pointed at a new kind of contributor.
|
||||
- **Volume goes up; the gate has to hold.** A human contributor opens a PR a day. An agent can open
|
||||
five before lunch. The review gate (Module 10) and the protected-branch rules are what keep that
|
||||
volume from landing unreviewed on `main`. The faster your contributors, the more the gate earns its
|
||||
keep — same lesson as Module 1, one layer up.
|
||||
keep, the same lesson as Module 1, one layer up.
|
||||
- **Parallel agents are a solved problem, on purpose.** Two agents at once is just two contributors
|
||||
needing isolation — worktrees (Module 7) and separate branches. You already have the answer; this
|
||||
needing isolation: worktrees (Module 7) and separate branches. You already have the answer; this
|
||||
module is where you see *why* you were given it.
|
||||
- **The auto-closing trail is memory for the next session.** Issue → PR → diff → merge is exactly the
|
||||
durable, on-disk-and-on-host record a fresh agent reads to reconstruct "why does this exist?"
|
||||
(Module 2's durable-memory reframe, now spanning the whole loop). Linking the PR to the issue isn't
|
||||
bookkeeping; it's writing the project's memory in a form the next contributor — human or machine —
|
||||
bookkeeping; it's writing the project's memory in a form the next contributor, human or machine,
|
||||
can follow.
|
||||
|
||||
You're not learning collaboration *and then* learning to work with agents. They're the same skill.
|
||||
@@ -251,27 +253,29 @@ You're not learning collaboration *and then* learning to work with agents. They'
|
||||
|
||||
## Hands-on lab
|
||||
|
||||
**Lab language:** shell (git commands) plus your host's web UI for the issue, PR, review, and merge
|
||||
steps. You'll implement the feature with your AI the way Module 4 taught — agent editing the files
|
||||
directly, you reviewing the diff.
|
||||
**Lab language:** shell plus your host's web UI for the issue, PR, review, and merge steps. From
|
||||
Module 4 on you direct the AI to do the git work and verify the result; the only commands you type by
|
||||
hand here are read-only checks like `git branch` and `git show`. You'll implement the feature with
|
||||
Claude Code (sub your own agent) the way Module 4 taught: the agent edits the files directly, you
|
||||
review the diff.
|
||||
|
||||
The goal is to run the **entire outer loop once**, on the `tasks-app`, and watch the issue close
|
||||
itself on merge. One small feature, all seven stations.
|
||||
|
||||
**The feature:** add a `clear-done` command to the CLI that removes every completed task. It's a
|
||||
deliberately small, two-file change (logic in `tasks.py`, wiring in `cli.py`) — small enough that the
|
||||
deliberately small, two-file change (logic in `tasks.py`, wiring in `cli.py`), small enough that the
|
||||
loop, not the code, is what you're practicing.
|
||||
|
||||
**You'll need:**
|
||||
|
||||
- Your `tasks-app` repo from earlier modules, with a remote on your git host (Module 8) that supports
|
||||
issues and PRs.
|
||||
- Your `tasks-app` repo from earlier modules (`~/ai-workflow-course/tasks-app`), with a remote on your
|
||||
git host (Module 8) that supports issues and PRs.
|
||||
- Push access to that repo (it's yours, so you have it).
|
||||
- Your editor-integrated AI tool (Module 4).
|
||||
- Claude Code (sub your own agent), your editor-integrated AI from Module 4.
|
||||
- Your host's CLI (`gh` for GitHub, `glab` for GitLab, `tea` for Gitea/Forgejo). The web UI covers the
|
||||
whole human-driven loop (Parts A–D), so there the CLI is just convenience. Part E is the exception:
|
||||
for an *agent* to open the PR itself it has to reach the forge, which needs the CLI installed and
|
||||
authenticated — or you take the no-CLI fallback that section spells out.
|
||||
authenticated, or you take the no-CLI fallback that section spells out.
|
||||
|
||||
Starter artifacts are in this module's `lab/`: `issue.md` (the issue to file) and `pr-body.md` (the
|
||||
PR description, including the load-bearing closing keyword).
|
||||
@@ -281,43 +285,55 @@ PR description, including the load-bearing closing keyword).
|
||||
Before the loop, make `main` enforce what you've been doing by hand. In your host's web UI, open the
|
||||
repo's branch-protection settings and protect `main` with **"require a pull request before merging."**
|
||||
|
||||
```bash
|
||||
# Confirm the rule bites — this push should now be REFUSED by the host:
|
||||
git switch main
|
||||
echo "# direct edit" >> README.md
|
||||
git commit -am "try to push straight to main"
|
||||
git push # expect: remote rejects the push to a protected branch
|
||||
git reset --hard HEAD~1 # undo the local commit; we'll add the feature the right way, via a PR
|
||||
```
|
||||
Now prove the rule bites. Working in `~/ai-workflow-course/tasks-app`, tell Claude Code to make a
|
||||
throwaway edit on `main` and push it straight up:
|
||||
|
||||
(That `git reset --hard HEAD~1` is a sharp, history-rewriting command from a later module — it drops
|
||||
your most recent commit *and* its changes. It's safe here only because that commit was a throwaway to
|
||||
test the guardrail; its full treatment and its real dangers are **Module 12**.)
|
||||
> "On the `main` branch, append a comment line to `README.md`, commit it, and push directly to the
|
||||
> remote. This is a deliberate test of branch protection."
|
||||
|
||||
If the push went through, protection isn't on — fix that before continuing. Feeling the server say
|
||||
*no* is the point: "never commit to `main`" is now a rule, not a resolution.
|
||||
Watch the push come back **rejected**: the host refuses a direct push to a protected branch. That
|
||||
refusal is the whole point of Part A. Then have the agent undo the throwaway commit:
|
||||
|
||||
> "Good, the host rejected it. Drop that last commit and its changes so we're back to a clean `main`,
|
||||
> then we'll do this the right way through a PR."
|
||||
|
||||
The agent reaches for `git reset --hard HEAD~1` here. That's a sharp, history-rewriting command from a
|
||||
later module: it drops your most recent commit *and* its changes. It's safe only because that commit
|
||||
was a throwaway to test the guardrail. Its full treatment and its real dangers are **Module 12**.
|
||||
|
||||
If the push went through instead of bouncing, protection isn't on; fix that before continuing. Feeling
|
||||
the server say *no* is the point: "never commit to `main`" is now a rule, not a resolution.
|
||||
|
||||
### Part B — Issue → branch
|
||||
|
||||
1. **File the issue.** Create a new issue from `lab/issue.md` (title and body). Note its number — say
|
||||
1. **File the issue.** Create a new issue from `lab/issue.md` (title and body). Note its number; say
|
||||
it's `#42`. This is the contract.
|
||||
|
||||
2. **Branch for it**, naming the branch after the issue:
|
||||
2. **Branch for it**, naming the branch after the issue. Tell Claude Code to sync `main` and cut the
|
||||
branch:
|
||||
|
||||
> "Sync `main` with the remote, then create and switch to a branch named `42-clear-done-command`
|
||||
> (use my issue number)."
|
||||
|
||||
Verify it landed before moving on:
|
||||
|
||||
```bash
|
||||
git switch main && git pull # start from current main
|
||||
git switch -c 42-clear-done-command # use YOUR issue number
|
||||
git branch # the new 42-clear-done-command branch, marked current with *
|
||||
git status # "On branch 42-clear-done-command", working tree clean
|
||||
```
|
||||
|
||||
The branch-naming convention (issue number plus a short slug) is the thing to get right here, not
|
||||
the keystrokes.
|
||||
|
||||
### Part C — Implementation (with AI)
|
||||
|
||||
3. Point your editor-integrated AI at the repo and ask for the feature:
|
||||
3. Point Claude Code at `~/ai-workflow-course/tasks-app` and ask for the feature:
|
||||
|
||||
> "Add a `clear-done` command. In `tasks.py`, add a `TaskList` method that removes all completed
|
||||
> tasks. In `cli.py`, wire up a `clear-done` command that calls it, saves, and prints how many
|
||||
> were removed. Match the existing style."
|
||||
|
||||
4. **Review the diff before you trust it** — the Module 2 habit, the Module 10 skill:
|
||||
4. **Review the diff before you trust it** (the Module 2 habit, the Module 10 skill):
|
||||
|
||||
```bash
|
||||
git diff
|
||||
@@ -337,12 +353,17 @@ If the push went through, protection isn't on — fix that before continuing. Fe
|
||||
Read the index off `list` rather than assuming it: `done` is positional, and your `tasks-app` has
|
||||
been carrying tasks since Module 1, so "trash" won't reliably land at index 1.
|
||||
|
||||
5. Commit and push the branch:
|
||||
5. **Have the agent commit and push.** Tell Claude Code to stage just the two changed files, commit
|
||||
with a message that closes the issue, and publish the branch:
|
||||
|
||||
> "Commit `tasks.py` and `cli.py` with a message like `Add clear-done command (closes #42)` (use my
|
||||
> issue number and the closing keyword), then push the branch to the remote."
|
||||
|
||||
Verify before you trust it: the commit staged **only** those two files, and the subject carries the
|
||||
closing keyword.
|
||||
|
||||
```bash
|
||||
git add tasks.py cli.py
|
||||
git commit -m "Add clear-done command (closes #42)"
|
||||
git push -u origin 42-clear-done-command
|
||||
git show --stat HEAD # only tasks.py and cli.py listed; subject ends "(closes #42)"
|
||||
```
|
||||
|
||||
### Part D — PR → review → merge → auto-close
|
||||
@@ -363,12 +384,18 @@ If the push went through, protection isn't on — fix that before continuing. Fe
|
||||
approval). Delete the branch when prompted.
|
||||
|
||||
9. **Watch the issue close itself.** Open issue `#42`. It should now be **closed**, with a link to
|
||||
the PR that closed it. You didn't touch the issue — the merge did. That click is the whole loop
|
||||
the PR that closed it. You didn't touch the issue; the merge did. That click is the whole loop
|
||||
landing.
|
||||
|
||||
Now have Claude Code bring the merged work down and tidy up:
|
||||
|
||||
> "Switch to `main`, pull the merged work, and delete the now-merged local branch
|
||||
> `42-clear-done-command`."
|
||||
|
||||
Verify the branch is gone:
|
||||
|
||||
```bash
|
||||
git switch main && git pull # bring the merged work down locally
|
||||
git branch -d 42-clear-done-command # tidy up the local branch
|
||||
git branch # 42-clear-done-command no longer listed; you're on main
|
||||
```
|
||||
|
||||
### Part E — Now make the contributor an agent
|
||||
@@ -379,7 +406,7 @@ method already exists, so this is wiring only).
|
||||
|
||||
**First, a reality check the rest of the lab let you skip.** Two of those steps cross the forge
|
||||
boundary: the agent has to *read* issue #43 from the forge and *open* a PR back into it. Your Module 4
|
||||
editor agent only edits files and runs local commands — and `git push` publishes a branch, it does
|
||||
editor agent only edits files and runs local commands, and `git push` publishes a branch, it does
|
||||
**not** open a PR. The web UI you've been clicking can't be handed to the agent. So before you prompt,
|
||||
give the agent a way to reach the forge. Pick one path:
|
||||
|
||||
@@ -391,20 +418,20 @@ give the agent a way to reach the forge. Pick one path:
|
||||
> referencing the issue with a closing keyword, push the branch, and open a PR into `main` whose
|
||||
> description closes #43."
|
||||
|
||||
- **No-CLI fallback (you open the PR).** Have the agent do everything local — branch, implement,
|
||||
commit, push — and *you* open the PR in the web UI, reusing `lab/pr-body.md` and keeping the
|
||||
- **No-CLI fallback (you open the PR).** Have the agent do everything local (branch, implement,
|
||||
commit, push) and *you* open the PR in the web UI, reusing `lab/pr-body.md` and keeping the
|
||||
`Closes #43` line. Prompt it the same way, but stop it at the push:
|
||||
|
||||
> "Take issue #43. Create a branch named `43-pending-command`, implement the feature, commit
|
||||
> referencing the issue with a closing keyword, and push the branch. I'll open the PR."
|
||||
|
||||
Wiring an agent *directly* into the forge — so it reads issues and opens PRs with no human hand-off
|
||||
and no CLI to shell out to — is what an MCP forge integration buys you in **Module 20**. Here you're
|
||||
Wiring an agent *directly* into the forge, so it reads issues and opens PRs with no human hand-off
|
||||
and no CLI to shell out to, is what an MCP forge integration buys you in **Module 20**. Here you're
|
||||
feeling the exact seam that module closes.
|
||||
|
||||
Either way, let the agent drive to the open-PR state. Then **you** are the human at the gate: review
|
||||
the diff, and merge (or request changes) yourself. You've just watched the exact loop run with a
|
||||
non-human contributor — and felt precisely where you, the human, stayed in it. If you want the
|
||||
non-human contributor, and felt precisely where you, the human, stayed in it. If you want the
|
||||
parallel-agents case, file two issues and run two agents in separate worktrees (Module 7), each on its
|
||||
own branch.
|
||||
|
||||
@@ -414,33 +441,33 @@ own branch.
|
||||
|
||||
- **Auto-close only fires on merge to the *default* branch.** Closing keywords close the issue when
|
||||
the PR lands on `main` (or whatever your default is). Merge into a non-default branch and the issue
|
||||
stays open — by design. Keep the keyword in the *PR description* (or a commit message); a closing
|
||||
stays open, by design. Keep the keyword in the *PR description* (or a commit message); a closing
|
||||
keyword buried in a mid-thread comment behaves differently across hosts.
|
||||
- **The exact keyword set is host-specific.** `Closes/Fixes/Resolves` are the safe, widely-supported
|
||||
trio, but the full list and the cross-repo syntax (`owner/repo#42`, needed when a fork's PR closes
|
||||
an upstream issue) vary by host. When in doubt, mention-link and close the issue by hand — the trail
|
||||
an upstream issue) vary by host. When in doubt, mention-link and close the issue by hand; the trail
|
||||
still exists.
|
||||
- **Auto-closed is not the same as actually done.** Merging closes the issue *mechanically*. It says
|
||||
nothing about whether the work was correct — that judgment was the review (Module 10), and if review
|
||||
nothing about whether the work was correct; that judgment was the review (Module 10), and if review
|
||||
was a rubber stamp, you just auto-closed an issue for broken work. The loop automates the
|
||||
bookkeeping, never the thinking.
|
||||
- **Protected branches protect against accidents, not admins.** Most hosts let admins bypass
|
||||
protection (sometimes silently). And an account with push access — including a *bot* account you set
|
||||
up for an agent — is an attack surface and a blast radius: its token can push branches and, if
|
||||
protection (sometimes silently). And an account with push access, including a *bot* account you set
|
||||
up for an agent, is an attack surface and a blast radius: its token can push branches and, if
|
||||
over-permissioned, merge them. Scope machine accounts to the least they need; this is the front edge
|
||||
of a problem Unit 4 takes head-on.
|
||||
- **Forks add real friction beyond the extra clone.** Keeping a fork in sync with a fast-moving
|
||||
upstream is ongoing work, and PRs *from* forks are deliberately limited by hosts (for example, they
|
||||
often can't access the upstream repo's CI secrets — relevant once you reach Module 14). For repos
|
||||
often can't access the upstream repo's CI secrets, relevant once you reach Module 14). For repos
|
||||
you own, prefer branches; reach for forks only when you genuinely lack push access.
|
||||
- **The loop diagram is the happy path.** Real PRs get change requests, need updating when `main`
|
||||
moves underneath them, or hit a merge conflict (Module 6) when two contributors touched the same
|
||||
lines — exactly
|
||||
lines, exactly
|
||||
the parallel-agent scenario worktrees mitigate but don't eliminate. The stations are fixed; the
|
||||
number of trips around them isn't.
|
||||
- **Squash-merge collapses authorship.** If your team squashes, the agent's (or your) individual
|
||||
commits become one commit on `main`, and the per-commit trail lives only on the now-deleted branch /
|
||||
closed PR. That's usually a fine trade for a clean history — just know the granular history moved
|
||||
closed PR. That's usually a fine trade for a clean history; just know the granular history moved
|
||||
from `main` to the PR record.
|
||||
|
||||
---
|
||||
@@ -449,7 +476,7 @@ own branch.
|
||||
|
||||
**You're done when:**
|
||||
|
||||
- You ran the full loop on `tasks-app` at least once and watched an issue close itself on merge —
|
||||
- You ran the full loop on `tasks-app` at least once and watched an issue close itself on merge,
|
||||
with `main` protected so the PR was mandatory, not optional.
|
||||
- You can draw the seven-station loop (issue → branch → implementation → PR → review → merge → closed)
|
||||
from memory and say which earlier module owns each station.
|
||||
@@ -461,7 +488,7 @@ own branch.
|
||||
- You can explain why the same tooling that coordinates human teammates is what makes accepting an
|
||||
agent's work safe.
|
||||
|
||||
When the loop feels like one motion rather than six separate tools — and when "give the agent a
|
||||
branch and review its PR" feels obvious rather than novel — you're ready for Module 12, where we make
|
||||
When the loop feels like one motion rather than six separate tools, and when "give the agent a
|
||||
branch and review its PR" feels obvious rather than novel, you're ready for Module 12, where we make
|
||||
the *recovery* half of this safety net its own discipline: reverting a bad PR after it's already
|
||||
merged.
|
||||
|
||||
Reference in New Issue
Block a user