Skip to content
System nominalUTC --:--:--Articles 085
MODULE 02 Lesson 06 / 18 30 MIN

A development environment an agent can drive

Commit Discipline When the Agent Writes the Code

When something else writes the code, small reviewed commits are the safety net. Baselines, diff review, commit messages that record what was verified.

An agent asked to fix one function will often return a diff that touches twelve files. It renamed a variable for consistency, reformatted an array, moved a function to the bottom of the file, updated three docblocks, and changed the thing you asked for somewhere in the middle. Nothing in that list is malicious and most of it is defensible on its own. The problem is that the change you actually asked for is now eleven files deep in a diff you are not going to read carefully, and your review will consist of scrolling and hoping.

Version control is the only tool in this course that gets more valuable as the agent gets more capable. The better it is, the more it writes, and the more you need to be able to throw away exactly one of its decisions without losing the other nine.

Commit the known-good state before you hand over the keyboard

The first thing to do before an agent touches a repository is to make sure the current state is committed and that you can get back to it. That sounds obvious and it gets skipped, usually because the repository already has uncommitted work in it.

Two commands make the baseline explicit. A clean status is the precondition; a tag names the point you are returning to.

git status --short          # anything uncommitted is work you are about to risk
git tag agent-baseline       # a name you can return to by name
git log --oneline -3         # confirm what the baseline contains

On a WordPress site there is a fourth step that matters more than the rest: know what is gitignored before the agent starts. An editor's debug log, a plugin's build directory, uploaded media, and vendor dependencies are all things you want out of the diff — and, in the case of the debug log, things that can contain credentials and absolute paths from the machine. Decide that with a .gitignore rather than with review attention later.

One concern per commit, and the agent must not commit for you

The rule that makes everything else work is small commits with one concern each. It is also the rule agents break most often, because combining changes is free for them. The practical instruction is to make the agent stop before committing: you want to review a diff, and you want to choose the boundary.

There is a second reason, and it is the one that converts a nice habit into a safety mechanism. WordPress's AI contribution guidelines name "large, unreviewed code dumps with minimal explanation or tests" as a failure mode and state that maintainers may reject contributions that look like AI slop. A repository whose history is one commit per task with a message naming the verification is a repository where that objection has an answer. A repository with a single Update files commit at the end of an afternoon is one where it does not.

If the agent does commit, the countermeasure is the same one you would use with a junior developer: git show --stat to see the shape, then commit by commit. What you are looking for in the stat is not the number of lines but the number of files, because a change that touches eleven files to fix one function is usually a rewrite.

Read the diff, not the summary

The summary an agent prints is generated from the same model that wrote the code. It is a description of intent, and it is written to be reassuring. The diff is the record of what happened.

A workflow that works on real WordPress code, in order:

git status --short                 # what did it touch, including files you forgot
git diff --stat                    # shape and scale before reading any code
git diff -- includes/class-acme-notice.php
git diff -- '*.php'                # review one file type at a time
git add includes/class-acme-notice.php
git commit -m "Fix the notice render callback dropping the message attribute" -m "Verified: wp acme-notice list returns the test row; front-end render via curl contains the escaped message."

Note the last line. The commit body records the command that proved the change, which is the part of the message that earns its length. Six months later, that line tells a reader what "working" meant on the day, and the AI guidelines' transparency expectation is satisfied in the place where it is actually useful rather than in a pull request description nobody reopens.

Reviewing by file type is worth the habit on WordPress work specifically. A single change often spans PHP, JavaScript and CSS, and reading them separately keeps you from skimming the PHP because the JavaScript scroll was long. In the recorded agent run for this course, the generated plugin produced fourteen files across PHP, JavaScript, SCSS, JSON and Markdown, and its correctness in each was a separate question.

The git operations that are hard to undo

Agents run git, and most of what they run is safe. Four operations are not, because they destroy something rather than add to it.

OperationWhat it destroysWhat to require instead
git add -A or git add . Nothing directly — but it stages the debug log, the local config and the build output in the same commit as real code git add with explicit paths, or review git status --short first
git commit --amend The previous commit's content, if a push already happened A new commit; amend only before the first push
git reset --hard Uncommitted work, without a prompt git restore <file> for a file, git stash when unsure
git push --force Other people's commits on a shared branch Never on a shared branch; --force-with-lease at minimum on your own

The realistic danger is not a rogue agent; it is a plausible one. Asked to fix a broken test, an agent may decide the fastest route is to reset to the last commit and try again. That is a reasonable engineering instinct and it deletes your uncommitted work in the same second. Naming the operations in the rules file costs one paragraph and removes the whole class of accident.

Recovering one file without losing the rest

The reason to keep commits small is that recovery becomes surgical. When a change is one commit, reverting it is one command and it cannot affect anything else. When a change is mixed into a larger commit, recovery becomes a manual exercise in re-editing, which is where people give up and accept broken code.

Lab 30 minutes

Set up a repository that an agent cannot damage, then practise the recovery once so it is not new when you need it.

  1. Take a plugin or theme repository with work in it. Commit everything, then tag agent-baseline.
  2. Write or extend .gitignore for the WordPress realities in your setup: debug logs, build output, dependency directories, uploaded media, and any local config that carries credentials. Check with git status --ignored --short that the files you expect are actually ignored.
  3. Add a short git section to AGENTS.md: never amend or reset, stage explicit paths, do not commit without being asked, and quote the verification command in the commit body.
  4. Ask the agent to make a small change. Then, before accepting it, note the exact file list from git status --short and compare it with what you asked for.
  5. Discard the part you did not want and keep the rest. If the agent has already made several commits, revert the one bad commit and show the log afterwards.
Show the commands, the reasoning, and the trade-offs

Step 5 has more than one correct answer, and picking between them is the skill. When the bad change is uncommitted, discard it per file rather than wholesale:

git status --short
#  M includes/class-acme-notice.php
#  M src/notice/edit.js          <- not asked for
git restore src/notice/edit.js
git diff --stat

git restore on a named path is the operation to reach for because it cannot touch anything you did not name. git checkout -- . and git reset --hard both do the same job on everything, which is exactly the problem when the agent has also made a change you wanted.

When the change is already committed, revert it rather than rewriting history:

git log --oneline -5
#  a1b2c3d Reformat every array in the plugin file
#  9f8e7d6 Add the dismiss button to the notice block
git revert a1b2c3d --no-edit
git log --oneline -3

git revert adds a new commit that undoes the named one, so the history records both the mistake and the correction. That is the right trade-off on any branch other people have, and it is usually the right one even on your own branch, because "we tried a whole-file reformat and it made every diff unreadable" is information worth keeping. The alternative, an interactive rebase that deletes the commit, produces a tidier log and a worse record, and it is the operation most likely to lose work when an agent is involved.

Step 4 has an answer people find uncomfortable the first time. When you compare the file list against what you asked for, it usually differs. That is not a bug to fix in the agent; it is the normal behaviour of a system that explores to build context, and it is why the review step is not optional. The habit to build is reading git diff --stat before reading any code, because the shape of a change tells you what kind of review it needs. One file with twelve changed lines is a careful read. Eleven files with four hundred changed lines is a decision about whether to keep the work at all.

One trade-off worth stating honestly. Small commits cost you time on every task, and the cost is real. The return is that a bad change is recoverable in one command instead of an afternoon, and that a reviewer six months from now can see which change was verified and how. On a solo project with no deploys, a heavier commit granularity is a defensible choice. On anything that reaches a customer, the cost of the small commits is smaller than the cost of the one time you cannot tell which of the agent's twelve files broke the site.

Progress

Mark this lesson done and it stays marked in this browser.