Codebase knowledge management CLI for AI coding agents
Project description
Relic solves the cold-read problem in AI coding agents.
Every time an agent opens a file it reads that file, then the files it imports, then the files those import — just to understand what connects to what. That's 5-10 file reads before it can start on your actual task. Every read costs tokens.
Relic builds a static knowledge graph from your source code in seconds (no LLM). Before the agent touches any file, it calls relic_query and gets:
- What that file exports (symbol names, signatures, line numbers, intent from docstrings)
- What it imports (resolved paths, not guesses)
- What else in the codebase depends on it (callers at the symbol level)
- Which test file covers it
- Class inheritance chains
- Decorator/annotation index (search by
@pytest.mark.parametrize,@app.route, etc.) - String literal index (search by quoting:
relic_search '"payment failed"') - Full blast-radius of any change (
relic impact) — every file transitively affected - Shortest dependency path between any two files or symbols (
relic path A B) - Architecture clusters — file communities discovered from the import graph (
relic communities) - Graph centrality weights — PageRank + betweenness to find load-bearing files (
relic centrality) - Circular dependency detection across the full file graph (
relic cycles) - Interactive D3 force-directed knowledge graph in the browser (
relic viz)
300–1200 tokens. Via MCP — works with Claude Code, Cursor, Copilot, and any MCP-compatible agent.
Relic also measures its own cost. relic audit shows exactly what relic adds to your agent's context (instructions block + MCP tool schemas) and proves it's a fraction of what it saves. No "trust us" — verifiable per project.
When to use relic
Relic pays off when your codebase is too large for an agent to hold in context at once — roughly 40+ files or 80k+ tokens. Below that threshold, an agent can read files directly and relic adds friction without much payoff.
relic index detects this automatically and warns you if your codebase is small. If it does, run relic --uninit claude to remove the MCP registration and let the agent work directly. You can always re-enable with relic --init claude.
relic benchmark <file> --vs ripgrep shows the exact token difference on your actual codebase, so you can decide with data rather than guessing.
How it works
relic init # scan project, build knowledge graph (seconds, no LLM)
relic --init claude # write CLAUDE.md + register MCP server in .mcp.json
Agent calls relic_query before touching unfamiliar code:
focus: src/core/PageExtension.ts
neighbors[9]{path,language}:
src/types.ts,typescript
src/layout/presets.ts,typescript
src/pagination/PaginationPlugin.ts,typescript
...
exports[8]{name,type,line,signature,intent}:
resolvePageSize,function,21,resolvePageSize(doc: PageDocument) -> number,Compute the effective page size for a document
resolveMargins,function,29,resolveMargins(config: MarginConfig) -> Margins,Apply margin config to a page layout
resolveHeader,function,38,resolveHeader(page: Page) -> HeaderBlock,Build the header block for a page
FolioStorage,interface,67,FolioStorage,
...
imports[8]{from,to}:
src/core/PageExtension.ts,src/types.ts
src/core/PageExtension.ts,src/layout/presets.ts
...
imported_by[1]{from,to}:
src/index.ts,src/core/PageExtension.ts
tested_by[1]{source,test}:
src/core/PageExtension.ts,tests/PageExtension.test.ts
callers[2]{file,symbol}:
src/index.ts,resolvePageSize
src/render/engine.ts,resolveMargins
Agent knows the structure — including signatures, intent, test files, and callers — before reading the code. Fewer follow-up reads. No hallucinated imports. No surprise broken callers.
Install
pip install relic-graph
Or with uv:
uv tool install relic-graph
If relic is not found after install:
uv tool update-shell
Then open a new terminal tab.
Upgrade
pip install --upgrade relic-graph
Or:
relic --update
Local dev
uv tool install --editable . --force
Setup
Run all setup commands in your terminal — not inside the agent.
1. Initialize and index
cd your-project
relic init
Scans the entire project tree, builds the knowledge graph via static analysis (no LLM), and adds .knowledge/ to .gitignore. No config file required — every source file with a recognized extension is indexed automatically.
To rebuild after changes:
relic index
Shows a delta (what changed since last index), which directories were skipped, and how many files were excluded by .relicignore. After the first relic index, agents call relic_reindex themselves — it's incremental (sub-second) and the response header tells them when it's needed.
Optional: To exclude files from indexing, create a .relicignore in your project root (same syntax as .gitignore):
generated/
*.pb.py
vendor/**
Optional: If you want subproject labels (for filtering search results), create a relic.yaml manually:
subprojects:
api:
path: ./src/api
description: REST API
web:
path: ./src/web
description: Frontend
2. Wire your agent
relic --init claude # Claude Code → CLAUDE.md + .mcp.json
relic --init copilot # GitHub Copilot → .github/copilot-instructions.md + .vscode/mcp.json
relic --init cursor # Cursor → .cursorrules + .cursor/mcp.json
relic --init codex # OpenAI Codex → AGENTS.md
relic --init all # all of the above
Writes agent instructions and registers the relic MCP server in the right config file per agent. Re-running is safe — updates the existing block without duplicating.
MCP tools
Relic exposes four tools over MCP (stdio transport). Every response is prefixed
with an index{age_s,stale,files_changed} freshness header and a
cost{response_tokens,focus_file_tokens} header so agents know when to reindex
and can decide whether to skip a query on small files.
| Tool | When to call |
|---|---|
relic_query |
Before editing unfamiliar code — returns imports, exports (with intent), signatures, neighbors, callers, calls, decorators, test files. Supports batch ("A B C"), dotted notation (Class.method), include_intent toggle. Shorthands: "impact:TARGET" for blast-radius, "A->B" for shortest path. |
relic_search |
When you don't know where a class/function/file lives. Quote the query ("error message") to search string literals inside function bodies. |
relic_reindex |
When the response header reports stale=true, or after creating, editing, or deleting source files. Incremental, sub-second. |
relic_diff |
When you want a per-file breakdown of what changed before reindexing |
See docs/MCP.md for full tool reference and agent setup.
Query context manually
relic query src/core/PageExtension.ts
relic query resolveMargins # by symbol name
relic query PageExtension.resolveMargins # dotted notation — scoped to one symbol
relic query "src/foo.ts src/bar.ts" # batch — merged TOON for multiple targets
relic query src/core/PageExtension.ts --depth 3 # wider graph
Output is TOON (Token-Oriented Object Notation) — tabular format that declares column names once and lists values row by row. ~40% fewer tokens than equivalent JSON for the same data.
Keep the index fresh
The agent owns this. relic_reindex is incremental — it stat-sweeps the
project tree, reparses only files whose mtime changed, and finishes in well under
a second on large repos. Every MCP response carries two headers:
index{age_s,stale,files_changed}: 42,false,0
cost{response_tokens,focus_file_tokens}: 847,312
stale=true means call relic_reindex. cost{focus_file_tokens} lets the agent
decide whether a relic_query on a tiny file is worth the roundtrip — if it's
under 200 tokens the agent can just read the file directly (SKIP rule). No
background watcher process, no extra terminal tab, no separate stats tool.
If you want to rebuild manually (after a big rebase or a tooling change), run
relic index — same as before.
Audit coverage
relic coverage
relic coverage --verbose # list every skipped file
Shows the count and identity of files that were indexed vs silently dropped, classified by reason: no_parser (extension not supported), too_large (over 200 KB), symlink (skipped for safety). Use this when a query unexpectedly comes back empty — it tells you whether the file is a tool limit instead of a model error.
Check for drift
relic diff
Compares on-disk source files against the last indexed graph. Shows new files, deleted files, and changed symbols (added or removed functions/classes). Agents use this to decide whether to call relic_reindex after big PR merges. Humans use it to sanity-check the index before a session.
Verify relic's own cost
relic audit
relic audit --usage # show MCP tool call counts from .knowledge/usage.json
Shows three numbers: the instructions block written to CLAUDE.md / .cursorrules / AGENTS.md, the MCP tool schemas the agent loads every turn, and a sample relic_query against your real graph. --usage adds a breakdown of how many times each MCP tool was called.
⬢ audit
instructions block ~651 tokens CLAUDE.md / .cursorrules / AGENTS.md
mcp tool schemas ~365 tokens 4 tools, every turn
─────────────────────────────────
baseline tax / turn ~1,016 tokens
sample query · src/core/PageExtension.ts · depth=2
relic_query response ~5,627 tokens
manual baseline ~27,952 tokens
net savings ~22,325 tokens (80%)
✓ baseline tax under 1,500 tokens — within healthy range
Background: 90-day instrumentation of Claude Code sessions found that 73% of tokens go to invisible chrome (CLAUDE.md bloat, MCP schemas, hooks, skills) before the agent reads a single user message. Relic's pitch is "save tokens" — it would be dishonest if relic itself were part of the problem. CI guards keep the instructions block under 800 tokens and the MCP schemas under 500 tokens. Loosening either is a deliberate decision, not a drift.
Benchmark token savings on a real file
relic benchmark src/core/PageExtension.ts
relic benchmark src/core/PageExtension.ts --depth 2
For a single target file, prints what an agent would read manually (target file + every direct import), what relic provides instead (one TOON subgraph + the target file), and the resulting savings. Also surfaces the imported_by callers — files an agent has no way to discover from the file alone.
relic init vs relic index
relic init |
relic index |
|
|---|---|---|
| When | First-time setup | After code changes |
| Builds graph | Yes | Yes |
Adds .knowledge/ to .gitignore |
Yes | No |
| Shows delta | No | Yes (new/removed files, symbols, edges) |
| Shows skip stats | No | Yes (skipped dirs, .relicignore exclusions) |
Run relic init once per project. After that, the agent's relic_reindex tool keeps the graph current incrementally; only run relic index again if you want a manual full rebuild.
Commands
relic init # first-time setup: build graph, configure .gitignore
relic index # rebuild graph, show delta + skip stats
relic query <file|symbol> # print TOON context subgraph to stdout
relic query Class.method # symbol-scoped query via dotted notation
relic query "fileA fileB" # batch query — merged TOON output
relic query <file> --depth N # adjust traversal depth (default 2)
relic search <term> # ranked search across files and symbols
relic search '"literal text"' # search string literals inside function bodies
relic search <term> -k symbol # filter to symbols (or `file`, `all`)
relic search <term> -s <name> # restrict to a subproject
relic impact <file|symbol> # blast-radius: every file transitively affected
relic path <source> <dest> # shortest dependency path between two nodes
relic communities # show file clusters from Louvain graph clustering
relic centrality [--top N] [--by pagerank|betweenness|in_degree|out_degree]
relic cycles [--limit N] # detect circular dependencies in the file graph
relic viz [--out path.html] # open interactive D3 knowledge graph in browser
relic stats # index health: counts, last_updated, subprojects
relic diff # what changed since last index (new/deleted/changed)
relic coverage # what's indexed vs skipped, with reasons
relic coverage -v # list every skipped file (not just samples)
relic audit # measure relic's own token footprint
relic audit --usage # show per-tool MCP call counts
relic benchmark <file> # compare token cost of context with vs without relic
relic benchmark <symbol> --vs ripgrep # compare relic vs ripgrep for a symbol search
relic mcp # start MCP stdio server (4 tools)
relic --list # list subprojects (if relic.yaml exists)
relic --init <agent> # write agent config + MCP registration
relic --init all # write config for all supported agents
relic --uninit <agent> # remove relic MCP registration + instructions
relic --uninit all # remove for all agents
relic --update # install latest GitHub release
relic --version # print version
What gets indexed
| Language | Files | Symbols + Signatures | Intent | Decorators | Imports | Calls | Inheritance | Test mapping |
|---|---|---|---|---|---|---|---|---|
| Python | ✓ | classes, functions (full signatures) | ✓ (docstring) | ✓ (@decorator) |
✓ (ast) | ✓ (ast) | ✓ (extends) |
✓ (test_foo.py) |
| TypeScript / TSX | ✓ | classes, functions, interfaces, types | ✓ (leading comment) | ✓ (@decorator) |
✓ | ✓ (regex) | ✓ (extends) |
✓ (foo.test.ts) |
| JavaScript / JSX | ✓ | classes, functions | ✓ (leading comment) | ✓ (@decorator) |
✓ | ✓ (regex) | ✓ | ✓ |
| Go | ✓ | structs, interfaces, functions | ✓ (leading //) |
— | ✓ | ✓ | — | — |
| Rust | ✓ | structs, enums, traits, functions | ✓ (leading ///) |
✓ (#[attr]) |
✓ | ✓ | ✓ (impl) |
— |
| Java | ✓ | classes, interfaces, methods | ✓ (Javadoc) | ✓ (@Annotation) |
✓ | ✓ | ✓ (extends) |
— |
| C# | ✓ | classes, interfaces, methods | ✓ (leading //) |
✓ ([Attr]) |
✓ | — | — | — |
| Kotlin | ✓ | classes, functions | ✓ (leading //) |
— | ✓ | — | — | — |
| Scala | ✓ | classes, traits, objects, functions | ✓ (leading //) |
— | ✓ | — | ✓ | — |
| PHP | ✓ | classes, interfaces, functions | ✓ (leading //) |
— | ✓ | — | — | — |
| Swift | ✓ | classes, structs, protocols, functions | ✓ (leading //) |
— | ✓ | — | — | — |
| Markdown | ✓ | H1/H2 headings as symbols | — | — | — | — | — | — |
| OpenAPI YAML/JSON | ✓ | HTTP endpoints (GET /path) |
✓ (summary) | — | — | — | — | — |
| JSON Schema | ✓ | definitions/$defs entries |
✓ (description) | — | — | — | — | — |
| pyproject.toml | ✓ | package name + script entry points | ✓ (description) | — | — | — | — | — |
| package.json | ✓ | package name + npm scripts | ✓ (description) | — | — | — | — | — |
Go, Rust, Java, C#, Kotlin, Scala, PHP, and Swift support requires the optional treesitter extra:
pip install relic-graph[treesitter]
Graph analysis
Blast-radius before refactoring
relic impact src/core/payments.py
relic impact PaymentProcessor
Shows every file that transitively imports, uses, or calls the target — and how many hops away each is. Run this before renaming a class or changing a function signature. Agents can call the same analysis via relic_query "impact:TARGET".
Shortest path between two nodes
relic path src/api/views.py src/core/database.py
relic path UserSerializer PaymentProcessor
Finds the shortest chain of import/call/use edges connecting SOURCE to DEST, with each hop's edge type and evidence label (ast/treesitter/regex/convention). Useful for understanding unexpected coupling. MCP shorthand: relic_query "src/api/views.py->src/core/database.py".
Architecture communities
relic communities
relic communities --limit 10
Runs Louvain clustering on the file import graph and prints each community as a TOON table. Communities represent cohesive module boundaries — files that strongly import each other end up together. Useful for spotting unexpected cross-module coupling or planning a monorepo split.
Graph centrality
relic centrality --top 10
relic centrality --by betweenness
Computes PageRank and betweenness centrality on the file dependency graph. PageRank identifies the most structurally important files (many important files depend on them). Betweenness identifies bridge files that sit between communities — highest risk to change. Run before a refactor to find load-bearing files.
Circular dependency detection
relic cycles
relic cycles --limit 5
Detects all circular import chains in the file dependency graph using nx.simple_cycles(). Cycles are shown as chains sorted by length. Each cycle is a set of files that mutually depend on each other — fix by extracting shared code into a common module. MCP shorthand: relic_query "cycles".
Interactive knowledge graph
relic viz
relic viz --out graph.html # save instead of opening
Opens a self-contained D3.js force-directed graph in your browser. Node size = PageRank, color = community (Nord palette), edge opacity = evidence quality (ast > treesitter > regex > convention). Features:
- Click any node → blast-radius overlay (red = affected files) + side panel with metadata
- Double-click any node → focus mode: collapses graph to 2-hop neighborhood, auto-zooms to fit
- Double-click canvas → exit focus mode
- Filter dropdowns → filter by language, community, or subproject with auto-zoom to matching nodes
- Search box → highlight matching nodes by filename
- Zoom controls → in/out/reset
Agentic pipelines (LangGraph, custom orchestrators)
Relic slots into multi-agent workflows. One relic index call, every agent in the chain benefits.
Typical integration:
- Orchestrator —
relic_queryto identify relevant files without reading them, scope the task cheaply - Planning agent — knows the dependency graph before planning, avoids plans that break callers
- Implementation agent — gets exact symbol names and paths, no hallucinated imports
- Review agent — sees
imported_byedges, knows what to test beyond the changed file
Register once per project, all agents in the session get all four relic tools natively.
Token comparison
| Approach | Context per file touch |
|---|---|
| Agent reads file + all imports manually | 5,000–40,000 tokens |
relic_query (depth=1) |
300–1,200 tokens |
relic_query (depth=2) |
800–3,000 tokens |
Security
Static analysis only — relic never executes your source. Python is parsed with ast.parse (parse-only, no eval); TypeScript and JavaScript are matched with regex. Reading a malicious repo cannot run code through relic.
Path traversal prevention — if subproject paths are defined in relic.yaml, they are resolved and checked against the project root. Entries like path: /etc or path: ../../secrets are rejected.
Symlinks skipped — the indexer ignores all symbolic links during traversal, so a malicious symlink pointing outside the project cannot pull foreign files into the graph. Same rule applies to relic coverage and incremental reindexes.
File size limit — skips files over 200 KB. Bounds per-file work and prevents a single bloated file from dominating the index.
No filesystem writes outside the project — relic only writes to .knowledge/ and (when explicitly invoked) .gitignore and the agent config files you ask it to update.
No external calls — no API calls, no telemetry. Code never leaves your machine. The only network calls relic makes are during relic --update: one GitHub API call to find the latest release tag, then uv tool install to reinstall from that tag.
For vulnerability reports see SECURITY.md.
Contributing
PRs welcome. See CONTRIBUTING.md for setup, conventions, and what we will (and won't) accept.
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 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 relic_graph-0.8.1.tar.gz.
File metadata
- Download URL: relic_graph-0.8.1.tar.gz
- Upload date:
- Size: 186.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b878afb03f58a59bf08c4027e3d8dca7db97b612274f3e5e1110670a1f7fb6d
|
|
| MD5 |
08bc415edc7de51c67875c1ba3b152aa
|
|
| BLAKE2b-256 |
3af95cc59e9fdd5321d7a405815cdcfdc877d0bc58ed060d85ec64a8c5d6600d
|
Provenance
The following attestation bundles were made for relic_graph-0.8.1.tar.gz:
Publisher:
release.yml on Swanand58/relic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
relic_graph-0.8.1.tar.gz -
Subject digest:
6b878afb03f58a59bf08c4027e3d8dca7db97b612274f3e5e1110670a1f7fb6d - Sigstore transparency entry: 1500974100
- Sigstore integration time:
-
Permalink:
Swanand58/relic@8b236d9e83b753fe736f6cc1f3d0d5be9883374b -
Branch / Tag:
refs/tags/v0.8.1 - Owner: https://github.com/Swanand58
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8b236d9e83b753fe736f6cc1f3d0d5be9883374b -
Trigger Event:
push
-
Statement type:
File details
Details for the file relic_graph-0.8.1-py3-none-any.whl.
File metadata
- Download URL: relic_graph-0.8.1-py3-none-any.whl
- Upload date:
- Size: 85.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 |
45cfefb4d9d2b40465542bfd4d5688af6ce69dfa2a1f897f2b94b99c7e1688d8
|
|
| MD5 |
c390524be551c7ec6e15600eb62ec685
|
|
| BLAKE2b-256 |
61c3612e137a7db4858b8a79ba010144733829123521a12e0e927d08c5b818f8
|
Provenance
The following attestation bundles were made for relic_graph-0.8.1-py3-none-any.whl:
Publisher:
release.yml on Swanand58/relic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
relic_graph-0.8.1-py3-none-any.whl -
Subject digest:
45cfefb4d9d2b40465542bfd4d5688af6ce69dfa2a1f897f2b94b99c7e1688d8 - Sigstore transparency entry: 1500974314
- Sigstore integration time:
-
Permalink:
Swanand58/relic@8b236d9e83b753fe736f6cc1f3d0d5be9883374b -
Branch / Tag:
refs/tags/v0.8.1 - Owner: https://github.com/Swanand58
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8b236d9e83b753fe736f6cc1f3d0d5be9883374b -
Trigger Event:
push
-
Statement type: