Skill: anderskev/artifact-analysis (version 1.0.0)

--- name: artifact-analysis description: "Use when the user wants a cited, structured read of local documents and project knowledge. Triggers on: \"analyze these docs\", \"scan my project for context\", \"read the docs folder\", \"summarize what's in .beagle/concepts/\", \"extract context from docs/\", \"what's in this folder\", \"go read everything in X and tell me what's there\". Also invoked programmatically by other beagle skills (prfaq-beagle Ignition, brainstorm-beagle reference points, strategy-interview context grounding) via the companion contract. Does NOT trigger on codebase lookups (\"find this function\", \"search the repo\"), web research (use web-research), LLM-as-judge evaluation (use llm-judge), or document editing (use humanize-beagle). Produces a written scan plan, parallel-subagent findings, and a cited synthesis report on disk — never inline prose, never unsourced claims." --- # Artifact Analysis Turn a set of local paths (or a beagle project's conventional knowledge locations) into a cited, structured extraction of insights, context, decisions, and raw detail. The deliverable is always on disk: a written scan plan the caller can audit, one findings file per slice, and a synthesized report with path-anchored citations. Nothing returns as inline prose, and no claim ships without a source path + verbatim excerpt behind it. ## When to use - A user asks for a local-document read — "analyze the docs folder", "scan the project for context", "extract what's in .beagle/concepts/". - Another beagle skill invokes this one programmatically as a grounding companion (see `references/companion-contract.md`). - The caller wants auditable output: a plan written before extraction, findings files per slice, and a citation-backed synthesis report. ## When NOT to use - Codebase lookups ("where is this function defined", "grep for this symbol"). Use Grep/Glob. - Web research. Use `web-research`. - Comparative evaluation of two implementations or source credibility adjudication. Use `llm-judge`. - Rewriting or editing the scanned documents. Use `humanize-beagle` or the file tools. - PDF / image OCR / format conversion. First version reads plain text and markdown only. `beagle-core:docling` is the future path. - Paywalled or authentication-gated remote sources. This is a local-filesystem primitive. - Coaching, challenge, or reshaping of the caller's question. That belongs to the caller. ## Workflow Four steps, in order. No step is skippable. ### Hard gates Advance to the next step only when the **pass condition** is true—confirm using files under `output_dir` (and tool output), not memory. | After | Pass condition | | --- | --- | | `plan.md` written | `plan.md` exists and includes intent, resolved paths, slices, per-slice briefs, skip patterns, budgets applied, and synthesis approach (same fields as **The scan plan (`plan.md`)**). | | Subagent dispatch | Either the **empty corpus** path was taken (no subagents; `plan.md` documents zero readable documents) **or** every slice listed in `plan.md` has `findings/<slice-slug>.md` on disk. | | `report.md` written | `report.md` exists; headings match `references/report-template.md` (seven sections plus `## Sources`). | | Before return to caller | Every row of `references/failure-modes.md` → **Verification checklist (orchestrator runs at end)** is checked off, *or* any failed check is recorded under `## Gaps & Limitations` in `report.md` as that failure-modes file prescribes. | 1. **Write `plan.md`** — resolved paths (with any auto-discovery applied), intent summary (when provided), per-slice briefs, skip patterns, and how findings will be synthesized. 2. **Dispatch subagents** — spawn 1-3 parallel subagents over non-overlapping slices of the resolved paths. Each writes `findings/<slice-slug>.md` under `output_dir`. 3. **Synthesize `report.md`** — fold findings into the seven fixed sections with path-anchored citations. 4. **Verify before returning** — satisfy the last **Hard gates** row; execute the numbered checklist in `references/failure-modes.md` (**Verification checklist (orchestrator runs at end)**). Any check that fails becomes an entry in `Gaps & Limitations` per that file—do not return a deliverable with silent checklist failures. ``` Receive paths + optional intent ──→ Auto-discover if paths empty ↓ Write plan.md (no user-confirmation pause) ↓ Dispatch subagents (up to 3 parallel) ↓ Collect findings/<slice>.md files ↓ Synthesize report.md ↓ Return paths to caller ``` Unlike `web-research`, artifact-analysis does **not** pause for a plan review gate. Local scanning is cheap; `plan.md` is written for auditability so a reader weeks later can tell what each subagent was told. Unlike web-research, there is no fail-fast on missing tools — filesystem tooling (Read, Glob, Grep) is assumed present in the Claude Code environment. ## Inputs | Field | Type | Required | Default | Purpose | | ------------ | ------------------ | -------- | ------------- | ----------------------------------------------------------------------------------- | | `intent` | string | no | — | What the caller is looking for / why. When absent, the skill extracts anything structurally important. | | `paths` | list of strings | no | auto-discover | Directories and/or explicit files. When absent, auto-discover (see below). | | `output_dir` | absolute path | no | derived | Where `plan.md`, `findings/`, and `report.md` land. | | `refresh` | bool | no | `false` | When true, allow overwriting a prior run in the same `output_dir`. | The skill does not parse caller-specific structures. Callers pass an intent string and/or a path list. ### Auto-discovery When `paths` is absent or empty, scan beagle's conventional knowledge locations: - `.beagle/concepts/` — concept specs and analysis folders. - `.planning/` — roadmap, state, and phase artifacts. - `docs/` — project documentation. - Top-level files matching `README*`, `BRIEF*`, `OVERVIEW*`, `CONTEXT*`, `CLAUDE.md`, `AGENTS.md`. Resolved paths (including any auto-discovery) are listed verbatim in `plan.md` so the caller can see exactly which files were included. ### Intent modes - **`intent` present** — extraction is targeted to what is relevant to the intent. Off-topic material goes into `Raw Detail Worth Preserving` only when it is a specific quote or metric worth keeping. - **`intent` absent** — generic-salient-extraction mode. Subagents extract anything structurally important (insights, decisions, technical constraints, user/market context) without an interpretive filter. ## Output location If the caller passes `output_dir`, use it verbatim. Otherwise derive the default: ``` .beagle/analysis/<slug>/ ``` **Slug derivation** (stable so re-running the same input on the same day lands on the same folder): 1. If `intent` is present, slug from the intent string: lowercase, strip punctuation, collapse whitespace to single hyphens, truncate to 60 characters on a word boundary (cut at the last hyphen before 60; if no hyphen exists before position 60, hard-cut at 60). 2. If `intent` is absent, slug from the first scanned path's basename using the same rules. 3. Prepend `YYYY-MM-DD-`. **Re-run protection.** Before writing anything, check whether `output_dir` already contains `plan.md` or `report.md`. If it does and `refresh` is not `true`, refuse with a message naming the existing folder. When `refresh: true`, archive the prior contents into `<output_dir>/.archive-<timestamp>/` before starting fresh. See `references/failure-modes.md`. Callers embedding artifact-analysis in a concept-folder convention (e.g. `prfaq-beagle`) pass `output_dir` explicitly so the analysis sits next to its consumer: `.beagle/concepts/<concept-slug>/analysis/`. ## The scan plan (`plan.md`) The plan is written before any subagent runs. It is the audit trail, not a review gate — the skill does not pause for user confirmation. `plan.md` contains: - **Intent** — the input string, verbatim, or `"generic salient extraction"` when intent is absent. - **Resolved paths** — every path that will actually be scanned, with a note next to any entry that came from auto-discovery vs. caller-specified. - **Slices** — how the resolved paths are partitioned across 1-3 subagents. Slices are non-overlapping. - **Per-slice briefs** — one paragraph per slice summarizing what that subagent is told to extract. Derived mechanically from the spec so a reader of `plan.md` can predict what each subagent was told. - **Skip patterns** — the denylist applied to this run (see `references/skip-patterns.md`). - **Budgets applied** — subagent count for this run (1-3) and the skim threshold in effect (see Budget defaults below). - **Synthesis approach** — how the per-slice findings will combine into `report.md`. Report: `Wrote plan.md` and proceed to dispatch. No pause, no gate. ## Subagent dispatch Up to 3 subagents run concurrently over non-overlapping slices. Each gets a mechanically-derived brief built from `plan.md` — no interpretation drift between the plan and the briefs. The brief template lives in `references/subagent-brief.md`. Each subagent: - Scans its assigned slice of paths, honoring skim strategies (sharded-doc: read index first; large-doc: TOC/headings first) and skip patterns. - Writes `findings/<slice-slug>.md` under `output_dir`. - Returns one terse status line to the orchestrator (path + status), never inline findings. The orchestrator waits for all subagents to finish, then verifies every expected findings file exists before synthesis. A missing file is a silent failure, recorded in `Gaps & Limitations` — see `references/failure-modes.md`. ### Skim strategies Subagents do not read everything end-to-end. They apply: - **Sharded documents** (folder with `index.md` plus multiple sub-files) — read `index.md` first, then only the sub-files the index points to as relevant. - **Large documents** (single file > ~50 pages or > ~2000 lines) — read the TOC, executive summary, and section headings first; pull full content only from sections relevant to the intent (or structurally important when intent is absent). The findings file records which sections were skimmed vs. read fully. - **Short documents** (single file, moderate size) — read end-to-end. ### Skip patterns Sensitive, binary, and vendor/build paths are skipped silently without the caller re-specifying them. The default denylist lives in `references/skip-patterns.md`. Each subagent records the paths it skipped under the `paths_skipped` frontmatter field so the audit trail shows exactly what was excluded. ## Citations Every claim in a findings file and in `report.md` carries a citation. The shape lives in `references/citation-schema.md`. At a glance: - **Required fields:** `path` (relative to the scanned root when possible), `excerpt` (a verbatim quoted string from the document). - **Optional fields:** `lines` (line range or single line, only when the subagent naturally has them — never synthesized), `heading` (the nearest enclosing heading), `document_type`. Inline references use `[^n]` footnotes; the full citation sits in the numbered `Sources` section at the bottom of the report. ## Synthesis (`report.md`) The report has a fixed seven-section layout, in this order. Every section is required, every time — even when a section is thin, the report includes a bullet saying so. 1. `## Documents Found` — each included path with a one-line note on its relevance. 2. `## Key Insights` — the highest-signal observations from the corpus, grouped by theme. 3. `## User / Market Context` — users, customers, competition, market data surfaced from the documents. 4. `## Technical Context` — platforms, constraints, integrations, dependencies. 5. `## Ideas & Decisions` — each tagged `accepted`, `rejected`, or `open` with rationale. Rejected ideas are preserved deliberately so future work does not re-propose them. 6. `## Raw Detail Worth Preserving` — specific quotes, data points, metrics, and other detail that would be lost to summarization. 7. `## Gaps & Limitations` — what the corpus could not establish; which paths were empty, skipped, or unreadable; which subagents failed. `Gaps & Limitations` is required even when the scan looks complete. Honest accounting of what was and was not in the corpus is part of the product. The full literal skeleton the skill copies from lives in `references/report-template.md`. ## Failure modes - **Partial success** — one or more subagents fail. The skill continues with what succeeded and enumerates each failed slice under `Gaps & Limitations`, including the last-known brief and the stub-file reason. - **Empty corpus** — path resolution (auto-discovery + explicit paths) yields zero readable documents. The skill writes `plan.md` and a minimal `report.md` with a single "no documents found" bullet under `Gaps & Limitations`, does not spawn subagents, and returns cleanly to the caller. Callers decide how to proceed. - **Silent-failure detection** — every subagent writes at least a stub `findings/<slice-slug>.md` with `status:` frontmatter (`ok`, `empty`, `failed`) before returning. Missing file after dispatch = silent failure, recorded in `Gaps & Limitations`. - **Re-run protection** — covered under "Output location" above; details in `references/failure-modes.md`. Unlike `web-research`, artifact-analysis does **not** fail-fast on missing tools. Filesystem tooling (Read, Glob, Grep) is assumed present in the Claude Code environment. If it is somehow absent, the skill will surface that as a subagent failure under partial-success rather than aborting the whole run. Full rules and the structured error shape live in `references/failure-modes.md`. ## Budget defaults Tunable knobs, not hard-coded invariants: | Knob | Default | | ----------------------- | -------------- | | Parallel subagents | 1-3 | | Slice overlap | none (enforced) | | Skim threshold (large) | > ~2000 lines or > ~50 pages | A caller that needs narrower or broader scope overrides by passing a more specific `paths` list — one path per subagent forces narrower slicing; a single folder lets the skill partition internally. ## Companion invocation contract Other beagle skills invoke this one via a small, documented contract. The minimal call passes only `intent`; the full call adds `paths`, `output_dir`, and `refresh`. Worked examples for the three known callers (`prfaq-beagle`, `brainstorm-beagle`, `strategy-interview`) plus the success and refusal return shapes live in `references/companion-contract.md`. Callers are expected to honor the contract verbatim rather than invent parallel invocation styles. ## Tone This skill is a tone-neutral primitive. It does not: - Coach the caller on which documents matter. - Adjudicate document quality or claim credibility (that is `llm-judge`'s job). - Reshape the caller's intent into a different question. - Adopt a posture (hardcore, Socratic, warm) — that is the caller's job. - Editorialize in findings or the report. If the caller is a coaching skill (`prfaq-beagle`, `brainstorm-beagle`), the coaching happens before and after this skill runs. Inside this skill, the intent is treated as final. ## Out of scope - Scanning paywalled or authentication-gated remote sources. Use the file tools to extract content first, then pass paths in. - LLM-as-judge evaluation of document quality or claim credibility. Use `llm-judge`. - Coaching, challenge, or opinionated reshaping of the intent. - Rewriting or editing the scanned documents. Read-only by design. - Binary / image OCR, PDF text extraction, or format conversion. First version reads plain text and markdown only; `beagle-core:docling` is the future path. - Multi-language analysis. English-only today. - Caching or re-use of prior findings across invocations. - Long-running or scheduled scans. ## Reference files - `references/subagent-brief.md` — template the orchestrator mechanically fills from `plan.md` when dispatching each subagent. - `references/citation-schema.md` — required and optional citation fields, footnote convention, and a well-formed example. - `references/report-template.md` — literal `report.md` skeleton with all seven fixed sections. - `references/failure-modes.md` — partial-success, empty-corpus, silent-failure detection, and re-run protection rules. - `references/companion-contract.md` — programmatic invocation shape with worked examples for `prfaq-beagle`, `brainstorm-beagle`, and `strategy-interview`. - `references/skip-patterns.md` — default denylist (sensitive, binary/media, vendor/build) applied to every run.

