mantis-structural-index
Skill2.5k starsChanged 15 days agoApache-2.0View on GitHub
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.
We split this skill into the rules it gives an agent
27 rules. About 0 are common, 7 are distinctive, and 20 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
20
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 82
Read-only on CODE_ROOT. Writes only to STATE-RELATIVE paths.
- Distinctive: line 139
MANDATORY FIRST STEP: Before writing any build scripts, probing backends, or extracting symbols, check for MODE-OFF or an existing manifest:
- Very specific: line 147
If workspace/kb/structural_index/manifest.json exists, read its snapshot_id field.
- Very specific: line 149
If snapshot_id matches the current SNAPSHOT_ID (and SNAPSHOT_ID is NOT "unknown") → reuse the index immediately and STOP.
- Very specific: line 153
If manifest.json is absent but workspace/kb/structural_index.jsonl exists (backward compat), read its provenance header (_provenance, …
- Distinctive: line 156
STOP. Otherwise proceed to rebuild.
- Very specific: line 157
If SNAPSHOT_ID differs → proceed to rebuild (Steps 2–5).
- Very specific: line 193
Probe instruction: Before evaluating per-partition backends, probe workspace/kb/structural_index/native/ and subdirectories …
- Very specific: line 268
Write the builder to workspace/helpers/build_structural_index.py.
- Very specific: line 298
Write the query helper to workspace/helpers/query_structural_index.py.
- Very specific: line 305
If catalog.sqlite is absent but structural_index.jsonl exists, the query helper falls back to linear scanning of the JSONL file (slower but …
- Very specific: line 312
Write the manifest to workspace/kb/structural_index/tmp/manifest.json first.
- Very specific: line 317
Write a compatibility pointer to workspace/kb/structural_index.jsonl (STATE-RELATIVE — NEVER under CODE_ROOT).
- Distinctive: line 336
If the index is empty (no tools available or no source files found), notify the caller: "Structural index is empty — structural context …
- Distinctive: line 338
Do not notify the user directly — this skill is invoked as a sub-agent by the harness, planner, or researcher.
- Very specific: line 500
Partitioning: When symbols exceed 500K or edges exceed 2M, partition into shard SQLite files under shards/ by lang:{language}:bucket:{NN} …
- Very specific: line 618
Build from
CODE_ROOT, not live tree (when pinned): When the snapshot is pinned, the structural index is built from the pinned CODE_ROOT, … - Very specific: line 621
Reuse-on-match: If manifest.json already carries the current SNAPSHOT_ID (and SNAPSHOT_ID is NOT "unknown" — in MODE-OFF, always rebuild), …
- Very specific: line 630
STALE flag in HALT mode: When snapshot_pinned is false (HALT), the index may be built from the unpinned CODE_ROOT but is marked as …
- Very specific: line 633
MODE-OFF: build, do not skip: When active_snapshot is absent (MODE-OFF), build against the current directory (cwd) with provenance …
- Very specific: line 647
The query helper IS the contract: All consumers use query_structural_index.py (or a compatible remote endpoint).
- Distinctive: line 649
NOT the query contract — it is a compatibility export only.
- Very specific: line 698
Use the structural index query helper for function-level dependency fan-out.
- Very specific: line 699
When planning investigations, call resolve_symbol() then find_callers() to identify all functions that call into a target — this broadens …
- Distinctive: line 709
Wave 1 (Rapid Triage): Run a repo-wide grep for the function name to build the exhaustive set of candidate call-sites — this is the …
- Very specific: line 716
Wave 2 (Deep Audit): Use get_function_boundary(file, line) to start with the enclosing function, expanding to callers/callees/file as …
- Distinctive: line 719
If the structural index is absent or empty, fall back to grep-based discovery (today's behavior).
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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
Semantic Units), computes content-addressed cache keys, checks
units/for reuse, selects a backend per partition (Step 2), extracts symbols + edges, and writes results tocatalog.sqlite. - The builder must extract:
- Symbols:
symbol_id,name,qualified_name,namespace,language,file_path,start_line,end_line,kind,signature,backend,precision. - Call edges:
caller_id,callee_id,callee_name,file_path,line,edge_kind. - Function boundaries:
symbol_id,file_path,start_line,end_line,signature,language. - Coverage:
file_path,indexed,backend,precision,unit_cache_key,status.
- Symbols:
- The builder writes the manifest LAST (Step 4) and the compatibility pointer.
- The builder MUST use ABSOLUTE paths and set its own working directory (Block
A step 6). It MUST NOT write anything under
CODE_ROOTwhensnapshot_pinnedis true (Block A step 4). Backends that produce sidecar files (ctagstags, cscopecscope.out, clangd cache) MUST be redirected to STATE-RELATIVE paths:ctags -f <state>/helpers/tags,cscope -f <state>/helpers/cscope.out,CLANGD_INDEX_STORAGE=<state>/helpers/. Read-only LSP/SCIP queries to a running server need no redirect.
Query helper: query_structural_index.py
- Write the query helper to
workspace/helpers/query_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 absent or a different integer, REGENERATE. - The query helper provides bounded, paginated operations against
catalog.sqlite(or a remote endpoint — identical API). It IS the consumption contract (see Query Interface below). - If
catalog.sqliteis absent butstructural_index.jsonlexists, the query helper falls back to linear scanning of the JSONL file (slower but functional). If both are absent, it returns empty results withcoverage.partition_status = "empty".
Step 4: Write Manifest and Commit
- Write the manifest to
workspace/kb/structural_index/tmp/manifest.jsonfirst. Then atomically rename it toworkspace/kb/structural_index/manifest.json. This is the atomic commit point — the manifest is written LAST, after all units, catalog, and coverage data are written. - Write a compatibility pointer to
workspace/kb/structural_index.jsonl(STATE-RELATIVE — NEVER underCODE_ROOT). Below a configurable threshold (default: 10K records), emit a complete JSONL export (provenance header + all records). Above the threshold, emit only a provenance header withcompat_pointer.full_export = falseandcompat_pointer.symbol_countset. Large consumers MUST use the query interface. - The manifest
provider.backend_versionsfield records which backend was used per language (e.g.,{"go": {"backend_name": "scip-clangd", "precision": "semantic"}, "python": {"backend_name": "tree-sitter", "precision": "ast"}}), so consumers know the precision level. - Interrupted builds leave unreferenced temp objects in
tmp/without corrupting the last published index. On resume, checkmanifest.jsonstatus andsnapshot_id(Step 1).
Step 5: Return Results / Notify Caller
- Return the path to
manifest.json,catalog.sqlite, and the query helper. Include a summary (unit count, symbol count, call-edge count, backends used, coverage status). - If the index is empty (no tools available or no source files found), notify the caller: "Structural index is empty — structural context unavailable."
- Do not notify the user directly — this skill is invoked as a sub-agent by the harness, planner, or researcher.
Index Schema and On-Disk Contract
On-Disk Layout
workspace/kb/structural_index/
├── manifest.json # Atomic commit point — written LAST
├── catalog.sqlite # Query-optimized serving store (both directions indexed)
├── units/ # Content-addressed immutable unit outputs
│ └── ab/cd/abcdef... # sha256 prefix sharding (2+2 hex dirs)
├── shards/ # Partitioned serving data (large corpora)
│ └── shard_0000.sqlite
├── native/ # Prebuilt index attachments (SCIP, Kythe, LSIF)
│ ├── provenance.json # Prebuilt index provenance manifest
│ ├── scip/
│ └── kythe/
└── tmp/ # Temporary objects during build
workspace/helpers/
├── build_structural_index.py # Builder (MANTIS_HELPER_VERSION = 5)
└── query_structural_index.py # Query helper (MANTIS_HELPER_VERSION = 5)
workspace/kb/structural_index.jsonl # Compatibility pointerManifest Schema (manifest.json)
{
"schema_version": 1,
"snapshot_id": "<SNAPSHOT_ID or 'unknown'>",
"root_fingerprint": "<sha256 of sorted (path, content_sha256) for all source files>",
"status": "complete|partial|empty|failed",
"provider": {
"kind": "local-build|baseline+overlay|remote",
"catalog": "catalog.sqlite",
"backend_versions": {
"cpp": {"backend_name": "tree-sitter", "backend_version": "0.20.8", "precision": "ast"},
"go": {"backend_name": "scip-clangd", "backend_version": "0.2.3", "precision": "semantic"}
}
},
"units": {"total": 0, "reused": 0, "rebuild": 0, "failed": 0},
"coverage": {"total_files": 0, "indexed_files": 0, "failed_files": 0, "deferred_files": 0},
"shards": [{"id": "", "path": "", "checksum": "", "partition_key": "", "symbol_count": 0, "edge_count": 0}],
"deferred_units": [{"unit_id": "", "language": "", "files": [], "priority": 4, "reason": ""}],
"native_indexes": [{"kind": "scip", "path": "", "snapshot_id": "", "root_fingerprint": "", "language": "", "indexer": "", "precision": ""}],
"baseline": {"source": "ci|local|none", "snapshot_id": "", "manifest_path": ""},
"overlay": {"units_added": 0, "units_modified": 0, "files": []},
"compat_pointer": {"path": "structural_index.jsonl", "full_export": true, "symbol_count": 0},
"created_at": "<ISO 8601>",
"build_duration_ms": 0
}Atomic commit: The manifest is written LAST (atomic rename from tmp/).
Interrupted builds leave unreferenced temp objects without corrupting the last
published index.
SQLite Catalog Schema (catalog.sqlite)
CREATE TABLE IF NOT EXISTS schema_meta (
key TEXT PRIMARY KEY, value TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS symbols (
symbol_id TEXT PRIMARY KEY,
name TEXT NOT NULL,
qualified_name TEXT NOT NULL,
namespace TEXT,
language TEXT NOT NULL,
file_path TEXT NOT NULL,
start_line INTEGER NOT NULL,
end_line INTEGER,
kind TEXT NOT NULL,
signature TEXT,
backend TEXT NOT NULL,
precision TEXT NOT NULL CHECK (precision IN ('semantic','typecheck','ast','symbol-only','heuristic','deferred','coverage-only')),
corpus TEXT DEFAULT 'default',
partition_key TEXT,
unit_cache_key TEXT,
source_layer TEXT NOT NULL DEFAULT 'baseline'
);
CREATE TABLE IF NOT EXISTS call_edges (
edge_id INTEGER PRIMARY KEY AUTOINCREMENT,
caller_id TEXT NOT NULL,
callee_id TEXT,
callee_name TEXT NOT NULL,
file_path TEXT NOT NULL,
line INTEGER NOT NULL,
edge_kind TEXT NOT NULL CHECK (edge_kind IN ('direct','indirect','virtual','macro','unresolved')),
corpus TEXT DEFAULT 'default',
partition_key TEXT,
source_layer TEXT NOT NULL DEFAULT 'baseline',
FOREIGN KEY (caller_id) REFERENCES symbols(symbol_id),
FOREIGN KEY (callee_id) REFERENCES symbols(symbol_id)
);
CREATE TABLE IF NOT EXISTS function_boundaries (
symbol_id TEXT PRIMARY KEY,
file_path TEXT NOT NULL,
start_line INTEGER NOT NULL,
end_line INTEGER NOT NULL,
signature TEXT,
language TEXT NOT NULL,
FOREIGN KEY (symbol_id) REFERENCES symbols(symbol_id)
);
CREATE TABLE IF NOT EXISTS coverage (
file_path TEXT NOT NULL,
indexed INTEGER NOT NULL DEFAULT 0,
backend TEXT,
precision TEXT,
unit_cache_key TEXT,
status TEXT NOT NULL DEFAULT 'pending',
corpus TEXT DEFAULT 'default',
partition_key TEXT,
PRIMARY KEY (file_path, corpus)
);
CREATE TABLE IF NOT EXISTS unit_cache (
cache_key TEXT PRIMARY KEY,
unit_id TEXT NOT NULL,
language TEXT NOT NULL,
extractor_name TEXT NOT NULL,
extractor_version TEXT NOT NULL,
file_count INTEGER NOT NULL,
symbol_count INTEGER NOT NULL,
edge_count INTEGER NOT NULL,
source_bytes INTEGER NOT NULL,
created_at TEXT NOT NULL,
snapshot_id TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS deferred_units (
unit_id TEXT PRIMARY KEY,
language TEXT NOT NULL,
files TEXT NOT NULL,
priority INTEGER NOT NULL,
reason TEXT NOT NULL,
cache_key TEXT,
created_at TEXT NOT NULL
);
-- Indexes: both directions!
CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);
CREATE INDEX IF NOT EXISTS idx_symbols_qualified ON symbols(qualified_name);
CREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_path, start_line);
CREATE INDEX IF NOT EXISTS idx_symbols_lang ON symbols(language);
CREATE INDEX IF NOT EXISTS idx_edges_caller ON call_edges(caller_id);
CREATE INDEX IF NOT EXISTS idx_edges_callee ON call_edges(callee_id);
CREATE INDEX IF NOT EXISTS idx_edges_callee_name ON call_edges(callee_name);
CREATE INDEX IF NOT EXISTS idx_edges_file ON call_edges(file_path, line);
CREATE INDEX IF NOT EXISTS idx_boundaries_file ON function_boundaries(file_path, start_line, end_line);
CREATE INDEX IF NOT EXISTS idx_coverage_status ON coverage(status);
CREATE INDEX IF NOT EXISTS idx_deferred_priority ON deferred_units(priority);Partitioning: When symbols exceed 500K or edges exceed 2M, partition into
shard SQLite files under shards/ by lang:{language}:bucket:{NN} (stable
hash). Each shard has the same schema. The query helper routes queries to the
correct shard(s) based on the manifest.
Content-Addressed Cache Key
cache_key = sha256(
schema_version +
extractor_name@version +
language +
compile_context_digest +
ordered_input_content_digests +
dependency_or_interface_digest
)Critical: snapshot_id is NOT in the cache key. It goes in provenance only.
This permits reuse across commits, branches, and snapshots with identical units.
Canonical Symbol IDs
Native IDs (when semantic backend is available):
- SCIP:
scip:{symbol} - Kythe:
kythe:{uri} - clangd:
clangd:{usr}
Fallback IDs (when no semantic backend):
fallback:{language}:{file_path}:{sha256(qualified_name|start_line|signature)[:16]}This distinguishes namespaces, overloads, methods, local functions, and duplicate names across languages or repositories.
Edge Kinds
Edge kinds are kept explicitly separate — never silently merged:
direct— statically resolved call to a known symbolindirect— function pointer, closure, callbackvirtual— virtual method dispatch (runtime-resolved)macro— call introduced by macro expansionunresolved— callee name found but no symbol_id resolved
Per-Language Semantic Units
| Language | Unit Type | Compile Context | Dependency Digest |
| C/C++ | Compilation unit | compile_commands.json entry | sha256 of transitive header interfaces |
| Go | Package | go.mod + build tags | sha256 of imported packages' exported API |
| Rust | Crate | Cargo.toml + features | sha256 of extern crate signatures |
| Java/Kotlin | Compiler batch | module path + classpath | sha256 of imported class signatures |
| TypeScript | Project | tsconfig.json | sha256 of imported module type declarations |
| Fallback | Individual file | None | Empty string |
Fallback Granularity Rule: For the fallback tier (regex, AST parser, or
lightweight crawler without a language build system), each source file MUST be
its own independent semantic unit. Never bundle multiple source files into a
single fallback unit. Per-file unit isolation is essential for content-addressed
cache efficiency — when one file changes in a future snapshot, only that single
file's unit invalidates while all unchanged files hit the cache
(reused = N-1).
Baseline + Delta Overlay
- Static baseline: Built once in CI for the complete snapshot.
- Incremental cache: Immutable unit outputs reused across snapshots.
- Delta overlay: Changed/target files indexed locally, layered over baseline.
- Remote serving: Optional when global index is too costly locally.
At query time, the query helper merges baseline + overlay results. Overlay
symbols supersede baseline symbols for the same file. The manifest records
provider.kind = "baseline+overlay" with baseline manifest reference and
overlay unit count.
Compatibility JSONL Export
The old structural_index.jsonl format is retained as a compatibility export
only — it is NOT the query contract. Below the threshold (default 10K records),
a complete JSONL export is emitted. Above the threshold, only a provenance
pointer is written. Large consumers MUST use the query interface.
Line 1 — provenance header:
{"_provenance": true, "snapshot_id": "abc123", "tool": "tree-sitter"}Lines 2+ — structural records (one per line, _type discriminator):
{"_type": "function", "key": "src/parser.c:parse_input", "start_line": 45, "end_line": 120, "signature": "int parse_input(char *buf, size_t len)", "calls": ["malloc", "validate_input", "memcpy"]}
{"_type": "call_edge", "caller": "parse_input", "callee": "malloc", "file": "src/parser.c", "line": 78}
{"_type": "call_edge", "caller": "main", "callee": "parse_input", "file": "src/main.c", "line": 203}Provenance header fields:
| Field | Type | Description |
_provenance | bool | Always true — marks this as the provenance header line |
snapshot_id | string | SNAPSHOT_ID the index was built against |
tool | string | Backend used (e.g. "lsp-clangd", "tree-sitter", "ctags", "regex", "grep") |
Record types:
_type | Description | Key fields |
function | Function definition with boundary and signature | key, start_line, end_line, signature, calls |
call_edge | A call from caller to callee at file:line | caller, callee, file, line |
Snapshot Safety
- Build from
CODE_ROOT, not live tree (when pinned). When the snapshot is pinned, the structural index is built from the pinnedCODE_ROOT, ensuring it reflects the exact bytes the pipeline is analyzing. - Reuse-on-match. If
manifest.jsonalready carries the currentSNAPSHOT_ID(andSNAPSHOT_IDis NOT"unknown"— in MODE-OFF, always rebuild), reuse it — do not rebuild. Rebuild whenSNAPSHOT_IDdiffers or is"unknown". Individual units may still be reused from the content-addressed cache. This bounds cost across retries/crash-resume. - Manifest atomicity. The manifest is written LAST via atomic rename from
tmp/. Interrupted builds leave unreferenced temp objects without corrupting the last published index. On resume, checkmanifest.jsonstatus andsnapshot_id. - STALE flag in HALT mode. When
snapshot_pinnedis false (HALT), the index may be built from the unpinnedCODE_ROOTbut is marked as potentially stale. Consumers treat structural hints as advisory. - MODE-OFF: build, do not skip. When
active_snapshotis absent (MODE-OFF), build against the current directory (cwd) with provenancesnapshot_idset to"unknown". This is the standalone-efficiency case — the index is still useful for the researcher/planner even without snapshot pinning. Do NOT return an empty index merely because the snapshot is absent.
Consumption Contract
These are runtime instructions for callers — they define how consumers use the structural index. The structural index is a HINT-only enhancement; skills that do not use it behave exactly as they do today.
Query Interface
The query helper IS the contract. All consumers use
query_structural_index.py (or a compatible remote endpoint). The JSONL file is
NOT the query contract — it is a compatibility export only.
Operations:
resolve_symbol(name, language?, file?, namespace?)→{results, total, ambiguous, coverage}- Returns ALL matches — no silent selection among ambiguous symbols.
- Caller MUST disambiguate before calling
find_callers/find_callees.
find_callers(symbol_id, limit=100, offset=0)→{results, total, has_more, coverage}- Bounded, paginated caller lookup.
- Each result carries
precision,backend,edge_kind. - Empty results carry
coverage.partition_status.
find_callees(symbol_id, limit=100, offset=0)→{results, total, has_more, coverage}- Same shape as
find_callers.
- Same shape as
get_function_boundary(file, line)→{symbol_id, start_line, end_line, signature, precision, backend}get_coverage(file?)→{total_files, indexed_files, failed, deferred, partition_status, backends_used}
Key properties:
- Bounded results and pagination (prevents loading entire index into memory).
- Explicit name resolution before graph traversal (no silent selection among ambiguous symbols).
- Precision and backend attached to every result.
- Coverage attached to empty results.
- Identical operations for local and remote providers (remote via
MANTIS_STRUCTURAL_INDEX_URLenv var or manifestprovider.kind = "remote").
Coverage on empty results:
partition_status | Meaning | Consumer action |
complete | All files indexed | "No indexed callers" (still run grep per HINT-only rule) |
partial | Some files deferred or failed | "Not fully indexed" — MUST run grep fallback |
empty | No backend available | "Not indexed" — MUST run grep fallback |
failed | Backend attempted but failed | "Index failed" — MUST run grep fallback |
mantis-plan
- Use the structural index query helper for function-level dependency fan-out.
When planning investigations, call
resolve_symbol()thenfind_callers()to identify all functions that call into a target — this broadens the audit set beyond single-file analysis. - The structural index decides ORDER of investigations (which functions to audit first based on call-graph centrality), never MEMBERSHIP. It may broaden the audit set (safe over-reporting), but must never REMOVE or drop a file; the planner's existing logic remains the membership floor.
mantis-researcher
- Wave 1 (Rapid Triage): Run a repo-wide grep for the function name to build
the exhaustive set of candidate call-sites — this is the mandatory floor. Then
use the structural index query helper (
resolve_symbolthenfind_callers) to RANK and prioritize which call-sites to audit first (the index distinguishes actual calls from comments/strings/variable names). Audit the union of both result sets — the structural index may miss macro-based calls, function pointers, and dynamic dispatch, so grep remains the floor. - Wave 2 (Deep Audit): Use
get_function_boundary(file, line)to start with the enclosing function, expanding to callers/callees/file as needed for cross-function context — this saves context while preserving coverage. - If the structural index is absent or empty, fall back to grep-based discovery (today's behavior). The structural index is a coverage HINT only — it improves audit quality but is never required.
Safety
Non-negotiable invariants:
- Agnostic. Nothing is ever required; no-tool / parse-fail / not-invoked → empty index → grep fallback = today's behavior byte-for-byte. Optional in the Pass Lifecycle Contract; a non-conformant harness simply skips it.
- HINT-only / union / never MEMBERSHIP. Consumers audit the union with
grep; a symbol the index misses must still be reachable by the exhaustive
sweep. The structural index decides ORDER, never MEMBERSHIP. The query
contract enforces this:
find_callersreturns HINTs, never authoritative membership — consumers MUST union with grep. - No verdicts, touches no findings. Cannot violate INV-1 and cannot itself drop a finding.
- Narrow scope: source cross-reference only. Binary/build-derived reachability ("is it compiled into production") is explicitly out of scope — a dev customization, not part of this skill, because absence-from-a-build can hide a real finding (INV-2). Do not fold build-derived reachability into this skill.
A reference blueprint is available at mantis-pipeline-adapter/references/mantis-structural-index.md. It is a stub that points to this SKILL.md as the single source of truth — do not duplicate spec content there.
Trending
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Who's talking about google/mantis
- Matheus Battisti“O Google lançou uma ferramenta que caça falhas de segurança com IA (Google Mantis)”YouTube · Jul 30, 2026 · 9.2k views
- ☕ Claude Code Cafe“🔒 コードの脆弱性を AI に探させて再現まで確かめる Google のリポジトリで公開された mantis #claude #claudecode”YouTube · Sep 8, 2026 · 647 views
- o0o0o0o“Your Tests Pass. Is Your Code Safe? Google’s AI Security Agents”YouTube · Sep 30, 2026 · 180 views
- ☕️ Claude Code Cafe“🔒 Let an Agent Find Your Security Flaws and Reproduce Them — mantis #claude #claudecode”YouTube · Sep 9, 2026 · 40 views
- 智用AI“Mantis:85% Token开销削减,AI漏洞扫描怎么做到的? #Shorts”YouTube · Sep 10, 2026 · 26 views
The biggest 5 of 46 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 46
Talked about on GitHub, YouTube and Bluesky (46 times).
On GitHub · 32
- Oct 30, 2026Design sandboxed agentic bug hunting, RCA, and novel vulnerability discovery — combustrrr/code-analysis-dashboard0 reactions
- Oct 30, 2026Epic: governed scanner and agentic analysis expansion — combustrrr/code-analysis-dashboard0 reactions
- Oct 28, 2026[radar-spike] google/mantis skills — sandbox threat-model (no CI gate) — pablontiv/a4s0 reactions
- Oct 27, 2026google 'mantis' — AI 코딩 에이전트용 취약점 자동 발견·재현·패치 툴킷 (10/26, GitHub) — roomedia/ax-trend0 reactions
- Oct 24, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-22 → 0-unstable-2026-10-24 — sudosubin/agents.nix0 reactions
27 more on GitHub
- Oct 23, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-17 → 0-unstable-2026-10-22 — sudosubin/agents.nix0 reactions
- Oct 17, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-16 → 0-unstable-2026-10-17 — sudosubin/agents.nix0 reactions
- Oct 16, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-15 → 0-unstable-2026-10-16 — sudosubin/agents.nix0 reactions
- Oct 15, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-14 → 0-unstable-2026-10-15 — sudosubin/agents.nix0 reactions
- Oct 14, 2026feat: SAST — LLM alert triage of CodeQL and Semgrep findings with human sign-off (PR/CI, Advanced) — sparkgeo/github-actions0 reactions
- Oct 14, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-13 → 0-unstable-2026-10-14 — sudosubin/agents.nix0 reactions
- Oct 13, 2026agent-skills.github.google.mantis: 52093f7 → 49ab993 — sudosubin/agents.nix0 reactions
- Oct 13, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-05 → 0-unstable-2026-10-13 — sudosubin/agents.nix0 reactions
- Oct 5, 2026agent-skills.github.google.mantis: 76bf653 → f671cd8 — sudosubin/agents.nix0 reactions
- Oct 5, 2026agent-skills.github.google.mantis: 0-unstable-2026-10-04 → 0-unstable-2026-10-05 — sudosubin/agents.nix0 reactions
- Oct 5, 2026agent-skills.github.google.mantis: 30447e1 → f5656dd — sudosubin/agents.nix0 reactions
- Oct 5, 2026agent-skills.github.google.mantis: f48a85e → 30447e1 — sudosubin/agents.nix0 reactions
- Oct 4, 2026Update skill: /google-mantis-patch (high risk) — aiskillstore/marketplace0 reactions
- Oct 4, 2026Update skill: /google-mantis-meta-agent (critical risk) — aiskillstore/marketplace0 reactions
- Oct 4, 2026Update skill: /google-mantis-dedupe (high risk) — aiskillstore/marketplace0 reactions
- Oct 4, 2026Update skill: /google-mantis-threat-model (low risk) — aiskillstore/marketplace0 reactions
- Oct 4, 2026Update skill: /google-mantis-history (medium risk) — aiskillstore/marketplace0 reactions
- Oct 4, 2026Update skill: /google-mantis-structural-index (high risk) — aiskillstore/marketplace0 reactions
- Oct 4, 2026Update skill: /google-mantis-calibrate (high risk) — aiskillstore/marketplace0 reactions
- Oct 4, 2026agent-skills.github.google.mantis: 0-unstable-2026-09-28 → 0-unstable-2026-10-04 — sudosubin/agents.nix0 reactions
- Oct 3, 2026agent-skills.github.google.mantis: 0-unstable-2026-09-18 → 0-unstable-2026-09-28 — sudosubin/agents.nix0 reactions
- Sep 27, 2026agent-skills.github.google.mantis: init at 0-unstable-2026-09-18 — sudosubin/agents.nix0 reactions
- Sep 22, 2026fix(rust): patch parameter bounds validation bugs to avoid panic — morrowc/mrtparser0 reactions
- Sep 22, 2026fix(cpp): add minimal bound checks for packet lengths — morrowc/mrtparser0 reactions
- Sep 11, 2026mode — chogng/ash0 reactions
- Jul 27, 2026Integrate Google Mantis Skills as CRSs — ossf/oss-crs0 reactions · 1 comment
- Jul 3, 2026Add Google Mantis — agentic AI security review pipeline — ottosulin/awesome-ai-security0 reactions
On YouTube · 9
- Jul 30, 2026O Google lançou uma ferramenta que caça falhas de segurança com IA (Google Mantis) — Matheus Battisti - Hora de Codar9.2k views · 29 comments
- Sep 8, 2026🔒 コードの脆弱性を AI に探させて再現まで確かめる Google のリポジトリで公開された mantis #claude #claudecode — ☕ Claude Code Cafe647 views
- Sep 30, 2026Your Tests Pass. Is Your Code Safe? Google’s AI Security Agents — o0o0o0o180 views
- Sep 9, 2026🔒 Let an Agent Find Your Security Flaws and Reproduce Them — mantis #claude #claudecode — ☕️ Claude Code Cafe40 views
- Sep 10, 2026Mantis:85% Token开销削减,AI漏洞扫描怎么做到的? #Shorts — 智用AIsays it tested it26 views
4 more on YouTube
- Sep 3, 2026今日のAI実用ニュース4選:Slack・Skills・動画理解・WebGPU【9月3日】 — 毎日最速AIニュース21 views
- Sep 10, 2026Mantis:85% Token开销削减,AI漏洞扫描怎么做到的? — 智用AIsays it tested it19 views
- Jul 15, 2026Developer tools and hidden risk & Enterprise agents need real infrastructure - AI News (Jul 15, 2... — The Automated Daily9 views
- Sep 3, 2026Googleの新Skills「Mantis」公開、本番PCで試すな #Shorts — 毎日最速AIニュース5 views
On Bluesky · 5
- Sep 15, 2026Mantis : toolkit open source de Google pour agents de coding, conçu pour trouver, reproduire et corriger des vulnérabilités de façon… — @camilleroux.com3 likes and reposts · 1 reply
- Oct 1, 2026GitHub - google/mantis: A modular, stack-agnostic toolkit for AI coding agents to autonomously find, reproduce, and patch vulnerabilities.… — @tech-trending.bsky.social1 likes and repost
- Sep 23, 2026#ばばさん通信ダイジェスト 賛否関わらず話題になった/なりそうなものを共有しています。 GitHub - google/mantis: A modular, stack-agnostic toolkit for AI coding agents to autonomously… — @netmarkjp.bsky.social1 likes and repost
- Jul 3, 2026Three repos that are leading our path forward in scaling AppSec workflows: 1. github.com/google/mantis 2. github.com/anthropics/d... 3.… — @javanrasokat.bsky.social1 likes and repost
- Oct 1, 2026🤖 GitHub - google/mantis: A modular, stack-agnostic toolkit for AI coding agents to autonomously find,... 要約:… — @ai-bs-bot.bsky.social0 likes and reposts · 1 reply
In this repository21 other files it gives its agents.
- AGENTS.mdAGENTS.md
- mantis-configureSkill
- mantis-launchSkill
- mantis-adviseSkill
- mantis-architectureSkill
- mantis-calibrateSkill
- mantis-chainSkill
- mantis-criticSkill
- mantis-dedupeSkill
- mantis-historySkill
- mantis-meta-agentSkill
- mantis-patchSkill
- mantis-pipeline-adapterSkill
- mantis-planSkill
- mantis-reflectSkill
- mantis-reportSkill
- mantis-reproduceSkill
- mantis-researcherSkill
- mantis-reviewSkill
- mantis-summarizeSkill
- mantis-threat-modelSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

