repokg
Generate an AI-ready knowledge graph of any codebase — so an AI agent (or a new developer) can read one file and start building immediately.
repokg extracts everything that can be known deterministically about a repo —
module inventory, internal import graph, every branch classified against every PR
(merged / squash-merged / abandoned / stale), contributor stats, CI/Docker/Helm/Make
surface — and renders it as:
KNOWLEDGE_GRAPH.md— a single human/AI-readable document with a mermaid architecture graph, module tables, branch & PR catalog, timeline, and ops inventory..repokg/kg.json— the same graph, machine-readable.
The semantic layer (module purposes, data-flow narratives, project eras, gotchas)
can't be produced by static analysis without guessing — so repokg is
agent-first: it emits .repokg/prompts/enrich.md, a rigorous prompt any AI coding
agent (Claude Code, Cursor, Copilot Workspace…) executes to verify-and-fill the
narrative sections, writing .repokg/narratives.json. Re-render and the knowledge graph is
complete. No API keys, no LLM dependency in the tool itself.
Install
pipx install repokg # or: pip install repokg
# from source:
pipx install git+https://github.com/NehharShah/repokg
Requirements: Python ≥ 3.9, git. Optional: gh (logged
in) for the PR/branch cross-reference — without it the knowledge graph still builds, minus PR data.
Usage
cd your-repo
repokg # = generate: scan + prompts + render
Output:
.repokg/kg.json # machine-readable knowledge graph
.repokg/prompts/enrich.md # hand this to your AI agent
KNOWLEDGE_GRAPH.md # the knowledge graph document
Then, in your AI agent of choice:
Follow the instructions in .repokg/prompts/enrich.md
The agent explores the code, writes .repokg/narratives.json, and runs
repokg render — KNOWLEDGE_GRAPH.md now carries verified purposes, data flows,
timeline eras, and gotchas alongside the deterministic structure.
Commands
| Command | Effect |
|---|---|
repokg scan [path] |
Extract structure → .repokg/kg.json |
repokg prompts [path] |
Write the enrichment prompt |
repokg render [path] |
kg.json (+ narratives.json) → KNOWLEDGE_GRAPH.md |
repokg generate [path] |
All three (default) |
repokg inject [path] |
Wire the knowledge graph into CLAUDE.md / AGENTS.md / Cursor rules (--diff for dry run) |
repokg audit [path] |
Show every inferred conclusion with confidence + evidence (--json for machines) |
repokg clean [path] |
Remove everything repokg authored — never touches your content (--diff for dry run) |
repokg check [path] |
Exit 1 if the knowledge graph is stale vs HEAD (CI-friendly) |
Flags: --out DIR (default <repo>/.repokg), --md FILE (default <repo>/KNOWLEDGE_GRAPH.md),
--exclude PATTERN (repeatable), --no-github, --no-cache, --pr-limit N, --diff, --json.
Incremental scans
scan caches what it extracted from each file in .repokg/cache.json and replays
it for files that have not changed, so a re-scan only parses what moved:
$ repokg scan .
cache: cold (no cache yet) — parsed 431 files
$ repokg scan .
cache: replayed 431 of 431 files, parsed 0
$ vim src/app.py && repokg scan .
cache: replayed 430 of 431 files, parsed 1
A file is replayed only when git has not flagged it — git diff against the
commit the cache was written at, plus git status for anything dirty, staged, or
untracked — and its size and mtime still match what was recorded. The second
check is what covers the files git cannot speak for: anything in .gitignore
that repokg still walks, submodule contents, or a directory that is not a git
checkout at all.
The cache is an optimization and nothing else. Output is identical either way
(a test enforces byte-for-byte equality), a missing or unreadable or unusable
cache degrades to a full scan and says so on stdout, and --no-cache forces one.
repokg clean removes it with everything else.
One caveat, shared with every build tool that trusts stat: a file rewritten
with its size and modification time preserved is invisible to both checks. Use
--no-cache if you have reason to think that happened.
Synthetic mixed Python/TypeScript/Java monorepos, one laptop, best of three — indicative only, not a benchmark suite (see #17):
| files | LOC | edges | cold | warm | speedup | cache.json |
|---|---|---|---|---|---|---|
| 300 | 30k | 21 | 144 ms | 121 ms | 1.2× | 0.1 MB |
| 1,500 | 228k | 111 | 336 ms | 129 ms | 2.6× | 0.3 MB |
| 6,000 | 1.2M | 450 | 1,316 ms | 176 ms | 7.5× | 1.0 MB |
The ratio grows with the repo because the saving is essentially the whole parse cost, while the warm floor does not shrink. That floor is worth knowing before optimising further: at 6,000 files it is roughly 100 ms of git metadata (branches, contributors, merge classification — none of which touches the cache) and 30 ms of walking, stat'ing and writing the output. Parsing, the part the cache removes, was around 1,150 ms of the cold scan.
Excluding paths
Common noise (node_modules, .git, build output, …) is skipped automatically.
For repo-specific noise — fixtures, snapshots, vendored trees, generated docs —
add globs on the command line or in a committed .repokgignore at the repo root:
repokg scan --exclude '*fixtures' --exclude 'docs/gen'
# .repokgignore — one glob per line, same semantics as --exclude
*fixtures
*.snap
packages/*/gen
Patterns are matched (fnmatch) against repo-relative paths; matching
directories are pruned wholesale and matching files dropped, so modules, import
edges, and ops all inherit the exclusion. * crosses /: *fixtures matches
at any depth, fixtures only at the root. CLI patterns and .repokgignore are
unioned. Exclusions are never silent — scan prints what it dropped, kg.json
records the patterns and counts, and repokg audit carries an uncertainty note.
Honesty layer
Most of the graph is measured fact. The parts that are heuristics are labeled
as findings with confidence and evidence, surfaced by repokg audit:
[git]
trunk = master high detected via origin/HEAD symref
integration = staging medium matched a well-known integration branch name
[modules]
4 flagged generated low path-name heuristic; verify before excluding
Agent-written narratives.json is schema-validated before rendering — malformed
enrichment fails loudly with errors precise enough for the agent to self-correct.
(Findings/confidence design inspired by RepoCanon.)
Agent integration
repokg inject adds a managed block (delimited by
<!-- repokg:begin/end -->, idempotent, never touches your hand-written
content) pointing agents at KNOWLEDGE_GRAPH.md:
CLAUDE.md(Claude Code) — updated if presentAGENTS.md(the cross-tool agent standard) — updated if present, created if no agent file exists at all.github/copilot-instructions.md(Copilot) — updated if present.cursor/rules/repokg.mdc(Cursor, withalwaysApply: true) — created if.cursor/rules/exists; falls back to legacy.cursorrules
Keep it fresh in CI:
- run: pipx run repokg check . || echo "::warning::KNOWLEDGE_GRAPH.md is stale"
KNOWLEDGE_GRAPH.md itself also lists any agent-context files it found, so an agent landing on the knowledge graph discovers your rules — and vice versa.
What gets extracted (all verified, never guessed)
| Area | How |
|---|---|
| Branch classification | git for-each-ref + --merged ancestry vs the integration branch (auto-detects staging/develop), cross-referenced with every PR's head ref via gh — distinguishes true merges from squash-merges from abandoned work |
| PR catalog | gh pr list --state all — open / merged / closed-unmerged, full appendix table |
| Module inventory | Filesystem walk with LOC per directory, language detection, generated-code flagging |
| Import graph | Go: import blocks resolved against go.mod module paths · Python: stdlib ast incl. relative imports · JS/TS: import/require resolution — relative paths, tsconfig/jsconfig paths + baseUrl aliases (nearest config wins), npm/yarn/pnpm workspace package names · Rust: use declarations resolved against Cargo crate names (cross-crate) and src/ module trees (intra-crate) · Java/Kotlin: imports resolved by longest prefix against package declarations. Directory→directory edges with counts |
| Ops surface | CI workflow names, Dockerfiles, compose files, Helm charts, Makefile targets, config/docs/test/migration dirs |
| Timeline | Merged PRs grouped by month with conventional-commit scope frequencies (replaced by agent-written eras after enrichment) |
Why agent-first instead of calling an LLM API?
Because the enrichment quality depends on reading the code, and your coding agent
already has the repo open, tools to search it, and your permission model. A prompt it
can execute beats a second LLM integration with its own keys, costs, and context limits.
The contract between tool and agent is one JSON file (narratives.json) with a fixed
schema — everything else stays deterministic and reproducible.
Known limitations
- JS/TS: relative imports, tsconfig/jsconfig
paths/baseUrlaliases and workspace package names are resolved;extendschains are not followed (a leaf config without its own aliases is skipped rather than shadowing the root's), and packageexportsmaps are not modeled — subpath imports fall back to the package dir. Alias imports whose targets ground nowhere are counted in an uncertainty note. - Fork PRs: a fork PR whose head branch name matches a local branch will be linked to it (GitHub's API reports bare head refs).
- Python: packages are discovered at the repo root and under
src/; deeper monorepo layouts (packages/*/src/…) get file-level edges only. - Rust:
usedeclarations only — macro-generated imports, re-export chains, and[dependencies] path = …(non-workspace) crates are not resolved;crate::paths ground only in module dirs/files that exist. - Java/Kotlin: explicit imports only — same-package references (no import needed) and fully-qualified inline names produce no edges; when a package is declared only in test roots, edges resolve there.
- Branch
aheadcounts use one batched git call on git ≥ 2.41, with a per-branch fallback on older git. - Incremental scans cache per-file facts, not repo metadata:
go.mod,Cargo.toml,tsconfig.json,package.jsonandpnpm-workspace.yamlare re-read every scan (one per package, against one read per source file).
Roadmap
- Rust import graph
- Java / Kotlin import graphs
-
--excludeglob patterns +.repokgignore - Incremental scan cache for large monorepos
-
llms.txtemission alongside KNOWLEDGE_GRAPH.md - tsconfig
pathsalias + workspace package resolution - PyPI release + prebuilt GitHub Action
Development
pip install -e .
python -m unittest discover -s tests -v
No runtime dependencies — stdlib only.
Contributing
All work goes through issue → branch (issue-<N>/<desc>) → PR → review → squash-merge to main.
See CONTRIBUTING.md for the workflow and the ground rules
(zero deps, findings for heuristics, clean reversibility).
License
MIT
Metadata
Release files for repokg 0.4.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| repokg-0.4.3.tar.gz | 63.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| repokg-0.4.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 108.5 kB
Release files / repokg-0.4.3.tar.gz
| Download URL | repokg-0.4.3.tar.gz |
|---|---|
| Size | 63.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0b2ebdd4446157167efc57505918f6d68dddfb937b1c8598a8d36010ed13304b
|
|
BLAKE2b-256 checksum How to use checksums |
23fbc07af796f5f1e8b2c556164d867d9c6b031b87ab0e215711f4e5844bcd6c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.
Transparency logRelease files / repokg-0.4.3-py3-none-any.whl
| Download URL | repokg-0.4.3-py3-none-any.whl |
|---|---|
| Size | 44.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
71c3c453254d5bce5bdbf3b7198a1e1e5096955f649a6736bd983180ea126d6a
|
|
BLAKE2b-256 checksum How to use checksums |
63e9ac7ba98bfe7bd19a57223038e16ff3c04f2b99cf4c61b66ae57326c1a1e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.
Transparency log