path: references/citation-schema.md
content: # Citation Schema

Every claim in a findings file and in `report.md` carries a citation. The shape is small on purpose — enough metadata to verify without re-reading the full document, not so much that subagents start fabricating fields.

## Required fields

- **`path`** — the document the claim was drawn from. Relative to the scanned root when possible (e.g. `docs/architecture.md`); absolute only when the path lives outside the scanned tree.
- **`excerpt`** — a verbatim quoted string from the document that supports the claim. Keep it short enough to read at a glance (typically 1-3 sentences), long enough to stand on its own.

If either required field is missing or would have to be fabricated, do not include the citation. Drop the claim or mark it as unverified in `Gaps & Limitations`.

## Optional fields

Include only when the subagent naturally has them. Never synthesize.

- **`lines`** — line range (`L42-L58`) or single line (`L42`) where the excerpt appears. Include when reading a text/markdown file with stable line numbers. Omit for documents where line granularity is ambiguous (prose documents without visible line numbers, transcluded markdown, rendered output). Never guess.
- **`heading`** — the nearest enclosing heading, copied verbatim. Useful for anchoring the reader in long documents.
- **`document_type`** — one of:
  - `spec` — specification, requirements doc, or formal brief.
  - `adr` — architecture decision record.
  - `readme` — README, overview, or project-root context doc.
  - `planning` — roadmap, state, phase, or plan artifact.
  - `concept` — beagle concept spec or analysis.
  - `transcript` — meeting notes, interview transcript, or chat log.
  - `other` — anything that does not fit.

