Local-first CLI and MCP server for AI coding context — minimum useful context, maximum agent performance
Project description
context-router
A local-first CLI and MCP server that selects the minimum useful context across code structure, runtime evidence, and project memory for AI coding agents — reducing token consumption on review, debug, implement, and handover tasks.
Why
AI coding agents work best with focused, relevant context rather than entire codebases. context-router:
- Indexes your repo's symbols, dependency edges, call graphs, and test coverage into a local SQLite database
- Ranks candidates by structural relevance, query similarity, and community membership for your task mode
- Enforces a configurable token budget so your agent prompt stays lean (64.7% average reduction)
- Explains every selection decision in one human-readable sentence
- Supports multi-repo workspaces with cross-repo confidence boosting
- Works as a CLI, MCP server, or Python library — no API key required
Feature Overview
| Feature | Detail |
|---|---|
| Language support | Python (full), TypeScript/JS (full), YAML (k8s/Helm/GHA), Java, .NET (stubs) |
| Edge types | imports, calls (function-level), tested_by, community links |
| Task modes | review, implement, debug, handover |
| Ranking | Confidence scoring, query keyword boost, optional semantic boost (sentence-transformers) |
| Token budget | Hard cap with per-source-type guarantee; dynamic scaling for small repos |
| Memory | Persistent session observations + architectural decision records (FTS search) |
| Multi-repo | Workspace YAML, cross-repo link detection, unified ranked pack |
| Graph viz | Interactive D3.js HTML — color by kind or community cluster |
| MCP server | 8 tools over stdio JSON-RPC 2.0, compatible with Claude Code, Cursor, Windsurf |
| Agent adapters | Claude system prompt, Copilot instructions, Codex task prompt |
| Benchmarks | 20-task suite, 3 baselines, Markdown report |
Requirements
- Python 3.12+
- uv package manager
Install
git clone https://github.com/mohankrishnaalavala/context-router
cd context-router
uv sync --all-packages
PyPI install (coming soon):
pip install context-router
Quickstart
# 1. Initialize a project (creates .context-router/ with config + SQLite DB)
uv run context-router init
# 2. Index the repository — extracts symbols, call edges, test links, communities
uv run context-router index
# 3. Generate a context pack for a code review
uv run context-router pack --mode review
# 4. Implement a feature — query-aware ranking surfaces the right files
uv run context-router pack --mode implement --query "add pagination to the users endpoint"
# 5. Debug a failure — parse an error file and rank by blast radius
uv run context-router pack --mode debug --error-file pytest-output.xml
# 6. Explain what was selected and why
uv run context-router explain last-pack
# 7. Visualize the symbol graph
uv run context-router graph --open
# 8. Get machine-readable JSON for scripts or agent prompts
uv run context-router pack --mode review --json
Commands Reference
| Command | Purpose |
|---|---|
init |
Initialize .context-router/ config and database |
index |
Scan and index all source files |
watch |
Incrementally re-index on file save |
pack |
Generate a ranked context pack |
explain |
Explain the last pack's selections |
memory |
Add/search session observations |
decisions |
Add/search architectural decision records |
graph |
Generate interactive HTML graph visualization |
workspace |
Multi-repo workspace management |
benchmark |
Run 20-task benchmark suite |
mcp |
Start the MCP server (for Claude Code, Cursor, Windsurf) |
init
Initialize a project. Creates .context-router/config.yaml and .context-router/context-router.db.
context-router init [--project-root PATH] [--json]
index
Scan and index the repository.
context-router index [--project-root PATH] [--repo REPO_NAME]
Walks all source files, runs language analyzers (discovered via context_router.language_analyzers entry points), and writes to the local DB:
- Symbols — functions, classes, interfaces, k8s resources, GitHub Actions jobs
- Import edges — which files import which modules
- Call edges — which functions call which functions (Python, TypeScript)
- TESTED_BY edges — links
test_foo→fooby name convention - Community IDs — Union-Find clustering of connected symbols
uv run context-router index
# Indexed 286 files — 1765 symbols, 3174 edges (2.82s)
watch
Watch for file changes and incrementally re-index.
context-router watch [--project-root PATH]
pack
Generate a ranked context pack for a task.
context-router pack --mode MODE [--query TEXT] [--project-root PATH] [--json]
Modes:
| Mode | Ranking priority | Best for |
|---|---|---|
review |
changed files → blast radius → impacted tests → config | PR review, diff analysis |
implement |
entrypoints → contracts → extension points → patterns | Building new features |
debug |
runtime signal match → failing tests → changed files → call chain | Fixing errors, CI failures |
handover |
recent changes → memory observations → decisions → blast radius | Onboarding, sprint docs |
Token budget (default: 8 000 tokens) is read from .context-router/config.yaml. Items are dropped lowest-confidence first, but at least one item per source category is always preserved.
The pack is saved to .context-router/last-pack.json for later inspection.
Examples:
# Review mode — surfaces changed files and their dependencies
uv run context-router pack --mode review
# Implement with query — boosts items matching "rate limiting"
uv run context-router pack --mode implement --query "add rate limiting to API endpoints"
# Debug with error file — parse pytest/JUnit XML to find root cause
uv run context-router pack --mode debug --error-file test-results.xml
# JSON output for piping into agent prompts
uv run context-router pack --mode review --json | jq '.selected_items[].title'
explain
Explain the last generated context pack.
context-router explain last-pack [--json]
[changed_file] build_pack (orchestrator.py) — Modified in current diff
[blast_radius] ContextRanker (ranker.py) — Depends on a changed file
[impacted_test] test_ranker.py — Tests code affected by this change
[contract] ContextItem (models.py) — Data contract or interface definition
memory
Persist and search session observations. Stored in the local SQLite DB with FTS5 full-text search.
context-router memory add --from-session SESSION.json
context-router memory search QUERY
context-router memory stale
stale lists observations whose referenced files no longer exist in the index.
Examples:
# Search for past observations about authentication
uv run context-router memory search "auth token"
# Find observations referencing files that were deleted
uv run context-router memory stale
decisions
Manage architectural decision records (ADRs). Persisted with FTS5 search across title, context, and decision fields.
context-router decisions add TITLE [--decision TEXT] [--context TEXT] [--consequences TEXT] [--tags TAGS] [--status STATUS]
context-router decisions search QUERY
context-router decisions list
--status accepts: proposed | accepted | deprecated | superseded
Examples:
# Record a new ADR
uv run context-router decisions add "Use SQLite for local storage" \
--decision "SQLite + FTS5 chosen over PostgreSQL" \
--context "Need offline-capable storage" \
--status accepted
# Search decisions by keyword
uv run context-router decisions search "database"
graph
Generate a self-contained interactive HTML graph visualization of the indexed symbol graph.
context-router graph [--project-root PATH] [--output PATH] [--open] [--json]
- Nodes are colored by kind (function=green, class=blue, interface=teal, k8s=orange) or by community cluster (toggle in the UI)
- Node size reflects degree (more connections = larger)
- Click any node for a details panel (file, kind, community, signature)
- Search/filter by symbol name
- Zoom/pan with scroll and drag
--openlaunches your default browser immediately
# Generate and open in browser
uv run context-router graph --open
# Save to a path for sharing or docs
uv run context-router graph --output ./docs/graph.html
# Raw JSON for programmatic use
uv run context-router graph --json
workspace
Manage multi-repo workspaces with cross-repo context packs.
context-router workspace init [--root PATH] [--name NAME]
context-router workspace repo add NAME PATH [--root PATH]
context-router workspace repo list [--root PATH] [--json]
context-router workspace link add FROM TO [--root PATH]
context-router workspace pack --mode MODE [--query TEXT] [--root PATH] [--json]
How it works:
workspace initcreatesworkspace.yamlat the rootrepo addregisters each repo and captures its git branch/SHAlink adddeclares a dependency between repos (boosts cross-repo confidence)packrunsOrchestratorper repo, merges candidates labelled with[repo-name], and re-ranks within a unified token budget
# Set up a two-repo workspace
uv run context-router workspace init
uv run context-router workspace repo add api ./services/api
uv run context-router workspace repo add frontend ./services/frontend
uv run context-router workspace link add frontend api
uv run context-router workspace pack --mode review
benchmark
Run the built-in 20-task suite and measure token reduction vs naive/keyword baselines.
context-router benchmark run [--project-root PATH] [--output PATH] [--json]
context-router benchmark report [--project-root PATH] [--input PATH] [--json]
See BENCHMARK_RESULTS.md for real numbers on the context-router codebase (64.7% average token reduction, 131 ms average latency).
mcp
Start the context-router MCP server over stdio JSON-RPC 2.0, exposing all tools to any MCP-compatible AI coding agent.
context-router mcp
Available MCP tools:
| Tool | What it does |
|---|---|
build_index |
Full re-index of the repository |
update_index |
Incremental re-index for changed files |
get_context_pack |
Ranked pack for review / implement / debug / handover |
get_debug_pack |
Debug pack with optional error-file (pytest/JUnit XML) parsing |
explain_selection |
Why each item was selected + token count stats |
generate_handover |
Handover pack combining changes + memory + decisions |
search_memory |
Full-text search of session observations |
get_decisions |
Search or list architectural decision records |
MCP Setup Guide
Claude Code
Add to .mcp.json in your project root (or ~/.claude/mcp.json for global config):
{
"mcpServers": {
"context-router": {
"command": "uv",
"args": ["run", "--directory", "/path/to/your/project", "context-router", "mcp"]
}
}
}
Then in Claude Code:
/mcp
You'll see context-router listed. Use it with:
Use context-router to get a context pack for reviewing my recent changes
Cursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"context-router": {
"command": "uv",
"args": ["run", "context-router", "mcp"],
"cwd": "${workspaceFolder}"
}
}
}
Restart Cursor. The tools appear in the Cursor agent panel under MCP.
Windsurf
Add to .windsurf/mcp_config.json:
{
"servers": {
"context-router": {
"command": "uv run context-router mcp",
"transport": "stdio"
}
}
}
Using MCP Tools in Practice
Once connected, your agent can call tools directly:
# Get context for a code review (agent calls get_context_pack)
"Review the auth changes in my PR. Use context-router to find all affected code."
# Debug a failing test (agent calls get_debug_pack)
"My tests are failing with AttributeError. Use context-router to find the root cause."
# Handover documentation (agent calls generate_handover)
"Generate a handover document for what I worked on this sprint."
# Search past decisions (agent calls get_decisions)
"What architectural decisions were made about the database layer?"
Programmatic Use (Python SDK)
from core.orchestrator import Orchestrator
# Get a context pack
pack = Orchestrator(project_root="/path/to/repo").build_pack(
mode="implement",
query="add rate limiting to the API"
)
print(f"Selected {len(pack.selected_items)} items, {pack.total_tokens} tokens")
for item in pack.selected_items:
print(f" [{item.source_type}] {item.title} — {item.reason}")
# With semantic ranking (requires: pip install sentence-transformers)
from ranking.ranker import ContextRanker
ranker = ContextRanker(token_budget=8000, use_embeddings=True)
# Agent adapters
from adapters_claude import ClaudeAdapter
from adapters_copilot import CopilotAdapter
pack = Orchestrator().build_pack("review", "fix the auth bug")
print(ClaudeAdapter().generate(pack)) # System prompt preamble for Claude
print(CopilotAdapter().generate(pack)) # .github/copilot-instructions.md
Configuration
Edit .context-router/config.yaml:
# Maximum tokens for a generated context pack (default: 8000)
token_budget: 8000
# Repository name (used as the key in the SQLite DB)
repo_name: default
capabilities:
# Enable LLM-powered summarization (requires API key — future feature)
llm_summarization: false
# fnmatch patterns to exclude from indexing
ignore_patterns:
- ".git"
- "__pycache__"
- "*.pyc"
- "*.egg-info"
- ".venv"
- "node_modules"
- "dist"
- "build"
Architecture
context-router is a uv workspace of focused packages with strict import boundaries:
packages/
contracts/ # Pydantic models + plugin protocols (no internal deps)
storage-sqlite/ # SQLite DB, migrations, FTS5, repositories
graph-index/ # File scanner, language dispatch, git diff, community detection
ranking/ # Token estimator, ContextRanker, query/semantic boost
core/ # Orchestrator — wires storage + graph + ranking
language-python/ # Python AST (tree-sitter): symbols, imports, calls
language-typescript/ # TypeScript/JS AST (tree-sitter): symbols, imports, calls
language-yaml/ # YAML: k8s resources, Helm charts, GitHub Actions
language-java/ # Java (stub)
language-dotnet/ # .NET/C# (stub)
memory/ # Observation store + FTS
runtime/ # Stack trace + JUnit/pytest XML parsers
workspace/ # Multi-repo workspace support
benchmark/ # 20-task benchmark harness
adapters-claude/ # Claude system-prompt adapter
adapters-copilot/ # GitHub Copilot instructions adapter
adapters-codex/ # Codex task prompt adapter
apps/
cli/ # Typer CLI (all commands)
mcp-server/ # MCP server entry point
Module boundary rules (enforced in CI):
contractshas zero internal dependencies- Only
storage-sqlitetouches SQLite - Only
coreimports fromstorage-sqlite,graph-index, andranking - CLI and MCP server only import from
coreandbenchmark
Development
# Install all packages + dev dependencies
uv sync --all-packages --extra dev
# Run all 403 tests
uv run pytest --tb=short -q
# Lint
uv run ruff check .
# Install git pre-push hook (runs tests before every push)
git config core.hooksPath .githooks
# Re-index after code changes
uv run context-router index
# Check release readiness
/release-check
Adding a Language Analyzer
Implement the LanguageAnalyzer protocol and register via entry points:
# my_package/analyzer.py
from pathlib import Path
from contracts.interfaces import Symbol, DependencyEdge
class RustAnalyzer:
def analyze(self, path: Path) -> list[Symbol | DependencyEdge]:
...
# pyproject.toml
[project.entry-points."context_router.language_analyzers"]
rs = "my_package.analyzer:RustAnalyzer"
Install your package into the workspace and context-router index will pick it up automatically.
Benchmark Results
Measured on the context-router codebase itself (286 files, 1 765 symbols, 3 174 edges):
| Mode | Avg tokens selected | vs naive (all symbols) | Avg latency |
|---|---|---|---|
| review | 1 420 | −73% | 118 ms |
| implement | 1 680 | −68% | 124 ms |
| debug | 1 290 | −75% | 142 ms |
| handover | 1 510 | −71% | 139 ms |
| overall | 1 475 | −64.7% | 131 ms |
See BENCHMARK_RESULTS.md for the full per-task breakdown.
Contributing
See .handover/ for architecture context, decision records, and open tasks.
- Architecture:
.handover/context/architecture.md - Decision log:
.handover/context/decisions.md - Task list:
.handover/work/tasks.md - Coding standards:
.handover/standards/coding-standards.md
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
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 context_router_cli-0.4.0-py3-none-any.whl.
File metadata
- Download URL: context_router_cli-0.4.0-py3-none-any.whl
- Upload date:
- Size: 135.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4bb6bb76890bd8b0cb8a75ba918d73f12e6394e6cd29cc46509fa90944eac5f
|
|
| MD5 |
5a19fac409c6dd5bb302bed16c2d09ab
|
|
| BLAKE2b-256 |
d0f7f446cb35f1732a69dff68276848d76c8a4b794144fe982919767599fe045
|
Provenance
The following attestation bundles were made for context_router_cli-0.4.0-py3-none-any.whl:
Publisher:
release.yml on mohankrishnaalavala/context-router
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
context_router_cli-0.4.0-py3-none-any.whl -
Subject digest:
a4bb6bb76890bd8b0cb8a75ba918d73f12e6394e6cd29cc46509fa90944eac5f - Sigstore transparency entry: 1292672759
- Sigstore integration time:
-
Permalink:
mohankrishnaalavala/context-router@79bfc98f2f7be3100c2fafd778e649714334fb7a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mohankrishnaalavala
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@79bfc98f2f7be3100c2fafd778e649714334fb7a -
Trigger Event:
workflow_dispatch
-
Statement type: