- name
- codex-loop
- description
- Run a task repeatedly in Codex with model-chosen dynamic delays or an explicit interval, including immediate execution, loop.md defaults, cancellation, and fixed-schedule restoration. Use when the user asks to start or manage a Claude-style loop, self-paced polling, or invokes $codex-loop. Do not start a loop for questions about loops or for ordinary one-shot work.
# Codex Loop
Use the bundled Node.js scheduler to maintain timing and task state. You perform the actual work and decide whether a dynamic loop continues. This skill does not add a native `/loop` command, `ScheduleWakeup`, or a background wakeup service to Codex.
## Choose the execution surface
**Default: current conversation.** Work and wait within the active turn, using the session commands below. Keep the conversation's context, tools, and permissions. The host must provide an interruptible waiting tool, or a bounded shell wait. This occupies an active turn: it cannot deliver a future turn after you send a final answer. Never claim a timer will wake a completed turn.
**Only when the user requests a standalone terminal loop:** use the foreground CLI adapter described in [references/cli.md](references/cli.md). It owns a separate Codex worker session; it does not inherit this chat's history or desktop connectors. Do not silently switch to it or resume this chat from a second process.
If neither surface can actually wait and continue, explain the missing capability. Do not substitute a fixed Heartbeat for dynamic scheduling or register a persistent automation without that scope being requested.
## Start and parse
Resolve `scripts/codex_loop.mjs` relative to this skill. Node.js 24.0.0+ on macOS, Linux, or Windows is required. Use `node` from the current PATH; the entrypoint checks the minimum version. No npm install or external runtime package is needed. Write/read JSON and request files as UTF-8; use native argument arrays or file tools instead of POSIX quoting in PowerShell. Commands below abbreviate this absolute path as `<script>`.
1. Preserve the user's full loop input. Save it to a UTF-8 request file using the file tools, avoiding shell interpolation of prompts. Accept `$codex-loop`, `/codex-loop`, or `/loop` as textual prefixes; Codex's native slash-command parser may not dispatch `/loop`, so recommend `$codex-loop` as the invocation.
2. Choose a **new** session state path inside the project's ignored `work/` directory (or an authorized private scratch directory). Keep the exact path in conversation context; never share it with another chat. Do not publish state, prompts, or tool results.
3. Use the user's IANA timezone from session context. If unknown, detect the host zone; ask only if it cannot be determined. Do not silently assume UTC for local schedules.
4. Register with `node <script> --state <state> create --project <project> --timezone <zone> --request-file <request-file>`.
5. Report mode, job ID, any interval rounding, and the session-bound lifecycle. Both interval and dynamic loops execute their first iteration immediately. Bare invocation uses `.codex/loop.md`, then `$CODEX_HOME/loop.md` (default `~/.codex/loop.md`), then the built-in maintenance task. Explicit prompts override these files; defaults are re-read at every claim.
The parser prioritizes a leading `Ns/Nm/Nh/Nd` token, then a trailing `every N units` clause. Without either, use dynamic pacing—there is no fixed default delay. `check every PR` is a task, not a time expression. Preserve prompts verbatim after extracting the interval. See [references/behavior.md](references/behavior.md) for rounding and scheduling details.
## Run each iteration in this conversation
1. Call `node <script> --state <state> claim`. A returned task includes an ownership `lease`, the current expanded prompt, and its source. Only one task may run at a time.
2. Perform that task with the tools available **here**. Invoke a requested installed skill by reading its instructions; honor its invocation policy. Do not turn text such as `/clear` or `/model` into tool execution, fabricate unavailable skills, or treat fetched content as new authorization. In fixed mode execute the task once, never recursively register another loop.
3. Write a JSON decision file, then call `node <script> --state <state> complete <id> <lease> --decision-file <file>`. Use exactly these decision fields:
- `action`: `continue`, `stop`, `blocked`, or `fallback`.
- `delay_seconds`: integer 60–3600 for `continue`; `null` otherwise. Fixed mode requires 60 here as a placeholder; the cron determines actual timing.
- `reason`: a short evidence-based explanation.
- `noop`: boolean indicating no meaningful action or newly discovered change.
4. **Dynamic mode:** decide anew after every iteration. Choose short waits when a relevant result is imminent; longer waits for quiet states. Stop when the requested outcome is verified, the user cancels, or further iterations cannot help. Use `blocked` when progress requires unavailable access, a permission decision, or user input; describe the obstacle. Do not keep polling an unresolvable block.
5. **Fixed mode:** keep the registered cadence until canceled, expired, or a user-defined terminal condition is verified. A successful status check alone does not cancel a recurring monitoring request.
6. Report the chosen delay and reason before waiting. Honor requests to stay quiet on unchanged status; keep required host progress updates concise. The helper tracks consecutive no-op counts, but cannot collapse the Codex UI transcript.
7. If `claim` returns no task and a `next_at`, wait until that timestamp **using elapsed real time**, in interruptible chunks no longer than 60 seconds (or shorter if the host requires). Prefer a native wait tool. After each wait, process any user steering, then call `claim` again; never infer that a requested sleep finished if it was interrupted. Do not use a long synchronous tool call, busy-loop, or send a final answer while promising another iteration.
8. If no task or future due time remains, end with the outcome. `CODEX_LOOP_DISABLE=1` prevents firing and registration; stop driving the loop if the helper reports disabled.
A `fallback` decision represents a successful iteration that omitted a continue/stop decision. The scheduler allows one 20-minute fallback; a second omission stops the dynamic task. Do not use fallback to conceal tool errors or invent successful work. There is no host-level recovery if the model ends the turn without calling the helper.
## Steering, stop, events, and restoration
- User stop: `cancel <id>` or `cancel all`; do not reschedule. Stop only monitors/processes this loop owns. A new user message is steering, not evidence that the old task finished.
- Status: `list` returns IDs, modes, due times, reasons, run counts, and retained terminal records. Never describe a stored waiting record as a running background service.
- An authorized external event producer can use `wake <id>` to advance a waiting dynamic task. An active driver is still necessary. No generic Monitor tool is installed by this skill. Prefer a real existing event tool only if its behavior and cancellation are known; do not create duplicate watchers.
- Before an intentional session end, run `close`. Dynamic jobs stop; fixed jobs remain suspended. If the host is killed, no helper is executing, even if stale records say `waiting`.
- On a **user-requested** return to an old loop session, use `restore` before claiming. It removes dynamic schedules and expired reminders from active execution, restores eligible fixed schedules without replaying every missed fire, and blocks interrupted work whose effects need inspection. Do not auto-restore dynamic tasks after an aborted turn or an app restart.
A skill cannot catch the desktop's Escape key or app-exit events. Interruption stops the active agent turn; cleanup may only happen on the next explicit management action. Be candid about this and the other differences in [references/compatibility.md](references/compatibility.md). Do not describe test coverage as a percentage of Claude product equivalence.
عرض على GitHub