Omit fields you do not have. An incomplete citation with two real fields beats a five-field citation with three guessed values.

## Footnote convention

In findings and in `report.md`, claims use `[^n]` inline footnote markers:

```markdown
The skill must not pause for user confirmation before spawning subagents[^3].
```

The numbered `Sources` section at the bottom of `report.md` lists each citation in order, matching the footnote number. Numbering is global across the report, not per-section.

## Example — well-formed citation block

In `report.md`, the `Sources` section entries look like this:

```markdown
[^1]: **Path**: .beagle/concepts/artifact-analysis/spec.md
      **Excerpt**: "Partial-success behavior: if a subagent fails, the skill continues with the remaining findings and records the failure explicitly under Gaps & Limitations."
      **Lines**: L29
      **Heading**: Requirements
      **Document type**: spec

[^2]: **Path**: docs/architecture.md
      **Excerpt**: "All long-running jobs run on the worker queue, never the request thread."
      **Heading**: Background Processing
      **Document type**: readme
```

Citation `[^2]` omits `Lines` because the subagent did not have a stable line-number anchor. That is correct behavior — omit rather than guess.

## Incomplete-metadata policy

If a claim is genuinely load-bearing but the document lacks a clear line number or heading, keep the citation with the required fields (`path` + `excerpt`) only. Do not invent a line number to satisfy a schema slot. If the absence makes the claim hard to verify, note the uncertainty in `Gaps & Limitations` rather than citing confidently.


