Open Agent Toolkit

Autonomous Project Execution

OAT autonomy is an explicit session policy for driving a project through its lifecycle without waiting at ordinary interactive gates. It does not bypass the gate-owning skills: each skill still applies its own checks, records provenance, and either resolves the gate or reports a boundary.

The provider-agnostic entry point is oat-project-autonomous. Invoke it deliberately with a goal, project slug, ticket reference, or active project. A restart does not silently resume autonomy; invoke the skill again and it resumes from the persisted project state.

Terms used on this page:

  • Active project: the project your checkout currently points to. The pointer is the activeProject value in .oat/config.local.json.
  • Synced project: a project whose artifacts live on a separate Git ref (refs/oat/projects/<project>) instead of on your feature branch. Skills publish its artifact changes with oat project push.
  • HiLL checkpoint: a human-in-the-loop stop after a plan phase. In an interactive run, the agent waits there for your approval.
  • Dispatch policy: the project's rule for which models its worker and reviewer subagents may use. See Dispatch Policy.
  • Boundary: a point where an autonomous run stops on purpose and reports what a person must decide or provide before it can continue.

Activation contract

An autonomous session uses both signals:

export OAT_AUTONOMOUS=1
export OAT_NON_INTERACTIVE=1

OAT_AUTONOMOUS=1 implies and sets OAT_NON_INTERACTIVE=1 for the current run. The distinction is intentional:

  • OAT_NON_INTERACTIVE=1 selects existing safe no-prompt paths for one workflow.
  • OAT_AUTONOMOUS=1 additionally enables lifecycle chaining, defined gate resolutions, boundary stops, and provenance requirements.

Both signals are session-scoped. Never write them to state.md, plan.md, repository config, user config, or any other durable artifact. A later interactive session therefore needs no autonomy cleanup and behaves interactively around the state the autonomous run left behind.

Kickoff limits and hard stops

Kickoff reads the owning recovery, gate and dispatch contracts and reports the effective project default and each known phase limit, source/override, prior durable usage, remaining capacity and pending-attempt status. For a new project, phase values remain unresolved until planning supplies them; the report is refreshed before implementation and on resume.

Phase recovery uses oat_phase_recovery_policy in state.md: a phase_attempt_limits.<pNN> override wins over default_attempt_limit, whose owning default is 10. Limits are integers from 0 through 20. Usage comes from the monotonic phase_attempt_usage.<pNN>.used_attempts ledger; remaining capacity is max(0, effective limit - used_attempts). A reconciled pending reservation finishes that same attempt without another increment, even at the limit.

These dry kickoff controls illustrate the unchanged policy, without launching a provider:

  • Default control: limit 10, used 3, remaining 7; source is the owning default when the project has no override.
  • Phase override control: limit 2, used 1, remaining 1; source is phase_attempt_limits.p01: 2, even when the project default is 10.
  • Zero limit: no new automatic attempt; a direction-required stop consumes no attempt.

Capacity is not permission. A failed attempt is terminal even with remaining capacity. A continue-after-failure policy remains a separate future choice. Route retries, review-fix rounds, gate maxAttempts, recovery events and reserved recovery attempts are separate counters. An elevated warning at three recovery events changes no limit and grants no permission.

Kickoff also names the applicable owning hard stops: recovery eligibility or proof failure, new-attempt budget exhaustion, malformed ledger or unresolved pending attempt, exact-target/accepted-launch failure, blocking review policy, missing credentials, repository authority, unresolved product judgment, unauthorized destructive risk and inventory gaps. Each stop retains its owning contract and configured gate semantics; the report names evidence and the operator action needed to resume.

Gate outcomes

Every interactive lifecycle gate has one of two autonomous outcomes:

  1. Auto-resolve using an existing safe path, then record the decision and evidence.
  2. Boundary stop with a structured blocker and a resumable next step.

The main boundary classes are:

  • Product judgment — repository evidence cannot resolve material scope or requirements ambiguity.
  • Destructive-change risk — an action could discard work, delete data, rewrite history, or broadly restructure an unapproved surface.
  • Unresolved Critical findings — a blocking review has not passed.
  • Repository-policy approval — protected operations require authority the session does not have.
  • Missing credentials — a required external action has no authenticated route or offline equivalent.

