prun (parallel run)
SkillProductivityLets your agent split a big task into pieces and run them in parallel on worker agents while it coordinates.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the prun (parallel run) skill
About this capability
Parallel delegation fan-out. The Claude session coordinates (on whatever Claude model is currently selected, e.g. Opus or Fable) while task units run in parallel on workers (never on the coordinator). Codex (`codex exec`, a separate abundant account) is the prioritized default; Sonnet is reserved fo
What this skill tells your AI
The instructions your AI receives, as published by yzhao062/anywhere-agents in skills/prun/SKILL.md and read by ahel’s review.
Overview
prun fans a task out into independent units that run in parallel while the current session only
coordinates. Every worker is an Agy process running Gemini through the Antigravity CLI, on the
Google AI plan authenticated in agy. The coordinator decomposes the task, dispatches the units,
gathers their results, reviews their diffs, and integrates. It never runs a unit itself.
No Claude-side workers. A Sonnet subagent, a Workflow agent, or any other Agent-tool worker draws
on the same Claude account as the coordinating session, so a fan-out of them spends that account's
quota at the rate of the fan-out. That is the pool the coordinating session itself needs, and it
drained fast once prun routed units to Sonnet. Codex is not a prun executor either; its
higher-cost quota is reserved for the default /vet gatekeeper role. Exact plan buckets can change,
so inspect current Agy quota before a large batch.
Relationship to the native Workflow tool
The native Workflow tool fans a task out across Claude subagents under a deterministic script, with structured output, judge panels, and resume. A Workflow run counts against the Anthropic plan's usage and rate limits, and its agents use the session model unless the script routes a stage to a different Claude model.
prun is the fan-out that stays off that account. Its units run on Agy and use the Google AI plan;
the coordinating session spends only the small Anthropic amount it needs to decompose, dispatch,
read results, and integrate. prun therefore never starts a Workflow or a Claude subagent, not as a
unit, a fallback, or a second panel. When the user explicitly asks for a Claude panel, that is a
Workflow run the user asked for, and it happens outside prun. A cross-vendor read on staged work
is what /vet is for.
When the Agy Gemini group cannot accommodate the next batch, queue or defer units instead of moving
them onto the Claude account. Read the meter with agent-quota, including snapshot age and reset
times, and do not silently shrink a genuinely parallel task to an arbitrary two or three workers.
The dispatcher's own quota route, described under dispatch-task usage, already stops a unit from
launching into an empty group.
When to use
Use prun when the task splits into independent units that can run at once (different
modules, separate research questions, parallel analyses). Units may be heterogeneous, and there
can be many of them: a dozen or twenty in parallel is normal when the task warrants it.
Do not use prun when the task is one sequential unit, or units depend on each other's output,
or a unit's result cannot be checked without redoing it.
Executors
| Executor | Quota | Notes |
|---|---|---|
Agy (agy) | Google AI plan authenticated in Antigravity | The only worker. Gemini 3.8 Flash High at high effort; fast, separately funded, and dispatched with full unattended tool permission inside a scratch dir or throwaway clone. |
| Claude session (this session) | Current Claude account; check Settings > Usage for the applicable limits or credits | Coordinator and integrator only, on whatever model is selected. Never a unit. |
Rules:
- Every unit runs on Agy. Research, verification, extraction, cross-checks, and code-writing
units in a throwaway clone all go through
dispatch-task-agy. The dispatcher gives a unit the same unattended capability as the/vetAgy reviewer, so it can verify numbers, run experiments, and fetch the web. Agy defaults togemini-3.8-flash-highat the CLI's maximumhigheffort. - Never a Claude-side worker. Do not spawn an Agent-tool subagent (Sonnet or any other model) or a Workflow agent for a unit, including as a fallback when the Agy pool is short. Those workers spend the coordinating session's own Claude account. When Agy cannot take a batch, queue it or tell the user.
- Codex is excluded from prun. Its quota is intentionally reserved for the
/vetreviewer role. Do not route a prun unit tocodex exec, even if a legacy dispatcher remains on disk for compatibility with old state directories. - Session-internal tools stay outside the fan-out. An Agy process cannot use the coordinator's
MCP, email connectors, or Artifact tool. Gather what a unit needs from those tools in the
coordinating session before dispatch, and put it in the unit prompt; leave a small action that
needs them to the coordinator as one inline step. A task whose substantive work needs those tools
throughout is not a
pruntask. - Keep the Agy pool busy with follow-up turns. Units return at different times. When one returns
while others are still running, dispatch a follow-up unit rather than idling, provided the
follow-up discharges real work: an acceptance criterion the result left open, a claim it made
without evidence, a source it cited but did not fetch, a check it proposed but did not run, or
the next independent unit in the queue. A slower sibling is not by itself a reason to invent
work.
--continue-from <state-dir>resumes the same conversation, so the follow-up keeps the earlier context; a fresh prompt with a fresh result path is the alternative. Record each follow-up in the ledger like any other unit. - The Claude session stays the coordinator, never a unit. Independent substantive work belongs in Agy workers.
Why Agy alone. Its pool is separate from the Claude plan, it is fast, and it adds an independent
model family without spending the higher-cost Codex pool used by /vet. The earlier split put
Sonnet beside Agy on the grounds that the two draw on separate pools. They do, but Sonnet's pool is
the coordinator's own Claude account, so every Sonnet worker spent the quota the coordinating
session runs on, and a wide fan-out consumed it quickly. The coordinator still reviews every result
and every diff. Check current quota before a large batch, but do not convert changing meter
readings into an arbitrary low worker cap.
Concurrency
The orchestrator decides the unit count autonomously. Partition the task by dependency structure (split only along genuinely independent boundaries) and balanced workload (roughly equal-sized units, each worth a full worker run). High autonomy is the intent: do not target a fixed number, and do not cap artificially. A dozen-plus in parallel is fine when the task genuinely decomposes that way.
Two soft bounds, not hard rules: local CPU/RAM (enough concurrent workers eventually contend and
the excess queues) and the headroom of the Agy pool. agent-quota reads the current snapshot of
both Agy groups. The usual real ceiling is
integration bandwidth, since the orchestrator must read and reconcile every result, so
prefer fewer well-scoped units over many tiny ones. Over-splitting into trivial units wastes
worker startup and tends to produce thin results. Dispatch in batches that fit the runtime's
concurrent-worker limit and the available quota, and leave the rest queued; a runtime's in-flight
limit is separate from how many units a run may have in total.
What a unit may do, and the one rule
A unit may read or write code, run commands, and fetch the web, with full access. The single
hard rule: a worker never commits, pushes, or runs destructive git (commit, push,
branch/tag mutation, reset --hard, clean). Everything else is allowed. The final gate is
the Claude session integrating the results and the user deciding; workers never touch the real repo history.
This is enforced structurally, not by trust:
- Read-only / research units run from a per-unit scratch cwd, so accidental writes stay out of
the repo.
dispatch-taskdoes this by default. - Code-writing units run inside a throwaway local clone of the repo with its remote removed:
The worker edits freely in the clone. An accidentalgit clone --local -c core.longpaths=true <repo> <clone-dir> # longpaths: Windows MAX_PATH safety git -C <clone-dir> remote remove origingit pushhas no remote to reach (GitHub / Overleaf stay untouched); an accidentalgit commitonly lands in the throwaway clone. The coordinator readsgit -C <clone-dir> diff, integrates the wanted changes into the real tree, and the user approves the actual commit. That is the only gate.
No credential scrubbing or sandbox wall: the user writes the prompts, the clone has no path to the real remotes, and the Claude session plus the user are the integration gate. That is the whole safety model.
Flow
- Gate: confirm the task splits into independent, checkable units. Else use a single worker.
- Decompose: write one prompt per unit. State the task; for a code-writing unit, that the working dir is a throwaway clone to edit freely but not commit or push; that the unit writes a result summary to its result file (a fresh path, in one write).
- Assign: every unit goes to Agy. Gather anything a unit needs from session-internal tools first and write it into that unit's prompt. Pick read-only (scratch) or code-writing (clone) mode, and record the mode in the ledger.
- Dispatch in parallel: run
<python> scripts/dispatch-task-agy.pyin the background for each unit. With no--modeit runsaccept-editswith--dangerously-skip-permissionsin a scratch directory it creates. A caller-supplied workspace, meaningPRUN_SCRATCH_CWD(a throwaway clone for a code-writing unit) or--add-dir(a clone or snapshot the unit should see), requires an explicit--mode accept-editsor--mode plan, so the write-capable mode is a named choice for any directory the dispatcher did not create.--continue-from <state-dir>resumes an earlier unit's conversation for a follow-up turn. - Monitor (do not go idle): launch
scripts/monitor.{sh,ps1} <state-dir> ...in the background (run_in_background=true) and wait on its completion. It wakes you on the first actionable event: all done, any unit stalled (tail no-growth forPRUN_STALL_THRESHOLD, default 10 min), or any unit failed (FALLBACKresult or dead dispatch), printing a per-unit digest. On a stall, surface it to the user with a likely cause (capacity or concurrency pressure; suggest lowering the worker count or re-dispatching) rather than waiting silently; act, then re-launch the monitor on the still-running units until all are done.monitoronly observes. The Agy dispatcher relies on the CLI's bounded--print-timeout; it does not scan for or terminate unrelated agent processes. (gather.{sh,ps1}remains for the plain wait-for-all case.) - Reconcile, then integrate: before integrating, reconcile the ledger: every dispatched unit
must have a non-empty result. If any is missing or empty, do not integrate the partial set;
recover the worker's output from its
<state-dir>/tail(dispatch-task-agy also salvages the tail into the result file automatically under aFALLBACKheader). If no usable result can be recovered, re-dispatch that unit or flag the user. Then the coordinator reads each result plus each clone'sgit diff, merges the wanted changes into the real tree, runs verification, and asks the user before any commit.
Resolve scripts via this order, first hit wins: skills/prun/scripts/, then
.claude/skills/prun/scripts/, then .agent-config/repo/skills/prun/scripts/.
dispatch-task usage (Agy)
<python> scripts/dispatch-task-agy.py --prompt-file <prompt> --result-file <fresh abs result> --unit-id <id>
- Emits exactly one stdout line
STATE-DIR <abs-path>; Agy stream events and stderr land in the state directory, the conversation id from Agy'sinitevent is recorded to<state-dir>/conversation-id, and the final response is published atomically to the result path. - Defaults to
gemini-3.8-flash-highathigheffort. Override withANTIGRAVITY_DISPATCH_MODELandANTIGRAVITY_DISPATCH_EFFORT. Agy takes--effortfor its Gemini models only, so the dispatcher omits the flag for the second group below rather than having Agy reject the whole call. - Agy Ultra exposes a second quota group for
claude-sonnet-4-6,claude-opus-4-6-thinking, andgpt-oss-120b-medium, metered apart from the Gemini group. A unit that names no model goes to whichever group has the freer meter, withclaude-sonnet-4-6as the second group's model. A unit is shallow work that either group handles, so the meter decides rather than the model family. The worker is the Agy CLI either way, so a Claude model here spends Agy quota and never the Claude account the coordinator runs on. This is a routing policy the user set on 2026-09-15, after a 198-unit batch spent 77 points of the Gemini five-hour meter in an hour while the second group sat untouched. An agent still does not reach for that group on its own outside this rule: one that did spent 646 generations of it in a day.ANTIGRAVITY_DISPATCH_MODELdisables headroom balancing for the run. The exhaustion rules below still apply to the model it names, including the fallback from an exhausted Claude and GPT group to Gemini. - The dispatcher checks group quota before launching. The two groups are
metered separately, and one dispatch names one model, so a batch aimed at an
empty group fails once per unit: on 2026-09-11 four units of a seven-unit
fan-out died in a row, each carrying
Individual quota reached ... Resets in 34m. Before launching, the dispatcher reads the snapshotagent-quotamaintains and decides:- No model was named: each unit starts from the Gemini default. When both
groups are reported, it moves to
claude-sonnet-4-6if the second group's lowest remaining fraction is at least 15 points higher, or if Gemini is empty and the second group has quota left. A move on headroom also needs both metered windows of the destination present in the snapshot, since a group entry is its emptiest bucket and an unreported window may be the empty one. An empty own group moves the unit without that evidence, because the alternative is not running at all. Units decide independently, so successive readings can switch the group a batch is using. The lineMODEL-BALANCE from=... to=... reason=freer-meter own=... other=...goes to stderr and to<state-dir>/quota-note. - A named model in the Claude and GPT group, with that group empty and Gemini
not: dispatch the Gemini default instead, and record the swap. The line
MODEL-FALLBACK from=... to=... reason=claude-and-gpt-quota-exhausted resets=...goes to stderr and to<state-dir>/quota-note.<state-dir>/modelalways names the model that actually ran, so the ledger's executor column is not the model the caller asked for when the two differ. - A named Gemini model whose group is empty: exit
75without launching, and say so. A model someone chose is not escalated into the metered group on its own; the message namesANTIGRAVITY_DISPATCH_MODELfor the operator who wants that. - Both groups are empty: exit
75with both reset times. - A group the snapshot does not report is unknown rather than empty, and an
unreadable snapshot skips the check entirely. The gate stops a dispatch
only into a group it read as empty.
PRUN_AGY_QUOTA_GATE=offdisables it. A run that fails at the backend forces a snapshot refresh before exiting, past the readout's own five-minute TTL, because the meter it just hit is newer evidence than the snapshot. Later units then route on what it recorded. This is not a guarantee: a refresh that cannot run, a meter that is unavailable, and units already in flight can still produce repeated quota errors.
- No model was named: each unit starts from the Gemini default. When both
groups are reported, it moves to
--modedefaults toaccept-editswith--dangerously-skip-permissions, the same unattended capability the implement-review Gemini reviewer already runs with, so a unit can verify numbers, run experiments, and fetch the web without a permission prompt. The default applies only to the scratch directory the dispatcher creates. When the caller supplies a workspace throughPRUN_SCRATCH_CWDor--add-dir, the dispatcher refuses to launch until--modeis given, because the write-capable mode could otherwise reach a directory it did not create. Safety stays structural either way: point those at a throwaway clone with no remote or a read-only snapshot, never the real tree.--mode planis the strictly read-only opt-in; it keeps request-review permissions and never gets the skip flag. In headless use a tool request that needs an approval nobody can give (run_command,read_url, browser tools) is denied, and the process can still exit 0 with a normal-looking result that reports it could not verify. A normal result file therefore does not prove those checks ran; read itsVerificationandOpen itemsfields. If the worker has not written a non-empty result file, a missing, empty, or shorter-than-20-byte final response producesFALLBACK, and so does a finalresultevent whosestatusis notSUCCESS. A standingpermissions.allowrule in Agy's ownsettings.json(~/.gemini/antigravity-cli/settings.json, entries such asread_url(*)orcommand(*)) is the alternative for a plan-mode unit.--add-dir PATH(repeatable) adds a directory outside the unit's working directory to its workspace without copying a repository into the scratch area, in either mode; it requires an explicit--mode. Point it at a clone or a read-only snapshot, never the real tree, sinceaccept-editscan write there. The dispatcher resolves each path to absolute and refuses to launch if it is empty or not an existing directory.--continue-from STATE_DIRresumes the conversation recorded at<STATE_DIR>/conversation-idfor a follow-up dispatch that should keep the earlier turn's context instead of re-embedding the prior result in a new prompt. It still needs its own fresh--result-file; an emptySTATE_DIRargument, or one whose conversation id file is missing or empty, is a pre-launch error.- Requires a fresh result path and refuses to overwrite an existing result. The final response is
published to that path, unless the worker already wrote a non-empty result file there itself: then
the worker's file is kept and the final response lands beside it as
<result>.response.<ext>, so a one-line closing reply never replaces a full result. If no non-empty worker result exists, a failed preflight, launch, worker run, or timeout, or an unusable final response, produces an atomicFALLBACKresult with captured tails. - Both signals decide the outcome. A non-zero process exit fails the unit, and after an exit of 0
the final
resultevent'sstatusis consulted, because Agy exits 0 when it stops on a quota limit and thatERRORevent still carries the opening narration inresponse. Publishing that response would hand the coordinator work that never happened. Any status other thanSUCCESSfails the unit and carries the event'serrortext into theFALLBACKresult. The one exception is a status that is missing or blank, which counts as success so that an older Agy keeps working. - A failed run whose worker had already written its own result keeps that file, because the worker
may have finished before the backend stopped. The partial response lands beside it as
<result>.response.<ext>, and the dispatcher exits non-zero with the backend error on stderr. Both monitors classify a stable worker-written result asdonewithout reading the backend status. Before integrating such a unit, wait for the dispatcher to finish and check its exit code. When that code is unavailable, read theresultevent'sstatusanderrorin<state-dir>/tailand the captured dispatch diagnostics. The sibling response is supporting context: a successful run writes one too, and it records no status. ANTIGRAVITY_DISPATCH_TIMEOUT_SECONDSdefaults to 2700 and is passed to Agy's bounded--print-timeout. The dispatcher never enumerates or terminates another agent process.- The dispatcher omits Agy's
--sandboxflag by default. On Windows that sandbox starts an elevated admin broker and raises a UAC prompt for every unit that runs a command; a declined prompt fails the command.PRUN_AGY_SANDBOXcontrols whether the flag is added; it does not disable a sandbox enabled in Agy's own settings (enableTerminalSandbox). Accepted values are1/true/yes/onto add the flag and0/false/no/off, empty, or unset to omit it. Values ignore case and surrounding whitespace; anything else exits 2 before state creation or launch. Scratch directories and throwaway clones reduce accidental changes to the working repository. They do not enforce filesystem or network isolation; the worker must follow the prompt's ban on commit, push, and destructive git. - The legacy
dispatch-task.{sh,ps1}Codex scripts remain shipped only so older deployments and state directories retain their recovery tooling. Currentprunrouting never selects them.
gather usage
scripts/gather.sh <result-file-1> <result-file-2> ...
- Prints
GATHER-START count=N timeout=Ss, thenDONE <abs-path>per file as it lands; exits 0 when all land, exits 2 withTIMEOUT remaining=<k>. - A file is "landed" when it exists, is non-empty, and has been quiet for the stable window (default 10s); no startup-snapshot race.
- Use a fresh result path per unit per run (delete any stale file before dispatch). Have each unit write its result in one operation.
monitor usage
scripts/monitor.sh <state-dir-1> <state-dir-2> ...
- Takes the
STATE-DIRpaths from each dispatch (not result files); reads each unit'stail(growth),result-file(done/fail), anddispatch-pid(liveness). - Prints
MONITOR-START units=N stall-threshold=Ts timeout=Ss, then on the first actionable eventMONITOR-EVENT <all-done|stall|fail|timeout>and oneUNIT <name> <status>line per unit (done/failed(fallback)/failed(dispatch-dead)/stalled(Ns)/growing). - Exit:
0all done,3attention needed (a stall or fail),2hard timeout. - Env:
PRUN_STALL_THRESHOLD(default 600, ten minutes; raise it for long code-writing units),PRUN_MONITOR_POLL(default 15),PRUN_MONITOR_TIMEOUT(default 3600),PRUN_MONITOR_STABLE_WINDOW(default 10). - Run it in the background; after handling a stall or fail, re-launch on the still-running units so a resolved unit is not re-flagged.
report-state usage
scripts/report-state.sh [--root DIR] [--json] [--summary] [--sort path|tail-bytes-desc]
[--min-tail-bytes N] [--include-legacy-pid]
scripts\report-state.ps1 (same flags)
Read-only. It inspects prun-task-* directories left behind by earlier runs and writes nothing at
all, which tests/test_prun_report.py checks by hashing the tree before and after a run. Reach for
it when a fan-out was interrupted and you need to know which unit output survived. --root repeats,
and defaults to the system temp directory.
Every unit carries two independent fields instead of one verdict. A single label such as "salvageable" would read as permission to act, and this command cannot support that reading without the process identity it deliberately does not record.
result_path_state | Meaning |
|---|---|
resolved | the unit recorded a result path and it could be read |
absent-entry | no result-file entry was written |
invalid-entry | the entry was empty, or a relative path escaping its unit |
unreadable | the entry exists but could not be read |
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 244
- Forks
- 25
- Last commit
- Sep 2026
ahel review
K6low
bundled executables the agent is told to run
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
prun- Source
- github.com/yzhao062/anywhere-agents