path: references/companion-contract.md
content: # Companion Invocation Contract

Other beagle skills invoke `artifact-analysis` via this contract. It is small on purpose — no required inputs (!), three optional parameters for scoping and one for overwrite control, two return shapes.

Callers are expected to honor the contract verbatim rather than invent parallel invocation styles. If a new caller needs behavior that the contract does not support, extend the contract here first, not in the calling skill.

## Minimal call

```yaml
# No parameters at all — auto-discover every beagle knowledge location, generic-salient-extraction mode.
```

With no inputs, the skill scans `.beagle/concepts/`, `.planning/`, `docs/`, and top-level README/brief/overview files, applies the default skip denylist, and extracts anything structurally important. Output lands at `.beagle/analysis/<YYYY-MM-DD>-<first-path-basename>/`.

## Full call

```yaml
intent: "competitive and technical grounding for PRFAQ on AI coding-assistant pricing"
paths:
  - .beagle/concepts/ai-coding-pricing/
  - docs/
output_dir: "/abs/path/.beagle/concepts/ai-coding-pricing/analysis/"
refresh: false
```

## Input semantics

- **`intent`** — one string describing what the caller wants. When present, extraction is weighted toward relevance to the intent. When absent, the skill runs in generic-salient-extraction mode. Tone-neutral; the skill does not reshape the intent.
- **`paths`** — directories and/or explicit files. When absent or empty, the skill auto-discovers beagle's conventional knowledge locations (see SKILL.md §Auto-discovery). When present, only the listed paths are scanned — auto-discovery does not run.
- **`output_dir`** — absolute path. Callers embedding artifact-analysis in their own concept folder (e.g. `prfaq-beagle`) pass this explicitly so the analysis sits next to its consumer.
- **`refresh`** — when `true`, a prior run in `output_dir` is archived to `<output_dir>/.archive-<timestamp>/` before the new run starts. See `failure-modes.md` for the archive rule.

## Return shapes

This skill returns one of two shapes. Callers that invoke multiple beagle companions should handle the union of error codes across all companions they call — sibling companions (e.g. `web-research`) may return different error codes (notably `web-tools-unavailable`).

- **success** — artifacts written. An empty-corpus run still returns this shape with a minimal `report.md`; the caller detects empty-corpus by reading the report, not by catching an error.
- **error: `prior-run-present`** — `output_dir` already holds a prior run and `refresh` is false; nothing written.

### Success

```yaml
plan: "<output_dir>/plan.md"
report: "<output_dir>/report.md"
findings_dir: "<output_dir>/findings/"
```

