
Product
Socket for Asana Is Now Available
Create and manage Asana tasks directly from Socket alerts, with manual task creation, automated ticketing rules, and two-way sync.
graphkeeper-cli
Advanced tools
Local-only CLI that mines git history for file-level co-change patterns and builds a queryable knowledge graph for AI coding agents, with optional enrichment from graphify's symbol/call-graph output when it is installed.
A local-only CLI that mines your git log for which files actually change
together, then hands an AI coding agent a queryable answer instead of a
grep across the whole history.
npx graphkeeper-cli build
npx graphkeeper-cli query co-change src/git.ts
Files that historically change alongside "src/git.ts":
1 src/store.ts
1 src/types.ts
1 test/git.test.ts
1 test/store.test.ts
1 test/test-helpers.ts
(Real output from running GraphKeeper against its own repo, this early in its history -- co-change counts grow as a codebase accumulates more commits.)
No server, no account, no embeddings API, nothing leaves your machine. Every
byte of output comes from git log on the repo you already have checked out.

GraphKeeper ships two independent, equally first-class packages -- pick
whichever fits your toolchain, or install both. Both mine the same git log co-change signal and share one on-disk .graphkeeper/graph.json
schema, so a store built by either can be read back by the other.
# npm -- JavaScript/TypeScript CLI + library
npm install -g graphkeeper-cli
# or run it once with no install
npx graphkeeper-cli build
# PyPI -- Python CLI + library (genuine port, not a wrapper around the Node binary)
pip install graphkeeper-cli
The npm package requires Node.js 18 or later; the Python package requires
Python 3.9 or later. Both require git on your PATH. The Python
package's CLI entry point is also graphkeeper (e.g. graphkeeper build);
see python/README.md for the Python-specific
walkthrough, and CHANGELOG.md for each distribution's
version history.
Run it against any git repo, including this one:
git clone https://github.com/RudrenduPaul/GraphKeeper.git
cd GraphKeeper
graphkeeper build
GraphKeeper build complete: /path/to/GraphKeeper
Co-change graph: 4 commit(s) analyzed, 80 file pair(s) found
graphify enrichment: skipped -- graphify was not found on PATH. Install it with
`uv tool install graphifyy` (or `pipx install graphifyy`) for symbol/call-graph
enrichment; GraphKeeper works fine without it, in co-change-only mode.
Wrote /path/to/GraphKeeper/.graphkeeper/graph.json
Now query it:
graphkeeper query co-change src/git.ts
Files that historically change alongside "src/git.ts":
1 src/store.ts
1 src/types.ts
1 test/git.test.ts
1 test/store.test.ts
1 test/test-helpers.ts
If graphify is installed
(uv tool install graphifyy), graphkeeper build automatically shells out to
its local, no-API-key graphify extract --code-only and merges its
symbol/call-graph into the same store, unlocking call-graph queries:
graphkeeper query calls mineCoChange
mineCoChange() (src/git.ts)
Calls (2):
--> assertIsGitRepo()
--> runGit()
Called by (1):
<-- build()
(Also real output, from running graphkeeper build against this repo with
graphify installed.)
Without graphify installed, that same command explains exactly why the answer isn't available instead of crashing or returning an empty result:
Call-graph query for "mineCoChange" is not available.
graphify was not found on PATH. Install it with `uv tool install graphifyy`
(or `pipx install graphifyy`) for symbol/call-graph enrichment; GraphKeeper
works fine without it, in co-change-only mode.
Every command also supports --json for scripts and agents:
graphkeeper query co-change src/git.ts --json
{
"file": "src/git.ts",
"results": [
{ "file": "src/store.ts", "count": 1 },
{ "file": "src/types.ts", "count": 1 },
{ "file": "test/git.test.ts", "count": 1 },
{ "file": "test/store.test.ts", "count": 1 },
{ "file": "test/test-helpers.ts", "count": 1 }
]
}

