Gapmap scans a repository to find the "Gaps", the dangerous, load-bearing parts of a codebase that are highly complex but have zero human documentation. It then compiles those risks into machine-readable guardrails so that AI coding assistants (like Cursor) are physically blocked from breaking your architecture.
Project description
GapMap
Find the riskiest undocumented code in a Python repository, generate machine-readable Context Manifests for AI agents, and answer questions about the codebase with grounded, cited retrieval.
| Component | Path | What it does |
|---|---|---|
| GapMap CLI | gapmap/ |
Entity call graph, documentation-debt scoring, manifest generation |
| GapMap Shield | gapmap/mcp_server.py |
MCP server exposing manifests to IDE agents |
| RAG pipeline | gapmap/src/, main.py |
Semantic search and grounded Q&A over repo text |
| Dashboard | dashboard/ |
Next.js UI over .gapmap/audit.json |
Enterprise use case
When a senior engineer leaves, undocumented load-bearing code does not have to become an outage. GapMap turns departure into a risk-reduction pipeline: audit the blast radius, encode tacit knowledge into manifests, and gate AI-assisted edits through MCP.
flowchart LR
subgraph S1["① Senior engineer departure"]
direction TB
D1["Primary author offboards"]
D2["High-centrality legacy entity<br/>e.g. payment_router.py::route_payment"]
D3["Undocumented · bus-factor = 1"]
D1 --> D2 --> D3
end
subgraph S2["② GapMap ownership audit"]
direction TB
A1["gapmap audit · gapmap ownership"]
A2["tree-sitter AST → entity call graph"]
A3["git blame → churn · temporal risk"]
A4["Risk score = callers × LOC × git factor"]
A5["Isolates CRITICAL asset → .gapmap/audit.json"]
A1 --> A2 & A3 --> A4 --> A5
end
subgraph S3["③ Automated handover"]
direction TB
H1["gapmap generate <entity>"]
H2["Context manifest JSON"]
H3["upstream_callers · source_hash<br/>ai_execution_invariants"]
H1 --> H2 --> H3
end
subgraph S4["④ GapMap Shield (FastMCP)"]
direction TB
M1["Junior engineer + IDE agent<br/>attempts refactor"]
M2["get_execution_invariants<br/>scan_workspace_risks"]
M3["Invariants injected pre-edit<br/>implicit contracts enforced"]
M4["Constrained change · no regression"]
M1 --> M2 --> M3 --> M4
end
S1 ==> S2 ==> S3 ==> S4
ASCII version (plain-text viewers)
Senior engineer GapMap CLI audit Automated handover MCP Shield (FastMCP)
departure + ownership
│ │ │ │
▼ ▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌─────────────────┐ ┌──────────────────────┐
│ Offboard │ │ AST call graph │ │ gapmap generate │ │ Agent edit request │
│ High inbound │ ───► │ git blame/churn │ ─────► │ .gapmap/ │ ───► │ get_execution_ │
│ callers │ │ bus-factor flag │ │ manifests/*.json│ │ invariants() │
│ Undocumented │ │ CRITICAL entity │ │ execution │ │ → safety params │
└──────────────┘ └──────────────────┘ │ invariants │ │ → regression avoided │
└─────────────────┘ └──────────────────────┘
Outcome: knowledge loss contained · tacit contracts machine-readable · AI edits grounded in graph + git signals
Configure departed authors via GAPMAP_DEPARTED_CONTRIBUTORS or
.gapmap.toml → [ownership] (see Configuration) before
running the audit.
Table of contents
- Enterprise use case
- Prerequisites
- Installation
- Run on any Python repo
- GapMap CLI
- Context manifests
- GapMap Shield (MCP)
- Documentation automation
- Risk dashboard
- Semantic search and Q&A
- Configuration
- CI workflows
- Development
- Publishing to PyPI
- Architecture
Prerequisites
| Requirement | Needed for |
|---|---|
| Python 3.10+ | All commands |
| Git (recommended) | git blame risk signals, ownership, trend history |
| Node.js 18+ & npm | gapmap dashboard only (not required for audit/CLI) |
| OPENAI_API_KEY (optional) | LLM-polished invariants and Q&A (pip install "gapmap-ai[llm]") |
GapMap analyzes Python repos only today. Point --repo at the root of the
project you want to scan (where your .py files live).
Installation
Option A — PyPI or uvx (recommended for users)
No clone required. Installs the CLI only (dashboard and MCP server need Option B
for development, or run MCP via python -m gapmap.mcp_server after install).
# Zero-install — runs in a temporary env (requires uv: https://docs.astral.sh/uv/)
uvx gapmap-ai audit --repo /path/to/your/project
# Or install permanently
pip install gapmap-ai
gapmap audit --repo /path/to/your/project
# Full features (vector search + LLM + MCP + tests)
pip install "gapmap-ai[all]"
Extras: pip install "gapmap-ai[vector]", "gapmap-ai[llm]", or "gapmap-ai[mcp]".
Option B — Clone and install (contributors / dashboard / MCP)
git clone https://github.com/Utkrisht12/GapMaP.git
cd GapMaP
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[all]"
[all] installs the CLI, vector search (FAISS), LLM support, FastMCP, and
pytest. For a minimal audit-only install:
pip install -e .
Option C — Install from Git without cloning (CLI only)
pip install "gapmap-ai[all] @ git+https://github.com/Utkrisht12/GapMaP.git"
The dashboard still requires a full clone (Option B) because gapmap dashboard
runs the Next.js app from the dashboard/ directory in this repo.
Verify
gapmap --help
# or
gapmap-ai --help
Run on any Python repo
Replace /path/to/your/project with the repository you want to audit.
# 1. Scan structure and call-graph quality
gapmap parse --repo /path/to/your/project
# 2. Top undocumented risks (writes .gapmap/audit.json)
gapmap audit --repo /path/to/your/project
# 3. Explain why a specific entity is risky
gapmap ask route_payment "why is this risky?" --repo /path/to/your/project
# 4. Generate a context manifest for the top gap (or a named entity)
gapmap generate --repo /path/to/your/project
# 5. Optional — open the risk dashboard (requires Node.js + repo clone)
gapmap dashboard --repo /path/to/your/project
# → http://localhost:3000
Audit this repo after install:
gapmap audit --repo .
gapmap dashboard --repo .
GapMap works fully offline for audit, parse, generate, stale, ownership, and
trend. Vector search and LLM polish need the optional extras ([vector],
[llm]).
GapMap CLI
GapMap parses every Python file with tree-sitter, builds an entity-level call graph (NetworkX), scores each entity with weighted incoming callers × LOC × a temporal git factor, checks which risky entities are missing from docs and docstrings, and turns the result into audits, explanations, context manifests, and an HTML report.
All commands
| Command | Purpose |
|---|---|
gapmap parse |
Files, LOC, imports, graph resolution breakdown |
gapmap audit |
Top undocumented high-risk entities |
gapmap ask |
Graph-grounded explanation for one entity |
gapmap generate |
Generate context manifest(s) under .gapmap/manifests/ |
gapmap report |
Self-contained HTML report |
gapmap dashboard |
Interactive risk UI (clone + Node.js) |
gapmap stale |
Find manifests whose source has drifted |
gapmap ownership |
Knowledge-debt ownership and bus-factor |
gapmap trend |
Documentation coverage over time |
gapmap autodoc |
Batch-generate manifests for critical hubs (CI / auto-PR) |
Common flags: --repo PATH (default: .), --refresh (ignore .gapmap_cache).
Example session
export REPO=/path/to/your/project
gapmap parse --repo "$REPO"
gapmap audit --repo "$REPO" --top 15
gapmap ask payment_router.py "why is this risky?" --repo "$REPO"
gapmap generate route_payment --repo "$REPO"
gapmap report --repo "$REPO" -o gapmap-report.html
What makes the graph accurate
- Import-aware call resolution.
from auth import Handlerresolves to the imported entity, not every same-named class. Edges carryconfidenceandresolution(symbol, qualified, same-file, import, ambiguous). - Smarter documentation detection.
MCPClientmatches "MCP client"; single-word names stay strict to avoid false positives. - Temporal risk from git history. Author churn and bus-factor signals from
git blameamplify volatile or single-owner hotspots.
Context manifests
gapmap generate writes hybrid JSON Context Manifests to
.gapmap/manifests/<entity_name>.json in the target repository (not inside
the GapMap package). Files are overwritten in place so agents always read current
ground truth.
Example: gapmap generate route_payment --repo /path/to/project creates
.gapmap/manifests/route_payment.json.
Schema
{
"metadata": {
"entity": "payment_router.py::route_payment",
"generated_date": "2026-06-18",
"source_hash": "a1b2c3d4e5f6",
"source_loc": 142
},
"risk_profile": {
"score": 500,
"rank_overall": 1,
"rank_undocumented": 1,
"risk_level": "CRITICAL",
"git_metrics": {
"primary_author": "alice",
"days_since_last_edit": 12,
"recent_commit_messages": ["fix routing edge case"]
}
},
"systemic_role": {
"upstream_callers": ["a.py::invoke"],
"downstream_callees": ["auth.py::check"]
},
"ai_execution_invariants": "## Structural Constraints\n* ..."
}
- Structured fields (
metadata,risk_profile,systemic_role) are deterministic and machine-parseable. ai_execution_invariantsis a markdown string: execution constraints, implicit contracts, and safety rules for an AI coding assistant.- With
[llm]andOPENAI_API_KEY, invariants are synthesized by GPT from source, callers, and git history. Offline, a deterministic template is used.
Manifests embed source_hash and source_loc so gapmap stale detects when
code has drifted away from the registered invariants.
GapMap Shield (MCP)
GapMap Shield exposes context manifests to IDE agents over the Model Context
Protocol (stdio). It ships a gapmap-mcp console entry point so launchers can
start it without you having to manage a Python interpreter.
Tools
| Tool | When to use |
|---|---|
get_execution_invariants(repo_root, entity_name) |
Before modifying or refactoring an entity — returns risk level and ai_execution_invariants |
scan_workspace_risks(repo_root) |
When orienting in a new repo — lists all HIGH and CRITICAL entities |
Add to Cursor (one click)
The button installs the
uvxconfiguration below. Requiresuvto be installed.
Cursor / IDE config
Recommended — uvx (no manual Python setup):
uv fetches and runs gapmap-ai[mcp] in an
isolated environment, so there is no "which Python?" problem and no separate
install step.
{
"mcpServers": {
"gapmap-shield": {
"command": "uvx",
"args": ["--from", "gapmap-ai[mcp]", "gapmap-mcp"]
}
}
}
Pin a version if you prefer: "--from", "gapmap-ai[mcp]==0.2.2".
Fallback — explicit Python interpreter:
If you don't use uv, install the MCP extra and point Cursor at the absolute
path of the interpreter you installed it into:
pip install "gapmap-ai[mcp]"
which python # copy this absolute path into the config below
{
"mcpServers": {
"gapmap-shield": {
"command": "/absolute/path/to/python",
"args": ["-m", "gapmap.mcp_server"]
}
}
}
Zero-dependency — standalone binary:
For machines without Python at all, download the prebuilt gapmap-mcp binary for
your OS from the Releases page
and point Cursor directly at it:
{
"mcpServers": {
"gapmap-shield": {
"command": "/absolute/path/to/gapmap-mcp"
}
}
}
⚠️ Cursor integration note (
spawn python ENOENT): Cursor runs local MCP servers in a detached shell context that often cannot resolve a bare"python"command. If you see a red dot or a connection failure, use the absolute path to your active Python interpreter (e.g./Users/yourname/miniforge3/bin/python), or switch to theuvxconfiguration above.GapMap Shield also suppresses the FastMCP startup banner on stderr (
show_banner=False) so Cursor does not treat banner output as a connection error.
Point agents at the target repo's repo_root when calling tools. Manifests must
exist under {repo_root}/.gapmap/manifests/ (create them with gapmap generate
first).
Documentation automation
export REPO=/path/to/your/project
# Batch-generate manifests for documentation gaps
gapmap generate --all-critical --repo "$REPO"
gapmap generate --top 10 --repo "$REPO"
gapmap generate --min-score 300 --repo "$REPO"
# Drift detection (exits non-zero in CI when stale manifests exist)
gapmap stale --repo "$REPO"
gapmap stale --fix --repo "$REPO"
gapmap ownership --repo "$REPO"
gapmap trend --repo "$REPO"
gapmap autodoc --regenerate-stale --repo "$REPO"
Risk dashboard
Requires Node.js, a clone of this repo, and an audit JSON file.
# From the GapMap repo root, after pip install -e ".[all]"
gapmap audit --repo /path/to/your/project
gapmap dashboard --repo /path/to/your/project --port 3000
Opens http://localhost:3000 with risk scores, call graph, coverage trends, stale
manifests, ownership, and graph-quality metrics from .gapmap/audit.json.
UI-only (mock data, no audit):
cd dashboard
npm install # first time only
NEXT_PUBLIC_GAPMAP_USE_MOCK=true npm run dev
See dashboard/README.md for component details.
Semantic search and Q&A
Separate from gapmap ask: main.py runs repo-wide semantic retrieval (not
entity-specific). Requires [vector] extra and a source checkout (main.py is
not shipped as a PyPI console command).
pip install -e ".[vector]" # or .[all]
python main.py --repo /path/to/your/project -v
python main.py --repo /path/to/your/project --query "How does caching work?"
python main.py --repo /path/to/your/project --ask "How does caching work?"
python main.py --repo /path/to/your/project --interactive
python main.py --repo /path/to/your/project --save .cache/gapmap-index
gapmap ask |
main.py --query |
main.py --ask |
|
|---|---|---|---|
| Scope | One entity | Whole repo | Whole repo |
| Output | Risk explanation | Raw chunks + scores | Synthesized answer + citations |
| Context | Call graph + risk + optional vectors | Vectors only | Vectors + synthesis |
Without openai or an API key, synthesis falls back to a deterministic
extractive engine (works offline).
pip install -e ".[llm]"
export OPENAI_API_KEY=sk-...
python main.py --repo . --ask "How does staleness detection work?"
Configuration
Copy .gapmap.toml.example to .gapmap.toml in the
target repo you are auditing:
[policy]
critical_threshold = 500
auto_document = true
regenerate_when_stale = true
[docs]
output_dir = ".gapmap/manifests"
min_score = 100
[ownership]
departed_contributors = ["alice", "bob@corp.com"]
Optional dependencies
pip install "gapmap-ai[vector]" # RAG
pip install "gapmap-ai[llm]" # LLM invariants and Q&A
pip install "gapmap-ai[mcp]" # GapMap Shield MCP server
pip install "gapmap-ai[all]" # full install
pip install -e ".[all]" # from source (contributors)
| Extra | Enables |
|---|---|
vector |
RAG indexing and search (sentence-transformers, faiss-cpu) |
llm |
LLM-backed execution invariants and Q&A (openai) |
mcp |
GapMap Shield MCP server (fastmcp) |
dev |
Test suite (pytest) |
all |
Everything above |
CI workflows
| Workflow | Purpose | Trigger |
|---|---|---|
gapmap-sentinel.yml |
Fail on new critical undocumented hubs | Manual only |
gapmap-autodoc.yml |
Open a PR with generated manifests | Manual only |
Both use workflow_dispatch while the project is under construction. Uncomment
push / pull_request in each file when ready.
gapmap audit --repo . --json-export report.json
Writes CI export JSON; .gapmap/audit.json is always updated for the dashboard.
Development
git clone https://github.com/Utkrisht12/GapMaP.git && cd GapMaP
pip install -e ".[all]"
pytest
Tests use a deterministic fake encoder — no network or model downloads.
Project layout
.
├── gapmap/ CLI, analysis engine, MCP server
│ └── mcp_server.py GapMap Shield (FastMCP)
├── dashboard/ Next.js risk dashboard
├── docs/ ARCHITECTURE.md
├── tests/ pytest suite
├── main.py RAG pipeline entry point (source checkout only)
└── .gapmap.toml.example policy template
Target repos receive generated artifacts under .gapmap/:
/path/to/your/project/
└── .gapmap/
├── audit.json machine-readable audit (from `gapmap audit`)
├── history.jsonl coverage trend (from `gapmap trend`)
└── manifests/ context manifests (from `gapmap generate`)
└── route_payment.json
Publishing to PyPI
Package name on PyPI: gapmap-ai (console commands: gapmap and
gapmap-ai). Published at https://pypi.org/project/gapmap-ai/
pip install -U packaging build twine
python -m build
# Production (username is always __token__)
export TWINE_USERNAME=__token__
export TWINE_PASSWORD='pypi-...' # your API token — never commit this
twine upload dist/*
Bump version in pyproject.toml before each upload — PyPI does not allow
overwriting an existing release.
After publish, users can run:
uvx gapmap-ai audit --repo /path/to/your/project
pip install gapmap-ai && gapmap audit --repo /path/to/your/project
Push to GitHub does not update PyPI automatically; publish is manual (or add a GitHub Actions release workflow later).
Architecture
Module-level diagrams, data flow, and CI details:
docs/ARCHITECTURE.md.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gapmap_ai-0.2.2.tar.gz.
File metadata
- Download URL: gapmap_ai-0.2.2.tar.gz
- Upload date:
- Size: 110.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8173e4863d13f9eca7aa78c84f0a64a26b7d01aa935ac9a35d0bdcff83a60473
|
|
| MD5 |
6bc70c257ab067dd8b894aadb3ac7cd2
|
|
| BLAKE2b-256 |
e9e988983615e4699f39d052a988351fed1599e04bbaae400a0e9bb37170b39e
|
File details
Details for the file gapmap_ai-0.2.2-py3-none-any.whl.
File metadata
- Download URL: gapmap_ai-0.2.2-py3-none-any.whl
- Upload date:
- Size: 96.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19bbba447ecffe89a3dad5605e39e71ad3e909266403823ddfde6eb1a774e595
|
|
| MD5 |
5b468fad37dcfc7efcfc4d688e379925
|
|
| BLAKE2b-256 |
bb391b11b16a3964d5b969f7444f395bfcbf02c5f2a8d5861da622f014250ba0
|