Skip to content

Automation Behavior

Reference for how commands and skills should adjust interaction ceremony based on the active automation level. The big-picture description of each level (and how to switch) is in project-orchestration-handbook.md §7.1; this doc is the per-decision behavior table. Warp-drive’s level-specific behavior is in the handbook §7.2 and warp-drive.md. For how the different loop archetypes (crons, retries, evaluator-gated loops, self-directing agents) map onto this trust scale, see the Loop Taxonomy & Trust Model.

Read .claude/settings.local.json in the project directory. Look for _automation.active_level (1, 2, 3, or 4). If not found or the file doesn’t exist, default to Level 1. An absent or unrecognised value never resolves to Level 4 — full-auto is only ever active when active_level is explicitly 4 and the full-auto profile is present.

  • Ask before every decision
  • Show all options with explanations
  • Wait for explicit confirmation before acting
  • This is identical to pre-automation behavior
  • Auto-proceed on safe, inferrable, or reversible decisions
  • Still confirm destructive operations (force push, delete, overwrite)
  • Still ask for subjective content (summaries, descriptions, priorities)
  • Show each auto-decision inline as it happens
  • Minimize prompts — only stop for destructive ops or subjective content
  • Auto-infer from git context, branch names, file paths, commit history
  • Batch auto-decisions into a summary rather than inline notifications
  • Ask for: rebase conflicts, subjective writing, destructive operations
  • A superset of Level 3: everything L3 auto-approves, L4 auto-approves too.
  • Decisions are resolved by reversibility, not escalated by default. A reversible (two-way-door) decision is auto-made — biased toward the most reversible option — and recorded as a decision issue. An irreversible (one-way-door) decision — spending money, a public contract, deleting data, external comms, prod deploy past the ceiling — is never auto-resolved: it notifies and waits, or stops.
  • The wait is bounded by decision_timeout_minutes (default 10), governed by the decision-timeout policy: on timeout with no reply a one-way door is deferred (skip it, keep working) or stops cleanly if it blocks everything — never a guess. 0 means never wait (“work around or stop”); with RDB off, “notify” degrades to a filed TODO with a defer default.
  • Inherits the L3 always-blocked floor and an irreversible-action floor, both carried by the full-auto profile (profiles/full-auto.json, delivered in #867).
  • Requires a cost ceiling to start (#879). A Level 4 run refuses to launch without a spend ceiling — --budget <usd> / --max-tokens <n> at kickoff, or _workflow.max_session_usd / max_session_tokens in config — so an unattended run is never uncapped. The existing cost breaker enforces it (no new breaker); a cost estimate is surfaced at kickoff. See Kickoff Flags.
  • Requires that profile to be present; until it is, /automation level 4 safely refuses and leaves the level unchanged.
  • The full-auto behavior (reversibility decision engine, in-session QA loop, session segmentation, decision budget) is built out under capability #865; this entry documents the level itself. The decision classification and promotion matrices below carry an L4 column so the full-auto behavior is documented where L1/L2/L3 are.

Commands must show what was auto-decided so the user stays informed.

Level 2 — inline per decision:

> Auto (L2): Branch type set to `tooling/` (inferred from .claude/ changes)
> Auto (L2): Stashed 2 uncommitted files

Level 3 — batched summary:

> Auto (L3) decisions:
> - Branch type: `tooling/` (inferred from .claude/ changes)
> - Stashed 2 uncommitted files
> - Branch name: `tooling/automation-behavior`
Category L1 L2 L3 L4 (full-auto)
Safe + inferrable Ask Auto, show Auto, show Auto, show
Reversible action Ask Auto, show Auto, show Auto-decide + record decision issue
Subjective content Ask Ask Ask Notify-and-wait (one-way; never auto-resolve)
Destructive operation Ask Ask Ask Blocked by the floor; escalate (one-way)
Push to remote Ask Confirm Auto (except main/master) Auto (prod past ceiling is a one-way door → blocked)
Conflict resolution Ask Ask Ask Auto if trivial; else escalate
Requirement/AC tracking Ask Auto-update, show Auto-update, show Auto-update, show
Documentation housekeeping Ask Auto-update, show Auto-update silently Auto-update silently
Warp-drive continue to next task Ask Ask Auto-continue, log Auto-continue (bounded), log
Warp-drive plan review Ask Ask Auto-proceed, log Auto-proceed, log

Level 4 formalizes the “Reversible action” row into an enforced engine. Where L2/L3 treat reversible actions as auto-and-show, L4 classifies every decision one-way (irreversible) vs two-way (reversible) via the reversibility decision engine (scripts/warp-drive/decision-engine.js, #871) and acts on the classification: two-way doors are auto-decided and recorded as decision issues (options considered + rationale); one-way doors notify-and-wait or stop and are never auto-resolved. An unrecognized decision defaults to one-way — the engine never guesses a one-way door. The irreversible categories are exactly the ones the full-auto floor denies at the tool level (money-spend, external comms, destructive data ops, prod deploy past the ceiling, history loss); the engine is the semantic layer above that floor. See the Reversibility Decision Engine reference.

Autonomous profile — auto-approved vs always-blocked (#420)

Section titled “Autonomous profile — auto-approved vs always-blocked (#420)”

Level 3 (the autonomous profile, profiles/autonomous.json) is the only level designed to run unattended — including overnight. Because nothing prompts, “what exactly is this allowed to do while I’m asleep?” needs a documented answer. This is it.

When to use it vs. interactive defaults. Use L3 only for a scoped, version-controlled repo where every change is recoverable from git and you have reviewed the work queue — e.g. an area:-scoped warp-drive batch of approved requirements. Stay at L1/L2 (interactive) for exploratory work, anything touching production credentials or external services by hand, or a repo whose state you are not ready to have advanced without review. L3 trades the per-action prompt for an after-the-fact audit trail (below) — that trade only pays off when the queue is trusted and the blast radius is git.

Auto-approved at L3 (no prompt): reads, search, edits/writes, Bash, the dev/test/commit/push/merge skills, Playwright, WebFetch/WebSearch, and push/merge to main/master (subject to the promotion ceiling — a pr ceiling still caps L3 at a pull request).

Always-blocked at L3 (denied even though everything else is auto-approved) — three layers, each entry carries a rationale in profiles/autonomous.json_meta.deny_rationale:

Layer Blocks Why
Destructive-git floor git push --force, git push origin --force, git reset --hard, git branch -D, rm -rf Irrecoverable history/working-tree loss. This floor is a deliberate guardrail and is never loosened — see the autonomous-deny-destructive-git guardrail.
Secrets / credential reads .env / .env.*, *credential*, ~/.ssh, ~/.aws, ~/.config/gcloud, ~/.kube, ~/.npmrc, ~/.netrc (via both Read and shell cat) An unattended run has no legitimate reason to read raw secret stores; blocking them shrinks the exfil surface.
Network-exfil shapes curl -T / --upload-file, curl -d @file, pipe-into-curl/wget, wget --post-file The obvious “send a local file to a remote host” shapes.

Honest limitation. The secrets/exfil blocks are defense-in-depth, not a sandbox. Bash is broadly allowed, so a sufficiently creative shell command can still read a file or reach the network — the deny patterns only catch the obvious shapes. The real backstop for an unattended run is the audit log, not the deny-list.

When _automation.active_level is 3 (autonomous) or 4 (full-auto), the autonomous-audit-log.sh PreToolUse hook records every auto-approved tool call — tool, target, timestamp, session, cwd — as one JSONL line per call. A full-auto run is at least as autonomous as L3, so it is audited on the same trail (#882):

  • Location: ~/.claude/logs/autonomous-audit/<session-id>.jsonl (override with $BOB_AUTONOMOUS_AUDIT_DIR).
  • Per session: one file per Claude Code session, so an overnight run is one reviewable trail.
  • Recorder, never a gate: it always exits 0 and never blocks — it only observes.
  • Strict no-op below L3: at L1/L2 (and outside BoB projects) it reads one settings field and exits, so it cannot affect interactive or Trusted-Dev runs.

To review an unattended run afterwards: jq -r '"\(.ts) \(.tool) \(.target)"' ~/.claude/logs/autonomous-audit/<session>.jsonl.

So — is it safe to leave running overnight? For a scoped, git-backed repo with a reviewed queue: yes — irrecoverable git ops, secret reads, and obvious exfil are blocked, and everything auto-approved is captured in the audit log for morning review. It is not a substitute for a sandbox on an untrusted workload, and the promotion ceiling still governs how far work is actually promoted.

The audit log above is the tool layer — every auto-approved tool call (“what did it touch?”). Sitting above it is the decision layer: at Level 4 the reversibility decision engine records each auto-made two-way-door decision as a decision issue and an entry in the in-state decision log (state.decisions[]). At session_ending warp-drive aggregates that log into a decisions digest and includes it in the session-summary issue, so the whole autonomous run is reviewable — and cheaply reversible — from one place:

  • Each decision is listed with its reversibility class and a link to its decision issue (options considered + rationale) for one-place review/reversal — revert any that look wrong (revert the commit / re-open the choice).
  • The digest cross-links the tool-level audit log (this section) but is distinct from it: the audit log answers “what was touched?”, the digest answers “what was decided, and can I undo it?”.
  • Generated by state-machine.js decisions-digest (pure renderer: scripts/warp-drive/decisions-digest.js); on a run with no auto-decisions it still emits an explicit “nothing to review” block so the absence is recorded, not silent.

Full-auto profile — the irreversible-action floor (#867)

Section titled “Full-auto profile — the irreversible-action floor (#867)”

Level 4 (the full-auto profile, profiles/full-auto.json) is a superset of Level 3: it inherits the autonomous allow-list and the entire always-blocked floor above verbatim (the destructive-git floor is never loosened), then adds a fourth deny layer for irreversible, one-way-door actions — the things a full-auto run must never do unattended:

Layer Blocks (representative shapes) Why
Destructive data ops DROP DATABASE, DROP TABLE, TRUNCATE TABLE, dropdb Data loss is irreversible — a one-way door.
Prod deploy past ceiling wrangler deploy --env prod / --env production A production release is a one-way door; the promotion ceiling owns this, the deny is defense-in-depth.
External communications sendmail, mail, mailx An unattended run must not contact the outside world on its own.
Money-spend / paid resources stripe, gcloud billing, aws … purchase… Spending real money is irreversible.

Every deny entry carries a _meta.deny_rationale, and the layer is enforced by the same native permissions.deny mechanism as the L3 floor plus the existing promotion-ceiling-guard hook — there is no parallel enforcement mechanism.

Honest limitation (same as L3). These deny patterns are defense-in-depth, not a sandbox — they catch the obvious command shapes, not every semantic variant of “spend money” or “message the outside world.” The real backstops for full-auto are the reversibility decision engine (one-way-door decisions notify or stop; #871), the promotion ceiling, and the per-session audit log. The floor is the guardrail of last resort, not the primary control.

The automation level governs how much autonomy the agent has. It used to also decide how far work is promoted — the two were fused: Level 2 ≡ “open a PR”, Level 3 ≡ “merge to master”. That made “run fully autonomously, but never push past a PR” impossible to express.

A project’s promotion ceiling (dev.jsonpromotion.ceiling, default external) decouples those axes. The merge/deploy decision becomes f(automation_level, ceiling), computed by the shared library scripts/promotion/promotion.js and enforced everywhere — warp-drive’s merging phase, /finish-work, and the promotion-ceiling-guard PreToolUse hook. View or set it with /promotion.

Git action (merge) — f(level, ceiling):

Ceiling ↓ \ Level → L1 L2 L3 L4 (full-auto)
pr PR PR PR (capped — never auto-merges to main) PR (capped — same as L3)
external (default) PR PR direct merge to main direct merge to main
test PR PR direct merge to main direct merge to main
prod PR PR direct merge to main direct merge to main

Deploy action — f(level, ceiling):

Ceiling ↓ \ Level → L1 L2 L3 L4 (full-auto)
pr none none none none
external (default) none none none (git only — deployment is out-of-band) none (git only)
test none none deploy to test deploy to test
prod none none deploy to prod deploy to prod

The default external reproduces the legacy fused behavior exactly (L3 → direct merge + no deploy, L2 → PR), so a project with no promotion block is unchanged. Setting a ceiling only ever narrows (pr) or extends (test/prod) from that baseline. Deploy adapters that execute the test/prod deploy land in #450; until then a non-external deploy action is a recorded intent, not yet an executed deploy.

L4 promotes exactly as far as L3 — the ceiling governs reach, not the automation level. Because Level 4 is a superset of Level 3, its git/deploy columns match L3 cell-for-cell: the promotion ceiling is the single axis that decides how far work is carried, and it caps L4 the same way it caps L3 (a pr ceiling still stops at a pull request). What L4 adds is enforcement above the matrix, not reach beyond it: a deploy or merge past the ceiling is an irreversible one-way door, refused by the reversibility engine and the full-auto floor (prod-deploy-past-ceiling), never auto-resolved. So L4 never promotes further than L3 — it only removes the human at the wheel within the ceiling.