Topic 01

Commit Before You Ask

Git

Before each request to the agent, commit. Whatever comes back is then a diff against a point you know is good, and throwing it away is one command. Without that commit, the agent's changes and yours share one working tree, and separating them takes longer than the task did.

Every habit in this book assumes that an agent's change can be discarded in seconds: rejecting a diff, restarting with a sharper task, narrowing to the two hunks that were right. This chapter is what makes that assumption true, and this page is its foundation. Git is assumed at the level of Git for Beginners; what is new is the rhythm.

A Known-Good Point

The commit made just before the request is the base the diff is read against, the way Chapter 6 read the refund diff, and the place a discard returns to. Chapter 3 set one up when the session starts. This page repeats it before every request, because after the third request the session's start is three diffs back, and a diff against it mixes three answers into one.

The rhythm of a session: every request starts from a commit
Commita known-good point
→
Askone request
→
Readthe diff since the commit
→
Keep or discardthen commit again

What Gets Mixed Without It

You fix a typo while the agent edits. It creates a file. You try an idea of your own in the same module. The working tree now holds several authors' changes, and the diff shows them as one. Narrowing the agent's answer turns into archaeology, and "discard the agent's attempt" also discards your idea, because nothing in the tree says which lines were whose.

With a commit before each request, the authorship is in the history. Your typo fix is in the commit before the request; the agent's answer is the diff after it. Discarding one never touches the other.

It happened to you on the refund change, before the habit stuck. While the agent worked on the deadline, you fixed the "24 hours" in the cancellation email by hand. When the diff came back wrong and you discarded it, the email fix went with it, because both sat uncommitted in the same tree. Ten minutes later you found the email saying 24 hours again and had to remember why.

Working Commits Are Cheap

Commit the failing test before asking for the code, as Chapter 8 did. Commit before each request. Commit after each accepted step. The messages can be terse, "wip: before deadline attempt 2", because a later topic in this chapter rewrites them into history a reviewer can follow before the branch is shared.

The cost is a few seconds per request and a slightly longer list of commits, which nobody but you sees until you shape it. The benefit is that every answer the agent gives can be read on its own, kept on its own or thrown away on its own. No other habit in this book buys as much for as little.

Below is the moment that matters, in the refund change. The commit before asking for step three is the base. After the agent's turn, the status shows what changed, the diff shows how much, and a dry run of the cleanup shows what a discard would remove.

Before the request: the commit to read the answer against
$ git log --oneline -1
2941125 (HEAD -> refund-window-12h) Use one refund window for refunds and the cancellation screen
After the agent's turn, with your own notes file in the tree
$ git status --short
 M src/cragmoor/booking.py
 M src/cragmoor/gyms.py
 M src/cragmoor/refunds.py
 M src/cragmoor/schedule.py
 M tests/test_refunds.py
?? notes.md
?? src/cragmoor/policy.py
$ git diff --stat
 src/cragmoor/booking.py  |  4 +++-
 src/cragmoor/gyms.py     |  3 +++
 src/cragmoor/refunds.py  | 20 ++++++++++----------
 src/cragmoor/schedule.py |  2 +-
 tests/test_refunds.py    | 49 ++++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 64 insertions(+), 14 deletions(-)
$ git clean -n
Would remove notes.md
Would remove src/cragmoor/policy.py
Before the request: the commit to read the answer against
$ git log --oneline -1
53c8d75 (HEAD -> refund-window-12h) Use one refund window for refunds and the cancellation screen
After the agent's turn, with your own notes file in the tree
$ git status --short
 M src/booking.ts
 M src/gyms.ts
 M src/refunds.ts
 M src/schedule.ts
 M tests/refunds.test.ts
?? notes.md
?? src/policy.ts
$ git diff --stat
 src/booking.ts        |  4 +++-
 src/gyms.ts           |  2 ++
 src/refunds.ts        | 21 +++++++++++----------
 src/schedule.ts       |  2 +-
 tests/refunds.test.ts | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 62 insertions(+), 14 deletions(-)
$ git clean -n
Would remove notes.md
Would remove src/policy.ts
Before the request: the commit to read the answer against
$ git log --oneline -1
6ee7a62 (HEAD -> refund-window-12h) Use one refund window for refunds and the cancellation screen
After the agent's turn, with your own notes file in the tree
$ git status --short
 M src/main/java/org/cragmoor/Booking.java
 M src/main/java/org/cragmoor/Gym.java
 M src/main/java/org/cragmoor/Refunds.java
 M src/main/java/org/cragmoor/Schedule.java
 M src/test/java/org/cragmoor/RefundsTest.java
