| name | fanout |
| description | Pre-load shared context for parallel agent dispatch (context mode), or shard a glob across N read-only research agents (shard mode). Use before /do for big read-mostly jobs. |
/fanout — Parallel Dispatch Helper
Two modes that each eliminate a piece of the manual orchestration dance
in /do:
context — pre-reads the root + folder-local CLAUDE.md files and
any explicit .ai/knowledge/ references for a task, emits a framed
markdown block ready to paste into N parallel agent prompts.
shard — expands a glob, splits the matches into N
non-overlapping buckets via deterministic path hash, and writes a
single canonical wave-fragment file that /do can merge into its
dispatch plan.
Neither mode launches agents on its own. Both produce output that the
orchestrator (the main Claude session running /do) consumes.
Mode: /fanout context
python3 .claude/skills/fanout/scripts/context-broker.py \
--task "<task text>" \
[--paths PATH1 PATH2 ...] \
[--knowledge-doc architecture/top-down-systems.md ...]
Arguments
--task (required) — the user's task text. Also scanned for
path-like substrings (regex (?:Assets|Tests|Editor|Packages|tools|\.ai)/[\w/.-]+)
so folder-local CLAUDE.md files get auto-included.
--paths (optional) — explicit paths whose folder-local CLAUDE.md
should be included in addition to anything detected in --task.
--knowledge-doc (optional, repeatable) — paths relative to
.ai/knowledge/ that should be pasted verbatim into the output.
Behavior
- Walks up from each input path to the nearest folder containing a
CLAUDE.md and includes it (deduped — never the same file twice).
- Always includes the repo root
CLAUDE.md.
- Silently skips missing paths, missing knowledge docs, and paths
that resolve outside the repo root. Best-effort by design.
- Writes a framed markdown block to stdout:
## Context (pre-loaded -- do NOT re-read these files)
### Project Conventions (from CLAUDE.md)
<root CLAUDE.md contents>
### Folder Rules — tools/do/CLAUDE.md
<folder CLAUDE.md contents>
### Reference — .ai/knowledge/architecture/top-down-systems.md
<knowledge doc contents>
The orchestrator pastes that block into every agent prompt in the
current wave, eliminating the Step 0 "Pre-Read Shared Context" manual
loop in .claude/skills/do/SKILL.md.
Mode: /fanout shard
python3 .claude/skills/fanout/scripts/shard-paths.py \
--buckets <N> \
--glob "<glob>" \
--task "<task text>" \
--task-hash <8-char-sha1-prefix> \
--out <output-fragment-path> \
[--agent-type unity-researcher|unity-reviewer|Explore]
Arguments
--buckets (required) — number of parallel agents to fan out to.
--glob (required) — a Python glob.glob(..., recursive=True)
pattern resolved from the repo root (supports **).
--task (required) — the user's task text, mirrored into the
fragment and surfaced in the per-bucket prompt suggestions.
--task-hash (required) — an 8-char sha1 prefix of the exact task
text. /do recomputes this and hard-fails if they diverge — the
fragment is bound to one specific task.
--out (required) — output fragment file path. Parent directories
are created automatically; written atomically via temp file +
os.replace.
--agent-type (optional, default unity-researcher) — one of
unity-researcher, unity-reviewer, Explore. See platform gate
below.
Platform gate for Explore
--agent-type Explore is only allowed when
subagent_type_explore is verified in
~/.tmp/r8eox/platform-primitives.json (via
tools/do/read-platform-primitives.py). If the primitive is
unverified or stale, the script exits non-zero with this stderr
message:
Explore subagent_type is not verified on this Claude Code version.
Run the §15 manual checklist or use --agent-type unity-researcher.
This keeps builtin-typed agents off the dispatch path until an
operator runs the §15 one-shot verification on the current Claude
Code build.
Sharding algorithm
- Resolve the glob from the repo root. Filter to files only. Sort.
- For each path, compute
bucket_index = int(sha1(path).hex, 16) % N.
- Group paths by bucket. Empty buckets are still emitted — this
preserves bucket-index alignment across runs for downstream
consumers.
Output fragment
{
"task_hash": "<passed via --task-hash>",
"id": null,
"agents": [
{
"index": 0,
"type": "unity-researcher",
"read_only": true,
"edits": [],
"creates": [],
"deletes": [],
"creates_dirs": [],
"deletes_dirs": [],
"reads": ["path1", "path2"],
"extra_writes": [],
"mcp_capable": false,
"pin_target": "none",
"isolation": null,
"background": false
}
]
}
All agents are read_only: true. All five write arrays
(edits, creates, deletes, creates_dirs, deletes_dirs) are
empty. extra_writes is also empty. The schema mirrors the canonical
manifest agent entry documented in .claude/skills/do/SKILL.md, so
tools/do/check-writesets.py can consume the fragment without any
adapter.
Stdout also prints:
- The fragment file path.
bucket N: M files for each bucket.
- One suggested short prompt per bucket the orchestrator can paste.
Handoff contract — /fanout shard -> /do
1. User runs: /fanout shard --buckets 6 --glob "Assets/**/*.cs" --task "audit uses of UnityEngine.Random" ...
2. Fragment written to .tmp/do/<run>/fanout-<hash>.json
3. User runs: /do --fanout-fragment .tmp/do/<run>/fanout-<hash>.json "audit uses of UnityEngine.Random"
4. /do recomputes sha1(task)[:8] and compares to fragment.task_hash
5. Match -> /do merges agents[] into its dispatch manifest
Mismatch -> HARD FAIL with both hashes printed; user regenerates fragment
Running /do --fanout-fragment with a task text different from the
one the fragment was generated for is a hard error — the hash binding
prevents accidentally reusing a stale fragment.
Conventions
- Python 3 stdlib only (same as
tools/do/).
- Tests live in
scripts/test_fanout.py and run via
tools/do/run-tests.sh.
- This skill never writes to
~/.tmp/r8eox/*. It is a read-only
consumer of the platform-primitives file.
- See
.claude/skills/do/SKILL.md for the full canonical manifest
schema the fragment's agents[] entries conform to.