Skip to main content

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 &lt;entity&gt;"]
        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

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 Handler resolves to the imported entity, not every same-named class. Edges carry confidence and resolution (symbol, qualified, same-file, import, ambiguous).
  • Smarter documentation detection. MCPClient matches "MCP client"; single-word names stay strict to avoid false positives.
  • Temporal risk from git history. Author churn and bus-factor signals from git blame amplify 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_invariants is a markdown string: execution constraints, implicit contracts, and safety rules for an AI coding assistant.
  • With [llm] and OPENAI_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)

Add to Cursor

The button installs the uvx configuration below. Requires uv to 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 the uvx configuration 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

gapmap_ai-0.2.2.tar.gz (110.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gapmap_ai-0.2.2-py3-none-any.whl (96.3 kB view details)

Uploaded Python 3

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

Hashes for gapmap_ai-0.2.2.tar.gz
Algorithm Hash digest
SHA256 8173e4863d13f9eca7aa78c84f0a64a26b7d01aa935ac9a35d0bdcff83a60473
MD5 6bc70c257ab067dd8b894aadb3ac7cd2
BLAKE2b-256 e9e988983615e4699f39d052a988351fed1599e04bbaae400a0e9bb37170b39e

See more details on using hashes here.

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

Hashes for gapmap_ai-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 19bbba447ecffe89a3dad5605e39e71ad3e909266403823ddfde6eb1a774e595
MD5 5b468fad37dcfc7efcfc4d688e379925
BLAKE2b-256 bb391b11b16a3964d5b969f7444f395bfcbf02c5f2a8d5861da622f014250ba0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page