Usage: graphkeeper [options] [command]
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
build [options] [path] Mine git history for co-change and (if available)
merge in graphify's symbol/call graph
query Query the GraphKeeper store built by
`graphkeeper build`
help [command] display help for command
graphkeeper build [path]Walks path (default: current directory), runs git log --no-merges --name-only across the whole history, and counts how often each pair of
files was touched in the same commit. Writes the result to
.graphkeeper/graph.json.
| Option | Description |
|---|---|
--json | emit machine-readable JSON instead of human-readable text |
--max-files-per-commit <n> | skip commits touching more than this many files (default: 100) -- keeps a single mass-reformat or vendoring commit from drowning out real co-change signal |
--no-graphify | skip graphify enrichment even if graphify is installed |
If graphify is detected on
PATH, build also runs graphify extract <path> --code-only --no-cluster
(graphify's own headless, local, no-API-key AST extraction path) into a
directory inside .graphkeeper/, and merges its nodes/edges into the same
store. The build output always states plainly whether that enrichment was
included, and why it was skipped if not.
graphkeeper query co-change <file>Lists files that historically changed alongside <file>, ranked by how many
commits touched both.
| Option | Description |
|---|---|
--json | emit machine-readable JSON instead of human-readable text |
--limit <n> | cap the number of results |
--graph <path> | path to a specific graph.json (default: <cwd>/.graphkeeper/graph.json) |
Exit code 0 when results are found, 1 when there's no co-change data for
that file yet, 2 on a usage or filesystem error.
graphkeeper query calls <symbol>Shows callers and callees of <symbol>, using graphify's calls edges from
the most recent build. Only meaningful when that build included graphify
enrichment -- if it didn't, this prints a clear explanation of why (never a
crash, never a silent empty result).
| Option | Description |
|---|---|
--json | emit machine-readable JSON instead of human-readable text |
--graph <path> | path to a specific graph.json (default: <cwd>/.graphkeeper/graph.json) |
Exit code 0 when the symbol is found, 1 when it isn't (or enrichment
wasn't available), 2 on a usage or filesystem error.
graphify (87K+ stars, MIT
licensed, pip install graphifyy) already does symbol, import, and
call-graph extraction across 36 tree-sitter grammars, ships as a
slash-command skill for Claude Code, Codex, Gemini CLI, and 20+ other
assistants, and is actively developed by a funded (YC S26) team. Building a
competing symbol extractor from scratch would mean re-deriving years of
tree-sitter grammar coverage and edge-resolution work that already exists,
for no real gain.
GraphKeeper does something graphify has no reason to prioritize instead:
it mines git log for file-level co-change -- which files actually get
edited together across the real history of the repo. That's a narrow,
single-agent-workflow signal (useful to one agent working solo on a
codebase it doesn't fully know yet), not something a symbol-graph extractor
or a team code-review dashboard is built around. When graphify is present,
GraphKeeper enriches its own co-change graph with graphify's symbol/call
data by shelling out to graphify's own local extract command and merging
the two outputs into one store. When graphify isn't installed, GraphKeeper
still works, just without call-graph queries -- that's a documented,
graceful degradation, never an error.
The broader landscape, honestly:
| Tool | What it does | Local-only? | Free/OSS? | GraphKeeper's relationship |
|---|---|---|---|---|
| graphify | Symbol/import/call-graph extraction via tree-sitter, AI-assistant skill | Yes (code parsing) | Yes, MIT | GraphKeeper enriches from it when installed; doesn't reimplement it |
| GitNexus | Browser/WASM knowledge graph + MCP tools, structural + call-flow analysis | Yes (runs client-side) | Yes, ISC | Different delivery model (browser app vs. CLI); no co-change mining |
| Greptile | Hosted AI code review with a graph-indexed codebase | No (hosted/enterprise) | No | Team/PR-review focused, not a local single-agent tool |
| Augment Code | Hosted coding assistant with its own code+docs+media knowledge graph | No (hosted) | No | Enterprise assistant platform, not a standalone local CLI |
GraphKeeper is not trying to out-graph any of these. It's a small, single-purpose complement: point it at a repo, and it tells an agent which files tend to move together, based on nothing but the commit history that's already sitting on disk.
graphkeeper build runs git log --no-merges --name-only (via a safe
argv-array subprocess call, never a shell string) across the whole
repo history.--max-files-per-commit files (default 100)
are skipped, so a single vendoring or mass-reformat commit can't drown
out real signal.graphify is detected on PATH, GraphKeeper also runs
graphify extract <path> --code-only --no-cluster -- graphify's own
local, no-LLM, no-API-key extraction mode -- into a directory inside
.graphkeeper/, then merges its nodes/edges into the same store..graphkeeper/graph.json.graphkeeper query reads that file back and answers co-change or
call-graph questions against it -- no network calls, ever.git and graphify invocation uses an argv array passed directly
to the OS (spawnSync), never a shell string, so commit messages, file
names, or repo paths can't be interpreted as shell syntax..graphkeeper/ output paths are checked against the resolved repo root
before every write (symlinks included), so a maliciously crafted repo
can't redirect GraphKeeper's writes outside .graphkeeper/.git log output and (optionally) graphify's own graph.json;
the only file it writes is .graphkeeper/graph.json.Is GraphKeeper a general codebase knowledge-graph indexer?
Not on its own. The package descriptions on npm and PyPI say it "builds a
queryable knowledge graph," but what that means in practice is narrower:
graphkeeper build mines git log for file-level co-change and writes
those edges to .graphkeeper/graph.json. That file only becomes a
symbol/call graph too if graphify is installed and gets merged in during
the same build. Without graphify on PATH, the store holds co-change
data only, and graphkeeper query calls says so directly instead of
returning an empty result.
What does GraphKeeper actually give an agent that grep or git log don't?
A pre-computed, queryable answer to "which files change together here,"
so an agent doesn't have to run its own git log --name-only scan and
tally the results by hand on every question. --json on every command
makes that answer script-consumable rather than something a human has to
read and re-type.
How do I install it, and does it work on Windows?
npm install -g graphkeeper-cli (Node.js 18+) or pip install graphkeeper-cli (Python 3.9+); both need git on PATH. Neither
package contains OS-specific branches or native bindings, and the PyPI
listing is classified Operating System :: OS Independent, so it runs
the same way on Windows, macOS, and Linux anywhere git and a supported
Node or Python runtime are available.
How is this different from graphify, the tool it links to for enrichment?
They answer different questions. graphify extracts symbols, imports, and
call graphs straight from source via tree-sitter, across 36 languages;
GraphKeeper mines commit history for which files were historically
edited together, a signal graphify has no reason to compute. GraphKeeper
shells out to graphify's own local extract command when it's present
and merges the result in, rather than reimplementing tree-sitter parsing
from scratch. Neither replaces the other; see the comparison table above
for how GitNexus, Greptile, and Augment Code differ from both.
What actually breaks GraphKeeper, or gives an empty result?
Two real cases, both documented, neither a crash: a shallow git clone
(GitHub Actions' default fetch-depth: 1) has no history to mine, so
build reports 0 commit(s) analyzed and writes an empty co-change
graph; full history (fetch-depth: 0) is required. Separately,
query calls only returns results if the most recent build ran with
graphify on PATH -- if it didn't, the command explains that plainly
(graphify was not found on PATH...) instead of pretending the symbol
doesn't exist.
Is it safe to run against a repo I don't fully trust?
Every git and graphify call goes through an argv array straight to
the OS (spawnSync / Python's subprocess.run with a list, never a
shell string), so filenames or commit messages can't be interpreted as
shell syntax. Every .graphkeeper/ write is checked against the
resolved repo root, symlinks included, before it happens. There are no
network calls anywhere in the tool, so nothing about the repo you point
it at leaves your machine.
Is the npm CLI just a wrapper around the Python one, or vice versa?
Neither. They're two independent, from-scratch implementations (src/
for TypeScript, python/src/graphkeeper/ for Python) that happen to
agree on the same .graphkeeper/graph.json schema, the same subcommands,
flags, and exit codes. A store built by one can be read by the other.
The Python port's own test suite (ported from the TypeScript vitest
suite) is 78 tests, run against a real subprocess CLI invocation, not a
mock of the other language's output.
What license is this under, and can I use it commercially?
Apache License 2.0, for both the npm and PyPI packages, with no dual licensing and no separate commercial tier. That permits commercial use, modification, and redistribution, with attribution and the standard Apache patent grant; see LICENSE for the full text.
Issues and PRs welcome. To build the TypeScript package from source:
git clone https://github.com/RudrenduPaul/GraphKeeper.git
cd GraphKeeper
npm install
npm run build
npm test
npm run lint
npm run typecheck
For the Python package, see python/README.md. Full
contribution guidelines covering both codebases are in
CONTRIBUTING.md.
FAQs
Local-only CLI that mines git history for file-level co-change patterns and builds a queryable knowledge graph for AI coding agents, with optional enrichment from graphify's symbol/call-graph output when it is installed.
The npm package graphkeeper-cli receives a total of 12 weekly downloads. As such, graphkeeper-cli popularity was classified as not popular.
We found that graphkeeper-cli demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.

Product
Create and manage Asana tasks directly from Socket alerts, with manual task creation, automated ticketing rules, and two-way sync.

Security News
Open VSX has removed three extension IDs from its malicious-extension list as the legitimate publishers they impersonated move to claim the names for themselves.

Product
Socket’s PHP and Composer support is now in Beta for all customers, with PHP reachability analysis generally available.