context-router
Problem
Working with AI tools on large codebases causes context explosion. Every task loads the entire codebase into the prompt.
What context-router does
Routes a task to the agent that owns it. Scopes the prompt to only the relevant files. Keeps a lightweight map of who owns what.
What context-router does NOT do
Does not call any LLM. Does not automate anything. Does not execute code.
Without context-router:
"fix the auth bug" → loads 847 files → model touches 6 modules it shouldn't
With context-router:
context-router ask "fix the auth bug" --file src/auth/token.py → Agent: backend-engineer → Touch only: src/auth/token.py, src/auth/session.py → Do not modify: src/api/, src/db/, src/frontend/
Install
pip install context-router
Local dev:
pip install -e .
Usage
1. Define your agents
context-router init creates 3 core agents automatically:
agents/
├── dispatcher.agent.yaml ← routes all tasks (do not edit)
├── memory-keeper.agent.yaml ← syncs memory after commits (do not edit)
├── validator.agent.yaml ← validates diffs before applying (do not edit)
└── default.agent.yaml ← template — copy and rename for your domains
Add one agent per domain in your project.
Create an agents/ directory in your project and add one YAML file per agent:
# agents/backend-engineer.agent.yaml
name: backend-engineer
owned_paths:
- src/auth/*.py
- src/api/*.py
- src/db/*.py
description: Handles backend logic including authentication, API routes, and database models.
2. Initialize
context-router init
Specify your AI tool:
context-router init --tool claude # Claude Code
context-router init --tool cursor # Cursor
context-router init --tool copilot # GitHub Copilot
context-router init --tool codex # Codex / OpenAI
context-router init --tool windsurf # Windsurf
context-router init --tool aider # Aider
context-router init --tool all # generate all
If you skip --tool, context-router detects your tool automatically or asks you to choose.
| Tool | Config file generated |
|---|---|
| Claude Code | CLAUDE.md + AGENTS.md |
| Cursor | .cursorrules |
| GitHub Copilot | .github/copilot-instructions.md |
| Codex | AGENTS.md |
| Windsurf | .windsurfrules |
| Aider | .aider.conf.yml |
Scans all *.agent.yaml files in agents/, writes .context-router/project_map.json, and
scaffolds the full memory structure.
After context-router init your project contains:
.context-router/
├── CORE.md ← global invariants (always loaded)
├── CORE_LITE.md ← minimal version for quick tasks
├── project_map.json ← agent ownership map (auto-generated)
└── memory/
├── MEMORY.md ← status, architecture, recent fixes
├── MEMORY_MAP.md ← file/function ownership
├── MEMORY_CHANGELOG.md ← full fix history (load on demand)
├── MEMORY_INTELLIGENCE.md ← domain knowledge (load on demand)
└── MEMORY_REFERENCE.md ← lessons learned, roadmap (load on demand)
Session start prompt for your AI tool:
Read: .context-router/CORE.md
Read: .context-router/memory/MEMORY.md
Read: .context-router/memory/MEMORY_MAP.md
Then paste: context-router ask "your task" --file path/to/file
For quick/simple tasks use CORE_LITE.md instead of CORE.md.
Load MEMORY_CHANGELOG.md only when debugging old behavior.
Load MEMORY_INTELLIGENCE.md only for domain-specialist tasks.
Initialized. 3 agents registered.
3. Route a task
context-router ask "fix the auth token expiry bug" --file src/auth/token.py
Agent: backend-engineer
Files: src/auth/token.py, src/auth/session.py
Prompt:
Read: agents/backend-engineer.agent.yaml
Task: fix the auth token expiry bug
Touch only: src/auth/token.py, src/auth/session.py
Do not modify: src/api/routes.py, src/db/models.py
Without --file, context-router keyword-matches your task against agent descriptions:
context-router ask "authentication is broken"
Agent: backend-engineer
Files: src/auth/*.py, src/api/*.py, src/db/*.py
Prompt:
Read: agents/backend-engineer.agent.yaml
Task: authentication is broken
Touch only: src/auth/*.py, src/api/*.py, src/db/*.py
Do not modify: src/ui/*.tsx, src/infra/*.sh
4. Validate a diff
context-router validate --staged # checks git diff --cached
context-router validate --diff my.patch # checks a saved diff file
Loads .context-router/validator.yaml and runs all matching rules against the diff.
Exits 0 on PASS, 1 on FAIL.
STATUS: FAIL
REASON: 'reader.readtext' used outside `with _ocr_lock:` block
RETRY_WITH:
FIX_HINT: Wrap reader.readtext() inside `with _ocr_lock:`
Rule types: lock_guard, pair_call, no_output, line_count, threshold_drift.
See .context-router/validator.yaml (generated by context-router init) for full field reference.
Usage — run command
Manual mode (no API key needed)
context-router run "fix the login form" --file src/frontend/login.js
─────────────────────────────────────
Agent: frontend
Prompt: .context-router/current-task.md
─────────────────────────────────────
1. Paste the prompt into your AI tool
2. Save the diff output as:
.context-router/output.diff
3. Run: context-router run --continue
─────────────────────────────────────
Auto mode (API key in .env)
cp .env.example .env
# add your key to .env
context-router run "fix the login form" --file src/frontend/login.js
Auto mode — using anthropic (claude-sonnet-4-6)
Attempt 1/3...
STATUS: PASS
Apply the diff to your codebase.
Override model
context-router run "task" --file path --model claude-opus-4-6
Meta-controller retry loop
MetaController wraps any agent/validator pair with a failure-aware retry loop.
from context_router.meta_controller import MetaController
from pathlib import Path
mc = MetaController(
task="fix the token expiry bug",
root=Path("."),
config_path=Path(".context-router/retry_config.yaml"),
)
result = mc.run(agent_runner, validator)
# result = {"passed": True/False, "attempts": N, "report_path": None | "logs/..."}
agent_runner(task, prompt_patches, param_patches) → str
validator(output) → (bool passed, str fail_text)
On FAIL, the controller:
- Stashes working tree (
git stash) - Builds a retry plan from
retry_config.yaml(prompt constraints + param overrides) - Re-runs the agent with accumulated patches
- On
retry_with: human— escalates immediately, writes failure report - After MAX_RETRIES (3) — restores working tree, writes report to
logs/
retry_config.yaml example:
categories: [system, logic, output, cross_agent]
prompt_patches:
logic:
2: "add inline comments explaining each change"
3: "minimal fix only — change one thing at a time"
category_map:
my_rule_id: logic
human_hints:
logic: "Logic error — review the change manually."
See examples/reel-engine/retry_config.yaml for a full real-world example.
Agent YAML format
name: string # unique identifier, used in output
owned_paths: # glob patterns — files this agent is responsible for
- src/auth/*.py
- src/api/*.py
description: one sentence # used for keyword fallback matching when no --file given
Adding a new agent
- Create
agents/<name>.agent.yaml - Run
context-router init
That's it.
How it works
context-router init
└── scans agents/*.agent.yaml
└── writes .context-router/project_map.json {glob → agent_name}
context-router ask "task" --file src/auth/token.py
└── loads project_map.json
└── matches file path against globs
└── prints structured prompt block
└── no network, no LLM, no side effects
Optional: graphify
graphify builds an AST-based knowledge graph of your codebase. Zero API cost. Run it after every code change:
graphify update .
Output: graphify-out/GRAPH_REPORT.md — node/edge/community structure for your codebase.
How graphify integrates with context-router
Data flow:
code change
→ graphify update .
→ graphify-out/GRAPH_REPORT.md (always regenerated)
→ @memory-keeper (post-commit)
reads GRAPH_REPORT.md
updates MEMORY_MAP.md (always, after every commit)
agents during a task
→ read MEMORY_MAP.md (session start, always)
→ read GRAPH_REPORT.md (on demand only — unknown deps)
Rules:
graphify update .is always a plain shell command — no API callsGRAPH_REPORT.mdis read on demand only (not at session start)MEMORY_MAP.mdis the agent-readable ownership tablegraphify-out/files are never loaded at session start- graphify never writes to
.context-router/directly
Trigger graphify after every code change:
graphify update .
Your AI tool reads the output:
Read graphify-out/GRAPH_REPORT.md only when tracing
unknown cross-file dependencies.
Success criteria
- Install in under 2 minutes
- Understand it fully in under 5 minutes
- Add a new agent by editing one YAML file
- Reduces context size when working with any AI coding tool
Metadata
Release files for llm-context-router 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| llm_context_router-0.6.0.tar.gz | 35.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llm_context_router-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.9 kB
Release files / llm_context_router-0.6.0.tar.gz
| Download URL | llm_context_router-0.6.0.tar.gz |
|---|---|
| Size | 35.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4da17e726fca7889cf177c5b8bc90870675fe6b61cabe7084e9eeac7b9f658d9
|
|
BLAKE2b-256 checksum How to use checksums |
d1508b04b5e7a1f4e9e099a9582c1293df9817acd7eb0f99012bca5497267924
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|
Release files / llm_context_router-0.6.0-py3-none-any.whl
| Download URL | llm_context_router-0.6.0-py3-none-any.whl |
|---|---|
| Size | 24.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7f0b2c7cfbcee5355779e05ef966050a1b969d4481c016e1cb5fc7b0e9f144c9
|
|
BLAKE2b-256 checksum How to use checksums |
8a3cffcffb5a80ae7b2c06d1f38606942f6135b05b89bda4daf8f85ccf97de3f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|