/ai-cli-task auto — Autonomous Execution Loop
Coordinate the full task lifecycle autonomously: plan → check → exec → check, with self-correction on failures. Runs as a single Claude session that internally dispatches sub-commands, preserving context across all steps.
Usage
/ai-cli-task auto <task_module_path> [--start|--stop|--status]
Architecture
Auto mode runs as a single long-lived Claude session that internally loops through sub-commands. The backend daemon starts the session and monitors it externally; it does NOT dispatch individual commands.
Components
┌─────────────────────────────────────────────────┐
│ Claude (single session) │
│ │
│ /ai-cli-task auto <module> │
│ ├→ execute plan logic ─┐ │
│ ├→ execute check logic │ internal loop │
│ ├→ execute exec logic │ (shared context) │
│ ├→ execute check logic │ │
│ ├→ execute merge logic ─┘ │
│ └→ execute report logic │
│ │
│ writes .auto-signal ──→ (progress report) │
│ reads .auto-stop ──→ (stop request) │
└─────────────────────────────────────────────────┘
│ ▲
▼ │
┌─────────────────┐ ┌──────────┴──────────┐
│ .auto-signal │ │ Backend Daemon │
│ (progress) │────▶│ - monitors progress │
│ │ │ - enforces timeout │
│ .auto-stop │◀────│ - writes stop file │
│ (stop request) │ │ - stall detection │
└─────────────────┘ └─────────────────────┘
Why Single Session
| Aspect | Multi-session (old) | Single session (current) |
|---|---|---|
| Context | Lost between steps, rebuilt from .summary.md | Naturally shared across all steps |
| Token cost | Re-read files each step, duplicate context loading | Read once, incrementally update |
| Coherence | Each step is blind to implicit decisions | Claude remembers why it made choices |
| Latency | Shell prompt wait + Claude startup per step | Zero inter-step overhead |
| Daemon complexity | Command construction + dispatch + readiness check | Just monitoring + stop signal |
Signal File (.auto-signal)
After each sub-command step completes, Claude writes a progress signal to the task module. This is a monitoring report for the daemon, NOT a dispatch trigger:
{
"step": "check",
"result": "PASS",
"next": "exec",
"checkpoint": "",
"iteration": 3,
"timestamp": "2024-01-01T00:00:00Z"
}
Fields:
- •
step: the sub-command that just completed - •
result: outcome of the step - •
next: what Claude will execute next (or"(stop)") - •
checkpoint: context hint (e.g.,"post-plan","mid-exec","post-exec"). Empty when not applicable - •
iteration: current iteration count (for daemon progress tracking). Auto-mode only — absent when sub-commands write.auto-signalin manual execution - •
timestamp: ISO 8601
The daemon reads this via fs.watch to:
- •Update progress display (iteration count, current step, elapsed time)
- •Check iteration limit (
iteration >= maxIterations→ write.auto-stop) - •Check timeout (
elapsed >= timeoutMinutes→ write.auto-stop) - •Update
last_signal_atin SQLite for stall detection baseline
The daemon does NOT construct or send commands based on the signal.
Stop File (.auto-stop)
The daemon writes .auto-stop to the task module directory to request graceful termination. Claude checks for this file before each iteration:
{
"reason": "timeout",
"timestamp": "2024-01-01T00:30:00Z"
}
Reasons: "timeout", "max_iterations", "user_stop", "stall_limit"
Signal Validation
The daemon validates .auto-signal fields for monitoring integrity:
| Field | Validation | Allowed Values |
|---|---|---|
step | Whitelist | plan, check, exec, merge, report |
result | Whitelist | PASS, NEEDS_REVISION, ACCEPT, NEEDS_FIX, REPLAN, BLOCKED, CONTINUE, (generated), (annotations), (done), (mid-exec), (step-N) (where N is integer), (blocked), success, conflict |
next | Whitelist | plan, check, exec, merge, report, (stop) |
checkpoint | Whitelist | "", post-plan, mid-exec, post-exec |
iteration | Integer | ≥ 0 |
timestamp | Format check | ISO 8601 |
Invalid signals are logged but do not affect Claude's internal loop (daemon is observer, not dispatcher).
Stall Detection & Recovery
Claude Code may stall mid-execution. The daemon detects stalls via heartbeat polling (60s interval, 3 consecutive unchanged captures = suspected stall) and recovers via pattern matching (continuation prompts, y/n prompts, shell prompt restart). Recovery limits: 3 per iteration, 10 total.
See
references/stall-detection.mdfor the full heartbeat polling logic, stall determination rules, pattern matching recovery table, and recovery limits.
Context Window Management & Quota Handling
Proactive /compact at >= 70% context usage prevents overflow. .summary.md files provide compaction recovery context. Quota exhaustion is NOT a stall — daemon enters quota-wait mode with timeout clock paused.
See
references/context-quota.mdfor the full context management strategy, quota exhaustion handling (daemon + Claude behavior), and SQLitequota_wait_sinceextension.
State Machine
AUTO LOOP (4 phases — all within single Claude session)
Phase 1: Planning
plan ──→ check(post-plan) ─── PASS ──────────→ [Phase 2]
│
NEEDS_REVISION ──→ plan (retry)
Phase 2: Execution
exec ─┬─ (mid-exec) ──→ check(mid-exec) ─── CONTINUE ──→ exec (resume)
│ │
│ NEEDS_FIX ──→ exec (fix then resume)
│ │
│ REPLAN ──→ [Phase 1]
│
└─ (done) ──→ [Phase 3]
Phase 3: Verification
check(post-exec) ─── ACCEPT ──→ [Phase 4]
│ │
NEEDS_FIX REPLAN ──→ [Phase 1]
│
└──→ exec (re-exec) → [Phase 3]
Phase 4: Merge & Report
merge ─── success ──→ report → (stop)
│
└── conflict unresolvable (after 3 retries, stays executing) → (stop)
Terminal: BLOCKED at any check → (stop, status → blocked)
Terminal: merge conflict → (stop, status stays executing — retryable)
Internal Loop Logic
The auto skill runs this loop within a single Claude session:
1. Read .index.md → determine entry point (status-based routing)
2. LOOP:
a. Check for .auto-stop file → if exists, break loop
b. Context check: if context window usage ≥ 70%, run /compact to compress context
c. Execute current step (plan/check/exec/merge/report logic per SKILL.md)
— SKIP the sub-command's own .auto-signal write step (auto loop handles it below)
d. Evaluate result → determine next step (result-based routing)
e. Write .auto-signal (progress report for daemon, WITH iteration field)
f. Increment iteration counter
g. If next == "(stop)" → break loop
h. Set current step = next step → continue loop
3. Cleanup: delete .auto-signal, report final status
Signal ownership in auto mode: Each sub-command's SKILL.md includes a "write .auto-signal" step. In auto mode, the auto loop subsumes that step — Claude writes the signal once at step 2d (with the iteration field included). The sub-command's own signal-write instruction is skipped to avoid double-writing. In manual (non-auto) execution, sub-commands write .auto-signal themselves (without iteration field).
Entry Point (Status-Based Routing)
| Current Status | First Step |
|---|---|
draft | Validate .target.md has substantive content (not just template placeholders) → if empty, stop and report "fill .target.md first". Otherwise execute plan (generate mode) |
planning | Execute check (post-plan) |
review | Execute exec |
executing | Execute check (post-exec) |
re-planning | Read phase field: if needs-plan → execute plan (generate); if needs-check → execute check (post-plan); if empty → default to plan (generate, safe fallback) |
complete | Execute report, then stop |
blocked | Stop loop, report blocking reason |
cancelled | Stop loop |
Result-Based Routing
After each step, Claude evaluates the result and determines the next step internally:
| step | result | next | checkpoint | Rationale |
|---|---|---|---|---|
| check | PASS | exec | — | Plan approved, proceed to execution |
| check | NEEDS_REVISION | plan | — | Plan needs revision, re-generate first |
| check | ACCEPT | merge | — | Task verified, merge to main |
| check | NEEDS_FIX | exec | mid-exec / post-exec | Minor issues, re-execute to fix first |
| check | REPLAN | plan | — | Fundamental issues, revise plan |
| check | BLOCKED | (stop) | — | Cannot continue |
| check (mid-exec) | CONTINUE | exec | — | Progress OK, resume execution |
| check (mid-exec) | NEEDS_FIX | exec | mid-exec | Fixable issues, exec addresses then continues |
| check (mid-exec) | REPLAN | plan | — | Fundamental issues, revise plan |
| check (mid-exec) | BLOCKED | (stop) | — | Cannot continue |
| plan | (any) | check | post-plan | Plan ready, assess it |
| exec | (done) | check | post-exec | All steps completed, verify results |
| exec | (mid-exec) | check | mid-exec | Significant issue encountered, checkpoint |
| exec | (blocked) | (stop) | — | Cannot continue |
| merge | success | report | — | Merge complete, generate report |
| merge | conflict | (stop) | — | Merge conflict unresolvable |
| report | (any) | (stop) | — | Loop complete |
Context Advantage
Because all steps run in one session, Claude naturally retains:
- •Plan decisions and trade-offs from the planning phase
- •Check feedback and evaluation rationale
- •Implementation details and workarounds from execution
- •Error context from previous fix attempts
The .summary.md file is still written by each sub-command as a compaction safety net — if the context window overflows and compaction occurs, .summary.md provides the condensed recovery context. But during normal auto execution, live conversation context is the primary source of truth.
Compaction recovery: If context compaction occurs mid-loop, Claude loses the iteration counter and current step position. To recover:
- •Read
.auto-signal— theiterationfield gives the last completed iteration count;stepandnextgive the position in the loop - •Read
.index.md— status confirms the current lifecycle phase - •Read
.summary.md— condensed task context from the last sub-command - •Resume the loop from
nextstep atiteration + 1
Backend REST API
| Method | Endpoint | Description |
|---|---|---|
POST | /api/sessions/:id/task-auto | Start auto mode for a task module |
DELETE | /api/sessions/:id/task-auto | Stop auto mode (writes .auto-stop) |
GET | /api/sessions/:id/task-auto | Get auto mode status |
GET | /api/task-auto/lookup?taskDir=<path> | Look up which session is running auto for a given task directory. Returns { session_name, status } or 404 if not found. Used by cancel to find the correct session to stop |
Request body for POST:
{
"taskDir": "/absolute/path/to/AiTasks/module-name",
"maxIterations": 20,
"timeoutMinutes": 30
}
| Field | Type | Default | Description |
|---|---|---|---|
taskDir | string | (required) | Absolute path to task module in main worktree (e.g., /project/AiTasks/auth-refactor). In worktree mode, this is still the main worktree path — NOT the task worktree path. Daemon's fs.watch monitors this path for .auto-signal |
maxIterations | number | 20 | Max plan/check/exec cycles before forced stop |
timeoutMinutes | number | 30 | Total execution time limit (minutes). User sets based on task difficulty |
Frontend displays these as editable fields in the auto-start dialog, with sensible defaults.
Daemon Startup Sequence
When POST /api/sessions/:id/task-auto is called:
- •Validate: check no active auto loop for this session or task_dir
- •Insert
task_autorow into SQLite - •Send
claude "/ai-cli-task auto <taskDir>"to the session's PTY - •Start
fs.watchontaskDirfor.auto-signalchanges - •Start heartbeat polling timer (60s interval)
The daemon does NOT send any further commands after step 3. Claude's internal loop handles all subsequent orchestration.
SQLite State
CREATE TABLE task_auto ( session_name TEXT PRIMARY KEY, task_dir TEXT NOT NULL UNIQUE, status TEXT DEFAULT 'running', max_iterations INTEGER DEFAULT 20, timeout_minutes INTEGER DEFAULT 30, iteration_count INTEGER DEFAULT 0, recovery_count_step INTEGER DEFAULT 0, recovery_count_total INTEGER DEFAULT 0, last_capture_hash TEXT DEFAULT '', stall_count INTEGER DEFAULT 0, quota_wait_since TEXT DEFAULT '', started_at TEXT, last_signal_at TEXT );
session_name as PRIMARY KEY enforces one auto loop per session. Starting a new auto task requires stopping the current one or creating a new session.
status column values: running (active loop) → row deleted on stop. The row only exists while the auto loop is active; cleanup removes it entirely. The status column exists for recovery: if the server crashes before cleanup, stale rows with status = 'running' are detected on restart (see Server Recovery).
Safety
- •Max iterations: user-configurable (default 20), daemon writes
.auto-stopwhen reached - •Timeout: user-configurable (default 30 min), daemon writes
.auto-stopwhen elapsed - •Stall detection: heartbeat polling (60s) + pattern matching recovery, with per-iteration (3) and total (10) recovery limits
- •Context management: proactive
/compactat ≥ 70% context window usage, with.summary.mdas compaction safety net - •Quota exhaustion: detected and handled as wait (not stall), timeout clock paused during quota-wait
- •Pause on blocked: Auto stops immediately on
blockedstatus (Claude's internal loop exits) - •Manual override: User can
/ai-cli-task auto --stopat any time, or daemon writes.auto-stopviaDELETEAPI - •Graceful stop: Claude checks for
.auto-stopbefore each iteration, ensuring clean exit between steps (not mid-step) - •Single instance per session: Only one auto loop per session (enforced by SQLite PK). If an auto task is already running,
POSTreturns 409 Conflict - •Single instance per task: UNIQUE constraint on
task_dirprevents same task from running in multiple sessions
Frontend Integration
The frontend is a pure observer for auto mode, except for start/stop control:
- •Start dialog: editable fields for
maxIterationsandtimeoutMinuteswith defaults - •Status display: polls
GET /api/sessions/:id/task-auto, shows in Plan panel toolbar:- •Current iteration / max iterations
- •Elapsed time / timeout
- •Current step (from latest
.auto-signal) - •Running / stopped status
- •Stop button: sends
DELETE /api/sessions/:id/task-auto(daemon writes.auto-stop) - •Does NOT drive the loop — Claude's internal loop handles all orchestration
Cleanup
When auto mode stops (complete, blocked, cancelled, or manual stop), cleanup is split between Claude and the daemon:
Claude-side (inside the session, at loop exit):
- •Delete
.auto-signalfile if exists - •Delete
.auto-stopfile if exists (consumed, no longer needed)
Daemon-side (backend, after detecting loop exit or stop):
- •Stop heartbeat polling timer
- •Stop
fs.watchon task directory - •Remove
task_autorow from SQLite (clears all stall detection state) - •Frontend status indicator clears on next poll
The daemon detects loop exit by: (a) receiving a DELETE API call (user stop), (b) heartbeat detecting shell prompt (Claude exited), or (c) .auto-signal with next: "(stop)" (natural completion). In all cases, daemon performs its cleanup steps above.
Git
Auto mode inherits git behavior from each sub-command it invokes. No additional git commits are made by auto itself — each plan, check, exec, merge, and report step handles its own state commits on the task branch.
Server Recovery
On backend server restart, auto state is recovered from SQLite:
- •Read all
task_autorows withstatus = 'running' - •For each active row:
a. Delete stale
.auto-stopif exists intask_dir(prevents restarted Claude from immediately exiting due to leftover stop file from pre-crash state) b. Check terminal state viatmux capture-pane:- •If Claude auto session still running → re-establish monitoring (fs.watch + heartbeat)
- •If shell prompt visible (Claude exited) → restart: send
claude "/ai-cli-task auto <task_dir>"to PTY (Claude's internal loop reads.index.mdto determine resume point) c. Resetstall_countto0andlast_capture_hashto""(fresh monitoring baseline) d. Start heartbeat polling timer e. Re-establishfs.watchontask_dirfor.auto-signal
- •Resume normal daemon operation (signal watching + heartbeat polling)
On restart, Claude's auto loop re-reads .index.md and .summary.md to reconstruct context. The conversation context from the previous session is lost, but .summary.md provides the condensed recovery information.
Notes
- •Auto mode starts with a single
claude "/ai-cli-task auto <module>"CLI invocation; all subsequent steps execute within that same session - •The daemon's only active intervention is writing
.auto-stop; all other daemon activity is passive monitoring - •
.auto-signaland.auto-stopare transient files — should be in.gitignore - •The daemon logs all signal events and stall detections to server console for debugging
- •Known trade-off: First entry on
executingstatus always runscheck --checkpoint post-exec. If execution was incomplete (completed_steps< total), check will detect this and route back to exec via NEEDS_FIX, adding one extra iteration. This is acceptable because the auto skill does not re-parse plan files to count total steps at entry - •Context window overflow: If Claude's context compacts during a long auto run,
.summary.md(written by each sub-command) provides recovery context. The auto loop continues normally after compaction — each sub-command re-reads relevant files as specified in its SKILL.md