The caller receives absolute paths. All evidence lives on disk — nothing returns inline.

### Success with empty corpus

Empty-corpus is **not** an error. When path resolution yields zero readable documents, the skill still returns the Success shape above: `plan.md` exists (with an empty `Resolved paths` list), `report.md` exists (with every section present plus a `Gaps & Limitations` entry explaining no readable documents were found), and `findings_dir` exists (empty). Callers detect empty-corpus by reading `report.md`, not by catching an error.

### Refused (prior run present, no refresh)

```yaml
error: "prior-run-present"
detail: "<output_dir> already contains plan.md or report.md. Pass refresh: true to archive and overwrite."
```

The caller decides whether to retry with `refresh: true`, pick a different `output_dir`, or surface the refusal to its user.

## Worked examples

### `prfaq-beagle` — Ignition grounding

The PRFAQ's Ignition phase needs competitive and technical grounding from the user's own documents (PRDs, briefs, prior decisions). PRFAQ passes:

```yaml
intent: "competitive and technical grounding for PRFAQ on AI coding-assistant pricing"
paths: []  # empty → auto-discover .beagle/concepts/, .planning/, docs/
output_dir: "/abs/path/.beagle/concepts/ai-coding-pricing/analysis/"
refresh: false
```

Empty `paths` triggers auto-discovery so PRFAQ does not have to know where the user keeps briefs. `output_dir` lands inside the PRFAQ concept folder so the audit trail travels with the concept.

### `brainstorm-beagle` — reference-point grounding

Mid-brainstorm, the user says "go read the docs folder and tell me what we already decided." Brainstorm calls:

```yaml
intent: "prior decisions and reference points relevant to the current idea"
paths:
  - docs/
  - .beagle/concepts/
output_dir: "/abs/path/.beagle/concepts/task-sub-tasks/analysis/"
refresh: false
```

Explicit `paths` keeps the scan narrow. `output_dir` lands inside the brainstorm concept folder so the reference points can link straight to `report.md`.

### `strategy-interview` — context grounding

During strategy interview Phase 1 discovery, the user needs a structured read of prior strategy artifacts. Strategy-interview calls:

```yaml
intent: "background context for platform-team H1 2026 strategy discovery"
paths:
  - .beagle/strategy/
  - docs/
output_dir: "/abs/path/.beagle/strategy/platform-team-h1-2026/analysis/"
refresh: false
```

`output_dir` lands inside the strategy interview's working-state folder so the analysis sits alongside `state.md`, `evidence.md`, and `composition.md`.

### Standalone user — "analyze these docs"

A user types "read everything in docs/ and tell me what's there" with no prior context. The skill is triggered directly and runs:

```yaml
# Triggered by user chatter. No intent passed → generic-salient-extraction mode.
paths:
  - docs/
# output_dir defaults to .beagle/analysis/<YYYY-MM-DD>-docs/
```

The user gets a `report.md` they can open immediately — no caller-specific wrapping.

## Non-obligations

The contract is explicit about what this skill does **not** do:

- **No intent reshaping.** The caller hands in an intent (or nothing). The skill does not argue with it, sharpen it, or reframe it.
- **No coaching posture.** `artifact-analysis` is tone-neutral. Callers that need a coaching tone (`prfaq-beagle`'s hardcore coach, `brainstorm-beagle`'s thinking partner) apply that tone before and after, not inside.
- **No inline findings.** Every deliverable is a file. Callers that want inline prose should summarize from `report.md` themselves.
- **No cross-run caching.** Each invocation stands alone. Callers that need caching build it themselves at the call site.
- **No doc editing or rewriting.** Read-only by design.

## Extending the contract

If a new caller needs behavior not covered here, add a field to the input table in SKILL.md first, document it in this file with a worked example, then update caller skills to use it. Parallel-invocation styles fragment the contract and re-introduce the reason this skill exists.


path: references/failure-modes.md
content: # Failure Modes

Four failure cases the skill handles explicitly. Silent failures are the worst kind — every rule below exists to make a failure visible to the caller and preserve what succeeded.

Unlike `web-research`, artifact-analysis does **not** fail-fast on missing tools. Filesystem tooling (Read, Glob, Grep) is assumed present in the Claude Code environment. If it is somehow absent, that surfaces as a per-subagent failure under partial-success rather than aborting the whole run.

## Partial success

One or more subagents fail; others return valid findings.

**Behavior:** continue with the successful findings. Do not abort the run.

In `report.md`, under `Gaps & Limitations`, enumerate every failed slice:

- Name the slice.
- Include the subagent's last-known brief (or a one-line summary of what it was asked to scan).
- Include the `reason` line from the stub findings file (see "Silent-failure detection" below).

Example:

```markdown
## Gaps & Limitations

- **Slice "planning-folder"** (status: failed) — subagent returned "Read timeout on .planning/phase-3/PLAN.md after 3 retries". Caller may retry this slice alone, or re-run with `refresh: true` after investigating the file.
```

## Empty corpus

Path resolution (auto-discovery + explicit paths) yields zero readable documents after the skip denylist is applied.

