AgentSkillsCN

auto

自主执行循环——单次 Claude 会话即可在内部统筹规划、检查与执行的全流程。

SKILL.md
--- frontmatter
name: auto
description: Autonomous execution loop — single Claude session orchestrates plan/check/exec cycle internally
arguments:
  - name: task_module
    description: "Path to the task module directory (e.g., AiTasks/auth-refactor)"
    required: true
  - name: action
    description: "Action: start, stop, or status"
    required: false
    default: start

/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

code
/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

code
┌─────────────────────────────────────────────────┐
│  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

AspectMulti-session (old)Single session (current)
ContextLost between steps, rebuilt from .summary.mdNaturally shared across all steps
Token costRe-read files each step, duplicate context loadingRead once, incrementally update
CoherenceEach step is blind to implicit decisionsClaude remembers why it made choices
LatencyShell prompt wait + Claude startup per stepZero inter-step overhead
Daemon complexityCommand construction + dispatch + readiness checkJust 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:

json
{
  "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-signal in manual execution
  • timestamp: ISO 8601

The daemon reads this via fs.watch to:

  1. Update progress display (iteration count, current step, elapsed time)
  2. Check iteration limit (iteration >= maxIterations → write .auto-stop)
  3. Check timeout (elapsed >= timeoutMinutes → write .auto-stop)
  4. Update last_signal_at in 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:

json
{
  "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:

FieldValidationAllowed Values
stepWhitelistplan, check, exec, merge, report
resultWhitelistPASS, NEEDS_REVISION, ACCEPT, NEEDS_FIX, REPLAN, BLOCKED, CONTINUE, (generated), (annotations), (done), (mid-exec), (step-N) (where N is integer), (blocked), success, conflict
nextWhitelistplan, check, exec, merge, report, (stop)
checkpointWhitelist"", post-plan, mid-exec, post-exec
iterationInteger≥ 0
timestampFormat checkISO 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.md for 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.md for the full context management strategy, quota exhaustion handling (daemon + Claude behavior), and SQLite quota_wait_since extension.

State Machine

code
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:

code
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 StatusFirst Step
draftValidate .target.md has substantive content (not just template placeholders) → if empty, stop and report "fill .target.md first". Otherwise execute plan (generate mode)
planningExecute check (post-plan)
reviewExecute exec
executingExecute check (post-exec)
re-planningRead phase field: if needs-plan → execute plan (generate); if needs-check → execute check (post-plan); if empty → default to plan (generate, safe fallback)
completeExecute report, then stop
blockedStop loop, report blocking reason
cancelledStop loop

Result-Based Routing

After each step, Claude evaluates the result and determines the next step internally:

stepresultnextcheckpointRationale
checkPASSexecPlan approved, proceed to execution
checkNEEDS_REVISIONplanPlan needs revision, re-generate first
checkACCEPTmergeTask verified, merge to main
checkNEEDS_FIXexecmid-exec / post-execMinor issues, re-execute to fix first
checkREPLANplanFundamental issues, revise plan
checkBLOCKED(stop)Cannot continue
check (mid-exec)CONTINUEexecProgress OK, resume execution
check (mid-exec)NEEDS_FIXexecmid-execFixable issues, exec addresses then continues
check (mid-exec)REPLANplanFundamental issues, revise plan
check (mid-exec)BLOCKED(stop)Cannot continue
plan(any)checkpost-planPlan ready, assess it
exec(done)checkpost-execAll steps completed, verify results
exec(mid-exec)checkmid-execSignificant issue encountered, checkpoint
exec(blocked)(stop)Cannot continue
mergesuccessreportMerge complete, generate report
mergeconflict(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:

  1. Read .auto-signal — the iteration field gives the last completed iteration count; step and next give the position in the loop
  2. Read .index.md — status confirms the current lifecycle phase
  3. Read .summary.md — condensed task context from the last sub-command
  4. Resume the loop from next step at iteration + 1

Backend REST API

MethodEndpointDescription
POST/api/sessions/:id/task-autoStart auto mode for a task module
DELETE/api/sessions/:id/task-autoStop auto mode (writes .auto-stop)
GET/api/sessions/:id/task-autoGet 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:

json
{
  "taskDir": "/absolute/path/to/AiTasks/module-name",
  "maxIterations": 20,
  "timeoutMinutes": 30
}
FieldTypeDefaultDescription
taskDirstring(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
maxIterationsnumber20Max plan/check/exec cycles before forced stop
timeoutMinutesnumber30Total 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:

  1. Validate: check no active auto loop for this session or task_dir
  2. Insert task_auto row into SQLite
  3. Send claude "/ai-cli-task auto <taskDir>" to the session's PTY
  4. Start fs.watch on taskDir for .auto-signal changes
  5. 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

sql
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-stop when reached
  • Timeout: user-configurable (default 30 min), daemon writes .auto-stop when elapsed
  • Stall detection: heartbeat polling (60s) + pattern matching recovery, with per-iteration (3) and total (10) recovery limits
  • Context management: proactive /compact at ≥ 70% context window usage, with .summary.md as 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 blocked status (Claude's internal loop exits)
  • Manual override: User can /ai-cli-task auto --stop at any time, or daemon writes .auto-stop via DELETE API
  • Graceful stop: Claude checks for .auto-stop before 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, POST returns 409 Conflict
  • Single instance per task: UNIQUE constraint on task_dir prevents 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 maxIterations and timeoutMinutes with 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):

  1. Delete .auto-signal file if exists
  2. Delete .auto-stop file if exists (consumed, no longer needed)

Daemon-side (backend, after detecting loop exit or stop):

  1. Stop heartbeat polling timer
  2. Stop fs.watch on task directory
  3. Remove task_auto row from SQLite (clears all stall detection state)
  4. 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:

  1. Read all task_auto rows with status = 'running'
  2. For each active row: a. Delete stale .auto-stop if exists in task_dir (prevents restarted Claude from immediately exiting due to leftover stop file from pre-crash state) b. Check terminal state via tmux 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.md to determine resume point) c. Reset stall_count to 0 and last_capture_hash to "" (fresh monitoring baseline) d. Start heartbeat polling timer e. Re-establish fs.watch on task_dir for .auto-signal
  3. 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-signal and .auto-stop are 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 executing status always runs check --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