---
description: Source-code analysis using launch-chart as the default tool. Routes structural / internal-state / content queries to the chart MCP first; falls back to grep/Read only when the chart cannot answer (non-TS files, missing layer, parser gap). Files a one-line LS feedback comment whenever the fallback is the chart's fault, so gaps get fixed.
when_to_use: |
  Auto-fire whenever the user wants to understand, explore, audit, or trace source code or codebase structure — INSTEAD of defaulting to grep / glob / Read. Trigger phrases: "analyse" / "analyze" / "analysis", "explain how X works", "how does X work", "where is X", "what depends on / calls / renders / imports X", "trace / walk through Y", "explore the codebase", "understand this module", "audit X", "show me all / list every X" (pages, endpoints, tables, hooks, components), "what state does X track", "what conditions exist in X", "which endpoints check Y", "what tables relate to X", "what permissions does role X grant", "is migration X destructive", "what seed roles / tags / providers exist", "find FIXME / TODO". Also auto-fire on open-ended structural questions ("how is auth set up", "where does the work-item flow happen") even without explicit "analyse" wording. Do NOT auto-fire for: bug investigation framed as symptom ("X is broken", "why doesn't Y work" — use /kit:debug), refactor blast assessment ("what breaks if I change Z" — use /kit:blast-radius), or render-as-diagram requests (use /kit:diagram).
allowed-tools:
  - mcp__launch-chart__read_graph
  - mcp__launch-chart__inspect_node
  - mcp__launch-chart__grep_nodes
  - mcp__launch-chart__detect_project_stack
  - mcp__launch-chart__blast_points
  - mcp__launch-chart__effects_index
  - mcp__launch-chart__list_notes
  - mcp__launch-chart__who_uses
  - mcp__launch-chart__trace_path
  - mcp__launch-chart__migration_audit
  - mcp__launch-chart__drift_report
  - mcp__launch-chart__auth_coverage_report
  - mcp__launch-secure__kit_feedback_submit
---

# /kit:analyse

Source-code analysis using launch-chart as the default tool. The chart indexes ~1,200 typed nodes across 4 layers (ui / api / db / static) with cross-layer edges and AST-level deep fields — almost everything grep/glob/Read would surface is queryable here, faster and cheaper in tokens.

## Input

Run the analysis for the user query → **$ARGUMENTS**

This is the target to analyse — a question, a node name (file / table / route / hook), or a module. Route it through the chart tools below. If `$ARGUMENTS` is empty, the user invoked the skill bare; ask them what they want analysed (or infer it from the surrounding conversation) before querying.

## Discipline (non-negotiable)

