You Can't Authorize Autonomy
Autonomy depends on the control system around an agent: scoped authority, durable state, bounded continuation and independent acceptance evidence. An illustrative design.
Permission and completion solve different problems. Permission defines what an agent may do; a controller determines what should happen next and whether the requested outcome has been achieved. Giving a worker more access does not solve task selection, evidence quality or stopping behavior.
This article describes a reference design for a repository automation system. Its interfaces and failure examples are illustrative. It does not publish a private operational history or claim that a hidden implementation has proved these properties.
Separate turn control from acceptance
A turn-control gate may ask an agent to continue when work remains. An acceptance verifier checks whether a required outcome is present. Releasing a turn because the gate timed out must not become a successful acceptance result.
Use explicit states: accepted, incomplete and unknown. A deterministic check can establish a narrow property such as a clean build or a valid reference. A model evaluator can flag unresolved requirements in the transcript. Neither should silently claim evidence it did not inspect.
A clean repository does not prove the task was completed. Conversely, a user-approved handoff can be appropriate while work remains unfinished. Record both the reason for ending the turn and the actual acceptance state.
The surrounding loop
Discovery reads authorized sources and proposes a ranked task list. Selection applies scope, dependency and resource rules. Workers receive bounded assignments. Verification checks the accepted revision and relevant external behavior. Persistence records evidence and recovery state. Scheduling determines when another attempt may begin.
A worktree helps prevent concurrent edits from colliding. It is not a security boundary. Enforce filesystem, credential and network restrictions separately where the task requires them.
Failure patterns worth testing
Self-observation: if a verifier writes a log that makes its own clean-tree check fail, it can create a feedback loop. Keep runtime evidence separate from the artifact being measured without hiding actual source changes.
Working-directory drift: a relative checker path may resolve differently inside a nested repository. Anchor the checker to a defined location, validate its inputs, and report unavailable checks as unknown.
Target substitution: a local test is not equivalent to a requested staging test merely because the code is similar. The environment, revision and data conditions are part of the requirement. State exactly what was tested.
Unsupported failure claims: a semantic evaluator can misread success or invent a failure. Require it to identify the relevant tool result and compare against structured evidence. Absence of a failure string alone does not establish success.
Stale acceptance: tracker state can change after a check. Bind verification to an exact revision and revalidate material external state before recording completion. A worker-authored Done label is coordination data, not independent proof.
Boundary confusion: a task can need an external action outside the worker’s authority. Complete useful preparation and record a concrete handoff. Do not invent permission or retry an unauthorized action merely to satisfy a continuation rule.
Evaluate the gate as software
Test both false blocks and false accepts using labeled cases. Include incomplete tasks, complete tasks, legitimate handoffs, contradictory logs, missing evidence, nested repositories, cancellation and resource exhaustion. A perfect score on a small corpus is an observation about that corpus, not a general guarantee.
Test the integrated interception path as well as the isolated judge. A correct model prompt cannot compensate for a hook that never ran, an unreadable checker or a result that the controller interpreted incorrectly.
Illustrative implementation interfaces
A controller might expose discover_tasks, select_ready_task, run_worker, verify_acceptance and persist_attempt operations. These names specify responsibilities; this article does not supply a runnable package. Implement each with explicit inputs, statuses, idempotency and error handling before connecting them.
Before a dependent mutation, establish its required backup and preconditions separately. After execution, inspect the actual result. On an interrupted mutation, recover from recorded intent and external state rather than assuming the operation failed or succeeded.
Protect the verifier
Keep acceptance definitions, checker code and expected integrity values outside the worker’s write authority. Hashes help detect change only when the expected hashes and verification path are themselves protected. Also control the credentials and dependencies that determine what the checker observes.
A worker may propose a controller repair. Review and validate the proposal through a separate authority path, preserve the original failure evidence and retest relevant cases. One frozen file does not make unrestricted self-modification safe.
Stopping honestly
Provide cancellation and resource limits that do not depend solely on the model agreeing to stop. If a conversational gate fails open to avoid trapping the user, retain an unknown verification result and surface it. Do not convert availability into a success claim.
The goal is an inspectable system that makes progress within its authority and reports the state accurately. Autonomy becomes useful when scheduling, recovery and verification work together; it remains bounded by the evidence those components can actually produce.