Dev-Loop Investigate Mode
Proactive finding queue pipeline. Scans project health across four sources,
deduplicates against existing work, and writes schema-valid queued findings in
the vault. Findings stay non-executable until a human promotes them into
status: planned work items.
Prerequisites
Vault required. If query_vault not in BACKEND_CAPS, refuse:
"Investigate mode requires a vault — run /dev-loop setup to configure one."
This gate is an architectural decision (ADR: projects/{slug}/architecture/ investigate-mode-vault-required.md). See the ADR for trade-off rationale
and upgrade path.
Invocation
The parent dev-loop controller parses args and delegates here with:
INTENSITY:normal|highINVESTIGATE_TOPIC: string or empty
/dev-loop investigate → normal, no topic
/dev-loop investigate high → high, no topic
/dev-loop investigate "plugin SDK changes" → normal, topic set
/dev-loop investigate high "plugin SDK changes" → high, topic set
Model Strategy
| Step | Model | Rationale |
|---|---|---|
| 1. QUERY | sonnet (agent) | Vault search — mechanical lookup |
| 2. SCAN | sonnet (agent) | Research-worker already runs on sonnet |
| 3. DEEPEN | sonnet (agent) | Deep-research manages its own model internally |
| 4. TRIAGE | parent (inline) | Judgment: which findings matter, ranking, dedup |
| 5. SPEC | parent (inline) | Writing specs is creative/architectural |
| 6. RETRO | parent (inline) | Low token, always inline |
| 7. SAVE | parent (inline) | Vault auto-commit, low token |
~70% token spend on sonnet (SCAN + DEEPEN), ~30% on parent (TRIAGE + SPEC).
Configuration
Read from investigate section in .claude/dev-loop.config.md:
investigate:
max_items: 5 # cap per invocation (high doubles it)
topic_seeds: [] # fallback when no user topic; reuses idle_deep_research.topic_seeds if empty
Defaults when absent:
max_items: 5topic_seeds: falls back toidle_deep_research.topic_seedsfrom config. If that's also empty, DEEPEN step is skipped unless user provides a topic.
Pipeline
┌─────────────────────────────────────────────────────────┐
│ 0. REFRESH (already done by parent dev-loop) │
├─────────────────────────────────────────────────────────┤
│ INVESTIGATE CORE │
│ 1. QUERY Context check — existing work items, │
│ prior investigate runs, retros │
│ 2. SCAN Research-worker (Track A + Track B) │
│ + unclaimed transcripts │
│ 3. DEEPEN Deep-research (high or user topic only) │
│ 4. TRIAGE Deduplicate, rank, cap │
│ 5. SPEC Queue findings (schema-adaptive output) │
├─────────────────────────────────────────────────────────┤
│ POSTLUDE │
│ 6. RETRO Log investigation results │
│ 7. SAVE Vault auto-commit │
└─────────────────────────────────────────────────────────┘
Step Details
1. QUERY — context for dedup
Gather existing state to prevent duplicate work-item creation:
- List existing work items —
ls {vault}/projects/{slug}/work/to get all current slugs and their statuses. Parse spec.md frontmatter forstatus,name,title, andkind. - Check project history —
ls {vault}/projects/{slug}/history/for archived work-item slugs (completed work that shouldn't be re-proposed). Ifhistory/is absent, treat as empty. - List queued raw captures — scan
{vault}/raw/transcripts/for ad-hoc captures withproject: "[[<project-slug>]]"and slugs matching investigation output (YYYY-MM-DD-<kind>-<slug>.md). - Read recent retros — scan
{vault}/log.mdfor the last 10 retro entries to understand what's been investigated recently. - Check prior investigate runs — grep log.md for
investigate-cycleentries. If the last investigate run was <24h ago AND intensity is the same, warn: "Investigate ran recently ( ago) — findings may overlap. Continue anyway." Do not block.
Store results as EXISTING_SLUGS (set of name slugs + statuses) and
HISTORY_SLUGS (set) for TRIAGE. Store queued transcript slugs as
QUEUED_CAPTURE_SLUGS.
2. SCAN — research-worker (code + vault health + transcripts)
Invoke the existing research-worker with the same interface as IDLE step 4:
Agent(description: "Investigate scan", subagent_type: "dev-loop:research-worker",
model: "sonnet", prompt: "Run research cycle with intensity: <INTENSITY>.
BACKEND_CAPS: <caps>. VAULT_TYPES: <types>. CRITICAL_PATHS: <paths>.
Scan code health and vault health per research/SKILL.md.
Return ALL findings regardless of P-score — do not filter.
Output as structured findings list.")
Key difference from IDLE: request ALL findings, not just top-N. TRIAGE handles filtering — the scan should be exhaustive.
Inline fallback: If agent spawn fails (1M-context error per session
memory), run the research scan inline using Skill("dev-loop:research").
Unclaimed transcripts — after research-worker returns, scan
{vault}/raw/transcripts/ for files matching the project slug that are
NOT referenced by any existing work item's closes: list. Each unclaimed
transcript is a candidate finding:
kind: idea→ P3 findingkind: bug→ P2 findingkind: task→ P2 finding- Other/unknown → P3 finding
3. DEEPEN — deep-research (conditional)
Hard skip gate (always):
deep-research:deep-researchinDEP_DRIFT
When this dependency is missing, skip DEEPEN regardless of intensity/topic. Continue with SCAN-only findings.
Run if ANY of (when dependency is available):
INTENSITY == high(usetopic_seedsround-robin or first unused seed)INVESTIGATE_TOPICis non-empty (user explicitly asked — run regardless of intensity)
Otherwise skip:
INTENSITY == normalANDINVESTIGATE_TOPICis empty
Execution:
If INVESTIGATE_TOPIC is set:
Invoke Skill("deep-research") with topic = INVESTIGATE_TOPIC
If topic is empty (high mode, no user topic):
- Pick next topic from
investigate.topic_seeds(or fall back toidle_deep_research.topic_seeds). Round-robin based on which seeds have NOT been investigated in the last 7 days (check vault query pages). - If all seeds are recently covered, skip DEEPEN.
Output: Extract actionable ideas from deep-research results. Each idea becomes a candidate finding with:
- P-score: P3 (exploratory by default)
- kind:
idea - Source:
deep-research: <topic>
Budget: Honor idle_deep_research.budget.* caps if configured.
Default: max_sources: 5, max_tokens: 50000.
4. TRIAGE — deduplicate, rank, cap
This step runs inline on the parent model — it's the judgment core of investigate.
Input: Combined findings from SCAN + DEEPEN (if run).
Step 4a — Deduplicate:
For each candidate finding, generate a slug from its title (lowercase, hyphens, strip common words). Then check:
- If slug ∈
EXISTING_SLUGS:- Status
proposedorplanned→ skip (already queued) - Status
in-progress→ skip (being worked on) - Status
completed→ skip unless the finding references changes since the completion date
- Status
- If slug ∈
QUEUED_CAPTURE_SLUGS→ skip (already queued as a raw transcript capture) - If slug ∈
HISTORY_SLUGS→ skip (work completed and archived) - If slug matches an existing slug with >70% character overlap (Levenshtein or common-prefix) → flag as "possibly related" but still include
Log skipped duplicates: "Skipped: (existing: )"
Step 4b — Rank:
Sort remaining findings by:
- P-score (P0 first)
- Within same P-score: critical-path matches first (if
CRITICAL_PATHSset) - Within same P-score and critical-path tier: concrete findings before exploratory ones
Step 4c — Cap:
Apply intensity-based cap:
normal:investigate.max_items(default 5)high:investigate.max_items * 2(default 10)
Discard findings beyond the cap. Log: "Capped at items ( total findings, deduplicated)."
Step 4d — Tier assignment:
For each surviving finding, assign an output tier:
- Full spec — the finding points to a concrete code change with identifiable files, functions, or expected behavior. Examples: "simplify has no tests", "marketplace.json version drift", "missing pre-flight check in script X."
- Stub — the finding points to a question, investigation, or exploratory improvement. Examples: "investigate agentmemory integration", "research Claude Code SDK v2 changes", "evaluate alternative lint rules."
Heuristic: if the finding references specific file paths or has a clear
acceptance criteria expressible as a command (test passes, lint clean,
version matches), it's a full spec. Otherwise, stub.
5. SPEC — queue findings
For each triaged finding, create a schema-valid queued artifact. The queue format is schema-adaptive because skillwiki installations differ on whether a non-executing work-item status exists.
Schema probe (before first durable output):
- Before creating durable output, create one disposable schema-probe candidate
that uses
status: proposed. Use the smallest valid candidate needed for validation; it is evidence, not a queued finding. - Run
skillwiki validate <candidate-spec.md>. - Always delete the probe candidate after validation.
- If validation passes, use Mode A: proposed work item queue for this invocation.
- If validation rejects
status: proposed,kind, or lifecycle fields, use Mode B: raw transcript capture queue for the whole invocation. Current SkillWiki schemas such as 0.9.16 rejectstatus: proposed, so this fallback is the expected path for those vaults.
Do not continue after a validation failure with the same invalid shape.
Mode A: proposed work item queue
Use this mode only when the local schema validates non-executing proposed work
items. This mode is unavailable for current SkillWiki schemas such as 0.9.16,
which reject status: proposed. For each triaged finding, create a work item
via proj-work and validate the resulting spec.md.
Common frontmatter:
---
title: "<conventional-commit-style title>"
name: <slug>
description: "<one-paragraph summary>"
kind: <feature|issue|refactor|decision>
status: proposed # only when local schema supports it
priority: <high|medium|low> # derived from P-score: P0-P1→high, P2→medium, P3+→low
project: "[[<project-slug>]]"
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags:
- <project-slug>
- investigate
- <source-track> # e.g., code-health, vault-health, transcript, deep-research
source_investigate: true # marker for investigate-created items
---
Full spec body:
# <title>
## Problem
<What's wrong or missing — from the finding>
## Requirements
<Concrete changes needed — files, functions, expected behavior>
## Acceptance
<Verifiable outcomes — commands to run, states to check>
## Sources Used
- <finding source reference>
Stub body:
# <title>
## Problem
<What's wrong or missing — from the finding>
## Investigation Questions
- <What needs to be explored before this can be spec'd>
- <What alternatives exist>
## Acceptance
- Investigation questions answered
- Decision recorded (ADR if architectural)
- Follow-up work item created if action needed
Work-item kind mapping:
| Finding source/type | Work-item kind |
|---|---|
| Concrete bug or failing behavior | issue |
| User-facing capability or new workflow | feature |
| Internal cleanup with no behavior change | refactor |
| Exploratory architecture choice | decision |
Mode B: raw transcript capture queue
Use this mode when skillwiki validate rejects proposed work items. This is
the expected path for current SkillWiki schemas such as 0.9.16. Create a
schema-valid ad-hoc capture under:
{vault}/raw/transcripts/YYYY-MM-DD-<capture-kind>-<slug>.md
Frontmatter:
---
source_url:
ingested: YYYY-MM-DD
kind: <task|bug|idea|note>
project: "[[<project-slug>]]"
---
No sha256 is used for ad-hoc captures; they are mutable working notes, not
immutable raw sources. Validate each capture with skillwiki validate.
Capture kind mapping:
| Finding source/type | Capture kind |
Claim behavior |
|---|---|---|
| Concrete actionable change | task |
Appears in unclaimed transcript discovery |
| Concrete defect/regression | bug |
Appears in unclaimed transcript discovery |
| Exploratory improvement | idea |
Preserved but not executable by default |
| Context-only observation | note |
Preserved but not executable by default |
Capture body:
# <title>
## Problem
<What's wrong or missing — from the finding>
## Recommended Promotion
Promote this capture into a `planned` project work item only after a human
confirms scope and priority.
## Requirements Or Questions
<Concrete requirements for task/bug, or investigation questions for idea/note>
## Acceptance
<Verifiable outcomes, or decision/output expected from investigation>
## Sources Used
- <finding source reference>
Rate limiting: If creating >3 items, batch-commit vault changes after every 3 items to avoid large uncommitted working trees.
6. RETRO — log investigation
Append to {vault}/log.md:
## [YYYY-MM-DD] retro | investigate-cycle: <project-slug>
- Mode: investigate (<intensity>)
- Topic: <user topic or "autonomous">
- Scanned: <N> total findings
- Deduplicated: <K> skipped
- Queued: <M> findings (<A> proposed work items, <B> raw captures)
- Items: <slug1> (P<x>), <slug2> (P<y>), ...
- Friction: <any issues during investigation>
- Generalize?: no
- ClaudeMd?: no
- WorkflowShift?: no
7. SAVE — vault auto-commit
Same as CORE step 7:
- If
VAULT_AUTO_COMMITis true AND vault is dirty:git -C $VAULT add -A && git -C $VAULT commit -m "dev-loop[investigate]: <N> queued findings for <slug>" - If
VAULT_SYNC_PEER_AWARE: acquire lock, push, release. - If presync skill available: run before push.
Hard Rules (investigate-specific)
- Never create
status: planneditems. Investigate output is queued, not executable. The human promotes. - Never execute work. Investigate queues findings, not code. If a finding is trivially fixable, still queue it — let CORE's trivial fast-path handle it after human promotion.
- Respect the cap. Never exceed
max_items * (2 if high else 1). If TRIAGE produces more, discard the lowest-ranked. - Dedup is mandatory. Every finding must pass the slug + status + archive check. Skipping dedup creates vault clutter.
- Validate the chosen queue shape. If
status: proposedfails validation, switch to raw transcript captures for the whole invocation. - Log everything. RETRO must include counts (scanned, deduped, queued) for auditability. Silent investigate runs are forbidden.
Interaction with Other Modes
| Scenario | Behavior |
|---|---|
/dev-loop investigate then /dev-loop |
CORE picks up only promoted planned work; raw task/bug captures surface as unclaimed transcripts |
/dev-loop investigate then /dev-loop investigate |
TRIAGE dedup prevents duplicates |
/loop 2h /dev-loop investigate |
Recurring investigation, safe due to dedup + 24h warning |
/dev-loop investigate with no vault |
Refuses with actionable message |
| IDLE research finds P2+ | Does NOT auto-create items (IDLE stays passive) |