| name | auto-iterate |
| description | Execute user-directed iterative workflows until explicit completion criteria are met. Use for 自动迭代, 循环迭代, 迭代, 循环执行, 重复直到, “iterate until”, or “loop until”, including single loops, nested loops, sequential multi-loop plans, and parallel branch orchestration with isolated cron coordination, watchdog recovery, quota-aware pause/resume, and direct reporting to the original DM or group topic. |
| metadata | {"openclaw":{"emoji":"🔄"}} |
Auto-Iterate
Use this skill as a low-freedom orchestration protocol. Treat the user's loop definition and exit criteria as authoritative.
Cron path: native cron first, exec+openclaw cron CLI fallback second.
1. Admit or stop
Start only when all are true:
- The user explicitly requested looping or repeat-until behavior.
- There is at least one executable step, function, or branch definition.
- There is at least one explicit completion criterion.
- The reporting destination can be persisted as
origin.report_to.
- Required tools for the selected mode are available under effective tool policy.
Before starting any automatic iterative workflow, ask the user for clarification if the loop body, parallel loops, nested loops, or the task itself contains ambiguity, unclear logic, missing decisions, or conflicting instructions. Do not start the automated iteration until those ambiguities are resolved.
Mode:
- Spawned-worker mode — required. Requires
cron, message, sessions_spawn, sessions_history. Use sessions_spawn(..., runTimeoutSeconds=1800) unless a shorter worker budget is explicitly justified.
Fallback:
- If spawned-worker mode is unavailable, do not start automatic iteration.
Always initialize every canonical schema field explicitly. Do not rely on implicit defaults.
2. Fix the roles
Use exactly these actors:
- Origin session — validate inputs, persist routing, initialize state, install coordinator wake and watchdog, send kickoff.
- Coordinator — an isolated cron wake only. Sole writer to
STATE.md. Sole authority to transition state, monitor workers, schedule wakes, and send user-visible updates.
- Worker — spawned subagent only. Never edits orchestration state.
- Watchdog — isolated recurring cron wake that repairs liveness only.
Never let a human-facing chat session become the long-running coordinator after init.
3. Initialize in one safe transaction
Initialization order is binding:
- Create the iteration directory.
- Write initial
STATE.md with every canonical schema field explicitly initialized.
- Use
coordination.poll_complexity = moderate unless the task clearly needs another polling tier.
- Add the first isolated coordinator wake and persist its job id.
- Add the watchdog wake and persist its job id.
- Validate state and protocol.
- Only after state + coordinator wake + watchdog are durable, send the kickoff message.
If any step fails before durability is reached, stop and repair state instead of sending kickoff.
4. Keep one source of truth
Store orchestration state in exactly one fenced YAML document at STATE.md. Read from disk on every coordinator or watchdog wake. Never trust chat history.
Core statuses are running, awaiting-result, paused, and complete.
Use scripts/validate_state.py whenever state may be inconsistent, after major edits, before terminal cleanup, and whenever a coordinator suspects drift between expected and persisted state.
5. Route messages one way
Persist origin.report_to on init and never rewrite it.
The coordinator sends progress, milestone, pause, resume, repair, and completion messages directly to origin.report_to via message(action="send").
Do not let workers or watchdog send user-visible progress directly, except for the narrow watchdog emergency exception defined in references/recovery.md.
Use scripts/render_progress.py to generate user-visible messages from committed state. Keep the progress message minimal: header + optional milestone + optional worker status + in-progress summary + next action + next check.
6. Run one coordination cycle per wake
Follow this order exactly:
READ -> RECOVER -> DECIDE -> PERSIST -> SCHEDULE -> REPORT -> END
Hard rules:
- Lease TTL is 120 seconds.
- Commit state before report.
- Add successor wake before removing superseded wake.
- Make every wake message self-contained.
- Use
payload.timeoutSeconds = 1800 for coordinator and watchdog isolated cron jobs unless a clearly simpler job justifies less.
- Long business work belongs in workers, not in the coordinator or watchdog.
- In isolated coordinator wakes, do not spend the cycle on long recap, broad re-planning, or user-facing explanation before dispatch/poll/persist/schedule.
- A non-terminal coordinator cycle is invalid if it ends without at least one concrete progress action: dispatching a worker, ingesting worker output, persisting a transition, or durably scheduling the successor wake.
Coordinator workflow:
- Read
STATE.md.
- Run
scripts/validate_state.py <state_path> to validate structure.
- Run
scripts/validate_protocol.py <state_path> to validate protocol invariants.
- Choose the minimal mode for this wake:
ingest-only if a worker result already exists and only needs ingestion
repair-only if the wake chain is broken
dispatch-only if no worker exists for the current step
- otherwise normal poll/advance
- Keep the wake narrow. Do not broadly re-read docs, examples, fixtures, or CLI help unless validation itself fails.
- In
ingest-only, prioritize result ingestion before any redispatch or broader repair.
- Run
scripts/evaluate_progress.py <state_path> --json to determine actionable loops, branch readiness, and merge readiness.
- Run
scripts/check_stall.py <state_path> --json to determine whether dead-loop or no-fix-rounds policy requires pause.
- Run
scripts/check_transition.py <state_path> --event <canonical-event> --to <status> --json for every candidate non-terminal transition. Do not bypass this check.
- Persist the full next state. When a loop completes or the workflow advances to a new loop, optionally append a milestone item to
progress.pending_reports.
- Compute deterministic next-poll delay with
scripts/compute_next_poll.py --state-path <state_path>.
- Schedule the successor wake if non-terminal.
- Render the correct report text with
scripts/render_progress.py <state_path> --mode <progress|pause|resume|repair|final>. If progress.pending_reports is non-empty, prefer the oldest queued milestone/progress item over a generic progress report.
- Send one short user-visible report from committed state.
- If a queued pending report was successfully delivered, persist queue cleanup before END. This is the only allowed post-report cleanup persist.
- End.
If the wake reached END without real progress and without a durable successor wake, treat the cycle as failed and rely on watchdog repair rather than emitting a long explanatory recap.
Use references/flow.md as the binding source for the explicit state machine, canonical transition vocabulary, loop progression semantics, and dead-loop policy.
7. Use spawned workers only
Worker path:
- Spawn via
sessions_spawn.
- Track in
subagents[].
- Poll via
sessions_history.
- Treat auto-announces as best-effort diagnostics only.
If the user provides an agent identifier, agent name, or profile-like agent reference for a worker role, resolve that request as an agent-profile selection. Spawn an isolated worker that reuses the matched agent profile (agentId, default model, and static persona).
Agent-profile reuse rules:
- Resolve a user-provided agent identifier, agent name, or profile reference with
scripts/resolve_agent_profile.py after collecting the runtime-available agent list (for example via agents_list).
- Reuse only the static agent profile for the fresh spawned worker. Do not inherit live session history, pending tasks, or transient context.
- If the resolver reports ambiguity, a missing profile, or a non-spawnable profile, ask the user for clarification before starting the automated iteration. Do not silently guess.
- A user-provided agent identifier, agent name, or profile reference for a worker role overrides the default generic spawned-worker choice and must resolve to a fresh spawned worker with the matched profile. Persist the requested profile id/name, the matched profile's expected primary model, and the worker's effective model once observed. If the effective model differs from the expected primary model, persist an explicit fallback reason instead of silently accepting the drift.
Worker dispatch contract:
- Dispatch in one wake.
- If the current wake already has everything needed to dispatch the first worker safely, dispatch the first worker immediately in the current wake. Do not defer the initial worker dispatch to a future coordinator wake without a concrete blocking reason.
- Validate
running --worker-dispatched--> awaiting-result.
- Immediately persist worker-dispatched state:
status=awaiting-result, subagents[].status=accepted, started_at, and worker session metadata.
- Schedule the successor wake and END.
- In later wakes, ingest results only via
sessions_history and validate awaiting-result --worker-result--> running|paused|complete.
- Lack of a same-wake final result is normal. Do not misclassify dispatch as failure after a worker was successfully spawned and recorded.
8. Keep the watchdog alive until reporting is done
Install one recurring isolated watchdog with delivery: {mode: "none"}.
Watchdog duties:
- Detect missing or overdue coordinator wakes.
- Recreate missing wakes.
- Retain obsolete wake ids in
cleanup_pending[].
- Set
coordination.alert_needed: true when repair is triggered.
- Stay alive until both
cleanup.wake_cleanup_complete and cleanup.terminal_report_sent are true.
Use references/recovery.md for watchdog rules, repair verification, and the narrow direct-alert exception.
9. Pause and resume on quota safely
Before expensive Claude-family worker spawns or respawns, verify quota from runtime-available provider metadata.
If quota is suspended:
- Set
status: paused, resume.mode: quota-auto, resume.blocked_by: claude-quota.
- Persist
resume.resume_at from provider reset metadata, or use a conservative fallback.
- Persist enough loop and branch context to resume without external skill state.
- Validate
running -> paused with scripts/check_transition.py.
- Schedule a resume wake.
- Render and send the pause message.
On resume:
- Re-check quota.
- If clear, clear
resume.*, validate paused -> running, render the resume message, and continue.
- If still blocked, update
resume.resume_at, reschedule, and only re-report if the resume time materially changed.
10. Finish in an idempotent way
On terminal completion or terminal pause:
- Run
scripts/validate_state.py <state_path> and scripts/validate_protocol.py <state_path>.
- Move current and next wake ids into
cleanup_pending[].
- Remove non-watchdog wake ids, retrying failed removals later.
- Mark
cleanup.wake_cleanup_complete: true.
- Render the final completion message with
scripts/render_progress.py <state_path> --mode final and send it if not yet delivered.
- If final delivery fails, keep the watchdog alive and require the watchdog or next recovered coordinator wake to retry final reporting before shutdown.
- Mark
cleanup.terminal_report_sent: true only after successful delivery.
- Remove the watchdog after both cleanup flags are true.
11. Read only what you need
Read these references as needed:
references/state-schema.md — canonical YAML schema and field semantics.
references/flow.md — explicit state machine, loop progression, and dead-loop policy.
references/recovery.md — wake repair, alert lifecycle, quota pause/resume, terminal cleanup.
references/examples.md — cron payload examples, worker briefs, report templates, and script examples.
references/script-interfaces.md — short invocation contracts for the orchestration scripts; prefer this over reading full script source when you only need args/output semantics.
Use these scripts when helpful:
scripts/validate_state.py — validate STATE.md structure and required fields.
scripts/validate_protocol.py — validate protocol invariants that go beyond schema shape.
scripts/check_transition.py — validate candidate status transitions against the orchestration state machine.
scripts/evaluate_progress.py — compute actionable loops, branch readiness, and merge readiness.
scripts/check_stall.py — detect dead loops or repeated no-fix rounds.
scripts/compute_next_poll.py — compute deterministic next-poll delay.
scripts/render_progress.py — render progress, pause, resume, repair, or final messages from state.