Run deep research on each item in outline.yaml by fanning out parallel web-search subagents. Writes one validated JSON per item to results/. Resumable — skips items that already have a complete JSON.
56
65%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Fix and improve this skill with Tessl
tessl review fix ./plugins/ultra-research/skills/research-deep/SKILL.md/ultra-research:research-deep
Manual-only via disable-model-invocation: true. Heavy phase — it spawns many parallel subagents and writes many files, so explicit user start is required.
Phase 3 of 5 (the heavy one). Consumes outline.yaml + fields.yaml. Produces one JSON per item in results/. At the end, offers to chain into /ultra-research:research-report.
The orchestrator (the agent reading this SKILL.md) MUST NOT perform web searches itself. Its job is dispatch + monitor + read results, nothing else.
| ✅ Orchestrator does | ⛔ Orchestrator MUST NOT do |
|---|---|
Read outline.yaml and fields.yaml | Call WebSearch, WebFetch, mcp__exa_websearch__* directly |
| Discover the validator path | Read the contents of web pages to extract field values |
| Slugify item names | Write the per-item JSON files itself |
Launch ONE web-search-agent subagent per item via the Agent/Task tool, in parallel, in the background | Compile data inline in this conversation and write the JSON itself |
Monitor results/<slug>.json files appearing on disk | "Optimize" by running fewer searches in the main session because the item count is "small" |
| Read completed JSONs to summarize for the user | Skip subagent dispatch because the data "is already known" |
Why this is a hard constraint. Parallelism is the entire point of this phase — fanning out N items across N subagents collapses N×search-time into ~1×search-time. Inlining the work in the orchestrator session serializes everything, blows out the orchestrator's context window with raw page content, and silently regresses the pipeline to a sequential single-thread flow. A reviewer cannot tell from the final report that this happened — only the absence of per-item subagent transcripts reveals it.
Item count is not an exemption. Even for 2 items, dispatch 2 subagents. Even for 1 item, dispatch 1 subagent. The wave size and batch_size may be lowered for small item counts, but the dispatch pattern does not change.
If you (the orchestrator) catch yourself about to call WebSearch or mcp__exa_websearch__* directly in this phase, stop and launch a subagent instead.
web-search-agent is launched as a background subagent (Task tool with background execution, or the harness's equivalent Agent tool with run_in_background: true). Task output is suppressed because each subagent's real output is the JSON file it writes — surfacing the subagent's chat transcript would be noisy.output_dir for existing <item_slug>.json files and skips those items. Safe to interrupt and restart.Glob */outline.yaml in the current working directory and read it. Capture topic, items, and execution (batch_size, items_per_agent, output_dir).
Locate the validate_json.py script. When this skill ships as the ultra-research plugin, the script lives at ${CLAUDE_PLUGIN_ROOT}/skills/research/scripts/validate_json.py. Fall back to legacy install paths only if ${CLAUDE_PLUGIN_ROOT} is unset:
VALIDATOR="${CLAUDE_PLUGIN_ROOT}/skills/research/scripts/validate_json.py"
[ -f "$VALIDATOR" ] || VALIDATOR=$(ls ~/.claude/skills/research/scripts/validate_json.py 2>/dev/null \
|| find ~/.claude -name validate_json.py -path '*/research/scripts/*' 2>/dev/null | head -1)If $VALIDATOR is empty, stop and tell the user the /ultra-research:research skill must be installed alongside /ultra-research:research-deep. Otherwise bind it to the {validator_path} placeholder used by the per-item prompt template.
List existing <output_dir>/*.json files. For each, if it parses as JSON and contains the expected fields, mark its item as done and skip it in Step 3.
Bucket the remaining items by items_per_agent. Process buckets in waves of batch_size:
web-search-agent subagent via the harness's Agent/Task tool with run_in_background: true (or equivalent). All subagents in a wave are launched in a single message with multiple parallel Agent tool calls so they actually run concurrently.references/prompt-templates.md — only substitute placeholders. Each subagent's prompt includes {validator_path} from Step 1, so the subagent runs validation as its final step.WebSearch, WebFetch, or mcp__exa_websearch__* itself during this step. Re-read the Hard Constraint block above if tempted.output_dir for <slug>.json files appearing on disk.See references/prompt-templates.md for:
{item_related_info}, {output_path}, {fields_path}, {validator_path}){item_name_slug}After each wave, check which <item_slug>.json files appeared in output_dir. Display progress (X of Y complete). Continue with the next wave until all items are processed.
Print a summary:
uncertain arrays (count + names)output_dir pathThen use AskUserQuestion with header: "Next step" and ask "Deep research complete — N items in ./{output_dir}/. Generate the report now?" with these options:
/ultra-research:research-report and let its Step 2 pick TOC fields interactively/ultra-research:research-report with sensible defaults (skip TOC picker)/ultra-research:research-report laterIf any items failed validation or have non-empty uncertain arrays, mention them in the question body so the user can decide whether to re-run problem items before reporting.
Invoke the picked skill immediately via the Skill tool when the user selects either Generate option.
{topic}/
├── outline.yaml
├── fields.yaml
└── results/
├── <item_slug_1>.json
├── <item_slug_2>.json
└── ...references/prompt-templates.md — verbatim per-item prompt template + variable reference + one-shot example. Read it before launching subagents.48bf6a4
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.