Standpat™
Leave your coding agent running. Come back to what you settled, unchanged.
Standpat is a brake for coding agents: you name what must not change, and the agent cannot change it until you say so.
The result can keep moving. The plan cannot. Stand pat.
› Change app.py so it prints hello, world. Standpat: hold 1, held for a stamp: Edit on app.py. Lines it crosses: The app. - print("hello") + print("hello, world") Cost: 1 handbrake move. Handbrake moves today so far: 0 of 3. Type `stamp` to allow exactly this, once, or `park` to stop.
stamp.Who it is for
For developers who run coding agents and want to step away.
You can walk away
Safe to leave. Type park before you go, and anything held is not run. When you are back, your next message goes through and the agent shows you the return card first: the goal, what it may not change, and what was done and refused while you were parked.
You decide what may change
A yes you still meant. You list what must not change in a handbrake file, by path or by phrase, and type brake in the chat. When the agent tries to change one of those lines, the action is held and shown to you with the change itself. One stamp lets exactly that action through, once.
You keep a record
Decisions, not hours. Every word you type to Standpat goes into a log chained line to line, so a cut or a rewrite shows. The ledger counts the decisions in a sitting, and the letter reads the log back for any period you name.
The moment it is for
You stopped watching. The agent did not stop working.
Think of the last time a coding agent changed something you had already settled. A fee, a schema, a sentence the client signed off, a point the meeting had closed. You found out later, if at all.
With the brake on, that change waits for you, with its diff, and runs only if you type stamp.
For leads and consultants
When you answer for what the agent changed.
If a client or a meeting holds you to what was agreed, the letter shows what was held, what was stamped and what was refused over the period you name, and every gap in the gate it found.
It is a personal record, not a client document.
How it works
Name it, brake, hold, stamp, park.
Every reply below is Standpat's own, copied from a rehearsal. Lines marked › are what you type in the chat. Your times and versions will differ.
-
Name what must not change
Each repository gets a handbrake file,
.standpat/handbrake. You list the lines the agent may not change: a path, or a phrase.{ "standpat_format": 1, "project": "Play", "must_not_change": [ {"id": "app", "label": "The app", "matcher": "path", "pattern": "app.py", "class": "other"} ], "done": "", "who_may_widen": ["owner"] } -
braketurns it on in a chatEvery chat starts free and holds nothing. Type
brake, name a goal, accept the handbrake's version. None of these words reaches the agent.› brake Standpat: the handbrake is on in this chat from the agent's next action; type `free` to turn it off. Type `goal <name>` to say what this chat is for, then `handbrake accept <version>` to accept what must not change, then your message for the agent. Nothing was sent to the agent. › goal demo Standpat: goal demo is open. Type `handbrake accept <version>` to accept the handbrake, then your message for the agent. Nothing was sent to the agent. › handbrake accept <version> Standpat: handbrake version <version> accepted. Type your message for the agent. Nothing was sent to the agent.
-
The change is held, with its diff
Ask the agent to change
app.py. Its edit is not run. The agent's output shows what it tried, the line it crosses and the change itself.Standpat: hold 1, held for a stamp: Edit on app.py. Lines it crosses: The app. - print("hello") + print("hello, world") Cost: 1 handbrake move. Handbrake moves today so far: 0 of 3. Type `stamp` to allow exactly this, once, or `park` to stop.
-
stamplets exactly that through, onceOne stamp allows that one action, for 30 minutes. Send the agent any message and it runs it. Nothing else gets through on it.
› stamp Standpat: stamped Edit on app.py, held at <time>, crossing The app. The action is allowed for 30 minutes. Send the agent any message and it will run it. -
parkwhen you walk awayAnything held is not run.
› park Standpat: parked; anything held for a stamp was not run, and this sitting used 1 handbrake move. When you are back, send your next message as usual and the card comes with it. Nothing was sent to the agent.When you come back, your next message goes through and the agent is told to show you the return card first. It runs from
Goal: demothroughAgent may not: The appand the budget toDone while parked: nothingandRefused while parked: nothing.
Also in 0.15.0
Slices, the reserve, the ledger, the letter.
Slices and review stops
Split a goal into slices, each with what done means. When the agent says a slice is done, it stops for your review, and any further change it tries is not run. accept closes the slice; redirect <what instead> sends the agent another way, and those words reach it.
› slices
Standpat review: slice 1 of 2, docs.
Why: the agent says the slice is done
Done when: notes.md says what app.py prints
Changed: notes.md
Shell commands run: 0
Stamped: nothing
Refused: nothing
Type `accept` to close the slice, or `redirect <what instead>` to send the agent another way.
The reserve
reserve 25 keeps 25% of the five-hour window for you; background jobs may use the rest. A job runner can ask before it starts. The usage reading comes only on a Pro or Max account, after the chat's first reply.
The decision ledger and load bar
Each word you type is weighed and counted in the sitting; the status line shows the load. It counts decisions, not you, and refuses nothing. garage lists them.
The letter
The letter checks both logs first, asks git what changed over the period, and lists every gap in the gate it finds.
python3 ~/standpat/standpat/standpat.py letter ~/standpat-play
A line whose changes were all stamped reads changed by stamped writes (see Stamped); any other change reads changed between the two dates.
On your machine
What it changes, and how it comes out.
Install changes three things, and only these:
~/.claude/settings.json, the agent app's settings file: one block of entries is added after yours (eight hook entries and a status line).- A hook file and a copy of the command line, in
/Library/Application Support/Standpat/<version>/, a folder owned by root, so the agent, which runs as you, cannot change the gate it has to pass. - A folder
~/.standpat, with Standpat's state and your user log.
Before it writes, install proves that taking its own lines back out of the new settings file gives your file back byte for byte. The one byte it adds to your part is a comma after the item its block follows. uninstall takes the entries out again under the same proof, and prints settings: restored byte for byte. You can check it yourself:
cp ~/.claude/settings.json ~/settings.before-standpat.json
# install, use it, then:
python3 ~/standpat/standpat/standpat.py uninstall
cmp ~/settings.before-standpat.json ~/.claude/settings.json
cmp prints nothing if you changed nothing else in the file. Your logs and the hook copy stay until you remove them; the install page says how.
Download
Standpat 0.15.0, a preview.
For a Mac with git and Python 3.9 or later. Install takes 5 minutes, and a walk through every step above takes 20.
Known limits
What it does not do yet.
- Linux is untried. No one has run Standpat on Linux yet.
- The always-on guard has blind spots. In a free chat, deleting by name a folder that holds Standpat's state is not refused. A second agent session started by a script in another language, or by a command built at run time, is not caught.
- Merge reviews. Some ways of calling
git merge(throughenv,command, its full path orsh -c) are not recognised as merges and run with no review stop. The handbrake's lines still hold. - The garage during a park prints the park twice on its Goal line.