1. **Chart-first.** Default to launch-chart MCP for any code-structure or behavior query. Do NOT reach for grep / glob / Read first.
2. **On illegitimate chart gap, file ONE LS feedback report** via `mcp__launch-secure__kit_feedback_submit` (the kit-self feedback channel — NOT `communication_write`, which would land in the user's own project Comm Hub instead of the launch-kit project). One report per invocation, not per query.
3. **Fall back to grep / Read** only per the rules below.
4. **Surface the fallback verbatim** in your final output — silent fallbacks hide gaps and let the chart rot.

## Routing table — chart tool per question shape

Specialized tools (use these first when the question matches):

| Question shape | Chart tool | Notes |
|---|---|---|
| "Where is X referenced from other layers / who uses permission P / who calls endpoint E / who references table T" | `who_uses(target: X)` | scans all layers' cross_refs (calls_api, references_static, reads_via, mutates_via, reads, mutates, references_api). Paginated. |
| "Trace path between A and B / how does page X end up reading table T" | `trace_path(from: A, to: B)` | BFS via cross_refs including via[] middleware chains. Bounded by max_hops/max_paths. Paginated. |
| "Are migrations safe / which destructive migrations lack guards" | `migration_audit` | codifies CLAUDE.md's three-layer discipline. Lists destructives missing orphan_check / sidecar_backup / pre_flight_notice. Paginated. |
| "Show drift / SQL vs ORM mismatches / unresolved routes / FK drift" | `drift_report(layer?, kind?, confidence?)` | aggregates contradictions + flagged_edges across layers. Generalizes db-only include_findings. Paginated. |
| "Audit auth coverage / which endpoints are public / how many use withAuth" | `auth_coverage_report(module?, strategy?)` | aggregates api endpoints by auth[] wrapper. Surfaces unauthenticated. Grouped by module. |
| "What endpoints call /api/X / what URLs does UI fetch / who calls this endpoint" | `effects_index(kind: "fetch_calls", key?)` | UI→API call inventory from cross_refs[calls_api] + raw effects.fetches. |
| "Invert endpoint effects / which endpoints call db.user.findUnique" | `effects_index(kind: "api_effects", key?)` | inverts api endpoint effects.{calls,fetches,persists,…}. Use `key` for full caller list across categories. |

General routes (use these when no specialized tool fits):

| Question shape | Chart tool | Notes |
|---|---|---|
| "Where is X defined / what is it" | `read_graph(search: X)` | substring match on id, name, route, JSX text, ui_labels, notes |
| "What pages / hooks / endpoints / tables / migrations exist" | `read_graph(layer: <L>, type: <T>)` | layer + type filters |
| "What's in module Y" | `read_graph(module: Y)` | module tags from `.launchchart.json` |
| "Filter by multiple conditions (e.g. destructive AND missing orphan check)" | `read_graph(tag_predicates: [{field,op,value},...])` | ops: eq/ne/gt/lt/gte/lte/exists/not_exists/in. Matches top-level node attrs OR tag keys. |
| "Per-node incoming + outgoing cross-layer refs" | `read_graph(node_id: X, include_cross_refs: true, cross_ref_type?)` OR `inspect_node(node_id: X, fields: ["crossRefs"])` | when you want crossRefs inline alongside other data |
| "Surface flagged_edges by confidence (DYNAMIC routes, FK drift)" | `read_graph(layer: <L>, edge_confidence: ["medium","high"])` | layer-independent flagged_edges filter |
| "What does X render / what renders X" | `read_graph(node_id: X, hops: 1, include_edges: true)` | renders / imports edges |
| "Which UI calls API endpoint E" | `read_graph(node_id: E, layer: "api", include_edges: true)` OR `who_uses(target: E)` | cross-layer `calls_api` edges |
| "What endpoints touch table T" | `read_graph(layer: "api", search: T)` then check `db_models[]` | endpoints already index `db_models` and `db_operations` |
| "What auth does endpoint E use" | `read_graph(layer: "api", search: E)` then check `auth[]` | auth wrappers extracted per endpoint |
| "Is endpoint E mutating" | `read_graph(layer: "api", search: E)` then check `mutates` flag | already extracted |
| "What state does Z hold" | `inspect_node(node_id: Z, fields: ["stateVars"])` | start narrow, always |
| "What conditions exist in Z" | `inspect_node(node_id: Z, fields: ["conditions"])` | if / else / ternary tests with their test expressions |
| "Which nodes match pattern P inside conditions/vars/elements" | `inspect_node(layer: <L>, filter: P, fields: ["conditions"])` | regex over deep fields, raises node limit to 50 |
| "DOM ids / storage keys / window events / fetch urls / timers / singleton risks" | `effects_index(kind: <kind>, key?)` | precomputed cross-cutting inverted indexes |
| "DOM-id / storage-key collisions" | `effects_index(kind: "collisions")` | impossible without graph |
| "What tables relate to X" | `read_graph(layer: "db", node_id: X, include_edges: true)` | belongs_to / has_many edges |
| "Single migration M's safety status" | `read_graph(layer: "db", type: "migration", search: M)` | migration nodes carry `is_destructive`, `has_orphan_check`, `has_sidecar_backup`, `has_pre_flight_notice`, `contains_backfill`, `contains_drop_column` (use `migration_audit` for cross-migration audits) |
| "What seed roles / permissions / tags / providers / plans exist" | `read_graph(layer: "static", type: "seed_role")` etc. | static layer covers `prisma/seed.ts` |
| "What permissions does role R grant" | `read_graph(layer: "static", node_id: "seed:role:R", include_edges: true)` | `grants` edges |
| "Find pattern P in module M's files only" | `grep_nodes(layer: <L>, module: M, pattern: P)` | grep scoped via graph — much narrower than raw grep |
| "What breaks if I delete / change X" | `blast_points(node_id: X, direction: "reverse")` | reverse-dep walk across all layers in one call |
| "Find FIXME / TODO / tagged notes" | `read_graph(search: "FIXME")` or `list_notes` | tagged comments indexed |
| "What's the current stack / which parsers run / which layers are available" | `detect_project_stack` | run before concluding a layer is missing |

## inspect_node strategy — start narrow, widen if needed

1. **Decide first**: structure or variables? Structure (renders/imports/depends) → `read_graph`. Variables/state/conditions → `inspect_node`.
2. **Always pass `fields` and/or `filter`** to keep the response small and inline. Examples:
   - State only → `inspect_node(node_id: X, fields: ["stateVars"])`
   - Pattern across many nodes → `inspect_node(layer: "ui", filter: "isAdmin", fields: ["conditions"])`
3. **Only broaden if narrow returns nothing.** Remove `filter`, add more `fields`, or omit `fields` entirely as a last resort.
4. **Never** call `inspect_node` with no `fields` and no `filter` on a large page or component — returns 50-80KB dumps that get persisted to disk and force a second read step.

## parser_warning awareness

Several chart tools (`who_uses`, `trace_path`, `drift_report`, `read_graph` with `include_cross_refs` or `edge_confidence`, `inspect_node` with `crossRefs`, `effects_index` with `fetch_calls`) attach a `parser_warning` field when the underlying source data (cross_refs / flagged_edges / contradictions) is completely empty for the scanned layer(s). This is the chart **telling you the parser may not have run** — not "there's no match."

When you see `parser_warning` in a tool response:
1. **Don't silently report "no results."** Empty-with-warning is a different signal than empty-without-warning.
2. **Run `detect_project_stack`** to verify which parsers are detected. If the parser referenced in the warning IS detected, the data should be present — that's a chart-gap worth filing per the protocol below.
3. **If the parser isn't detected for this stack** (e.g. cross-layer parsers don't apply because the project isn't TS/Next), surface that to the user — the chart doesn't claim coverage here.
4. **Never strip `parser_warning` from your output.** Include it (or a short paraphrase) in the user-facing summary so they can act.

## Chart breakage triage — BEFORE filing any feedback comment

When a chart query returns empty / errors / fires `parser_warning`, walk this triage. Two upstream causes are common and require NO feedback comment — they're user-action gaps, not chart bugs. File a comment ONLY after both are ruled out.

### Step 1 — does the graph file even exist?

If a chart tool returns an error like `"No <layer> graph found at .launchsecure/graphs/<layer>.json"` or `"Run generate_graph first"`, the user hasn't built the graph yet. **Do NOT file a comment.** Tell the user verbatim and stop:
- `"No chart graph found in this project. Run mcp__launch-chart__generate_graph (or `npx launch-chart generate`) once, then retry the query."`

### Step 2 — is the graph stale?

Every chart response carries `_meta.state`. If it's anything other than `"fresh"` (e.g. `"stale"`, `"escalated"`), the graph hasn't been regenerated since recent file edits — your query may be looking at an outdated snapshot. **Do NOT file a comment for stale-graph results.** Surface to the user:
- `"Chart graph is <state> (last full regen: <_meta.lastFullRegenAt>, <N> patches since). Recent edits may not be visible. Run generate_graph to refresh, then retry."`
- Then either stop OR proceed with the stale results, flagging the staleness in your final output.

### Step 3 — parser produced empty/wrong output (the only chart-gap case)

Only AFTER ruling out steps 1 + 2: if `detect_project_stack` shows the relevant parser is detected, the graph file exists, AND `_meta.state` is fresh — and the query still returns empty / missing expected fields / missing cross-layer edges — that's a real chart gap. File the LS feedback comment per the template below, with parser-specific fields populated (parser name, layer, graph_meta).

## When the fallback is legitimate (NO feedback comment)

These are expected gaps — the chart doesn't claim coverage here:

- **Non-TS source files** — SQL (`prisma/migrations/**/*.sql` and other), JS/CJS/MJS files, JSON, markdown (docs/), env files, CSS / Tailwind config, YAML / TOML
- **CSS classes, Tailwind utilities, inline styles** — chart doesn't model class names or computed styles
- **CLI bin / Node script files** — the typescript-project parser is Next.js-shaped and may skip standalone server entrypoints (e.g. `packages/cli/src/server/init-entry.ts` is known to be unindexed)
- **Untagged comment content** — only notes-tagged comments are indexed; arbitrary inline comments are not
- **Verifying a file's literal contents for review or editing** — Read is correct for "show me lines 40-80 of foo.ts"

In these cases, jump to grep / Read directly. Tell the user explicitly which non-coverage rule applied — e.g. `"Symptom is in an SQL migration file; chart doesn't model raw SQL — using Read directly."`

## When the fallback is illegitimate (FEEDBACK COMMENT REQUIRED)

The chart should have answered but didn't. File ONE comment before falling back:

- `read_graph(search: "X")` returns 0 candidates AND a quick `grep` confirms "X" exists in indexed TS source
- A layer listed by `detect_project_stack` returns 0 nodes for any well-formed query (parser misconfig)
- `inspect_node` returns no `columns` / `elements` / `stateVars` for a known table or component (extractor gap)
- A cross-layer edge that should exist (e.g. UI page that fetches `/api/foo` should have a `calls_api` edge) is missing

### Feedback report template

Call `mcp__launch-secure__kit_feedback_submit` — routes to the launch-kit project regardless of which repo the user is in:

```
title: "launch-chart gap: <one-line, e.g. 'fetch-resolver produced 0 calls_api refs on ui layer'>"
source: "kit:analyse"
body: |
  Skill: /kit:analyse
  Query: <one-line what the user asked>
  Tool:  <chart_tool>(<args>)
  Returned: <summary — e.g. "0 nodes" or "missing 'columns' field">
  Cross-check: grep "<term>" matched <N> files (sample: <path1>, <path2>)
  Project stack: <one-line from detect_project_stack>
  Triage:
    graph_exists: yes
    graph_state: <_meta.state>           # fresh — ruled out staleness
    parser_detected: <parser_id>          # from detect_project_stack
  Parser: <parser_id>                     # e.g. fetch-resolver, typescript-project
  Layer:  <layer_id>                      # ui / api / db / static
  Graph meta:
    state: <_meta.state>
    last_full_regen_at: <_meta.lastFullRegenAt>
```

One report per invocation. After filing, surface to the user: `"(Filed chart-gap report to launch-kit project. Falling back to grep / Read for this query.)"` and continue.

## Output shape

For every analysis, return:

1. **One-paragraph answer** to the user's question — direct, no preamble.
2. **Citations as chart node ids** — each claim links to a node (file path like `app/api/orgs/.../route.ts`, table name like `WorkItem`, route like `/admin/analytics`). The user must be able to verify by clicking through.
3. **The chart query path you used** — one or two lines naming the tools + arguments. Lets the user re-run or extend the investigation.

If a fallback happened, prefix the output with one of:
- `(Filed gap report id: <id>. Falling back to grep — chart should have answered.)`
- `(Symptom is in <non-TS asset class>; chart doesn't model it — using grep / Read directly.)`

## Constraints

- **Chart-first. No exceptions.** Default to MCP queries. grep / glob / Read only per the fallback rules above.
- **One feedback report per invocation.** Do not spam — bundle multiple chart issues into one report if they fire in the same run.
- **Cloud LS by default.** Use `mcp__launch-secure__kit_feedback_submit` (cloud). The local variant only if the user explicitly said "local".
- **No implementation.** This skill explains and traces; it does not edit. If the user wants the fix, hand the diagnosis back and let them invoke an editor flow.
- **Cite by node id.** Every claim links to a chart node so the user can verify.
- **Surface the fallback verbatim.** Silent fallbacks hide gaps and let the chart rot.