?? notes.md
?? src/main/java/org/cragmoor/Policy.java
$ git diff --stat
 src/main/java/org/cragmoor/Booking.java     |  3 +-
 src/main/java/org/cragmoor/Gym.java         |  7 ++++-
 src/main/java/org/cragmoor/Refunds.java     | 19 ++++++------
 src/main/java/org/cragmoor/Schedule.java    |  2 +-
 src/test/java/org/cragmoor/RefundsTest.java | 48 +++++++++++++++++++++++++++--
 5 files changed, 65 insertions(+), 14 deletions(-)
$ git clean -n
Would remove notes.md
Would remove src/main/java/org/cragmoor/Policy.java

Two details in that output are the rest of this page. The diff's file count leaves out the agent's new policy file, because a new file is untracked until it is added. And the cleanup would remove your notes file along with the agent's work.

What Git Cannot Undo

Git restores tracked files in the working tree. It does not undo a database migration the agent ran, a package installed for the whole machine, a file written outside the repository, a message sent or a push made. Those effects live outside version control, so no commit protects you from them.

That is why approval modes from Chapter 3 keep certain commands asking every time, and why the sandbox limits what the agent can reach at all. The commit makes file changes free to throw away. Everything else has to be prevented, because it cannot be reverted.

New Files and Ignored Files

Files the agent created are untracked, so restoring tracked files leaves them in place. The command that removes untracked files removes every untracked file, including your own notes, scratch scripts and half-written ideas, unless you dry-run it first and narrow it to the paths the agent touched.

Files matched by the ignore list never appear in the status at all: build output, caches, environment files. They are never committed, never restored and never cleaned by default. An agent that writes a secret into an environment file leaves no trace in any diff, which is one reason Chapter 12 treats environment files on their own.

Letting the Agent Commit

Agents can commit their own steps, which gives a sequence of small diffs, each one readable on its own. That is a convenience and it changes nothing about who reviews them: a commit the agent made is a diff you have not read yet. Whether it may commit without asking is an approval-mode choice. Pushing stays off the list, because a push is the moment private history becomes shared.

When the agent does commit, review commit by commit rather than the branch as a whole: each small diff is easier to read than their sum, and a commit message that claims more than its diff does is easy to spot. A run of agent commits is still one answer to one request, and the base for reading it is still the commit you made before you asked.

Misconceptions
  • "The editor's undo covers this." Editor undo is per file and per editing session. The agent changed six files in one action, some of them through commands the editor never saw.
  • "Committing unfinished work pollutes history." Working commits are private until you push, and they are rewritten into clean history before anyone sees them.
  • "A clean start to the session is enough." After several requests the start is several diffs back. The base you need is the moment just before this request.
  • "Git can undo anything the agent did." It restores file contents in the repository. Commands with effects outside it are not under version control.
  • "Stashing is as good as committing." The stash is a single stack shared by every worktree of the repository, and easy to apply onto the wrong state. A commit on a branch has a name and a place.
Why It Matters
  • Commit before every request, not only at the start of the session. The base of each diff should be the moment you asked.
  • Commit the test you wrote before asking for the code. Your work and the agent's then sit in separate commits.
  • Dry-run every cleanup of untracked files. It deletes your notes as readily as the agent's scratch files.
  • Keep every command with effects outside the repository behind an approval prompt. Git cannot take those back.

Knowledge Check

You committed just before asking for step three of the refund change. What does that commit buy you when you decide to discard the agent's answer?

  • It stops the agent from editing any of the files you committed
  • A discard returns to it and removes exactly the agent's answer
  • It backs the whole repository up to the team's shared remote
  • It lets git reverse any command the agent ran during its turn

Which of these agent actions can a git discard not take back?

  • An edit to the refund module that is tracked in the repository
  • A new file it created inside the repository's source directory
  • A migration it ran against the shared development database
  • A commit it made on your private branch that was never pushed

After restoring tracked files, the agent's new policy file is still in the tree. Why?

  • The file matches the ignore list, so git does not see it at all
  • Restoring only covers the first file it finds, then it stops there
  • The agent marked the file as protected when it created it earlier
  • It is untracked, and restoring tracked files leaves untracked ones

You committed at the start of the session and have since made three requests without committing. Why is that start commit the wrong base for reviewing the third answer?

  • Its diff mixes three answers, so the third cannot be read alone
  • Commits older than an hour can no longer be used as a diff base
  • Git labels each answer separately, so the base does not matter
  • The start commit has been replaced by the agent's later changes

You got correct