**Behavior:** do not spawn subagents. Return cleanly.

The skill writes:

- `plan.md` with an empty `Resolved paths` list and a note that no readable documents were found.
- `report.md` with every section present but containing a single bullet each, plus a `Gaps & Limitations` entry:

```markdown
## Gaps & Limitations

- No readable documents found under the resolved paths. The caller passed <paths> and auto-discovery surfaced <auto-discovered paths>; every entry was either absent, empty, or matched the skip denylist. Pass a broader `paths` list, or point at a different folder.
```

Returning cleanly lets callers handle "no documents found" gracefully (e.g. fall back to asking the user to paste content) rather than crashing on an expected-but-uncommon state.

## Silent-failure detection (stub-file rule)

Context exhaustion and tool errors can cause a subagent to return without producing any output file. The orchestrator has no way to distinguish that from "the subagent finished but the file is missing for some other reason" — so the contract requires every subagent to write at least a stub file before returning.

**Contract (enforced by `subagent-brief.md`):**

- Every subagent writes `findings/<slice-slug>.md` with a `status:` frontmatter field: `ok`, `empty`, or `failed`.
- On `empty` or `failed`, the file includes a one-line `reason:` field.
- On `ok`, `reason` is omitted.

**Orchestrator check, post-dispatch:**

For every expected slice, test that the findings file exists. For any missing file, record a silent-failure entry under `Gaps & Limitations`:

```markdown
- **Slice "<name>"** — subagent returned without producing a findings file (likely context exhaustion or tool error). Last known brief: "<brief summary>".
```

This is why "legitimately empty" results must use `status: empty` with a reason rather than writing nothing — so empty-but-ok is never confused with silent context loss.

## Re-run protection

Each run is supposed to be self-contained and auditable. Silently overwriting a prior run destroys the audit trail; silently appending produces incoherent findings.

**Rule:** before writing anything to `output_dir`, check whether it already contains `plan.md` or `report.md`.

- **If it does and `refresh` is not `true`:** refuse with a message naming the existing folder.

  ```
  Refusing to write: <output_dir> already contains a prior analysis run. Pass `refresh: true` to archive and overwrite, or choose a different output_dir.
  ```

- **If it does and `refresh: true`:** move the existing contents to `<output_dir>/.archive-<YYYYMMDD-HHMMSS>/` first, then proceed with a fresh run. The archive preserves the audit trail.

- **If it does not:** proceed normally.

This rule applies even when the default slug matches a prior run on the same day — stable slugs are a feature (callers can re-derive the folder), but the user must explicitly opt in to overwriting.

## Verification checklist (orchestrator runs at end)

Before returning success to the caller, verify:

- [ ] `plan.md` exists at `<output_dir>/plan.md`.
- [ ] `findings/<slice-slug>.md` exists for every slice in `plan.md` (unless the empty-corpus path was taken).
- [ ] Every findings file has `status:` frontmatter.
- [ ] Every `status: empty` or `status: failed` file has a `reason:` line.
- [ ] `report.md` exists at `<output_dir>/report.md`.
- [ ] `report.md` has all seven top-level sections in order: `Documents Found`, `Key Insights`, `User / Market Context`, `Technical Context`, `Ideas & Decisions`, `Raw Detail Worth Preserving`, `Gaps & Limitations`.
- [ ] `report.md` has a `Sources` section and every `[^n]` footnote in the body has a matching entry.

Any check that fails becomes an entry in `Gaps & Limitations` — the run does not silently produce a broken deliverable.


path: references/report-template.md
content: # Synthesis Skeleton

The synthesis document, saved as `report.md` under the run's output directory, uses a fixed seven-section layout. Sections appear in this order, every time, even when one is short. `Gaps & Limitations` is required even when findings look complete — honest accounting of what could not be established is part of the product.

Copy the skeleton below into the synthesis file and fill each section.

## Layout