A boundary is a successful fail-closed outcome, not permission to continue with a guessed answer. The run reports what stopped, the evidence, and the operator action needed to resume.

When a review or gate budget runs out (a review-cycle cap, the orchestration retry limit, or a gate's maxAttempts), the run first dispatches the complexity review and includes its decision-message content in the boundary report. The run never selects the disposition, including simplify: the operator chooses when resuming. A quick-start plan gate outcome is persisted as oat_quick_start_gate (see Gate approval records); a failed prompt gate is recorded as blocked, never as approved.

The canonical autonomy contract and exhaustive gate inventory (.agents/docs/autonomy-contract.md, vendored into each consuming skill at references/docs/autonomy-contract.md) map each prompt to its autonomous resolution and provenance.

Dispatch-ladder scope selection

An incomplete reusable dispatch ladder is auto-resolvable when an authorized adoption-compatible config scope is available. Autonomous planning checks config-file existence in this fixed order without prompting or reordering from effective value or matrix-cell provenance:

  1. user config (~/.oat/config.json);
  2. repo-local config (.oat/config.local.json);
  3. shared config (.oat/config.json), only when repository policy already authorizes that write.

Before writing, planning rejects a candidate that would preserve a provider-level scalar in that scope or remain shadowed by one at higher precedence. It always tries the next authorized compatible candidate and stops without mutation only when none remains.

The planner runs exactly one matching oat config adopt dispatch-matrix --keep-existing command, records file-existence and compatibility evidence plus the selected scope, and re-runs dispatch preflight. Existing explicit cells remain unchanged; their provenance does not select the persistence scope. No authorized compatible scope, or a ladder that remains incomplete after adoption, is still a repository-policy boundary. OAT_NON_INTERACTIVE=1 without OAT_AUTONOMOUS=1 does not select a scope and continues to fail closed.

Review contract

Autonomous execution preserves independent review:

  • Discovery, design, and plan artifacts run their configured exit gates. Quick-start reviews the discovery, optional lightweight design, and plan as one bundle when those artifacts exist.
  • Review routing is selected before launch through the dispatch substrate. A configured gate target is preferred when available; otherwise policy may choose a target-preserving subagent route. Any reduced independence is explicit in the dispatch record.
  • Once a launch is accepted, it is terminal for route selection. Failures use bounded recovery with the same payload; they do not silently fall through to a cheaper or less independent reviewer.
  • Eligible review artifacts are received immediately. Fix tasks use the normal bounded implement-and-re-review loop.
  • Critical findings and failed blocking reviews stop progression. High findings follow the configured gate policy.
  • A normal phase or final lifecycle review cannot satisfy a configured implementation exit gate. Only gate invocation provenance with the matching run ID can authorize that boundary.

Project review artifacts and review rows reference launcher-owned dispatch records. The configured invocation is authoritative evidence; child self-reporting is optional corroboration. See Evidence Layers and Reviews.

HiLL and lifecycle closeout

Autonomous runs ignore the configured workflow.hillCheckpointDefault and workflow.autoReviewAtHillCheckpoints settings. When an autonomous run starts implementation, it chooses checkpoints this way:

  • If the plan already stores a valid checkpoint list in oat_plan_hill_phases, the run keeps it unchanged. A stored [] means every phase, never no phases.
  • If the plan stores no list yet on the first implementation run, the run sets a checkpoint at the final phase only.
  • In both cases, the run turns on review at checkpoints, even if an earlier interactive setup turned it off.

For a plan with no stored list, the run writes:

oat_plan_hill_phases: ['<final-phase-id>']
oat_auto_review_at_hill_checkpoints: true

At each checkpoint, the run reviews the phase and processes that review instead of waiting for you. An invalid stored value is not replaced; the run stops at a boundary instead.

At final closeout, autonomy follows the same authoritative order as an interactive run: final verification, mandatory final lifecycle review, configured implementation exit gate, pre-approval sequence, final HiLL approval, post-approval sequence, then implementation completion and success output. A not_configured resolution persists an explicit no-gate allowance before the sequence starts; a null, missing, or unrecognized resolver result fails closed as unresolved. A gate this project disabled persists an allowed/configured result with disposition: project_disabled and never launches the configured command.

Autonomy does not turn an ordinary independent review into configured-gate provenance. A configured review must produce a gate-originated artifact with the matching run ID, and eligible receive must be durably reconciled. Blocked, ambiguous, malformed, or stale gate state is a boundary stop: the run remains resumable through oat-project-implement and cannot continue to approval, completion, or output.

The default autonomous tail is summary, documentation, and final PR when no post-implementation sequence is configured; stored legacy or structured sequences retain their documented meaning.

Execution-learnings loop

Autonomous runs record learnings in the project log, not in a separate file. Each learning is a judgment entry written with oat project log append carrying --category (the source taxonomy: gotcha, efficiency, documentation-gap, candidate-skill-content, decision, or environment-limited), a stable per-observation --source id that is also the --idempotency-key, and --origin oat-project-autonomous. The category maps to the judgment type: gotcha and environment-limited become friction, efficiency and candidate-skill-content become worked-well, and documentation-gap and decision become feedback. The body records an observation, impact, recommendation and, where it applies, uncertainty. A retried write with the same source id appends nothing. oat-cursor-cloud-projects and oat-project-goal use the same write with their own origin.

When the project log is disabled (workflow.projectLog: false) and project-log.md does not exist yet, the append creates nothing: the producer prints one warning line and continues, and no learning is persisted anywhere. The flag only stops the log's creation; an existing project-log.md keeps accepting learnings. No producer creates oat-execution-learnings.md any more; summary and retro still read an existing legacy file after the log.

When category-bearing entries (or a legacy file) exist, oat-project-summary synthesizes actionable recommendations into ## Autonomous Execution Learnings, grouped as:

  • agent-instruction updates;
  • cloud-environment improvements;
  • code follow-ups; and
  • workflow issues.

Each recommendation names its source entry with a plain-text oat-project:<slug>#<entry-id> token rather than a link. Projects without learnings render normal summaries with no autonomous-learnings section. The summary export keeps the synthesized recommendations after project archival.

Taking over interactively

After an autonomous session ends:

  1. Start a normal session without the autonomy environment signals.
  2. Open the same project from its repository-local .oat directory.
  3. Resume the owning lifecycle skill.

Persisted review rows, task state, explicit HiLL checkpoints, and dispatch provenance remain valid. Interactive prompts and checkpoint pauses return normally because autonomy itself was never persisted.

oat-project-autonomous

Use this entry only after an explicit request for end-to-end autonomous project execution. It chains the existing lifecycle owners rather than replacing their gates or creating another implementation coordinator.

WARNING

What it does without asking: after every lifecycle phase, an autonomous run commits its work and pushes the current branch to its remote (never with force). It also commits its own state and project-log learning updates, dispatches worker and reviewer subagents under one authorization for the whole run, generates a project recap, and opens the final pull request. None of these steps asks for confirmation. It never merges the pull request.

  • Start it on a feature branch, never on main. It pushes whichever branch you are on.
  • Set a dispatch policy first. The run never chooses a dispatch policy for you. If the project has none, the run stops at a repository-policy boundary.
  • Clear the active project if you want a new one. If a valid active project is set, the run resumes that project even when you pass a new goal. Run oat-project-clear-active before you pass a new goal.

The run stops and reports instead of guessing when it reaches any of these boundaries: a product decision the repository evidence cannot settle (product-judgment); an action that could delete data, overwrite work, or rewrite history (destructive-change-risk); an unresolved Critical review finding or a blocking review that cannot pass (unresolved-critical-findings); a protected branch, required approval, or unresolved dispatch policy (repository-policy-approval); a missing credential (missing-credentials); or a prompt that has no autonomous rule in the gate inventory (inventory-gap). A configured gate that fails with onFailure: prompt, or that cannot run or return a valid result, also stops the run.

Invocation: Provide a substantive goal for new work, or an existing project slug or path to resume. These are agent requests, not terminal commands. Providers with $ syntax use $oat-project-autonomous.

/oat-project-autonomous "Add resumable exports and open the final PR."
/oat-project-autonomous export-filter

Prerequisites: Needs an active OAT project: no. A new goal can create a project through the entry skill the run selects. An explicit existing project or a valid active project supports resume, and empty input requires a valid active project. The skill resolves an explicit project first, then a valid active project, then a new goal. Because of that order, a goal you pass while a valid active project is set resumes the active project instead of creating a new one. Use the first example only when no project is active, or clear the active project with oat-project-clear-active first.

oat must be on PATH, and repository policy must permit the work on the current branch. A dispatch policy must already be configured or recorded in the project: autonomy never picks one, and an unresolved policy stops the run at a repository-policy boundary. Required worker and reviewer capabilities must resolve before the run makes any change.

Example scenario: You are on a new feature branch, no project is active, and a dispatch policy is already configured. You authorize the bounded resumable-export goal through a final PR without ordinary mid-run approval pauses. Autonomous entry chooses lite, brief, quick, or spec-driven review density from the actual uncertainty and invokes its owning creation skill. It never selects goal: each milestone's approval and the final declaration need a person, so an existing goal project stops at a product-judgment boundary instead of running unattended. If an export-filter project is already active, the second example explicitly resumes its earliest incomplete step instead of replaying finished phases.

When autonomous entry selects brief, oat-project-brief derives the project name and description only from the explicit goal and stops if it is not substantive. The brief's single approval resolves autonomously under BRIEF-11: the reviewed brief is approved and the approval line records the autonomous run, while contradictory or materially incomplete outcomes stop at a product-judgment boundary. A brief records no HiLL checkpoints unless it lists phases explicitly.

Expected output: Session-only autonomy signals, persisted lifecycle progress, reviewed task commits, and category-bearing project-log learnings. Existing projects retain their mode. A successful run reports the actual final PR and review evidence. A blocked run names the boundary, durable completed work, operator action, and resumable project.

The default topology is one working branch and one final PR. The skill pushes that branch after every phase, but it does not merge or force-push. Missing credentials, protected operations, destructive work, unresolved blocking review, and material product ambiguity are boundaries, as are an unresolved dispatch policy and any prompt the gate inventory does not cover (inventory-gap). Autonomy does not let an ordinary review impersonate a configured exit gate.

Next step: Inspect the final report and PR, or resolve the named boundary. After a restart, deliberately invoke the skill again. Persisted project state supports resume, but does not silently reactivate autonomy.

Choosing how unattended to run

ModeChoose whenTradeoff
Interactive (default)You want to steer approvalsRequires a person at prompts
Non-interactiveA scripted step needs documented defaultsUnresolved choices stop; no continuous autonomous consent
Explicit autonomousA clear goal can run within declared boundariesLess live steering; review outputs and publication consequences

A restarted session is interactive. If you want autonomy to continue after a restart, invoke oat-project-autonomous again. Autonomy never chooses a dispatch policy for you, and it never merges a pull request. An autonomous run stops when it reaches a product decision, a destructive or protected action, a missing credential, an unresolved blocking review, or a required check it cannot perform.

  • If this is your first trial of OAT, choose interactive, because you see every approval and can steer the work as you learn the lifecycle.
  • If you need one scripted or CI step, choose non-interactive (OAT_NON_INTERACTIVE=1), because each skill takes its documented default and stops on any choice without one. It does not chain skills or approve anything on your behalf.
  • If you have a well-specified change you trust to run unattended, choose autonomous, because it carries the work through to a final pull request. Set the dispatch policy, the candidate-ladder config, and each gate's onFailure behavior first, start on a feature branch, and review the pull request yourself.
  • If the change is high-risk, choose interactive, because a person then approves each checkpoint. If you still run it autonomously, set oat_plan_hill_phases: [] in the plan first, because that adds a checkpoint review after every phase.

Running without prompts does not authorize any action outside these boundaries.

On this page