Apply ONE operation to EVERY item of a list — the **map** (N→N). The operation is a prompt; items
come from a JSON list, a markdown checklist, or another run's output. Runs in parallel subagents or
inline in the main thread, with persistent state and cross-turn auto-continue.
USE on any "do the same thing to each of these" intent — formal OR casual: "for each X…", "per ogni…",
"go through these one by one", "do every item in TODO.md", "review each of these files", "handle all
of them", a glob, a folder. Trigger on the INTENT, then judge by count (the count gate, Step 2.5):
- 1–2 items → just do it inline, no machinery;
- a borderline handful (~3–10) → ask whether to use the durable/parallel mechanism or handle inline;
- genuinely many, or heavy/independent items → use foreach.
DON'T use when the list must first be generated from a spec (→ /agentflow:enumerate, then foreach), or you
need one combined output (→ /agentflow:reduce). For the prebuilt "review every file → digest", use /agentflow:audit.
Explicit
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Apply ONE operation to EVERY item of a list — the **map** (N→N). The operation is a prompt; items
come from a JSON list, a markdown checklist, or another run's output. Runs in parallel subagents or
inline in the main thread, with persistent state and cross-turn auto-continue.
USE on any "do the same thing to each of these" intent — formal OR casual: "for each X…", "per ogni…",
"go through these one by one", "do every item in TODO.md", "review each of these files", "handle all
of them", a glob, a folder. Trigger on the INTENT, then judge by count (the count gate, Step 2.5):
- 1–2 items → just do it inline, no machinery;
- a borderline handful (~3–10) → ask whether to use the durable/parallel mechanism or handle inline;
- genuinely many, or heavy/independent items → use foreach.
DON'T use when the list must first be generated from a spec (→ /agentflow:enumerate, then foreach), or you
need one combined output (→ /agentflow:reduce). For the prebuilt "review every file → digest", use /agentflow:audit.
Explicit invocation (`/agentflow:foreach …`) skips the count check — the user already chose the mechanism.
Make it visible: the moment you start, say so in one line (skill + run-id) so it's clear an Agent Flow
run is happening; /agentflow:board then lists every run on disk — the audit trail.
Portable bundle. To use this skill in another project, copy:
the Stop hook is wired automatically by the plugin (hooks/hooks.json)
All paths in this file are relative to the workspace root (the dir where Claude Code runs). No absolute references.
You are the orchestrator of a /agentflow:foreach run. Your only job:
resolve a (deterministic) list of items from a source,
dispatch items to subagents in parallel chunks,
persist state at every step.
The state file is the source of truth — not the conversation. You are the only writer of state. Subagents process items and return results; they NEVER write to state.
Invocation
foreachconsumes a list — it does not generate one. To produce a list from a spec, run
/agentflow:enumerate first and pass its output here. Provide exactly one source plus the operation:
Source (one of):
--items <file.json> — a JSON array of {id, data, task?}
--folder <dir> — a file kanban (todo/ / in-progress/ / done/, or a flat folder = all pending)
--source '<json>' — an explicit SourceSpec (incl. {"source":"run","cmd":"…","run_id":"…"})
Operation (the per-item instructions, one of):
--prompt "<instructions applied to each item>" — inline, the primary config
--prompt-file <path> — read the operation from a file (use for long/multi-line prompts);
mutually exclusive with --prompt
Optional knobs:--kind <code-review|…>, --model …, --subagent-type <name> (which agent
runs each item; per-item override via {subagent:…} in a checklist), --execution main-thread|subagent,
--concurrency N, --chunk-size N|auto, --max-retries N, --cache, --run-id NAME,
--no-auto-continue, --force, plus serial mode:
--serial — process one item at a time, in list order (no fan-out; forces concurrency 1,
chunk 1). Use when items must not run concurrently (shared resource, rate limit, ordering matters).
--carry — implies --serialand feeds each item the previous item's output (a sequential
scan / accumulation). Each step depends on the one before it.
--shard k/N — keep only the items at positions index % N == k. Run N terminals with
k = 0..N-1 and distinct run-ids to split one list across processes — each shard is its own
state file, so there are no concurrent writers (read-partition, no locks).
--stop-file <path> — a pause gate: while this file exists, the dispatch loop stops claiming
new items and the Stop hook does not auto-resume the run. Delete the file (and send a message)
to continue. Lets you halt/resume external workers by touching a file.
--max-usd N (also --max-tokens N, --max-agents N) — a cost cap: once the run's recorded
budget exceeds it, the run pauses exactly like --stop-file (status shows paused, the Stop hook
won't resume). Record spend with budget-add so the cap is real; raise the cap to continue.
--gate-cmd "<cmd>" --gate-every N — a mid-run integration gate: after every N completed items,
complete-batch runs the full <cmd> (e.g. a build); if it fails, the run pauses with a
gate_failure so an integration break surfaces EARLY, not only after the whole pass. Off by default.
(complete-batch returns gate + paused; fix the break and resume.)
Invoked with natural language? (e.g. /agentflow:foreach review every .cs file in src/ for bugs) —
translate the user's words into a source + --prompt, don't ask them for flags. If they name files you
can list deterministically (a glob, a folder), build the items list yourself with Glob/Grep (or use
--folder); only if the list must be generated from a higher-level spec do you need /agentflow:enumerate
first. If no source and no operation can be inferred → ask one short clarifying question.
Folder-kanban flow (--folder)
With --folder, state.json is authoritative and the engine moves the files for you,
automatically — you don't run view and you don't read the engine source. The file base is stored
in config.folder at init; every state transition projects onto the board in the same call:
claim → moves the item's file todo/ → in-progress/.
complete / complete-batch → moves it in-progress/ → done/ (a terminal fail also lands in
done/; a retried item goes back to todo/).
The subfolders are created on demand; a flat folder (no subfolders) is treated as all-pending, and
files migrate into todo//in-progress//done/ as they're worked.
Each item's data.file is its filename; data.path is the absolute path to read while processing.
view <run-id> --folder <dir> still exists as a manual resync (e.g. after editing state by hand),
but you should not need it during a normal run.
Step 0 — Load defaults
Read ${CLAUDE_PLUGIN_ROOT}/skills/foreach/defaults.md (YAML frontmatter). Extract defaults. When a value is missing in CLI or spec, use the default from here.
Override priority (high → low): CLI flag > defaults.md > the state helper's built-in fallback. If
defaults.md is missing or unparseable, use the fallback and surface a non-blocking WARNING.
Step 1 — Parse and validate
Confirm exactly one source flag (--items / --checkbox / --folder / --source) and the
operation --prompt are present.
Resolve config by priority.
If run-id is missing: derive a deterministic foreach-<8 char hash> from the source + prompt.
Step 1.5 — Task preflight enrichment
Read ${CLAUDE_PLUGIN_ROOT}/skills/foreach/task-kinds.md. Classify the user's task-prompt into one of the kinds (code-review, transformation, extraction, validation, audit, unknown).
Explicit override: if the user passed --kind <name> (CLI) or kind: <name> (spec frontmatter), use it and skip classification.
If no match OR task-prompt < 80 chars with generic verbs ("check", "look", "see if"): kind = unknown.
If kind = unknown: use AskUserQuestion with the question + options described in task-kinds.md. Map the choice to a kind. If the user picks "other" with a description: enrich using the unknown fallback.
Effective model: the kind template suggests a model (haiku/sonnet/opus). If the user did NOT force --model, use the suggested one. If they did force, honor the user's choice but log "kind=X would suggest Y, forced to Z".
Enriched task-prompt: do NOT pre-enrich manually in this step. Instead, pass --kind <name> to state/foreach.js init (Step 2). The state helper loads the matching template from task-kinds.md, prepends it to the user task-prompt, and stores the enriched prompt in state.task_prompt + the chosen kind in state.config.kind. This way the enrichment happens once, in one place, and any downstream resume (including /agentflow:pipe-spawned children whose dispatch loop bypasses this SKILL flow) uses the already-enriched prompt without re-doing the work.
Confirm to the user in a single line: run-id, kind, effective model, concurrency, chunk-size, auto-continue, first 150 chars of list-prompt and user task-prompt.
Step 2 — Resolve items, gate by count, init
Resolve the items from the chosen source — foreach does NOT invent the list. The state
helper reads --items / --checkbox / --folder / --source at init; you don't pre-generate
anything. (Need a list produced from a spec? That's /agentflow:enumerate — its items.json becomes your
--items.) A groups.json from /agentflow:group is items.json-compatible: pass it as --items, and
each item is a whole group (data: {group_id, items, size}).
Count gate (skip if the user invoked /agentflow:foreach explicitly). Read the source to get the
item count, then:
≤ 2 → do the work inline this turn; no state, no subagents.
~3–10 → AskUserQuestion: "N items — run the durable/parallel mechanism (resumable across
turns), or handle them inline now?" Proceed per the answer.
> 10 (or fewer but heavy/independent) → proceed.
This is what lets the skill trigger on a casual "do X for each of these" without forcing the full
mechanism onto a handful of items.
The state helper applies --kind (prepends the matching task-kinds.md template to --prompt and
stores the enriched prompt in state.task_prompt). If the run-id exists without --force: ask
resume (process pending) or reset (start over) — never overwrite silently.
Step 3 — Compute effective chunk_size
If config says chunk_size: <int>: use it.
If auto: compute chunk = max(1, min(50, ceil(total / concurrency))).
Example: 1000 items, concurrency 4 → chunk = 50 → 20 chunks total in 5 waves.
Operation config & execution mode
The operation applied to each item is, first and foremost, a prompt (--prompt, the
instructions). --model and --subagent-type are optional. --execution chooses how the work runs:
subagent (default): fan claimed items out to parallel Agent calls (the dispatch loop below).
main-thread: the orchestrator processes each claimed item inline — read it, do the work
in this thread, complete it — with no Agent dispatch. Use for cheap/short operations or when
you want everything in one context. The state mechanics (claim → complete-batch) are identical;
only who does the work changes. Read config.execution and branch accordingly.
Serial / carry (config.serial / config.carry): when either is set, do not fan out. Process
one item at a time in list order using claim-serial (see Step 4b). serial alone is a throttle
(items stay independent); carry additionally threads each item the previous item's result. These
work with either execution mode (a single subagent per item, or inline).
Step 4 — Dispatch loop
For each iteration (safety cap: max 100):
Status check:
node "${CLAUDE_PLUGIN_ROOT}/dist/state/foreach.js" status <run-id>
If pending == 0 && in_progress == 0: exit the loop, go to Step 5.
If paused == true (a --stop-file is present): stop claiming, report the run is paused, and
exit — the Stop hook will not auto-resume until the file is removed. (Same check applies in Step 4b.)
Output: JSON array of items just marked in_progress.
Split into chunks: divide the array into at most concurrency chunks, each with up to chunk_size items. If claim returned fewer items than expected (end of queue), make smaller chunks — one chunk per Agent.
Prepare chunk files: write each chunk (array of items) to .agentflow/foreach/<run-id>/wave-<W>-chunk-<N>.json via Write. Subagents read this as compact input; the orchestrator keeps it as reference if a subagent fails to write.
Parallel fan-out: launch one Agent per chunk, all in the same message (single message, multiple Agent tool uses). For each Agent:
subagent_type: from config (default general-purpose)
model: from config if not inherit, otherwise omitted
description: short, format enum:<run-id>:chunk-<N>
prompt: self-contained (the subagent does not see this conversation). Include:
the enriched task-prompt from preflight (see Step 1.5)
chunk file path: .agentflow/foreach/<run-id>/wave-<W>-chunk-<N>.json (list of {id, data})
"Run the analysis silently. DO NOT comment while working. DO NOT emit draft output."
"When done, write the result to .agentflow/foreach/<run-id>/results-chunk-<N>.json via the Write tool: a JSON array [{"id": "...", "ok": true|false, "result": <any>, "error": <string|null>}, ...] covering ALL items in the chunk."
"The array MUST be the ONLY thing in the file. No prose, no markdown fence."
"Your final response to the orchestrator must be: a single line OK <N> where N is the count of items processed. Nothing else."
Record budget + commit results (single-writer model, bulk): for each completed chunk N, do BOTH of:
6a. Budget: every Agent tool return includes a <usage>total_tokens: N ...</usage> block. Extract total_tokens and record it as a budget event:
Do this once per Agent return (one budget-add per chunk). Cost tracking aggregates across all chunks; /agentflow:inspect budget <run-id> will show the cumulative figures.
complete-batch reads the array and commits in one shot (atomic save). Items with ok: false are placed in retry/failed automatically following max_retries.
Order matters: record budget first (always succeeds even if the result file is malformed), then commit state. That way a parsing failure does not lose the cost signal.
Degenerate cases:
File results-chunk-<N>.json missing or unparseable: mark every item in the chunk as fail --retry with error "agent crashed / no result file". Use claim + manual fail --retry for each item in the chunk.
File present but only covers M < N items: complete-batch applies the M present; the rest stay in_progress. Mark them manually as fail --retry with error "missing in agent output".
Continue?: if auto_continue == false, exit and show status. Otherwise go back to step 1.
Step 4b — Serial / carry dispatch (when config.serial or config.carry)
If either flag is set, replace Step 4's wave/fan-out with this one-at-a-time loop (no parallel
Agents). Each iteration handles a single item, in list order, and is resumable across turns:
Returns {item, prev_id, prev_result}. If item == null → done, go to Step 5. prev_result is the
output of the item that ran just before this one (reconstructed from disk, so it's correct even after
a resume).
Process the item (one item, so no chunk file needed):
config.execution == "subagent": dispatch one Agent for this item (same self-contained prompt
strict I/O rules as Step 4.5, writing a 1-element results array).
config.execution == "main-thread": do the work inline.
If config.carry: prepend the previous result to the operation, e.g. "Previous item's output
(build on it): <prev_result>". On the first item prev_result is null — say "this is the first item".
Commit with complete <run-id> <item-id> --result '<json>' (or fail … --retry), record budget,
then loop to 1. Honor auto_continue exactly as in Step 4.7.
Because items are committed one by one, the Stop hook resumes mid-list cleanly and claim-serial
re-hands an interrupted in_progress item without double-counting attempts.
Sharding across terminals (--shard k/N)
To split one big list across N parallel terminals/sessions, init N separate runs with distinct
run-ids, each taking one shard of the items (positions where index % N == k):
Each run is its own state.json, so there are no concurrent writers (read-partition, no locks). The
shards are disjoint, so even a --folder source is safe (each terminal only moves its own files).
Pair with --stop-file to pause every worker by touching one file. /agentflow:board shows all shards.
Step 5 — Final report
node "${CLAUDE_PLUGIN_ROOT}/dist/state/foreach.js" status <run-id>
node "${CLAUDE_PLUGIN_ROOT}/dist/state/foreach.js" list <run-id> --status failed --limit 20
Print: totals per status, and — if any failed — a compact list with error truncated to 200 chars.
Cross-turn auto-continue
A Stop hook (${CLAUDE_PLUGIN_ROOT}/dist/hook/continue.js) exists that:
at the end of each turn, scans .agentflow/foreach/,
if it finds a run with auto_continue=true and residual work,
forces Claude to continue in the next turn with the instruction "resume /agentflow:foreach ".
Cap: max_auto_continues per run (default 20). Beyond that, the hook stops.
When this hook re-activates you (you'll see a system message with the run-id):
DO NOT re-init. Go directly to Step 4 (dispatch loop) for the given run-id.
If you see items in_progress inherited from a prior turn that died midway: