Best for
- Activation Triggers
- Use Cases
- When NOT to Use
MichelKerkmeester/opencode--skilled-agent-loops-with-spec-kit-memory/.opencode/skills/system-deep-loop/deep-research/SKILL.md
Autonomous deep-research loop: iterative investigation, externalized state, convergence detection, fresh context per pass.
Decision brief
Note: Task is allowed for the command executor that manages the loop. The @deep-research agent itself is LEAF-only and does not dispatch sub-agents.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/MichelKerkmeester/opencode--skilled-agent-loops-with-spec-kit-memory --skill ".opencode/skills/system-deep-loop/deep-research"Inspect the Agent Skill "deep-research" from https://github.com/MichelKerkmeester/opencode--skilled-agent-loops-with-spec-kit-memory/blob/6f0b93906be829894c38e580010885d54199067f/.opencode/skills/system-deep-loop/deep-research/SKILL.md at commit 6f0b93906be829894c38e580010885d54199067f. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Review the “Phase Signals” section in the pinned source before continuing.
Default: 0.05 on newInfoRatio (fully-new=1.0, partially-new=0.5, +0.10 simplicity bonus, capped 1.0)
Use this skill when: - Deep investigation requiring multiple rounds of discovery - Topic spans 3+ technical domains or sources - Initial findings need progressive refinement - Overnight or unattended research sessions - Research where prior findings inform subsequent queries
Use this skill when: - Deep investigation requiring multiple rounds of discovery - Topic spans 3+ technical domains or sources - Initial findings need progressive refinement - Overnight or unattended research sessions - Research where prior findings inform subsequent queries
Use deep-research for multi-round technical investigation, source triangulation, repeated exploration with fresh context, and research sessions where prior findings should shape the next focus.
Permission review
The documentation asks the agent to run terminal commands or scripts.
The YAML workflow owns executor selection (native `@deep-research` by default, or a routed CLI executor -- never ad hoc shell loops). Cross-CLI delegation inside an executor sandbox is possible but discouraged: do not invoke the same CLI frThe documentation asks the agent to create, modify, or delete local files.
Record a JSONL delta through the append gateway (`runtime/scripts/append-mode-event.cjs --mode research --run-directory <spec folder> --event-json <file>`) with required fields: `type`, `iteration`, `newInfoRatio`, `status`, and `focus`. ThThe documentation asks the agent to run terminal commands or scripts.
**Invoke through the command workflow** -- Use `/deep:research:auto` or `/deep:research:confirm`, and let the YAML workflow own dispatchEvidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 92/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 32 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Note: Task is allowed for the command executor that manages the loop. The @deep-research agent itself is LEAF-only and does not dispatch sub-agents.
Iterative research protocol with fresh context per iteration, externalized state, and convergence detection for deep technical investigation.
Runtime path resolution: OpenCode/Copilot runtime uses .opencode/agents/*.md; Claude runtime uses .claude/agents/*.md.
Operator contract precedence for this skill surface (highest first): command entrypoint syntax in .opencode/commands/deep/research.md; convergence math in references/convergence/convergence.md and the deep-research YAML workflow; runtime agent inventories from the checked-in runtime directories above.
Default: 0.05 on newInfoRatio (fully-new=1.0, partially-new=0.5, +0.10 simplicity bonus, capped 1.0)
Semantic: convergenceThreshold compares newly discovered information against accumulated research knowledge with negative-knowledge emphasis. Lower = more iterations / higher signal threshold.
NOT INTERCHANGEABLE with siblings:
deep-review uses 0.10 default on weighted P0/P1/P2 severity ratiodeep-ai-council uses 0.20 default on adjudicator-verdict stabilityCarrying threshold expectations across siblings will cause unexpected iteration counts; see this skill's changelog/decision records for the parity research confirming thresholds do not carry across siblings.
Use this skill when:
Keyword triggers:
autoresearchdeep researchautonomous researchresearch loopiterative researchmulti-round researchdeep investigationcomprehensive researchUse deep-research for multi-round technical investigation, source triangulation, repeated exploration with fresh context, and research sessions where prior findings should shape the next focus.
/speckit:plan)/speckit:plan)/speckit:implement)@context or direct Grep/Glob)Pattern: aligned with the sk-doc smart-router resilience template.
The router discovers markdown resources from references/ and assets/, then applies intent scoring from RESOURCE_MAP. Keep routing domain-focused rather than hardcoding exhaustive inventories.
references/guides/quick-reference.md -- first-touch operator cheat sheet.references/protocol/loop-protocol.md -- lifecycle, dispatch, reducer sequencing, command-owned state flow.references/protocol/spec-check-protocol.md -- bounded spec.md anchoring and generated-fence write-back.references/convergence*.md -- stop contracts, signals, recovery, graph gates, reference-only convergence ideas.references/state*.md -- packet layout, JSONL records, markdown outputs, reducer ownership, reconstruction.references/guides/capability-matrix.md -- runtime parity.assets/*.md -- markdown templates and prompt assets safe for guarded markdown loading.| Level | When to Load | Resources |
|---|---|---|
| ALWAYS | Every skill invocation | Quick reference baseline |
| CONDITIONAL | If intent signals match | Loop, convergence, state, spec anchoring, runtime parity references |
| ON_DEMAND | Only on explicit request | Full reference set and markdown assets |
| Phase | Signal | Primary Resources |
|---|---|---|
| Init | No JSONL exists or setup context | loop-protocol.md, state-format.md, state-jsonl.md |
| Iteration | Dispatch context includes iteration number | loop-protocol.md, state-outputs.md, convergence-signals.md |
| Stuck | Dispatch context includes recovery language | convergence-recovery.md, state-reducer-registry.md |
| Synthesis | STOP candidate or final report | convergence.md, state-outputs.md, spec-check-protocol.md |
The authoritative routing logic for scoped loading, weighted intent scoring, ambiguity handling, and graceful fallback, via four patterns: runtime discovery (discover_markdown_resources() scans references//assets/), existence-check-before-load (load_if_available() guards paths against inventory and seen), extensible routing keys (intent labels map to resource families, not static file lists), and multi-tier graceful fallback (UNKNOWN_FALLBACK_CHECKLIST for disambiguation; missing families return a helpful notice).
from pathlib import Path
SKILL_ROOT = Path(__file__).resolve().parent
RESOURCE_BASES = (SKILL_ROOT / "references", SKILL_ROOT / "assets")
DEFAULT_RESOURCE = "references/guides/quick-reference.md"
INTENT_SIGNALS = {
"LOOP_SETUP": {"weight": 4, "keywords": ["autoresearch", "deep research", "research loop", "autonomous research", "setup", "init"]},
"ITERATION": {"weight": 4, "keywords": ["iteration", "next round", "continue research", "research cycle", "delta", "focus"]},
"CONVERGENCE": {"weight": 4, "keywords": ["convergence", "stop condition", "diminishing returns", "legal stop", "newInfoRatio"]},
"RECOVERY": {"weight": 4, "keywords": ["stuck", "recovery", "timeout", "reconstruct", "blocked stop", "blocked_stop"]},
"STATE": {"weight": 4, "keywords": ["state file", "jsonl", "strategy", "dashboard", "registry", "lineage"]},
"SPEC_ANCHORING": {"weight": 3, "keywords": ["spec.md", "generated fence", "folder_state", "lock", "spec anchoring"]},
"RUNTIME_PARITY": {"weight": 3, "keywords": ["runtime", "capability", "parity", "opencode", "claude"]},
"RESOURCE_MAP": {"weight": 3, "keywords": ["resource map", "resource-map", "inventory", "coverage gate"]},
}
RESOURCE_MAP = {
"LOOP_SETUP": ["references/protocol/loop-protocol.md", "references/state/state-format.md", "references/state/state-jsonl.md", "references/protocol/spec-check-protocol.md", "references/protocol/context-snapshot.md"],
"ITERATION": ["references/protocol/loop-protocol.md", "references/state/state-outputs.md", "references/convergence/convergence-signals.md"],
"CONVERGENCE": ["references/convergence/convergence.md", "references/convergence/convergence-signals.md", "references/convergence/convergence-graph.md"],
"RECOVERY": ["references/convergence/convergence-recovery.md", "references/state/state-reducer-registry.md"],
"STATE": ["references/state/state-format.md", "references/state/state-jsonl.md", "references/state/state-outputs.md", "references/state/state-reducer-registry.md", "assets/deep-research-strategy.md"],
"SPEC_ANCHORING": ["references/protocol/spec-check-protocol.md", "references/state/state-outputs.md"],
"RUNTIME_PARITY": ["references/guides/capability-matrix.md"],
"RESOURCE_MAP": ["references/protocol/loop-protocol.md", "references/state/state-outputs.md"],
}
LOADING_LEVELS = {
"ALWAYS": [DEFAULT_RESOURCE],
"ON_DEMAND_KEYWORDS": ["full protocol", "all references", "complete reference", "resume deep research", "state log", "research/iterations", "deltas", "overnight research", "active lineage", "reference-only", "optimizer"],
"ON_DEMAND": [
"references/protocol/loop-protocol.md",
"references/protocol/spec-check-protocol.md",
"references/convergence/convergence.md",
"references/convergence/convergence-signals.md",
"references/convergence/convergence-recovery.md",
"references/convergence/convergence-graph.md",
"references/convergence/convergence-reference-only.md",
"references/state/state-format.md",
"references/state/state-jsonl.md",
"references/state/state-outputs.md",
"references/state/state-reducer-registry.md",
"references/guides/capability-matrix.md",
],
}
UNKNOWN_FALLBACK_CHECKLIST = [
"Confirm setup vs iteration vs convergence vs state recovery",
"Confirm the target spec folder and research packet",
"Provide the current phase, latest iteration, or failing state file",
"Confirm whether full references or quick routing guidance are needed",
]
def _task_text(task) -> str:
return " ".join([
str(getattr(task, "text", "")),
str(getattr(task, "query", "")),
" ".join(getattr(task, "keywords", []) or []),
]).lower()
def _guard_in_skill(relative_path: str) -> str:
resolved = (SKILL_ROOT / relative_path).resolve()
resolved.relative_to(SKILL_ROOT)
if resolved.suffix.lower() != ".md":
raise ValueError(f"Only markdown resources are routable: {relative_path}")
return resolved.relative_to(SKILL_ROOT).as_posix()
def _guard_resource_map(resource_map: dict[str, list[str]]) -> None:
for intent, resources in resource_map.items():
for relative_path in resources:
guarded = _guard_in_skill(relative_path)
if guarded.startswith("references/"):
tail = guarded.removeprefix("references/")
if "/" not in tail and "-" in Path(tail).stem:
raise ValueError(f"RESOURCE_MAP must target canonical references, not compatibility stubs: {intent} -> {guarded}")
def discover_markdown_resources() -> set[str]:
docs = []
for base in RESOURCE_BASES:
if base.exists():
docs.extend(path for path in base.rglob("*.md") if path.is_file())
return {doc.relative_to(SKILL_ROOT).as_posix() for doc in docs}
def score_intents(task) -> dict[str, float]:
text = _task_text(task)
scores = {intent: 0.0 for intent in INTENT_SIGNALS}
for intent, cfg in INTENT_SIGNALS.items():
for keyword in cfg["keywords"]:
if keyword in text:
scores[intent] += cfg["weight"]
return scores
def select_intents(scores: dict[str, float], ambiguity_delta: float = 1.0, max_intents: int = 2) -> list[str]:
ranked = sorted(scores.items(), key=lambda item: item[1], reverse=True)
if not ranked or ranked[0][1] <= 0:
return ["LOOP_SETUP"]
selected = [ranked[0][0]]
if len(ranked) > 1 and ranked[1][1] > 0 and (ranked[0][1] - ranked[1][1]) <= ambiguity_delta:
selected.append(ranked[1][0])
return selected[:max_intents]
def route_deep_research_resources(task):
_guard_resource_map(RESOURCE_MAP)
_guard_resource_map({"ALWAYS": LOADING_LEVELS["ALWAYS"], "ON_DEMAND": LOADING_LEVELS["ON_DEMAND"]})
inventory = discover_markdown_resources()
scores = score_intents(task)
intents = select_intents(scores)
loaded = []
seen = set()
def load_if_available(relative_path: str) -> None:
guarded = _guard_in_skill(relative_path)
if guarded in inventory and guarded not in seen:
load(guarded)
loaded.append(guarded)
seen.add(guarded)
for relative_path in LOADING_LEVELS["ALWAYS"]:
load_if_available(relative_path)
if max(scores.values() or [0]) < 0.5:
return {
"intents": intents,
"intent_scores": scores,
"load_level": "UNKNOWN_FALLBACK",
"needs_disambiguation": True,
"disambiguation_checklist": UNKNOWN_FALLBACK_CHECKLIST,
"resources": loaded,
}
matched_intents = []
for intent in intents:
before_count = len(loaded)
for relative_path in RESOURCE_MAP.get(intent, []):
load_if_available(relative_path)
if len(loaded) > before_count:
matched_intents.append(intent)
text = _task_text(task)
if any(keyword in text for keyword in LOADING_LEVELS["ON_DEMAND_KEYWORDS"]):
for relative_path in LOADING_LEVELS["ON_DEMAND"]:
load_if_available(relative_path)
result = {"intents": intents, "intent_scores": scores, "resources": loaded}
if not matched_intents:
result["notice"] = f"No knowledge base found for intent(s): {', '.join(intents)}"
return result
This skill is invoked exclusively through /deep:research:auto or /deep:research:confirm -- the command YAML owns state, dispatch, convergence, and synthesis. Never simulate the loop with ad hoc shell dispatch, nested CLI loops, direct @deep-research Task dispatch, /tmp prompt files, or state outside the resolved local research packet.
The YAML workflow owns executor selection (native @deep-research by default, or a routed CLI executor -- never ad hoc shell loops). Cross-CLI delegation inside an executor sandbox is possible but discouraged: do not invoke the same CLI from within itself, and do not assume auth propagates to child CLIs. The seven executor kinds are owned by runtime/lib/deep-loop/executor-config.ts; the inline research YAML currently carries branches for native, cli-claude-code, cli-opencode, and cli-codex, while cli-cursor, cli-devin, and cli-pi are handled by the shared fan-out adapters. Flag compatibility remains in loop-protocol.md §3.
Executor invariants:
{state_paths.iteration_pattern}.runtime/scripts/append-mode-event.cjs --mode research --run-directory <spec folder> --event-json <file>) with required fields: type, iteration, newInfoRatio, status, and focus. The gateway authorizes, fences, and receipts the write, then refreshes {state_paths.state_log} from the ledger; do not write that file directly.Failure modes include iteration_file_missing, iteration_file_empty, jsonl_not_appended, jsonl_missing_fields, and jsonl_parse_error. Three consecutive failures route to stuck recovery.
Runtime-supported lifecycle modes:
| Mode | Meaning |
|---|---|
new | First run against the spec folder |
resume | Continue the active lineage and append a typed resumed JSONL event |
restart | Archive the existing research tree, mint a fresh sessionId, increment generation, and append a typed restarted event |
Deferred modes fork and completed-continue are reserved but not runtime-supported.
The live code-graph readiness contract reaches four TrustState values: live, stale, absent, and unavailable. cached, imported, rebuilt, and rehomed remain declared in the shared TrustState type for compatibility, but the readiness helpers used here do not emit them today.
When {spec_folder}/resource-map.md exists at init, resource_map_present: true is persisted, the map is summarized into deep-research-strategy.md Known Context, and listed files count as known inventory (gaps flagged only when missing from the map). When absent, resource_map_present: false is persisted and the loop continues normally -- absence is informational, not a failure. Full field-level rules live in state-outputs.md §6.
For codebase-scoped targets, initialization captures a bounded, pointer-based snapshot (source paths/symbols, integration points, conventions, and gaps) into deep-research-strategy.md Known Context -- oriented toward the first iteration, not a substitute for @context or /speckit:plan. Full capture rules and routing guidance live in context-snapshot.md.
/deep:research owns the YAML workflow: it initializes state, dispatches one LEAF iteration at a time, evaluates convergence, synthesizes research/research.md, and saves continuity. @deep-research executes only one research cycle per dispatch.
The research state packet always lives under the target spec's local research/ folder: root-spec targets use {spec_folder}/research/ directly; child-phase and sub-phase targets use flat-first -- a first run with an empty research/ directory writes flat, and a pt-NN subfolder ({basename(spec_folder)}-pt-{NN}) is allocated only when prior content already exists for a non-matching target. This avoids the unnecessary pt-01 wrapper on first runs. Worked examples, the ownership model, and the file-protection table live in state-format.md §2.
State files include deep-research-config.json, deep-research-state.jsonl, deep-research-strategy.md, findings-registry.json, deep-research-dashboard.md, .deep-research-pause, .deep-research.lock, resource-map.md, research.md, and iterations/iteration-NNN.md.
Each agent dispatch gets a fresh context window. State continuity comes from files, not memory. This solves context degradation in long research sessions. Design provenance is documented in quick-reference.md §1.
Init creates config, strategy, and state logs. Each loop reads state, checks convergence, dispatches @deep-research, writes iteration markdown and JSONL deltas, refreshes reducer-owned state, and either continues or synthesizes and saves continuity.
Late-INIT can also anchor the research run to spec.md: the workflow acquires the advisory lock at research/.deep-research.lock, classifies folder_state (always one of no-spec, spec-present, spec-just-created-by-this-run, or conflict-detected), seeds or appends bounded context before LOOP, and replaces exactly one generated findings fence under the chosen host anchor during SYNTHESIS -- while keeping research/research.md canonical. The lock is held from late-INIT through save, skip-save, or cancel cleanup. Full marker syntax, audit events, and bounded mutation rules live in spec-check-protocol.md.
Convergence uses newInfoRatio/stuck/question signals; JSONL state remains append-only. Externalization, reducer ownership, and synthesis behavior are covered above.
loop-protocol.md Step 7a for the full check and confirm-mode review flow.[SOURCE: url] or [SOURCE: file:line]research/research.mddeep-research-* artifacts and research/.deep-research-pause; legacy names are read-only migration aliases/deep:research:auto or /deep:research:confirm, and let the YAML workflow own dispatch/tmp prompt dispatchers, or direct Task loops for @deep-research. Command-driven fan-out via step_fanout_spawn (--executor/--executors/--concurrency flags) IS SUPPORTED; ad-hoc shell fan-out and intra-lineage wave orchestration remain forbidden.complete | timeout | error | stuck | insight | thought
insight: Low newInfoRatio but important conceptual breakthroughthought: Analytical-only iteration, no evidence gatheringReference-only (documented for future design work, not part of the live executable contract for /deep:research; full detail in loop-protocol.md §4-5):
claude -p or similar dispatch modes are used internally by fanout-run.cjs; do not write them ad-hoc from within a research sessionMulti-lineage fan-out is SUPPORTED (not reference-only) via --executor/--executors flags on the command (see §8 EXAMPLES). Each lineage is an independent full loop in {artifact_dir}/lineages/{label}/, converging independently. This is not "wave orchestration"; it is N independent loops.
Core documentation: references/guides/quick-reference.md, references/protocol/loop-protocol.md, references/protocol/spec-check-protocol.md, references/convergence/convergence.md, and references/state/state-format.md.
Focused convergence references: references/convergence/convergence-signals.md, references/convergence/convergence-recovery.md, references/convergence/convergence-graph.md, and references/convergence/convergence-reference-only.md.
Focused state references: references/state/state-jsonl.md, references/state/state-outputs.md, and references/state/state-reducer-registry.md.
Templates: assets/deep-research-config.json, assets/deep-research-strategy.md, assets/deep-research-dashboard.md, assets/prompt-pack-iteration.md.tmpl, and assets/runtime-capabilities.json.
Cross-skill alignment: deep-research owns iterative investigation; its resource family mirrors deep-review/deep-ai-council, but vocabulary stays novelty/sources/negative-knowledge/question-coverage/synthesis, not severity findings or council agreement.
config.resource_map.emit == false (operator flag: --no-resource-map)Blocking: valid config/strategy/state before loop; iteration markdown + JSONL + reducer refresh per iteration; final research/research.md and convergence report after loop; quality guards for source diversity/focus/no weak single source. Continuity save is expected but non-blocking.
Every completed loop produces a convergence report:
Operates within the active runtime's root-doc behavioral framework (CLAUDE.md/AGENTS.md).
Key integrations:
skill_advisor.py (keywords: autoresearch, deep research)/speckit:resume is the operator-facing recovery surface; canonical packet continuity is written via generate-context.jsBefore research: recover context via /speckit:resume (handover.md -> _memory.continuity -> spec docs). During each iteration: write iterations/iteration-NNN.md, record the JSONL delta through the append gateway, let the reducer refresh strategy/registry/dashboard. After research: save continuity via generate-context.js.
| Command | Relationship |
|---|---|
/deep:research | Primary invocation point |
/speckit:resume | Canonical recovery surface before resuming/extending a packet |
/speckit:plan | Next step after deep research completes |
/memory:save | Manual memory save (deep research auto-saves) |
The router discovers reference and markdown asset docs dynamically: start with references/guides/quick-reference.md, then route by intent to loop protocol, spec anchoring, convergence, state, runtime parity, or recovery references.
Scripts: scripts/reduce-state.cjs, scripts/runtime-capabilities.cjs.
Related skills: deep-review (iterative audit loops), system-spec-kit (command-owned state, packet anchoring, continuity saves). Shared executor/state/coverage-graph runtime lives in this hub's own runtime/ infrastructure layer, not a separate skill.
Frequently asked questions
Note: Task is allowed for the command executor that manages the loop. The @deep-research agent itself is LEAF-only and does not dispatch sub-agents.
The source record exposes this install command: npx skills add https://github.com/MichelKerkmeester/opencode--skilled-agent-loops-with-spec-kit-memory --skill ".opencode/skills/system-deep-loop/deep-research". Inspect the command and pinned source before running it.
Static rules flagged exec-script, write-files in the source; the page lists the matching lines and excerpts.
Alternatives
brucesongs/kali-claw
Multi-source intelligence gathering through systematic web research — producing thorough, cited reports from diverse sources.
lovstudio/skills
Use when the user needs multi-source research with citation tracking, evidence persistence, and structured report generation. Triggers on "deep research", "comprehensive analysis", "research report", "compare X vs Y", "analyze trends", or "state of the art". Not for simple lookups, debugging, or questions answerable with 1-2 searches.
samber/cc-skills
Deep research skill — broad parallel web searches, multi-source validation, confidence tracking, cited Markdown report. Supports 11 research types: market (TAM/SAM, segments, pricing, trends), domain (industry structure, ecosystem, regulatory landscape), technical (architecture, tools, benchmarks), competitive (competitor teardown, positioning, win/loss), product (feature analysis, reviews, roadmap signals), academic (literature survey, citation networks, key authors), person/org (due diligence
Imbad0202/academic-research-skills
Universal deep research agent team. 13-agent pipeline for rigorous academic research on any topic. 8 modes: full research, quick brief, paper review, lit-review, fact-check, three-way literature scan, Socratic guided research dialogue, and systematic review with optional meta-analysis. Covers research question formulation, Socratic mentoring, methodology design, systematic literature search, source verification, cross-source synthesis, risk of bias assessment, meta-analysis, APA 7.0 report compi