Standpat™
Leave your coding agent running. Come back to what you settled, unchanged.
Standpat writes down everything your coding agent does and says as it happens, and holds the decisions that matter until you rule on them. Each one carries its cost.
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. Or it deleted a folder, added a dependency or pushed. You found out later, if at all.
With Standpat, those decisions are caught before the agent acts and wait for you, with the change itself. Everything else is written down as it happens, so you can go back and read it.
For leads and consultants
When you answer for what the agent did.
If a client or a meeting holds you to what was agreed, the record shows every decision the agent made: its type, who reviewed it and what it cost. 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.
The record stays in a private folder on your machine. It is a personal record, not a client document.
How it works
Record it, type it, hold it, count it, review it.
The reply shown in step 3 is Standpat's own, copied from a rehearsal. Your times and versions will differ.
-
Everything is recorded as it happens
Each prompt, each action with its content, each answer and each reply's token usage is written down the moment Standpat sees it. Code does the writing, not a model, so it costs no tokens. The record sits in a private folder on your machine.
-
Every decision has a type and a review state
Routine decisions, which are most of them, are approved automatically by rule. You do not turn that on. Six kinds are key decisions: a delete, a new dependency, a schema change, a settings change, anything that publishes (a push, a deploy, a send), and anything outside the goal.
-
Key decisions are caught before the agent acts
The agent is told to raise a key decision as a card and stop. When its answer holds a card, Standpat records it as waiting and holds work on it. If the agent acts on a key decision it never raised, the hook holds the first action and asks for the same card. The first two layers depend on the agent cooperating. The third does not. You approve, redirect or reject.
The brake on named lines is one part of this. You list the lines the agent may not change, by path or by phrase. A change to one of them is held with the change itself until you type one word.
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.
-
Every decision carries its cost
The budget is three connected limits: the five-hour window, the week and total spend. Each shows what is used and what is left. Spending beyond any of them is flagged, always, whatever the decision's review state. Nothing is hidden because it was approved automatically.
-
Review anything, and go back into any job
One word reviews the last work, the last so many decisions, or any past job, including work already reviewed. You can go back into a job and read its decisions and verdicts. The reviewer is a second model from the provider you already use. Tokens are spent only on judgement, when you ask for a review or when the agent writes a card. Nothing re-reads a session.
Also part of it
Slices, the reserve, the letter, and later a desktop app.
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 desktop app
Later, the typed words become clicks. One app shows every project, what runs under it, what it spent and what waits for your ruling, with a picture of the whole estate.
Other agent apps
Later, the record and then the brake reach other agent apps, not only the one Standpat runs in today. Which apps is not yet settled.
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 keeps, and what it changes.
The record is yours. It sits in a private folder on your machine. It is never in git, never in a release and never on a website. The README says in one line what is stored and where. Standpat itself sends nothing anywhere. A review sends only the decisions in scope and their changes to the provider you already use, never the whole record.
Install changes three things, and only these:
~/.claude/settings.json, the agent app's settings file: one block of entries is added after yours.- 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.1, a preview.
0.15.1 is the brake alone. The rest is being built.
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.
- What the always-on guard cannot see. A delete, a move or a second agent session that the command's own text does not show is not caught: a folder named only by a variable (
rm -rf $D), or a script in another language that deletes a folder or starts a session (python3 -c ...).