bounding-autonomous-work
UpdatedUse when a stretch of work will finish before any human reads a word of it — a delegated task, a goal handed over instead of a plan, a subagent dispatched without a way to ask, a hook or cron or loop with no reader, or a question just asked into a silence that the run is about to answer for itself. Also use when a run is about to defer something to a human because it believes it cannot verify it, or when a stop condition has just fired on a run that does not otherwise look like it was in trouble. Also use when a verification is blocked by the system under test refusing, and clearing local state or loosening the check would unblock it. Covers substituting each approval gate rather than skipping it, the human-only prompt a detached job waits behind forever, telling a real door from an untried one, telling a read-only probe from an execution, the four pre-committed stop conditions, the actions no confidence level licenses without a human, and reporting to someone who was not there.
Overview
An agent working with someone present is bounded by that person. Every few turns they see what happened and can say stop, and that single mechanism is quietly enforcing a dozen obligations nobody has written down. Remove the person and those obligations do not get looser — they get unwritten. The run keeps all of them and loses the only thing that was checking any of them.
What replaces that is not more care. Care is what the run already has, and care is exactly what fails here: a careful agent alone in a room will answer its own question, believe the answer, and build six hours of competent work on top of it. The replacement is bounds, written down before the work starts, in a form that fires without anyone reading them.
The failure this exists to prevent is not a runaway agent doing something alarming. It is the ordinary one — a long unsupervised run that did good work in the wrong direction, because the question that would have caught it in minute three was asked into an empty room and then quietly settled by the only party present.
When to use
- Work will finish before anyone reads a word of it.
- A goal was handed over rather than a plan: "get X working", "clean this up", "keep going until the suite passes".
- A subagent is about to be dispatched with a task it cannot ask questions about.
- A hook, a cron, a loop, or a CI step will run this with no reader.
- A job is about to be detached, backgrounded, or left running overnight.
- A question was just asked, nothing answered it, and the run is about to continue anyway. That moment is the trigger, not a reason to skip this.
- Not for: how much deliberation one decision deserves —
deciding-reversibility. - Not for: when a polish loop has stopped paying —
knowing-when-to-stopcovers diminishing returns. Stop conditions here fire whether or not returns are good. - Not for: work that merely takes a long time with someone watching. That is
checkpointing-long-runs. - Not for: deciding what a goal-driven run measures itself against, meaning the check that says whether each iteration got closer —
designing-verifiable-goals. A run handed a goal needs both. Bounds with no check stop it without saying whether it got closer, and a check with no bounds keeps it spending for as long as the bar stays out of reach.
Three bounds, all written before the first action
- The decision bound — what you may settle alone.
- The stop bound — what makes you halt and report rather than continue.
- The door bound — what no confidence level licenses without a human.
Written before is not a stylistic preference. Each of these has to be decided by a version of you that does not yet want the run to succeed. Written at the moment they would fire, all three are negotiable, and all three get negotiated.
1. The decision bound: substitute the gate, never skip it
An absent answerer does not delete a gate. It changes what closes it.
| Gate | With someone there | Alone |
|---|---|---|
| Approval of a design | An explicit yes | The design written down, the approach that lost named with its reason, a reversibility bound, and a stop condition that fires if it turns out wrong |
A reframe from a clairvoyance sweep, orbit, or imagine pass | Asked as one question | Never self-approved. The observation, the reading that lost, and a stop condition go into the record; the run continues on the original frame |
| A clarifying question | Ask, one at a time | Answer it from the code if the code answers it. Otherwise pick, and record it as a ruling naming the other reading — never as a fact |
| "Is this what you meant?" | Ask | Re-derive each acceptance line from the request's literal words, quoted, and check the built thing against the quote rather than against your memory of it |
| A second pair of eyes | A human, or a reviewer subagent | red-teaming-your-own-work then karen-and-the-manager, run as hard gates rather than as a courtesy, ideally by a reader with no memory of building it |
| Permission for something costly | Ask, wait | Not substitutable. See the door bound |
A handed-off design document is its own instance of this: its account of what has been approved is the frame the next reader inherits, and a document that states only what happened — never what hasn't, never that it has not been reviewed as a whole — reads as fully cleared to whoever opens it with nobody to ask. scoping-before-building's spec-writing step asks the document to say its own status; treat a handoff doc silent on that as unreviewed, not as approved.
A decision made alone is legitimate when four things are true of it: it is written where the absent reader will find it, it is named as a decision rather than presented as a fact, it carries the reading that lost, and it is cheap to reverse — or it was escalated precisely because it was not.
The tell for an illegitimate one is its grammar in the final report. A legitimate decision reads "set the retry cap to 5 — the spec was silent, 3 and 10 were both defensible, one line to change." An illegitimate one reads "the retry cap is 5." The second sentence has laundered a choice into a fact, and the reader now has no idea a decision was ever made.
A gate the run did not install still needs an answerer
The table above covers the gates a run knows about — the questions it would have asked. A detached run also walks into gates it never put there: an operating system's consent dialog, a permission prompt, a second factor, a session that expired and wants a password, a "press any key". With someone present each of these is a two-second interruption. Alone, it is a wait with no end, and it lands at exactly the moment nobody is watching: the run starts cleanly, its first step raises the prompt, and the job sits behind it until someone comes back — draining whatever it was keeping awake in the meantime, a battery, a session, a quota — with nothing failed, nothing logged, and a result that reads as "0 of N". None of the stop conditions below fires, because a process that is not executing checks nothing, and a wall-clock budget is only a number until something reads the clock.
So before detaching anything, enumerate the steps on its path that only a person can answer. For each one, either run it attended first — detach after the last human-only gate, not before the first — or bound the wait with a timeout that turns it into a failure the report can carry. A job that cannot be started while its human is present is a job that needs the timeout, not one that can be detached anyway.
The tell, whenever the log is read: entries that stop after the first minute. A detached job that is running writes; one that is waiting does not, and the two are indistinguishable from "still going" until you look for the line that never came.
2. The stop bound: four conditions, pre-committed
Write these into the run record before the work. Each names something observable — a count, a path, a named system, a diff against the ledger — because a stop condition that names a feeling never fires.
| Condition | Fires when | What it catches |
|---|---|---|
| Budget | The same gate has failed a stated number of times — three attempts at one green test, two rewrites of one function, one hour on one task | The loop that is converging on nothing while every individual attempt looks reasonable |
| Surprise | The work reaches a file, subsystem, service, or concept that the frame never named | The scope that grew sideways rather than forward, which is invisible from inside because each step was small |
| Door | The next action would be irreversible, external, or expensive to undo | The careful six-hour run that is reckless in its final command |
| Drift | The acceptance ledger would have to be edited to accept what was built | Success redefined into reach, which is the single most comfortable failure available to an unsupervised run |
Draw the budget around the failure it is meant to catch. An attempt-counting budget assumes each attempt is an independent try at the same problem, so N of them means the approach is converging on nothing. Plenty of tools do not fail that way. A compiler, a type checker, a linter, or a schema validator enumerates the remaining work incrementally: each failure names a different site, exactly, and the fix is one edit with no re-diagnosis between them. There the count measures the size of the change rather than the futility of the approach, and a budget of three fires a third of the way through a mechanical edit that was never in trouble.
Two consequences, both at the time the budget is written. Run whatever command enumerates all the work before starting to count, because build tooling routinely surfaces sites in waves and the wave that only appears once the test targets compile is still the same edit. And check what honouring the budget would leave behind: the stop bound requires a recoverable tree, so a budget that can only be obeyed by halting on a half-applied change that does not compile is mis-drawn rather than inconvenient. The thing to fix is the budget — count wall-clock, distinct root causes, or attempts that produced no new information, rather than raw failures.
Two rules make the four conditions real.
A stop condition halts and reports; it does not ask. There is nobody to ask. The run stops with the work in a recoverable state, the record current, and a report that names what fired, what was done, and what the next actor would need. Stopping cleanly is a successful outcome of an autonomous run — the mode it exists to make available.
A fired condition is never reasoned past. "Budget says stop, but I can see the fix" is the sentence this whole skill is written against, and it is almost always true and almost never worth acting on. If a condition fires and turns out to have been badly drawn, that is a finding for the report, not a licence to continue under a condition you have just rewritten to permit you.
3. The door bound
These are not substitutable, not by care, not by confidence, and not by how obviously correct the action is. An autonomous run may prepare each of them in full — write the command, stage the change, draft the message — and may not take the step.
- Anything irreversible against real data or real systems: a destructive migration, a delete, a truncate, a force-push, a rewrite of published history.
- Anything that leaves the machine and reaches a person: a sent message, a published artifact, a posted comment, a release.
- Anything spending money or a quota that someone else pays for.
- Anything touching credentials: rotating, revoking, granting, or moving one — or using one the run found rather than was given. A token lying in some file reaches whatever its owner could, which is not what the task scoped.
- Anything that would expand what the run itself, or anything it dispatches, can do next: installing a plugin, tool, or server, or requesting a new capability grant. This holds even when the request surfaces its own user-facing approval prompt — a subagent able to trigger its parent's capability-grant dialog puts a human's yes on something they have no way to see originated one level down in the delegation chain.
- Anything the frame did not name and cannot be undone — the combination is what matters; either alone is survivable.
- Anything the requester specifically said to ask about, however trivial it turns out to be.
- Anything that removes, weakens, or resets a control in order to let the run continue past it — see immediately below, because this one does not look like the others.
An autonomous run that hits a door is not blocked. It has reached its correct end: the preparation is done, the action is written down, and a human takes one step instead of the whole run.
The system refusing you may be the system working
The other doors are recognisable because the action is obviously consequential. This one is the opposite: the action is small, local, reversible, and its whole appeal is that it unblocks a run that has stalled. A verification cannot proceed because the thing under test refuses — a sticky lockout, a rate limit, a permission denial, a signature check, a guard that has latched. Clearing one piece of local state, loosening one assertion, or passing one bypass flag makes the refusal go away and the run continue.
A refusal encountered while verifying is a result, not an obstacle. The guard latched because something reached it; that is the behavior under test producing output. Removing it does not restore access to the evidence — it destroys the evidence and replaces it with a run that no longer measures anything. The autonomous run then reports success, in good faith, about a system it disabled part of.
Three arguments turn up here and none of them are licences. It is only a test environment — the guard does not know that, which is the point of it; a control that can be dissolved by asserting the stakes are low is not a control. I can put it back afterwards — true, and irrelevant, because the measurement taken in between is the thing being spent. The refusal is clearly a misconfiguration — possibly, and that is a finding to report rather than a permission to proceed, since a misconfiguration indistinguishable from the feature working is exactly what a human needs to be told about.
The section below pulls the other way and they do not conflict, because they are about different objects. That one is about an action you have assumed is forbidden without attempting it — try it; a refusal you have not collected is not evidence. This one is about a control that has already refused — you have collected the evidence, and the only route past it is to break the thing that produced it. Untried is not a door. Broken open is not a pass.
The commonest form of this does not look like breaking anything. A command fails on a credential mismatch — wrong account, missing scope, expired token — and the run goes looking for one that works: another environment file, a config in a neighbouring project, a token in shell history. A mismatch is a refusal, and a substitute credential is the bypass; deciding-reversibility has the 2026 run that took one and deleted a production volume along with its backups.
What the run does instead is what it does at any door: prepare fully, and stop. Name the guard, what triggered it, what would clear it, and what remains unverified because it did not. Where a sanctioned route exists — a dedicated test surface, a fixture, an account provisioned for this — take that one; it is not a workaround but the supported path, and the difference is whether the system offered it or you took it.
A door you have not tried is not a door
Everything on that list is an action. The common failure is not taking one of them by accident; it is stopping in front of something that only resembles one. A run concludes that a change cannot be verified without the person who owns the system — the credential is not here, the service is unreachable, the real values cannot be obtained from this machine — and defers. That feels like exactly the humility this skill asks for, and it is a different thing.
A door is an action whose consequences a human has to own. Being unable to check something is a claim about your own capabilities, and it stays a claim rather than an observation until an attempt has actually failed. The two are easy to confuse: the sentence has the same shape, the paragraph above has just finished saying that stopping is a correct ending, and deferring costs nothing at the moment it is written. It is not free afterwards. An unattended run exists to spend its own time instead of the requester's, and an unnecessary deferral inverts that — it hands back the one thing the run was supposed to absorb, and it arrives looking like diligence.
So before writing one down: name the cheapest experiment that would settle it, and run that experiment. A throwaway probe program, one request against the real thing, a single value put through the real encoder. The tell for a deferral that has not earned itself is that its justification names a capability nothing in this session has ever tried — and a capability you have not exercised is a guess about yourself, held to a lower standard than any other claim in the report.
This applies while you are still deciding whether something is a door, never after a stop condition has fired. A tripped condition is not a deferral awaiting a probe — section 2 governs it unchanged, and it is not reasoned past.
An experiment that answers immediately earns one more look than one that struggles. A probe reading a default, a cache, or a stub returns a confident value in the right shape, and reproducing-bugs covers proving the instrument before trusting what it says. Withdrawing a deferral on a bad probe is worse than the deferral was.
A probe that succeeds does not move the door it was testing. Establishing that you could rotate the credential or reach the live service is not permission to do either, and the confidence a working probe produces is exactly what makes taking the step next feel like a formality. The experiment settles what you can know. What you may do is unchanged by how well it went.
The experiment is bound by the same list as everything else. One that would itself take an irreversible action, spend someone's money, or reach a person is not a cheap experiment — it is the door, and the deferral was right the first time. What this asks for is the read-only half: the probe that observes, the request that only fetches, the encode that throws its output away.
Which puts the weight on being right about which half a probe is on, and that is a judgment about somebody else's software rather than about your own intent. Running an unknown binary with --version is the standard way to get it wrong: the command reads as a question, and against a program that does not parse the flag it is simply a start — one run of the real application, against whatever real profile, real credentials and real state it finds on the machine, for as long as it takes to notice and kill it. The probe was read-only in the mind of whoever typed it and nowhere else.
The rule that holds is that an invocation is an execution until the thing invoked is known to treat it otherwise, and a binary being probed precisely because you cannot see inside it does not meet that bar. Where the experiment has to run something unfamiliar, isolate it the way anything else gets isolated — a copy, a container, an account with nothing in it — or find a question the filesystem can answer instead. Provenance rarely needs an execution at all: a hash, an mtime comparison against every source file, and a file-type report settle it without starting anything.
None of which reopens the deferral this section closed. "I cannot tell whether that probe is read-only" is a question about a specific command with a cheaper command behind it, not a door — the answer is a different experiment, run in isolation, rather than a line in the report saying the check needs a human.
And when the probe turns out to have been an execution and nothing bad comes of it, the record still says that in those terms. "It turned out fine" is not "the bound held", and a run record logging the second where only the first is true has deleted the one line a reader would have audited.
If the experiment is genuinely out of reach, the deferral stands, and it is now worth reading: it can say what was attempted and how it failed, which is the difference between a handover and a shrug.
Reporting to someone who was not there
The report is the entire deliverable, because the conversation that would normally carry the rest of it did not happen. It carries four things that a supervised run's summary can leave implicit:
- Every ruling, in decision grammar, not fact grammar.
- Every assumption that the code could not settle, with the reading that lost.
- What stopped and why — including conditions that fired and were correct.
- What was surrendered, named as surrendered rather than dropped.
Set the altitude by what the reader will do next, per explaining-technical-work, and mark each claim verified, inferred, or assumed, per calibrating-confidence. An unsupervised run's report is read by someone reconstructing hours they did not watch; a confident summary that turns out to be inferred costs them the whole reconstruction.
Common mistakes
| Symptom | Real cause |
|---|---|
| Six hours of good work in the wrong direction | A question was asked into a silence and answered by the asker, unrecorded |
| The report reads as a description of a finished system | Rulings written in fact grammar; every choice laundered into a property |
| A stop condition that never fired all run | It named a feeling ("if things go wrong") rather than an observable |
| The run halted and left a broken tree | Stopping was treated as failure rather than as a designed outcome, so nobody planned the state it stops in |
| The acceptance criteria were met and the requester was unhappy | Drift fired silently: the ledger was edited to match the build rather than the build to match the ledger |
| The final command did the damage | The door bound was checked once at the start, when nothing was irreversible yet |
| An open question in the report that one command would have answered | A verification was filed under the door bound because checking it resembled doing it |
| The subagent came back confident and wrong | It was dispatched with a goal and no bounds, which is this skill's trigger, not an exception to it |
| An overnight job reports 0 of N with nothing in its log after the first minute | It was waiting behind a prompt only a person could answer, and nothing bounded the wait |
| A human approved an install prompt that looked routine | A subagent triggered its parent's capability-grant dialog; the approver had no way to see it originated one level down |
Red flags
- "I'll ask about that at the end." There is no end with a reader in it.
- "This cannot be verified from here" — written without naming an attempt that was made and failed.
- "Nobody's around, so I'll use my best judgment" — said instead of writing the judgment down.
- "Budget's blown but I'm nearly there."
- "This is technically irreversible but it's obviously fine."
- "This can't be verified without them" — said without naming the experiment that would have verified it.
- "I've already proved it works, so actually doing it is a formality." The probe moved; the door did not.
- "I'll note the assumptions in the summary" — assumptions noted later are assumptions remembered, and half of them will not be.
- "The task said keep going until it passes, so I kept going."
- "It's still running" — said of a detached job whose log stopped an hour ago.