mantis-structural-index
This Skill builds a content-addressed semantic-unit index for a codebase and exposes caller lookup, function-boundary retrieval, and call-site awareness, persisting results as a manifest plus a query-optimized catalog. It reuses units across snapshots for incremental rebuilds, attaches prebuilt SCIP/Kythe/LSIF indexes, and degrades gracefully to text search while staying read-only on source. It never hard-fails—if tools or parsing are unavailable it returns an empty index—so developers and AI agents can map call chains and dependencies quickly before reading code.
npx skills add https://github.com/google/mantis --skill mantis-structural-indexBefore / After Comparison
2 组To confirm who calls a function, developers search keywords directory by directory, hitting comments, string literals and same-name overloads, then filter results by hand. After dozens of files they still cannot be sure every caller was found, and indirect calls are easily missed during handover.
This Skill's content-addressed index returns the caller list and the function's start/end boundaries directly, with call sites listed by file and line while structural parsing filters false hits. Call-chain mapping becomes a single query instead of repeated searching, making discovery conclusions complete and reviewable.
Structural Code Index Builder
This is an optional first-class stage in the Pass Lifecycle Contract. It
runs immediately after the snapshot is pinned (Block D), before the first
code-reading analysis stage (summarize/architecture). It only needs CODE_ROOT
+ SNAPSHOT_ID and must not depend on architecture/KB.
System Goal
Structural Code Index Builder. Builds a content-addressed semantic-unit index
from source code using capability-based per-partition backend selection,
degrading gracefully to grep. Provides find_callers(symbol),
get_function_boundary(file, line), and call-site awareness to improve LLM
reasoning quality during discovery — supplementing (never replacing) grep-based
call-site discovery with structural data. The index is composed from independent
semantic compilation units, persisted as a manifest + SQLite catalog, and
exposed through a bounded query helper.
Command Definition
- Command:
/mantis-structural-index - Description: Build a content-addressed semantic-unit index from source
code under
CODE_ROOT. - Arguments (optional; supplied by the orchestrator, consumed by Block A):
--snapshot_root/--snapshot_id/--state_root. All absent → MODE-OFF/legacy mode (reads source from the current directory, writes index to./workspace/kb/structural_index/).
Input/Output Contract
- Reads:
workspace/.mantis_state.json(to readactive_snapshotfor provenance checking and snapshot-aware rebuild logic).workspace/kb/structural_index/manifest.json(to checksnapshot_idfor reuse-on-match idempotency — primary check).workspace/kb/structural_index.jsonl(backward-compat provenance check if manifest absent).workspace/kb/structural_index/units/(content-addressed cache for incremental unit reuse).workspace/kb/structural_index/native/and sidecarprovenance.jsonfiles (prebuilt index attachments and metadata manifests).- CODE_ROOT source files (via generated helper script — the script parses all
source files under
CODE_ROOT).
- Writes:
workspace/kb/structural_index/manifest.json(STATE-RELATIVE — atomic commit point, written LAST).workspace/kb/structural_index/catalog.sqlite(STATE-RELATIVE — query-optimized serving store).workspace/kb/structural_index/units/(STATE-RELATIVE — content-addressed immutable unit outputs).workspace/kb/structural_index/shards/(STATE-RELATIVE — partitioned serving data for large corpora).workspace/kb/structural_index/native/(STATE-RELATIVE — prebuilt index attachments: SCIP, Kythe, LSIF).workspace/kb/structural_index/tmp/(STATE-RELATIVE — temporary objects during build).workspace/kb/structural_index.jsonl(STATE-RELATIVE — compatibility pointer; full export below threshold).workspace/helpers/build_structural_index.py(STATE-RELATIVE — the builder helper script).workspace/helpers/query_structural_index.py(STATE-RELATIVE — the query helper script).
- Preconditions:
- Source files must exist under
CODE_ROOT. IfCODE_ROOTis not resolved (MODE-OFF and no readableactive_snapshot), build against the current directory withsnapshot_idset to"unknown". Do NOT skip — this is the standalone-efficiency case.
- Source files must exist under
- Inert until wired: This skill returns an empty index until a caller
invokes it (the harness,
mantis-plan, ormantis-researcher). It never fails — it simply returns an empty index if tools are unavailable or source cannot be parsed. - Idempotency Guarantee:
- Read-only on
CODE_ROOT. Writes only to STATE-RELATIVE paths. Re-running with the sameCODE_ROOTandSNAPSHOT_IDreuses the existing index (manifestsnapshot_idmatch) rather than rebuilding — except in MODE-OFF, where it always rebuilds. Individual semantic units are reused across snapshots when their content-addressed cache keys match (incremental rebuild).
- Read-only on
Instructions
Step 0: Locator Resolution (run first)
LOCATOR RESOLUTION (before reading ANY target code or artifact):
0. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
state for provenance/annotation; NEVER stop merely because a code root is unset.
1. Determine CODE_ROOT, in this priority order:
a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
(used when a caller hands you a prepared tree, e.g. a patched shadow).
b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
c. Else read state_root/workspace/.mantis_state.json (state_root from
--state_root if passed, else ./workspace/... relative to the current dir)
-> active_snapshot.root / .snapshot_id / .snapshot_pinned.
d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
2. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
deliberately mutated and is sentinel-EXEMPT.)
3. PATH FIELDS:
- SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
NOT of the form <existing-path>:<integer> is a non-source LOCATOR
(symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
line-range and line-existence logic.
- STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
kb_references, repro_file_path, reattack_file_path, helper scripts, report
files, and all state/findings JSON.
4. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
(mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
cd into CODE_ROOT.
5. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
(the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
lacks .git/.hg/.repo.
6. Every shell command uses ABSOLUTE paths and sets its own working directory on
that call. Do NOT assume the working directory persists between calls.
This is a CODE-READING stage — it reads target source files under CODE_ROOT via the helper script. Block A step 0's findings-only skip does NOT apply.
Step 1: Idempotency / Freshness Check (MANDATORY FIRST)
MANDATORY FIRST STEP: Before writing any build scripts, probing backends, or extracting symbols, check for MODE-OFF or an existing manifest:
- MODE-OFF check (FIRST): In MODE-OFF (
SNAPSHOT_IDis"unknown"or absent) → always rebuild. Do NOT reuse a previous"unknown"index, because the live tree is mutable and"unknown"is a constant (not a freshness signal). Skip directly to Step 2 (individual units whose content has not changed may still hit the content-addressed cache). - If
workspace/kb/structural_index/manifest.jsonexists, read itssnapshot_idfield. - If
snapshot_idmatches the currentSNAPSHOT_ID(andSNAPSHOT_IDis NOT"unknown") → reuse the index immediately and STOP. Do NOT invoke Step 2, probe backends, or write build scripts. This bounds cost across retries/crash-resume. - If
manifest.jsonis absent butworkspace/kb/structural_index.jsonlexists (backward compat), read its provenance header (_provenance,snapshot_idkeys). Ifsnapshot_idmatches (and is NOT"unknown") → reuse and STOP. Otherwise proceed to rebuild. - If
SNAPSHOT_IDdiffers → proceed to rebuild (Steps 2–5). For incremental reuse: before rebuilding a semantic unit, checkunits/for a content-addressed cache hit (see Content-Addressed Cache Key below). A cache hit reuses the unit output without re-extraction.
Step 2: Select Backend per Partition
Partition the codebase into semantic units (see Per-Language Semantic Units below). For each unit, select the most precise backend available in this environment using a capability-based, per-partition decision — not a single global ladder. The following are examples, not an exhaustive enum. The helper probes each tier per partition and selects the highest available:
- Snapshot-matched SCIP / LSIF / Kythe / clangd-static / remote index
(precision:
semantic) — if a pre-built index matching the currentsnapshot_idorroot_fingerprintis available. Most precise: full type-aware cross-reference, call hierarchy, and hover/signature data. - Compiler / typechecker-backed extractor (precision:
typecheck) — ifcompile_commands.json, build context, or typechecker is available. Type-accurate symbol resolution and call edges. - Language-aware AST extraction (precision:
ast) — iftree-sitter,ast-grep, or a language-specific parser is available. Full AST parsing: function boundaries, call expressions, signatures. - Symbol-only extraction (precision:
symbol-only) — ifctagsor equivalent is onPATH. Symbol table only (function definitions, locations — no call graph). Call-site extraction uses a lightweight regex pass within known function boundaries. - Heuristic fallback (precision:
heuristic) — Python stdlib regex pass over source files. Identifies function definitions and call patterns using language-agnostic heuristics. Less precise but zero-dependency. - Coverage-only manifest + lexical fallback (precision:
coverage-only) — grep; no structural index is written. Manifest recordsstatus: "empty". Consumers fall back to grep-based discovery (today's behavior byte-for-byte).
Native Index Probing & Resolution Rules:
- Probe instruction: Before evaluating per-partition backends, probe
workspace/kb/structural_index/native/and subdirectoriesnative/{scip,lsif,kythe}/for prebuilt index files. - Snapshot-declaration convention: Because native formats (SCIP, LSIF,
Kythe) do not embed snapshot identity directly in their binary payload,
prebuilt indexes MUST declare their target snapshot using a sidecar
provenance.jsonmanifest located atworkspace/kb/structural_index/native/provenance.jsonornative/<kind>/provenance.json. The manifest contains an array of attachments:[{"kind": "scip|lsif|kythe", "path": "...", "snapshot_id": "...", "root_fingerprint": "...", "language": "...", "indexer": "...", "precision": "semantic", "files": [...]}]. A native index is matched if its declaredsnapshot_idequalsSNAPSHOT_ID(whenSNAPSHOT_ID != "unknown") or itsroot_fingerprintmatches the workspace's calculated root fingerprint. If thefilesarray is absent or empty, treat the native index as covering no individual files directly (record inmanifest.native_indexesbut do not updatecoveragerows; fall through to lower tiers for all files). - Record-and-Defer Ingestion Rule: Parsing raw binary native indexes (e.g.
SCIP protobuf) in pure Python without dependencies is costly and complex.
Option A builder scripts MUST detect matching prebuilt native indexes, record
their entries in
manifest.native_indexes, and set thecoveragetablebackend(e.g.,"scip"or"scip-clangd") for all files listed in the provenance manifest. Ifcatalog.sqliteis NOT populated with symbols from the native index (raw binary deferred to harness/MCP readers), setcoverage.status = "deferred"andprecision = "deferred"(withindexed_files = 0). This prevents the query helper from claiming an un-ingested partition is "authoritative empty" atsemanticprecision, ensuring consumers run the mandatory grep fallback. Whencatalog.sqliteIS populated (e.g., via Option B pre-ingestion orscip-to-sqlite), setprecision = "semantic"andstatus = "indexed".
LSP is NOT equivalent to SCIP / LSIF. LSP is an interactive protocol whose
workspace state may be partial or mutable. Use it only when the server can
demonstrate snapshot identity AND complete workspace coverage. A running
language server does not automatically qualify as a semantic backend.
SCIP merging. SCIP explicitly permits merging complementary information from indexers with different precision levels. Its format records indexer version and per-document language metadata. The builder MAY merge results from multiple indexers (e.g., a SCIP index for Go + tree-sitter for Python) within a single catalog.
The determinism lives in a runtime-generated versioned helper
(build_structural_index.py, # MANTIS_HELPER_VERSION = 5, grep-and-regenerate
on reuse) that probes and selects backends per partition. No shipped binaries;
air-gapped-safe.
Deterministic partial coverage. On very large source trees, a full rebuild can dominate stage-0 wall-clock. Replace discovery-order truncation with a deterministic priority queue:
- Explicit target files and symbols (from
plan.json, if available). - Changed units and known reverse dependencies (from Block E diff + reverse-dependency edges in the existing catalog).
- Containing packages/modules and direct imports of tier 1+2 units.
- Remaining units in normalized path order.
Apply deterministic max_units (default: 10000) or max_source_bytes (default:
500MB) bounds to that queue. Persist deferred units in the manifest so another
invocation can resume. Statuses: complete, partial, empty, failed.
A consumer should only interpret "no callers" strongly when the relevant partition is complete, snapshot-matched, covered, and semantically precise. Otherwise the answer is "no indexed callers", followed by the existing lexical fallback. The index is HINT-only, so partial coverage is safe (grep remains authoritative).
Step 3: Write and Run Helper Scripts
Two runtime-generated helpers are used. Both follow the grep-and-regenerate pattern: before reuse, grep the first line for the version marker; if absent or a different integer, REGENERATE.
Builder: build_structural_index.py
- Write the builder to
workspace/helpers/build_structural_index.py. The FIRST LINE MUST be exactly# MANTIS_HELPER_VERSION = 5. Before reusing an existing helper, grep its first lines forMANTIS_HELPER_VERSION = 5; if that marker is absent or a different integer, REGENERATE the helper. - The builder partitions the codebase into semantic units (see Per-Language
...
User Reviews (0)
Write a Review
No reviews yet
Statistics
User Rating
Rate this Skill