mantis-structural-index
Builds a content-addressed semantic-unit index from source code for structural context. Use when a pinned or live codebase is available and structural cross-reference data would improve research quality. Don't use for findings analysis, patching, or reporting.
By google · 961 installs
npx skills add google/mantis --skill mantis-structural-index
Source repository · Upstream listing
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 read active snapshot for provenance
checking and snapshot aware rebuild logic).
workspace/kb/structural index/manifest.json (to check snapshot id for
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 sidecar provenance.json files
(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 . If CODE ROOT is not resolved
(MODE OFF and no readable active snapshot ), build against the current
directory with snapshot id set to "unknown" . Do NOT skip — this is the
standalone efficiency case.
Inert until wired: This skill returns an empty index until a caller
invokes it (the harness, mantis plan , or mantis 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 same CODE ROOT and SNAPSHOT ID reuses the existing index
(manifest snapshot id match) 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).
Instructions
Step 0: Locator Resolution (run first)
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:
1. MODE OFF check (FIRST): In MODE OFF ( SNAPSHOT ID is "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).
2. If workspace/kb/structural index/manifest.json exists, read its
snapshot id field.
3. If snapshot id matches the current SNAPSHOT ID (and SNAPSHOT ID is 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.
4. If manifest.json is absent but workspace/kb/structural index.jsonl exists
(backward compat), read its provenance header ( provenance , snapshot id
keys). If snapshot id matches (and is NOT "unknown" ) → reuse and
STOP . Otherwise proceed to rebuild.
5. If SNAPSHOT ID differs → proceed to rebuild (Steps 2–5). For incremental
reuse: before rebuilding a semantic unit, check units/ 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:
1. Snapshot matched SCIP / LSIF / Kythe / clangd static / remote index
(precision: semantic ) — if a pre built index matching the current
snapshot id or root fingerprint is available. Most precise: full
type aware cross reference, call hierarchy, and hover/signature data.
2. Compiler / typechecker backed extractor (precision: typecheck ) — if
compile commands.json , build context, or typechecker is available.
Type accurate symbol resolution and call edges.
3. Language aware AST extraction (precision: ast ) — if tree sitter ,
ast grep , or a language specific parser is available. Full AST parsing:
function boundaries, call expressions, signatures.
4. Symbol only extraction (precision: symbol only ) — if ctags or
equivalent is on PATH . Symbol table only (function definitions, locations —
no call graph). Call site extraction uses a lightweight regex pass within
known function boundaries.
5. 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.
6. Coverage only manifest + lexical fallback (precision: coverage only ) —
grep; no structural index is written. Manifest records status: "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 subdirectories
native/{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.json manifest located at
workspace/kb/structural index/native/provenance.json or
native/<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 declared snapshot id equals SNAPSHOT ID
(when SNAPSHOT ID != "unknown" ) or its root fingerprint matches the
workspace's calculated root fingerprint. If the files array is absent or
empty, treat the native index as covering no individual files directly (record
in manifest.native indexes but do not update coverage rows; 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 the coverage table
backend (e.g., "scip" or "scip clangd" ) for all files listed in the
provenance manifest. If catalog.sqlite is NOT populated with symbols from
the native index (raw binary deferred to harness/MCP readers), set
coverage.status = "deferred" and precision = "deferred" (with
indexed files = 0 ). This prevents the query helper from claiming an
un ingested partition is "authoritative empty" at semantic precision,
ensuring consumers run the mandatory grep fallback. When catalog.sqlite IS
populated (e.g., via Option B pre ingestion or scip to sqlite ), set
precision = "semantic" and status = "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:
1. Explicit target files and symbols (from plan.json , if available).
2. Changed units and known reverse dependencies (from Block E diff +
reverse dependency edges in the existing catalog).
3. Containing packages/modules and direct imports of tier 1+2 units.
4. 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
1. Write the builder to workspace/helpers/build structural index.py . The FIRST
LINE MUST be exactly MANTIS HELPER VERSION = 5 . Before reusi