AgentStack
SKILL verified MIT Self-run

Deep Research

skill-michelkerkmeester-opencode-skilled-agent-loops-with-spec-kit-memory-deep-research · by MichelKerkmeester

Autonomous deep-research loop: iterative investigation, externalized state, convergence detection, fresh context per pass.

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-michelkerkmeester-opencode-skilled-agent-loops-with-spec-kit-memory-deep-research

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Deep Research? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Autonomous Deep Research Loop

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: .opencode/agents/*.md
  • Claude runtime: .claude/agents/*.md
  • Codex runtime: .codex/agents/*.toml

Operator contract precedence for this skill surface:

  • 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

Convergence Threshold Semantics

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 ratio
  • deep-ai-council uses 0.20 default on adjudicator-verdict stability

Carrying threshold expectations across siblings will cause unexpected iteration counts. See this skill's changelog and decision records for the cross-sibling threshold research and parity invariants that confirm thresholds do not carry across siblings.

1. WHEN TO USE

Activation Triggers

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

Keyword triggers:

  • autoresearch
  • deep research
  • autonomous research
  • research loop
  • iterative research
  • multi-round research
  • deep investigation
  • comprehensive research

Use Cases

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.

When NOT to Use

  • Simple, single-question research (use direct codebase search or /speckit:plan)
  • Known-solution documentation (use /speckit:plan)
  • Implementation tasks (use /speckit:implement)
  • Quick codebase searches (use @context or direct Grep/Glob)
  • Fewer than 3 sources needed (single-pass research suffices)

2. SMART ROUTING

> Pattern: aligned with the [sk-doc smart-router resilience template](../sk-doc/assets/skill/skillsmartrouter.md).

Resource Domains

The router discovers markdown resources recursively 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 for the first-touch operator cheat sheet.
  • references/protocol/loop_protocol.md for lifecycle, dispatch, reducer sequencing, and command-owned state flow.
  • references/protocol/spec_check_protocol.md for bounded spec.md anchoring and generated-fence write-back.
  • references/convergence*.md for stop contracts, signals, recovery, graph gates, and reference-only convergence ideas.
  • references/state*.md for packet layout, JSONL records, markdown outputs, reducer ownership, and reconstruction.
  • references/guides/capability_matrix.md for runtime parity.
  • assets/*.md for markdown templates and prompt assets that are safe to route through guarded markdown loading.

Resource Loading Levels

| 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 Signals

| 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 |

Smart Router Pseudocode

The authoritative routing logic for scoped loading, weighted intent scoring, ambiguity handling, and graceful fallback.

  • Pattern 1: Runtime Discovery - discover_markdown_resources() recursively scans references/ and assets/.
  • Pattern 2: Existence-Check Before Load - load_if_available() guards paths, checks inventory, and suppresses repeats with seen.
  • Pattern 3: Extensible Routing Key - intent labels route to loop resource families without static file inventories.
  • Pattern 4: Multi-Tier Graceful Fallback - UNKNOWN_FALLBACK_CHECKLIST requests disambiguation and 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", "codex", "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"],
    "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"],
    "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]  1 and ranked[1][1] > 0 and (ranked[0][1] - ranked[1][1])  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])  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

3. HOW IT WORKS

Invocation Contract

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.

Executor Selection Contract

The YAML workflow owns executor selection. Native @deep-research is the default path; CLI executors are routed through the workflow, not through ad hoc shell loops.

Cross-CLI delegation is possible inside each executor sandbox but discouraged. Do not invoke the same CLI from within itself, and do not assume auth from a parent executor propagates to child CLIs.

Executor invariants:

  1. Produce a non-empty iteration markdown file at {state_paths.iteration_pattern}.
  2. Append a JSONL delta record to {state_paths.state_log} with required fields: type, iteration, newInfoRatio, status, and focus.
  3. Respect the LEAF-agent constraint: no sub-dispatch, no nested loops, and max 12 tool calls per iteration.

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.

Lifecycle Contract

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 are fork and completed-continue. They are reserved but not runtime-supported.

Code-Graph Readiness TrustState Surface

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.

Resource Map Integration

When {spec_folder}/resource-map.md exists at init, deep research promotes it from ad hoc context to canonical packet state.

  • Persist resource_map_present: true in deep-research-config.json.
  • Read the map once during init and summarize it into deep-research-strategy.md Known Context.
  • The snapshot MUST include per-section entry counts across READMEs, Documents, Commands, Agents, Skills, Specs, Scripts, Tests, Config, and Meta.
  • The snapshot MUST also include a one-line theme summary for each resource-map section so later iterations inherit the map's structure without rereading the entire file.
  • Per-iteration prompts surface resource-map.md as the exclusion set for previously inventoried files.
  • Treat files already listed on the map as known inventory, not as net-new discoveries.
  • Only flag files as gaps when they look relevant to the active investigation and are missing from the map.
  • Final synthesis cites {spec_folder}/resource-map.md in research.md References when the map was present at init.
  • Convergence also emits {artifact_dir}/resource-map.md from research delta evidence unless the operator passes --no-resource-map.

When {spec_folder}/resource-map.md is absent at init:

  • Persist resource_map_present: false.
  • Write resource-map.md not present; skipping coverage gate into Known Context.
  • Omit the exclusion-set hint from iteration guidance.
  • Continue the loop normally; absence is informational, not a failure.

Architecture: 3-Layer Integration

/deep:research owns the YAML workflow, which initializes state, dispatches one LEAF iteration at a time, evaluates convergence, synthesizes research/research.md, and saves continuity. The @deep-research agent executes only one research cycle per dispatch.

State Packet Location

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 at {spec_folder}/research/. A pt-NN subfolder ({basename(spec_folder)}-pt-{NN}) is allocated only when prior content already exists in research/ for a non-matching target (continuation runs reuse the

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.