```markdown
# Analysis: <intent, verbatim from plan.md — or "Generic extraction of <slug>" when intent is absent>

## Documents Found

- `<relative path 1>` — <one-line note on what this document covers and why it was included>
- `<relative path 2>` — <...>
- `<relative path N>` — <...>

Include every path that was actually scanned (end-to-end or skimmed). Paths that were under the skip denylist go in `Gaps & Limitations`, not here.

## Key Insights

Group by theme. Every claim carries a [^n] footnote.

### <Theme 1>

<Bullets or short paragraphs. Each factual claim has a footnote.>

### <Theme 2>

<...>

### <Theme N>

<...>

## User / Market Context

<Users, customers, competition, market data surfaced from the documents. Footnote every specific claim. If the corpus does not contain user/market content, write a single bullet: "No user/market content surfaced by this scan." — do not delete the section.>

## Technical Context

<Platforms, constraints, integrations, dependencies, operational considerations. Footnote every specific claim. If the corpus does not contain technical content, write a single bullet noting so — do not delete the section.>

## Ideas & Decisions

Every idea carries a tag — `accepted`, `rejected`, or `open` — and rationale. Preserve rejected ideas so future work does not re-propose them.

- **[accepted]** <idea> — <rationale from the document> [^n]
- **[rejected]** <idea> — <rationale for rejection> [^n]
- **[open]** <idea> — <what is still undecided> [^n]

## Raw Detail Worth Preserving

Specific quotes, metrics, and data points that would be lost to summarization. Each entry is a verbatim excerpt (or near-verbatim with explicit ellipsis) plus a footnote.

- "<quote>" [^n]
- "<data point>" [^n]

## Gaps & Limitations

- <What the corpus could not establish, and why. One bullet per gap.>
- <Any path that was empty, unreadable, or skipped via the denylist — name the path and the reason.>
- <Any subagent that failed or returned empty — name the slice and the reason from its stub file.>
- <Claims that were dropped because the citation would have had to be fabricated.>

This section is never empty. If the scan was clean, include at minimum a bullet naming what follow-up reading would sharpen the picture.

## Sources

[^1]: **Path**: <relative path>
      **Excerpt**: "<verbatim quote>"
      **Lines**: <optional, omit if absent>
      **Heading**: <optional, omit if absent>
      **Document type**: <optional, omit if absent>

[^2]: **Path**: <...>
      **Excerpt**: "<...>"

[^n]: <...>
```

## Rules

- **Title line** uses the intent verbatim from `plan.md`. When intent is absent, use `Generic extraction of <slug>`.
- **`Documents Found`** lists every included path (read or skimmed). Skipped paths go in `Gaps & Limitations`.
- **`Key Insights`** groups by theme, not by source document. If one theme only came from one document, that is fine — one bullet, one footnote.
- **`User / Market Context`, `Technical Context`, `Raw Detail Worth Preserving`** — never delete these sections. If the corpus has nothing to say, include a single bullet saying so. Prefer `"No <section> content surfaced by this scan."` over synthesized content — an empty placeholder is correct when the corpus is thin; fabricated content is not.
- **`Ideas & Decisions`** preserves rejected ideas with the rationale for rejection, not just accepted ones. This is the feature, not a nice-to-have.
- **`Gaps & Limitations`** is never empty. At minimum, name what follow-up reading would sharpen the answer.
- **`Sources`** uses global numbering — `[^1]` through `[^n]` across the whole document, not per-section. Citation shape per `citation-schema.md`.

## Sourcing discipline

- Every bullet in `Key Insights`, `User / Market Context`, `Technical Context`, and `Ideas & Decisions` that makes a specific factual claim carries a footnote. Broad synthesis statements can stand without a footnote only if they summarize cited claims elsewhere in the document.
- `Raw Detail Worth Preserving` is 100% cited — every entry is an excerpt with a footnote.
- If a claim cannot be cited, either drop it or move it to `Gaps & Limitations` as something the corpus did not establish.
- `Sources` entries match every `[^n]` used in the body. Orphan citations (listed in `Sources` but never referenced) should be removed.


path: references/skip-patterns.md
content: # Default Skip Patterns

The subagent's default denylist. Applied without the caller re-specifying. Every skipped path is recorded under the `paths_skipped` frontmatter field so the audit trail shows exactly what was excluded.

Three groups: sensitive, binary/media, vendor/build.

## Sensitive

Secrets, credentials, and user-level config. Never scanned.

- `.env`, `.env.*`
- `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.crt`, `*.cer`
- `.aws/`, `.ssh/`, `.gnupg/`
- `credentials.*`, `secrets.*`
- `*.htpasswd`, `*.netrc`

## Binary / media

Formats the first version does not parse. Passed over without an error. `beagle-core:docling` is the future path for richer parsing (PDF / DOCX / PPTX) when a caller needs it.

- Images: `*.png`, `*.jpg`, `*.jpeg`, `*.gif`, `*.webp`, `*.ico`, `*.svg`, `*.bmp`, `*.tiff`
- Documents: `*.pdf`, `*.docx`, `*.doc`, `*.pptx`, `*.ppt`, `*.xlsx`, `*.xls`
- Archives: `*.zip`, `*.tar`, `*.tar.gz`, `*.tgz`, `*.gz`, `*.bz2`, `*.xz`, `*.7z`, `*.rar`
- Audio/video: `*.mp3`, `*.wav`, `*.flac`, `*.ogg`, `*.mp4`, `*.mov`, `*.mkv`, `*.avi`, `*.webm`
- Databases: `*.sqlite`, `*.sqlite3`, `*.db`
- Binaries: `*.exe`, `*.dll`, `*.so`, `*.dylib`, `*.a`, `*.o`, `*.class`, `*.jar`

## Vendor / build

Generated output and vendored dependencies. Noise, not signal.

- `.git/`
- `node_modules/`
- `.venv/`, `venv/`, `env/`
- `__pycache__/`, `*.pyc`
- `dist/`, `build/`, `out/`, `target/`
- `coverage/`, `.coverage`
- `.next/`, `.nuxt/`, `.svelte-kit/`
- `.cache/`, `.parcel-cache/`
- `vendor/`, `Pods/`
- `.DS_Store`, `Thumbs.db`

