A standalone blog/ folder (not course content) with drafts for jpaul.me: an announcement, a getting-started piece, then a hybrid weekly series — one post per module for Units 1-2 (posts 03-13) and one per unit for the back half (14-16) plus a capstone finale (17). Each post carries WordPress metadata, a [COURSE LINK] placeholder, and [insert screenshot] blocks for Justin to fill before publishing. README.md holds the manifest + checklist. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015EghAChc9UbcF78t55mfdf
15 KiB
Half Your Teammates Aren't Human (and the Loop Doesn't Care)
A few posts back we filed an issue. Last post we opened a pull request and learned to review a diff we didn't write. Both of those are real, useful skills on their own — but they've been sitting in your toolbox as separate tools, and that's not how a team actually uses them.
So here's the thing I want you to see in this post, because once you see it you can't un-see it: there's one loop that connects all of it, and nothing in that loop says the contributor has to be a person.
That's not a cute observation. It's the most useful property of the whole system right now. The exact tooling you learned to coordinate human teammates turns out to be the tooling that lets you safely put an agent to work. Same loop. Same gate. Same rules. Let me walk you through it — and then point at the spot where some of the "contributors" running through it are machines, and it doesn't matter one bit.
(New here? This is part of [The Workflow]([COURSE LINK]), a free course about the engineering scaffolding around AI coding. You can read this one standalone, but if "file an issue" or "open a PR" feels fuzzy, the earlier posts have you covered.)
Two loops, not one
Way back, you learned the inner loop: edit, git diff, commit, repeat. That loop lives on your disk and it's yours alone. It's how you — or your agent — make progress in a working session. Nobody else sees it while it's happening.
This post is about the outer loop — the one the team sees:
issue → branch → implementation → pull request → review → merge → issue closed
Every one of those stations is something you've already met as a separate skill. 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.
The reason to finally assemble these into a single loop — instead of keeping them as a pile of separate git tricks — is that the handoffs between stations are where collaboration actually happens. And where it breaks. Skip the issue and you get work nobody asked for. Skip the branch and changes land straight on main with no net. Skip the review and "done" means "merged," not "correct." The stations matter, but the seams between them matter more.
[insert a screenshot referencing the seven-station loop diagram (issue → branch → implementation → PR → review → merge → closed) here]
The loop, station by station
Let's run it for real, on the little tasks-app the course carries the whole way through. The feature: add a clear-done command that removes every completed task. Deliberately small — the point is to practice the loop, not the code.
1 — The issue is the contract. Before any code, there's a statement of intent with a number on it (#42). It exists so "what we're doing and why" lives somewhere durable and shared, not in one person's head or one chat session that'll evaporate. You assign it to whoever's taking it — a person, or an agent.
2 — The branch is the workspace. You never implement on main. You cut a branch named for the work, and the convention is to make it traceable:
git switch -c 42-clear-done-command # branch off main and switch to it
That name does more than it looks like. Months from now, git branch and your host's branch list become a map of what's in flight, and the issue number ties each branch back to its contract.
3 — Implementation is the inner loop. This is the edit/diff/commit rhythm you already have — you, or an agent, making commits on the branch. Nothing new here. The branch keeps it isolated, so however bold the change gets, main stays untouched until the loop says otherwise.
git push -u origin 42-clear-done-command # publish the branch so others (and the host) can see it
4 — The pull request makes it reviewable. Opening a PR says "this branch is ready to be considered for main." It bundles the diff, a description, and a discussion thread into one reviewable unit. And — this is the load-bearing part — it's where you link back to the issue so the loop can close itself (more on that in a second).
5 — Review is the judgment gate. Someone who isn't the author reads the diff for correctness and plausibility. 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. Approve, request changes, or comment.
6 — Merge is the commitment. Approved, the PR merges into main. Squash, merge-commit, rebase — pick one; the effect is the same. The branch's work is now part of the shared trunk. Delete the branch after; its job is done.
7 — The issue closes itself. If you linked the PR correctly, merging closes the issue automatically. Nobody touches the issue — the merge writes the receipt. That quiet click of the whole loop landing is the thing the lab makes you actually feel.
The one line that closes the loop for free
Here's the mechanic behind station 7. Put a closing keyword in the PR description:
Closes #42
Closes, Fixes, and Resolves (and their variants) all work on the major hosts — GitHub, GitLab, Gitea/Forgejo, Bitbucket. When the PR merges into the default branch, the host closes the referenced issue and cross-links the two so each points at the other. One line in the PR body buys you a self-closing loop and a permanent trail from "why we did this" (issue) → "what we did" (PR/diff) → "when it landed" (merge).
A plain #42 with no keyword links the two but does not close on merge. That's useful for "related to" references — just know the difference, because the keyword is the load-bearing part.
And that trail is the real prize. Six months from now someone asks "why does clear-done exist?" — and that someone might be an agent reading the repo as durable memory. The answer is one click away: issue → PR → diff → merge. You built that trail for free by typing one line.
Branch or fork? It's just push access
Two ways a contributor gets work in front of the team, and the deciding question is dead simple: can you push to the repo?
- You have push access → branch in the repo. The normal case for a team on a shared repo, and everything above assumes it. PRs go branch →
maininside one repo. - You don't have push access → fork, then PR from the fork. The open-source / outside-contributor case. You clone the repo into your own copy (a fork), push branches there, and open a PR across repos.
# Forked-contributor flow (no push access to upstream):
# 1. Fork upstream/repo -> you now own you/repo (one click on the host)
# 2. git clone https://host/you/repo
# 3. git switch -c my-fix ; ...commit...
# 4. git push -u origin my-fix # origin = your fork, which you CAN push to
# 5. Open a PR from you/repo:my-fix -> upstream/repo:main
For most of what you do — repos you control — branches are the default, forks are the exception. And here's where the AI angle sneaks in early: 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.
Who's allowed to push (and making the server enforce it)
"Never commit directly to main" started life as a personal discipline. On a shared repo it becomes an enforced rule — and that enforcement is the half of collaboration nobody mentions until it bites.
Roles. Hosts hand out access in tiers: read (clone, comment), then write (push branches, open PRs), then maintain/admin (settings, protections, force-merge). A contributor only needs write to run the whole loop above. Give out the least that lets someone do their job — the same least-privilege instinct you already have for production systems.
Protected branches are the enforcement. You mark main as protected and the host refuses direct pushes to it — the only way in is a PR. You can layer rules: require a PR, require a review approval, restrict who can merge. Turning these on converts "we agreed not to push to main" into "the server won't let you."
Don't skip this in the lab, because feeling the server say no is the whole point:
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 do it the right way
For a solo learner this can feel like bureaucracy. But it's exactly the guardrail that makes it safe to add a contributor you trust less than fully — including a machine one. Hold that thought, because it's the whole point of the next section.
The contributor who isn't human
Okay. Re-read that loop — issue, branch, implementation, PR, review, merge — and notice what's not in it: any requirement that the contributor be a person. That's not an oversight. It's the most useful thing about the entire system right now.
An agent is a contributor with a branch. You hand it an issue. It cuts a branch, implements, opens a PR — exactly the loop above. A human reviews that PR on the same gate used for any teammate. 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. Which is the exact profile of an agent.
In the lab you run the loop a second time and let the agent be the contributor. There's one honest snag worth calling out, because it's a seam you'll feel: your editor-integrated AI edits files and runs local commands, but git push only publishes a branch — it does not open a PR, and the web UI you've been clicking can't be handed to a machine. So you either give the agent your host's CLI (gh, glab, tea) so it can run gh pr create itself, or you take the no-CLI fallback: let the agent branch, implement, commit, and push, and you open the PR. Either way, the agent drives the first five steps and you stay the human at the merge.
Two agents at once? That's just two contributors needing branches. The moment you run more than one agent, you've got the oldest collaboration problem there is: two workers who must not edit the same files in the same directory. Not a new problem, and it already has an answer — worktrees. Each agent gets its own working directory and its own branch, they work simultaneously, each opens its own PR, you review and merge them independently. Worktrees earned their own module precisely so this case would already be solved by the time you got here.
[insert a screenshot referencing two agents running in parallel worktrees, each with its own branch and PR, here]
The merge stays human — for now. An agent can do every step up to merge. The merge — the commitment to shared main — is where you stay in the loop, because review is judgment and judgment is the thing you haven't delegated yet. Later in the course we carefully, conditionally move that line. Today, the win is just being able to picture an agent doing the first five steps while you do the sixth, and not finding that the least bit exotic.
So here's the reframe to carry out of this post: collaboration tooling was never really about humans. It's about coordinating contributors — isolating their work, making it reviewable, controlling who commits it to the trunk. Those are exactly the guarantees you need to safely let an agent contribute. The team layer you just learned doubles as the agent-safety layer you'll lean on for the rest of the course. You're not learning collaboration and then learning to work with agents. They're the same skill.
Where it breaks (because I always tell you this part)
- Auto-close only fires on merge to the default branch. Merge into a non-default branch and the issue stays open — by design. And keep the keyword in the PR description or a commit message; buried in a mid-thread comment it behaves differently across hosts.
- The exact keyword set is host-specific.
Closes/Fixes/Resolvesare the safe, widely-supported trio, but the full list and the cross-repo syntax (owner/repo#42) vary. When in doubt, mention-link and close 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 was the review's job. If review was a rubber stamp, you just auto-closed an issue for broken code. 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. Scope machine accounts to the least they need.
- Forks add friction. Keeping a fork synced with a fast-moving upstream is ongoing work, and PRs from forks are deliberately limited by hosts (they often can't reach the upstream's CI secrets). For repos you own, prefer branches.
- The diagram is the happy path. Real PRs get change requests, need a rebase onto a moved
main, or hit a merge conflict when two contributors touch the same lines — exactly the parallel-agent scenario worktrees mitigate but don't eliminate. The stations are fixed; the number of trips around them isn't.
You're done when the loop feels like one motion
You're there when you can draw the seven stations from memory, state the branch-vs-fork rule in one sentence (push access → branch; no push access → fork), and — the real milestone — when "give the agent a branch and review its PR" feels obvious rather than novel. When the six tools collapse into one motion in your head, you've got it.
That's also the moment a quiet worry shows up: if an agent can run five of the six steps, what happens when a bad PR makes it all the way through review and lands on main? That's exactly where the next post goes — turning the recovery half of this safety net into its own discipline: cleanly reverting a merged change after the fact, without a panic.
Running the loop with an agent for the first time? Tell me where it got weird — the CLI hand-off, the parallel-worktrees thing, wherever it snagged. Drop it in the comments. I read them, and the rough edges you hit are what make the course better.