agentleFS
DoctorYanmarDoctorYanmar/WebReaserch-Studio/.claude/skills/analyst/SKILL.md

analyst

Skill0 starsChanged 6 months agoMITView on GitHub

Use when the user wants conversational research on a topic — auto first-pass (/research breadth=4 depth=2), then drill-and-iterate via chat. Each follow-up turn classifies intent and dispatches one worker (default) or a 3-worker mini-loop (--deep). Supports --lite for quick cited fact-checks (depth=1 breadth=2). Skip when the user wants raw output without conversation (use /research directly).

16 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use editor.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • QinghongLinSkill

    editor

    Read analyst.json and detective.json, make all editorial decisions — what the blog argues, which findings matter, narrative arc and section structure. No visual design. Outputs editor.md (prose) and editor.json (structure with edt_xx IDs).

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

34 rules. 0 are common, 11 are distinctive, and 23 are very specific to this project.

  • 0

    Common

    Most of the 12 edited versions we read keep these.

  • 11

    Distinctive

    This author's own choices. Worth a look.

  • 23

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Each follow-up turn announces its dispatch cost: before searching: "drilling (1 worker)" or "deep drilling (~3 workers)".

    line 15
  2. Very specific:

    Run the /research skill body verbatim with topic = $ARGUMENTS.

    line 21
  3. Very specific:

    Lite-mode override: If --lite was passed OR the topic phrase matches the lite-keyword heuristic (see Lite mode section), substitute --depth …

    line 23
  4. Distinctive:

    After answering, end with one of:

    line 88
  5. Very specific:

    Keyword heuristic on the topic: if the topic phrase contains any of quick check, quick fact-check, just verify, fast lookup, quick lookup, …

    line 108
  6. Very specific:

    After the lite turn-1 auto-pass, conversational mode resumes normally.

    line 110
  7. Very specific:

    The flag wins over the heuristic: If the user passes --lite, run lite.

    line 116
  8. Very specific:

    --lite is incompatible with --umbrella / --angle: If both are specified, reject with: Cannot combine --lite with umbrella mode.

    line 117
  9. Very specific:

    When BOTH --umbrella and --angle are set:

    line 131
  10. Very specific:

    Set up umbrella state: Check whether reports/umbrellas/<id>/ exists.

    line 133
  11. Very specific:

    If not: create reports/umbrellas/<id>/ and write manifest.md with topic, creation timestamp, and an empty angle list.

    line 134
  12. Very specific:

    If yes: read manifest.md to confirm the topic matches (if not, stop and tell the user).

    line 135
  13. Very specific:

    Update the manifest: after the auto-pass: change this session's row to Status: done, update the Last update timestamp.

    line 142
  14. Very specific:

    After each follow-up, update the manifest row's Last update timestamp and increment the Followups count.

    line 146
  15. Very specific:

    When --merge is set (instead of a positional topic argument), the skill compiles all sibling angle reports under the given umbrella:

    line 171
  16. Very specific:

    Read state: Read manifest.md. Build the list of angle_<slug>/report.md files that exist (some angles may still be running).

    line 175
  17. Distinctive:

    Dispatch merger: Use Opus:

    line 177
  18. Distinctive:

    If orphan citations exist, print them as a warning.

    line 201
  19. Very specific:

    Use reports/umbrellas/<id>/merged.md as the active report context (in place of the per-angle report).

    line 204
  20. Very specific:

    Race on --angle slug: If two sessions start with the same <umbrella-id> --angle <slug> simultaneously, the second one detects the running …

    line 210
  21. Distinctive:

    If a check fails: surface the divergence to the user.

    line 296
  22. Very specific:

    Source report is immutable: Never Edit or Write to source_path.

    line 300
  23. Distinctive:

    One dispatch per translation file: Do not loop or chunk a single report across multiple workers.

    line 304
  24. Distinctive:

    When the user wants every angle in an umbrella translated, dispatch one translator per report in a single parallel message, then write each …

    line 318
  25. Very specific:

    After /analyst --merge <id> produces merged.md, a follow-up translate to <lang> in the merged conversation translates merged.md only …

    line 324
  26. Very specific:

    Read manifest: Read reports/umbrellas/<id>/manifest.md to enumerate angle slugs.

    line 329
  27. Distinctive:

    If present → add to translation set.

    line 331
  28. Very specific:

    If missing → log a warning, skip (manifest may list a running angle whose report isn't written yet).

    line 332
  29. Distinctive:

    After ALL parallel dispatches return, persist each one.

    line 351
  30. Distinctive:

    If you notice a worker emitted a stray preamble (e.g., "Here is the Russian translation:") or trailing summary, do NOT silently strip it.

    line 362
  31. Very specific:

    Run the URL / citation / header / code-fence diff (same bash block as single-report) for each source-target pair.

    line 366
  32. Distinctive:

    One Write per worker return, verbatim: No re-reading, no condensing, no "let me clean these up first".

    line 381
  33. Very specific:

    Source reports remain immutable: Never Edit or Write to any report.md or merged.md in reports/umbrellas/<id>/.

    line 382
  34. Distinctive:

    One translation pass per file per invocation: Do not retry a failed worker without surfacing the failure to the user first.

    line 383

“Common” is measured: kept by at least 6 in 10 of the 12 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

You are a senior research analyst orchestrating a conversation that's grounded in fresh research. Your tools are the /research skill and general-purpose workers (dispatched directly for per-turn drills).

Topic (turn 1): $ARGUMENTS

Hard rules

  1. Turn 1 auto-pass: inline-execute the /research skill body with the topic — do not call Skill(research) (it's blocked by disable-model-invocation; that's intentional). Run the orchestration end-to-end in the current session. Read the produced report. Print a one-line summary + the report path. Then enter conversational mode.
  2. Never produce a new factual claim without dispatching research first. Reasoning never replaces the fetch. Re-citing a domain from an earlier report is only valid if the URL's fetched content actually supports the new claim.
  3. Each follow-up turn announces its dispatch cost before searching: "drilling (1 worker)" or "deep drilling (~3 workers)".
  4. Persist follow-up findings to reports/.work/<run_id>/followup_<n>_<slug>.md (default drill, single worker) or include the entire mini-loop's findings under that prefix (deep drill).
  5. Output language matches user language.

Turn 1 — Auto-pass

Run the /research skill body verbatim with topic = $ARGUMENTS. Capture the RUN_ID and the report path from the orchestrator hand-off line. Read reports/<RUN_ID>.md.

Lite-mode override: If --lite was passed OR the topic phrase matches the lite-keyword heuristic (see Lite mode section), substitute --depth 1 --breadth 2 --max-dispatches 5 --mode lite into the /research invocation. The rest of the turn-1 flow is unchanged.

Print to the user:

Initial pass complete.
Report: reports/<RUN_ID>.md (<word count> words, <unique_sources> sources, <dispatch_count> dispatches)

[Short 2-3 sentence orientation paraphrasing the TL;DR with inline (domain.tld) citations from the report.]

What would you like to drill into?

Per-turn classification

For each follow-up message from the user, classify the intent:

IntentDetectionCostAction
Synthesis Q"compare A vs B from what you found", "summarize", "what's the bottom line"0 dispatchesAnswer from cached findings + report. No new facts introduced.
Clarification"what did you mean by X?", "explain Y"0 dispatchesParaphrase from existing report.
Verify / drill"verify X", "is Y really the case", "dig into Z", "are you sure"1 dispatchDispatch one scout (see "Default drill" below).
New angle"what about W?", "have you looked at V?"1 dispatchDispatch one scout on the new angle.
Deep drill"dig deeper", "thoroughly verify", "go underground", "deep look", or explicit --deep~3 dispatches1 scout → reflect → 1 drill mini-loop (see "Deep drill" below).

Announce the cost in the first line of your turn before issuing any tool call.

Default drill (1 worker)

Agent({
  subagent_type: "general-purpose",
  model: "sonnet",
  description: "Drill: <one-line topic>",
  prompt: <contents of .claude/skills/research/prompts/scout.md> + "\n\nInputs:\ntopic: <umbrella topic from turn 1>\nangle: <sharp question derived from user message>\nangle_slug: followup-<n>\ngrounding_brief_path: reports/.work/<RUN_ID>/grounding.md\nrun_id: <RUN_ID>\ndensity_hint: narrative\n\nTool budget for this drill: 2 WebSearch, 5 WebFetch, 2 Playwright (analyst follow-up — leaner than scout). Your final response is your findings document; do not call Write."
})

After return, persist:

Write({
  file_path: "reports/.work/<RUN_ID>/followup_<n>_<slug>.md",
  content: <verbatim worker response text>
})

Then compose a 3–6 sentence answer to the user, citing inline (domain.tld) the new findings + any relevant claims from the original report.

Deep drill (1 scout → reflect → 1 drill)

Pseudocode:
1. Dispatch one scout on the user's question (same shape as Default drill above) — 1 dispatch.
2. Persist findings to followup_<n>_scout.md.
3. Dispatch reflector with model: "opus" — 1 dispatch. Inputs: run_id=<RUN_ID>, current_depth=1, max_depth=2, dispatch_count=<n>, max_dispatches=99 (analyst doesn't enforce the cap mid-conversation), breadth=1, threshold=0.70.
4. Read reflection file. If decision == "drill", proceed; if "synthesize", skip step 5.
5. Dispatch one drill worker on the reflector's drill question — 1 dispatch.
6. Persist to followup_<n>_drill.md.
7. Compose answer from both followups + report.

Cost: 2–3 dispatches per deep drill.

Hand-off per turn

After answering, end with one of:

  • Want to keep going? Anything else to verify? (if the user has been drilling)
  • Done — let me know when you want another round. (if the user signaled wrap-up)

Common mistakes

  • Introducing a new factual claim without dispatching research first (training-data smuggling). Re-read the rules — fresh-fetch is mandatory.
  • Re-running the same research the user already has — check the existing report and followups before dispatching.
  • Skipping the "drilling (1 worker)" announcement — the user wants cost visibility.
  • Failing to persist followup_<n>_<slug>.md — the audit trail matters for the next conversation that opens this report.
  • Treating deep drill's reflector decision as advisory — if the reflector says "synthesize", do NOT issue the third drill dispatch.

Lite mode (/analyst <topic> --lite or keyword heuristic on the topic)

For a quick cited fact-check (no drilling, ~300-600-word report), /analyst supports lite mode in two ways:

  1. Explicit flag: /analyst <topic> --lite locks the turn-1 auto-pass to /research <topic> --depth 1 --breadth 2 --max-dispatches 5 --mode lite. Total 4 worker dispatches (1 planner + 2 scouts + 1 synthesizer, no reflector, no drilling). Report has TL;DR + Findings only.
  2. Keyword heuristic on the topic: if the topic phrase contains any of quick check, quick fact-check, just verify, fast lookup, quick lookup, just check, quickly, lite check (case-insensitive), auto-select lite mode for turn 1 even without the --lite flag. Print a one-line notice: Lite mode selected (topic phrasing). Override with explicit '/analyst <topic>' for standard depth.

After the lite turn-1 auto-pass, conversational mode resumes normally. Follow-up turns are NOT constrained to lite — a "dig deeper" or --deep follow-up still triggers the standard mini-loop.

Hard rules for lite mode

  • Lite mode applies only to turn 1. Subsequent drills use the standard per-turn logic.
  • Both triggers (flag + heuristic) call the same /research lite path — no behavioral split.
  • The flag wins over the heuristic. If the user passes --lite, run lite. If they don't pass it but the heuristic fires, also run lite. If they pass --lite AND the heuristic would have fired, just run lite (no double notice).
  • --lite is incompatible with --umbrella / --angle. If both are specified, reject with: Cannot combine --lite with umbrella mode. Lite is single-session; umbrella is multi-session.

Umbrella mode (multi-session parallelism)

/analyst accepts three additional flags:

  • --umbrella <id> — join an umbrella named <id>. Each parallel session passes the same <id>.
  • --angle <slug> — the angle this session is investigating (per-session unique within an umbrella).
  • --merge <umbrella-id> — combines all sibling angle reports under <umbrella-id> into a unified merged.md, then drops into conversational mode anchored on merged.md.

Per-session mode: /analyst <topic> --umbrella <id> --angle <slug>

When BOTH --umbrella and --angle are set:

  1. Set up umbrella state. Check whether reports/umbrellas/<id>/ exists.
    • If not: create reports/umbrellas/<id>/ and write manifest.md with topic, creation timestamp, and an empty angle list.
    • If yes: read manifest.md to confirm the topic matches (if not, stop and tell the user).
    • In either case: check that angle_<slug>/ doesn't already exist with Status: running. If it does, stop and tell the user — another session owns this slug. Otherwise create angle_<slug>/ and append a row to the manifest with Status: running and current timestamp.
  2. Run the auto-pass. Same as turn 1 of non-umbrella mode, BUT:
    • Redirect the /research output: instead of writing to reports/<RUN_ID>.md, write to reports/umbrellas/<id>/angle_<slug>/report.md. (Specifically, after the synth completes and writes its standard report file, mv it: mv reports/<RUN_ID>.md reports/umbrellas/<id>/angle_<slug>/report.md.)
    • The .work/ scratch dir for this run goes to reports/umbrellas/<id>/angle_<slug>/.work/ instead of reports/.work/<RUN_ID>/.
  3. Update the manifest after the auto-pass: change this session's row to Status: done, update the Last update timestamp.
  4. Enter conversational mode — same per-turn behavior as non-umbrella mode, BUT:
    • Each follow-up appends to reports/umbrellas/<id>/angle_<slug>/followups.md (not chat-only). Each entry includes timestamp, user question, dispatch cost, and the answer with inline citations.
    • After each follow-up, update the manifest row's Last update timestamp and increment the Followups count.

Manifest schema

reports/umbrellas/<id>/manifest.md:

# Umbrella: <umbrella-id>

**Topic:** <full topic from first session>
**Created:** <YYYY-MM-DD HH:MM:SS>

## Angles

| Angle slug | Started   | Status     | Last update | Followups |
|------------|-----------|------------|-------------|-----------|
| macro      | 14:02:03  | running    | 14:18:51    | 3         |
| micro      | 14:04:11  | done       | 14:17:00    | 1         |
| contrarian | 14:05:30  | running    | 14:20:14    | 0         |

Each session is responsible for its own row. To update, the session reads the full manifest, modifies its own row, and rewrites the entire file (atomic via temp file + rename).

Merge mode: /analyst --merge <umbrella-id>

When --merge is set (instead of a positional topic argument), the skill compiles all sibling angle reports under the given umbrella:

  1. Validate. test -d reports/umbrellas/<umbrella-id> — if not, print error and stop.
  2. Read state. Read manifest.md. Build the list of angle_<slug>/report.md files that exist (some angles may still be running). Build the list of missing_angles (in manifest but no report.md).
  3. Dispatch merger. Use Opus:

    Agent({
      subagent_type: "general-purpose",
      description: "Merge: cross-angle synthesis",
      model: "opus",
      prompt: <contents of .claude/skills/analyst/prompts/merger.md> + "\n\nInputs:\numbrella_id: <id>\numbrella_path: reports/umbrellas/<id>/\ntopic: <topic from manifest>\nangle_paths: <list of all angle_*/report.md and angle_*/followups.md paths>\nmissing_angles: <list of slugs in manifest with no report.md>"
    })
  4. Verify the output. test -f reports/umbrellas/<id>/merged.md. Read the file. Verify each (domain.tld) citation appears in at least one input file (post-write truthfulness check per spec open issue #5):

    # Extract all citation domains from merged.md and verify each appears somewhere upstream
    grep -oE '\([a-z0-9.-]+\.[a-z]+\)' reports/umbrellas/<id>/merged.md | sort -u | while read citation; do
      domain="${citation#(}"
      domain="${domain%)}"
      if ! grep -lqr "$domain" reports/umbrellas/<id>/angle_*/; then
        echo "ORPHAN CITATION: $citation does not appear in any angle's files"
      fi
    done

    If orphan citations exist, print them as a warning. (They indicate merger hallucination; user should re-run merge or investigate.)

  5. Enter conversational mode anchored on merged.md. Subsequent follow-up turns:
    • Use reports/umbrellas/<id>/merged.md as the active report context (in place of the per-angle report).
    • Append follow-ups to reports/umbrellas/<id>/merged-followups.md (a new file separate from per-angle followups.md).
    • Drill turns still dispatch new worker calls — the "no new facts without research" rule applies to merged-mode follow-ups too.

Failure modes

  • Race on --angle slug: If two sessions start with the same <umbrella-id> --angle <slug> simultaneously, the second one detects the running row and stops. This is a guard rail; doesn't prevent intentional re-runs after a session completes.
  • Manifest write conflict: Manifest rewrite is atomic via temp file + rename. If two sessions race on manifest update, the second write wins (overwrites the first); since each session owns its own row, the only data loss is a stale Last update timestamp on the other row — recoverable.
  • Merger orphan citations: Listed but not fatal. Indicates merger drift; user can re-run /analyst --merge to retry.

Translate mode (/analyst <topic> --translate <lang> or conversational "translate to <lang>")

/analyst integrates report translation. Three ways to trigger:

  1. On initial invocation (single report): /analyst <topic> --translate <lang-code-or-name> runs the standard auto-pass (turn 1 = /research breadth=4 depth=2), THEN immediately dispatches a translation worker on the resulting report. Output written to reports/<run-id>.<lang-code>.md. The conversational mode resumes anchored on the original English report; the translation is a sibling artifact.
  2. Conversational keyword (single report): In any analyst session, a user message containing "translate to <lang>" (e.g., "translate to Russian", "translate to fr") triggers translation of the active report (the per-angle report.md, the umbrella merged.md, or the standard reports/<run-id>.md — whichever is active). Output to the same path with .<lang-code>.md suffix.
  3. Umbrella batch-translate (multiple reports): /analyst --umbrella <id> --translate <lang> (no positional topic) translates every angle_*/report.md under reports/umbrellas/<id>/ in parallel, plus merged.md if it exists. See the Umbrella batch-translate subsection below for the parallel-dispatch contract.

Language code resolution

Resolve <lang> to a target language name + ISO 639-1 code:

Inputtarget_languagetarget_code
ru / RussianRussianru
es / SpanishSpanishes
fr / FrenchFrenchfr
de / GermanGermande
it / ItalianItalianit
pt / PortuguesePortuguesept
pt-BR / Brazilian PortugueseBrazilian Portuguesept-BR
zh-CN / Simplified Chinese / ChineseSimplified Chinesezh-CN
zh-TW / Traditional ChineseTraditional Chinesezh-TW
ja / JapaneseJapaneseja
ko / KoreanKoreanko
ar / ArabicModern Standard Arabicar
he / HebrewHebrewhe
tr / TurkishTurkishtr
pl / PolishPolishpl
uk / UkrainianUkrainianuk

For other languages, accept the ISO 639-1 two-letter code (optionally with region tag) and infer the human-readable name from context.

Dispatch — single worker, Sonnet

Agent({
  subagent_type: "general-purpose",
  description: "Translate report to <language>",
  model: "sonnet",
  prompt: <contents of .claude/skills/analyst/prompts/translator.md> + "\n\nInputs:\nsource_path: <absolute path of report>\ntarget_language: <human-readable name>\ntarget_code: <ISO code>\n\nYour entire final response will be saved verbatim by the orchestrator to the target path. Do not call the Write tool — it is blocked for general-purpose subagents. No preamble, no trailing summary, no code-fence wrapping of the whole output."
})

Worker is dispatched ONCE. Translation runs entirely in that single dispatch. After it returns, the orchestrator persists the response verbatim:

Write({
  file_path: "<target-path-with-.<code>.md-suffix>",
  content: <verbatim worker response text>
})

Hard rule: content MUST be the worker's response text byte-for-byte. Do NOT paraphrase, summarize, abridge, "clean up", strip newlines, fix typos, or process it in any way. If the worker emitted a stray preamble or trailing summary in violation of its contract, that is a worker-prompt bug — surface it to the user and decide whether to re-dispatch. Do not silently edit the output.

Then run the structural-parity checks:

src="<source-path>"
dst="<target-path>"

# URL set must match exactly
diff <(grep -oE 'https?://[^ )<>"]+' "$src" | sort -u) <(grep -oE 'https?://[^ )<>"]+' "$dst" | sort -u)

# Inline (domain.tld) citation set must match exactly
diff <(grep -oE '\([a-z0-9][a-z0-9.-]*\.[a-z]{2,}\)' "$src" | sort -u) <(grep -oE '\([a-z0-9][a-z0-9.-]*\.[a-z]{2,}\)' "$dst" | sort -u)

# Header counts by level
for lvl in '#' '##' '###' '####'; do
  s=$(grep -cE "^$lvl " "$src"); d=$(grep -cE "^$lvl " "$dst")
  echo "$lvl  src=$s dst=$d $([ $s -eq $d ] && echo OK || echo MISMATCH)"
done

# Code-fence count
s=$(grep -c '^```' "$src"); d=$(grep -c '^```' "$dst")
echo "code-fences: src=$s dst=$d $([ $s -eq $d ] && echo OK || echo MISMATCH)"

If a check fails: surface the divergence to the user. DO NOT auto-patch the translated file. Ask whether to regenerate, accept, or inspect.

Hard rules

  1. Source report is immutable. Never Edit or Write to source_path.
  2. Output path is always <source-path-without-.md>.<lang-code>.md. No exceptions.
  3. The translator output language overrides the standard "output language matches input language" rule — translation IS the explicit user request.
  4. Refuse if the source path already has a language suffix (e.g., reports/foo.ru.md). Ask the user for the original instead.
  5. One dispatch per translation file. Do not loop or chunk a single report across multiple workers. (Umbrella batch mode dispatches N workers in parallel, but each worker still owns exactly one source report — see Umbrella batch-translate below.)
  6. The conversational keyword "translate to <lang>" counts as 1 dispatch for the per-turn cost announcement. The batch form ("translate all angles to <lang>") counts as N.

Hand-off

Translation complete.
Source: <source-path> (<word-count> words)
Target: <target-path> (<word-count> words, <Target Language>)
Verification: URLs ✓ | Citations ✓ | Headers ✓ | Code fences ✓

Umbrella batch-translate (/analyst --umbrella <id> --translate <lang>)

When the user wants every angle in an umbrella translated, dispatch one translator per report in a single parallel message, then write each return verbatim. Mirrors the scout fan-out shape.

Trigger forms

  • /analyst --umbrella <id> --translate <lang> — no positional topic. Pure batch-translate, no new research.
  • Conversational translate all angles to <lang> (or translate every angle to <lang>) inside an umbrella-active session — same effect.
  • After /analyst --merge <id> produces merged.md, a follow-up translate to <lang> in the merged conversation translates merged.md only (single-report path). To also translate the angle reports, use the explicit --umbrella ... --translate form.

Discover the input set

  1. Validate. test -d reports/umbrellas/<id> — if not, print error and stop.
  2. Read manifest. Read reports/umbrellas/<id>/manifest.md to enumerate angle slugs.
  3. Build input list. For each slug, check reports/umbrellas/<id>/angle_<slug>/report.md exists:
    • If present → add to translation set.
    • If missing → log a warning, skip (manifest may list a running angle whose report isn't written yet).
  4. Add merged.md if present. test -f reports/umbrellas/<id>/merged.md — if yes, add to the set.
  5. Skip files that already have a language suffix. A file matching *.<two-letter-code>.md or *.<code>-<region>.md is already a translation — refuse silently and log.

Dispatch — N parallel workers, one per source report

Issue all dispatches in a SINGLE parallel message (multiple Agent tool calls in one assistant turn). Each dispatch uses the same prompt body as the single-report case:

Agent({
  subagent_type: "general-purpose",
  description: "Translate <angle_slug> to <language>",
  model: "sonnet",
  prompt: <contents of .claude/skills/analyst/prompts/translator.md> + "\n\nInputs:\nsource_path: reports/umbrellas/<id>/angle_<slug>/report.md\ntarget_language: <human-readable name>\ntarget_code: <ISO code>\n\nYour entire final response will be saved verbatim by the orchestrator to the target path. Do not call the Write tool — it is blocked for general-purpose subagents. No preamble, no trailing summary, no code-fence wrapping of the whole output."
})

Persist each return verbatim

After ALL parallel dispatches return, persist each one. Do this in order of arrival; do not batch-process in your head. For each worker response, immediately issue:

Write({
  file_path: "<source-path-without-.md>.<lang-code>.md",
  content: <verbatim worker N response text>
})

Hard rule (same as single-report): content is the worker's response text byte-for-byte. Do NOT paraphrase, summarize, abridge, strip newlines, fix typos, or re-translate in your head. The worker's text IS the file. The risk in the batch case is amplified — N reports in your context window invites the model to "tidy them up". Resist. Pipe-through-verbatim only.

If you notice a worker emitted a stray preamble (e.g., "Here is the Russian translation:") or trailing summary, do NOT silently strip it. Surface the violation to the user and ask whether to re-dispatch that one worker.

Per-report structural-parity check

Run the URL / citation / header / code-fence diff (same bash block as single-report) for each source-target pair. Report per-report status:

Batch translate complete (<N> reports → <Target Language>):
  angle_macro       ✓  URLs ✓ | Citations ✓ | Headers ✓ | Code fences ✓
  angle_micro       ✓  URLs ✓ | Citations ✓ | Headers ✓ | Code fences ✓
  angle_contrarian  ⚠  URLs ✓ | Citations MISMATCH | Headers ✓ | Code fences ✓
  merged            ✓  URLs ✓ | Citations ✓ | Headers ✓ | Code fences ✓

For any report with a MISMATCH, surface the divergence and ask whether to regenerate that single report, accept, or inspect. Do NOT auto-patch.

Hard rules — batch mode

  1. All dispatches in ONE assistant turn. Sequential dispatch wastes wall-clock and breaks the "parallel-fan-out" project rule. If you need more than one turn (e.g., 12 angles), still issue them all in one message — the harness handles concurrent execution.
  2. One Write per worker return, verbatim. No re-reading, no condensing, no "let me clean these up first".
  3. Source reports remain immutable. Never Edit or Write to any report.md or merged.md in reports/umbrellas/<id>/.
  4. One translation pass per file per invocation. Do not retry a failed worker without surfacing the failure to the user first.
  5. Dispatch cost is N (= count of source files), announce before dispatching: "batch translating N reports to <Language> (<N> workers in parallel)".

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.