## Rules

- **Silent skip, audited record.** Subagents do not stop to explain why a path was skipped. Every skipped path lands in `paths_skipped`.
- **Case-insensitive extension matching.** `.ENV` is skipped just like `.env`.
- **Directory patterns match as prefixes.** `node_modules/` skips everything under it.
- **No runtime extension.** The denylist is read-only during a run. A caller that wants to scan a normally-skipped path passes it explicitly in `paths` — the brief records it, and the subagent reads it. (Explicit caller intent overrides the default.)
- **Sensitive list is non-overridable.** `.env`, `*.pem`, `*.key`, and credential files are always skipped even when explicitly passed. If a caller needs those contents, they paste them in directly rather than routing through this skill.


path: references/subagent-brief.md
content: # Subagent Brief Template

The orchestrator builds one brief per slice, mechanically, from `plan.md`. Every subagent gets the same shape so a caller reading `plan.md` can predict what each subagent was told.

Fill the template verbatim — no paraphrasing, no interpretation drift. Subagents return one terse status line to the orchestrator; all findings land in the output file.

## Template

```
You are one of up to 3 parallel artifact-analysis subagents. Scan a single slice of paths and write findings to disk.

Slice: <slice name, copied from plan.md>
Intent: <intent string, verbatim from plan.md — or "generic salient extraction" if absent>
Paths to scan:
  - <path 1 from plan.md for this slice>
  - <path 2 from plan.md for this slice>
  - <...>

What to extract:
  - Key insights — structurally important observations, decisions, and themes
  - User / market context — users, customers, competition, market data
  - Technical context — platforms, constraints, integrations, dependencies
  - Ideas & decisions — tagged accepted / rejected / open (preserve rejected ideas with rationale)
  - Raw detail worth preserving — specific quotes, metrics, and data points
  - Gaps — what the corpus could not establish; empty/unreadable paths

  When intent is present, weight extraction toward what is relevant to that intent. When intent is absent, extract anything structurally important without an interpretive filter.

Skim strategy:
  - Sharded documents (folder with index.md plus multiple files): read index.md first, then only the sub-files the index points to as relevant.
  - Large documents (single file > ~2000 lines or > ~50 pages): read the TOC, executive summary, and section headings first; pull full content only from relevant sections. Record skimmed-vs-read status per file.
  - Short documents: read end-to-end.

Skip patterns: apply the default denylist from references/skip-patterns.md (sensitive, binary/media, vendor/build). Record every skipped path under the paths_skipped frontmatter field.

Output path: <output_dir>/findings/<slice-slug>.md

Citation rules: every claim carries a [^n] footnote. Citations use source path (relative to the scanned root when possible) + verbatim excerpt. Include lines and heading only when the subagent naturally has them; never synthesized or guessed. See references/citation-schema.md for the full shape.

Required frontmatter on the output file:
---
status: ok | empty | failed
slice: <slice name>
brief_hash: <hash of this brief, supplied by the orchestrator>
started_at: <ISO timestamp>
finished_at: <ISO timestamp>
paths_read: [<paths read end-to-end>]
paths_skimmed: [<paths where only TOC/index/headings were consumed>]
paths_skipped: [<paths skipped via the default denylist>]
reason: <one line — required when status is empty or failed, omit otherwise>
---

Partial-failure protocol: always write the output file, even if the subagent fails or finds nothing. Use status: failed with a one-line reason on tool errors or exhaustion. Use status: empty with a reason when the slice is legitimately empty ("all paths under this slice were under the skip denylist" or "all files were unreadable"). Never exit without writing the file — absence of the file is treated as a silent failure.

Return: a single status line in this exact shape, and nothing else:
<path-to-findings-file> <status>

Example: /abs/path/findings/planning-folder.md ok
```

## Orchestrator responsibilities

- **Build `<slice-slug>`** by the same rule as the run slug in SKILL.md (lowercase, punctuation stripped, whitespace → hyphens, truncated to 60 chars on a word boundary). Keep it stable across runs so `refresh: true` can match archived prior files.
- **Compute `brief_hash`** over the filled-in brief text before dispatch so the findings file's provenance is verifiable.
- **Guarantee non-overlapping slices.** The orchestrator partitions resolved paths before building briefs; no path appears in more than one slice.
- **Verify every expected file exists** after all subagents return. Any missing file = silent failure per `failure-modes.md`.
- **Never merge findings into one file.** Synthesis happens later, in `report.md`.

## Subagent responsibilities

- **Write the output file even on failure.** Absence is treated as silent context exhaustion.
- **Do not reshape the intent or the slice.** If the brief is wrong, flag it in `reason` and return `status: failed` — do not silently pivot to a different scope.
- **Apply skim strategies.** Do not read a 2000-line file end-to-end when the TOC tells you only three sections are relevant. Record the skim/read decision in the frontmatter path lists.
- **Apply skip patterns silently.** Every skipped path goes in `paths_skipped` — no need to note it in the findings body.
- **No inline returns.** The only thing that crosses back to the orchestrator is the status line. All evidence lives in the findings file.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)