GitNexus/README.md
Gergő Magyar cef63dd044
feat(install): toolchain-free tree-sitter via vendored prebuilds (#2113)
* feat(install): toolchain-free tree-sitter via vendored GitNexus-built prebuilds

Eliminate the C/C++-toolchain requirement at install for the at-risk grammars
(dart, proto, kotlin) by generating + vendoring native prebuilds, mirroring the
existing vendored tree-sitter-swift. The 10 grammars that already ship 6 upstream
prebuilds stay npm dependencies (toolchain-free AND dependency-review-tracked).

- .github/workflows/build-tree-sitter-prebuilds.yml: a registry-parameterized
  workflow that builds {dart,proto,kotlin} x {linux,darwin,win32}-{x64,arm64}
  prebuilds natively, validates each loads + parses on its arch, and opens a PR
  vendoring them. A `guard` job gates the heavy matrix to run ONLY on dispatch
  or a real grammar-version change — ordinary code PRs cost zero matrix minutes.
- dart/proto: prefer a committed prebuild; fall back to today's source build
  when none matches (no behavior change until prebuilds are vendored).
- kotlin: vendor it (Swift parity) instead of compiling the third-party
  optionalDependency from source at the user's install — supersedes #2110's
  optionalDependency mechanism. The ~23 MB parser.c is NOT vendored (the
  workflow builds from the published package); only node-types + bindings +
  prebuilds are. Removed from optionalDependencies; lock regenerated; probe,
  parser-loader note, README/.devcontainer docs, and the #2110 tests updated.

DO NOT MERGE until vendor/tree-sitter-kotlin/prebuilds/ is populated by the
build-tree-sitter-prebuilds workflow: until then Kotlin is unavailable (vendored
with no source-build fallback). dart/proto remain fully functional throughout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(install): guard 6/6 N-API prebuild coverage for every grammar

Regression guard so a toolchain-less install can never silently lose a tree-sitter
language on a supported platform-arch:

- Vendored grammars (vendor/tree-sitter-*): every one MUST ship a loadable N-API
  prebuild for all 6 tuples {linux,darwin,win32}-{x64,arm64}. Asserts the
  napi_register_module_v1 entry symbol in each .node (cross-platform, no need to
  run the binary). Currently RED for dart/proto/kotlin until the
  build-tree-sitter-prebuilds workflow populates their prebuilds/ — this is the
  must-fill-before-merge gate (swift already passes 6/6).
- npm-dependency grammars: asserts upstream ships 6/6 N-API too, catching a
  future platform drop. tree-sitter-c is allow-listed at 4/6 (missing
  linux-arm64/win32-arm64) pending #2116; the guard also fails if that gap is
  silently closed (prompting allow-list removal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(install): vendor tree-sitter-c at 0.21.4 with GitNexus-built prebuilds (#2116)

tree-sitter-c is the one grammar dependency upstream ships incomplete prebuilds
for (4/6 — no linux-arm64/win32-arm64), AND it is a REQUIRED grammar: its own
`install` (node-gyp-build) compiles from source when no prebuild matches and
exits non-zero, so on a toolchain-less ARM host `npm install gitnexus` HARD-FAILS
at the c step — during npm's dependency phase, before any GitNexus postinstall
runs (so a postinstall "supplement" can't help).

Fix: vendor c prebuild-only at the pinned 0.21.4 (Kotlin pattern), with all six
prebuilds GitNexus-cross-built, and drop it from `dependencies`:
- vendor/tree-sitter-c/ (bindings + node-types + manifest + prebuilds); build
  probe scripts/build-tree-sitter-c.cjs; added to the build workflow registry
  (kind 'npm' — built from c@0.21.4 source).
- materialize-vendor-grammars.cjs: c is REQUIRED, so it is always materialized,
  even under GITNEXUS_SKIP_OPTIONAL_GRAMMARS (it needs no toolchain).
- Removed from package.json dependencies + lockfile (nothing else needs npm c —
  tree-sitter-cpp's dep on c is dev-only and not installed). Preserves the #1242
  ABI pin: vendoring 0.21.4 keeps the good ABI while closing the ARM gap.
- parser-loader note + the prebuild-coverage guard + a cli-commands assertion
  updated; c moves from the npm-gap allow-list into the vendored 6/6 cohort.

Verified: tsc clean, 31 unit tests pass, c loads/parses; the guard is RED for
c/dart/proto/kotlin until the workflow populates prebuilds (the must-fill gate).
Closes the operational risk in #2116.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ci): source-build fallback for vendored c/kotlin so CI is healthy pre-prebuilds

The vendored prebuild-only grammars (c, kotlin) had empty prebuilds/ until the
build-tree-sitter-prebuilds workflow runs, so they could not load in CI — and
C is hard-required by cross-platform tests (tree-sitter-languages/parsing on
ubuntu+macos+windows), which I cannot pre-build for macos/windows locally. The
robust fix is a source-build fallback that works on every CI runner (all have a
toolchain), mirroring dart/proto:

- Vendor the grammar source (binding.gyp + src/) for c and kotlin; their build
  scripts now PREFER a committed prebuild (toolchain-free) and fall back to
  `node-gyp rebuild` from the vendored source when no prebuild matches. Verified
  both compile against the hoisted node-addon-api@^8 and the runtime loads.
- prebuild-coverage guard is now bootstrap-tolerant: a grammar that vendors its
  source (binding.gyp) may have an incomplete prebuild set (the workflow fills
  it); a prebuild-only grammar (swift) still must ship all six. Any present
  prebuild must still be N-API. Guard goes green; it re-tightens per-grammar as
  the workflow populates prebuilds.
- actionlint: silence a false-positive SC2016 (JS template literals inside the
  single-quoted `node -e` validate block).

Note: kotlin's generated parser.c is large (~23 MB on disk; compresses heavily
in git). Once the workflow populates all six kotlin prebuilds, the source serves
only as the fallback and could be slimmed if desired.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(docker): re-materialize+rebuild vendored grammars after npm prune

`npm prune --omit=dev` in the gitnexus CLI image drops anything not in
package.json's dependency tree — including the VENDORED tree-sitter grammars
(materialized by postinstall, not declared deps) and their built bindings. The
`serve` image analyzes/parses repos at runtime, so re-run the grammar postinstall
after the prune (in the toolchain-equipped builder) to restore them. Load-bearing
for tree-sitter-c, a core REQUIRED grammar now vendored (#2116): as a former
dependency it survived prune; vendored, it would not. Also restores
swift/dart/proto/kotlin, which were silently pruned from the image before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(grammars): unify tree-sitter-swift with the vendored-source build pipeline

Swift was the last grammar handled differently — it shipped only upstream
prebuilds, while c/dart/proto/kotlin vendor their grammar source and use a
prefer-prebuild -> source-build-fallback activation script. Vendor swift's
source so all five are handled identically (one uniform build path).

- vendor/tree-sitter-swift: add binding.gyp (win-hardened), bindings/node/
  binding.cc, src/parser.c (ABI-14 default, ~18 MB), src/scanner.c, and
  src/tree_sitter/ headers. The 6/6 prebuilds are retained. The legacy
  parser_abi13.c alternate is intentionally not vendored.
- build-tree-sitter-swift.cjs: rewrite the prebuild probe into the dart-style
  prefer-prebuild then source-build fallback (keeps the GITNEXUS_SKIP gate and
  the never-exit-non-zero postinstall invariant).
- build-tree-sitter-prebuilds.yml: register swift (kind 'vendored'); add its
  package.json to the version-gated pull_request paths and a validate snippet.
- prebuild-coverage guard auto-moves swift into the source-fallback cohort
  (binding.gyp now present); refresh the stale "swift is prebuild-only" comments.
- tests: add build-tree-sitter-swift-probe.test.ts; fix the pre-existing
  build-tree-sitter-kotlin-probe.test.ts breakage (it still asserted the old
  probe strings after kotlin's dart-style conversion); assert swift's vendored
  source in cli-commands.test.ts.
- docs: README / .devcontainer / kotlin vendor README — swift's prebuilds are
  now GitNexus-cross-built from vendored source like the rest, not upstream-only.

Verified: swift source-builds against node-addon-api@8 -> N-API binary -> loads
against the pinned tree-sitter@0.21.1 (ABI 14) -> parses cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(publish): gate a lean prebuilds-only npm tarball behind a coverage guard

Vendoring grammar source (parser.c) alongside the prebuilds means the npm
tarball now carries ~50 MB of generated source it almost never compiles (every
supported platform-arch has a prebuild). Prepare to drop it from the published
package once all prebuilds exist — safely.

- .npmignore: add a GATED, commented-out "lean publish" block that excludes the
  source-build inputs (parser.c/scanner.c/tree_sitter/binding.gyp/binding.cc) but
  keeps prebuilds/ + the runtime files. Uncommenting ships prebuilds-only.
- scripts/assert-publish-grammar-coverage.cjs: a prepack guard that refuses to
  pack/publish if the source exclusion is active while any vendored grammar still
  lacks 6/6 prebuilds (which would ship a grammar with no loadable binding). Wired
  into `prepack` (runs on npm pack + publish, incl. the publish.yml dry-run) and
  exposed as `npm run assert-publish-coverage`.
- test: pure-core decision cases + a real-repo publish-safety check that fails CI
  if .npmignore is activated prematurely.

Net: the prebuilds already publish today (files: ["vendor"]); this makes the
future switch to a prebuilds-only tarball a one-line uncomment that can't ship a
dead grammar. The guard currently reports "source + prebuilds" (only swift has
6/6 prebuilds so far) and passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(grammars): consolidate the 5 build-tree-sitter-*.cjs into one

The per-grammar activation scripts (c/dart/proto/swift/kotlin) were ~95%
identical — same prefer-prebuild → source-build → never-fail flow, differing only
in name, target_name, required-vs-optional, and the display label in warnings.

- scripts/build-tree-sitter-grammars.cjs: one registry-driven script. Bare call
  builds all (postinstall); `... <name>` builds only the named grammars (so the
  probe test can isolate one). c is `required: true` (ignores the opt-out gate);
  the rest honor GITNEXUS_SKIP_OPTIONAL_GRAMMARS. Per-grammar try/catch + a final
  process.exit(0) preserve the postinstall never-exit-non-zero invariant.
- package.json: postinstall is now `materialize && build-tree-sitter-grammars.cjs`
  (was five chained `build-tree-sitter-<name>.cjs` calls).
- tests: replace the two near-identical *-probe.test.ts files with one
  parameterized build-tree-sitter-grammars-probe.test.ts that also covers the
  required-vs-optional opt-out split and an unknown-grammar arg.
- update cli-commands.test.ts postinstall assertions + the vendor c/kotlin/swift
  README + swift provenance to reference the consolidated script.

Behavior is preserved (warnings normalized to one consistent format). Removes 5
scripts + 1 test file; adds 1 script + 1 test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ingestion): lazy-load tree-sitter-c to prevent module-load crash

tree-sitter-c is now vendored prebuild-only (#2116) with 0/6 committed
prebuilds, so on a toolchain-less or `--ignore-scripts` install C has no native
binding. Three modules loaded it via a hard top-level `import C from
'tree-sitter-c'`, which throws ERR_MODULE_NOT_FOUND at module-load — crashing
`analyze` before parser-loader's optional/severity:error degradation can run.
This is the #2091/#2093 bug class (previously fixed for swift/dart/kotlin); C was
left static because it used to be an always-present npm dependency.

- languages/c/query.ts: load via the lazy guarded getLanguageGrammar(C), mirroring
  swift/query.ts; the main-thread isLanguageAvailable filter ensures the getters
  are reached only when C is present.
- workers/parse-worker.ts: guarded `_require('tree-sitter-c')` + conditional
  languageMap spread, like swift/dart/kotlin.
- group/extractors/include-extractor.ts: guarded `_require`; getLanguageForFile
  returns null for .c/.h when absent, so C include-extraction degrades to a no-op
  (C++ unaffected).
- extend the registry-import-closure regression test (#2091/#2093) to assert C
  also loads lazily at registry static-import time.

* fix(ci): repin attest-build-provenance to the real v2.4.0 SHA

The workflow pinned actions/attest-build-provenance@bd77c077… commented
`# v2.4.0`, but v2.4.0 is e8998f94… (verified via the GitHub API); bd77c077…
is an untagged mid-stream commit, so the SLSA-attestation step ran unvetted
action code and the comment misrepresented what runs. Repin to the real
v2.4.0 commit and drop the `# PLACEHOLDER-PIN` markers on both this line and
the setup-python pin (a26af69b… is already the correct v5.6.0 — only its
comment was stale). Update the header NOTE accordingly.

* fix(ci): skip the prebuild-PR aggregate when release App secrets are absent

The aggregate job mints a GitHub App token as its first step; with
RELEASE_APP_ID/RELEASE_APP_PRIVATE_KEY unset it hard-failed AFTER a full
(up-to-6-runner) native build. Since the `secrets` context isn't available in
a job-level `if:`, the guard job now computes a `release_app` boolean output
(a step can read secrets) and emits an actionable `::notice::`; aggregate
gates on it and skips cleanly, while the build job's artifacts still upload
(run with open_pr=false for artifacts-only).

* chore(ci): drop package-lock.json from the prebuild paths filter; widen build timeout

`gitnexus/package-lock.json` changes on nearly every dependency PR, so it
fired the prebuild workflow's guard job on unrelated churn (the matrix stayed
correctly skipped — `gitnexus/package.json` already covers the transition-window
pin, so removing the lock only drops guard noise). Also bump the native build
job timeout 30 -> 45 min for headroom compiling the 23 MB kotlin / 18 MB swift
parser.c, especially under arm emulation.

* fix(ci): event-gate the aggregate open-PR condition explicitly

`inputs.open_pr` is null on pull_request events, and the prior
`inputs.open_pr != false` leg relied on GHA's direction-ambiguous null
coercion (Codex F4) to decide whether to open the prebuild PR. Gate
explicitly on the event: a non-fork pull_request that bumped a grammar
version opens the prebuild PR (the documented flow), and `open_pr` is only
consulted on workflow_dispatch — so a manual run with open_pr=false stays
artifacts-only and no event's behavior rests on coercion.

* fix(publish): validate the effective npm-pack contents in the coverage guard

The publish guard inferred "is source shipped?" from a single .npmignore toggle
line, which a partial/out-of-order edit could defeat (exclude binding.gyp but
leave parser.c → unbuildable yet "source-shipping"). It now inspects the
EFFECTIVE tarball via `npm pack --dry-run --ignore-scripts --json` (the
--ignore-scripts avoids re-entering this guard through prepack): a grammar
"ships source" only when EVERY on-disk source-build input (binding.gyp +
binding.cc + parser.c + scanner.c when present + a tree_sitter header) is
actually in the packed file list.

This also surfaced that the gated lean-publish .npmignore block was inert:
package.json's `files: ["vendor"]` allow-list overrides .npmignore for the
vendored subtree, so those exclusion lines never dropped anything. Replace the
dead toggle with documentation of the real mechanism (narrow the `files` field)
and note the guard enforces safety on the effective pack regardless of how the
slim is done.

* test(prebuild): hard-gate declared-fully-prebuilt grammars on 6/6 coverage

The strict 6/6 prebuild assertion was dormant whenever a grammar vendors source
(binding.gyp) — which is every grammar — so a dropped prebuild passed CI
silently. Add a FULLY_PREBUILT allowlist of grammars GitNexus has committed 6/6
for (today: swift); those must keep all six even with a source fallback, so
losing one now fails CI. Grammars graduate into the set as the
build-tree-sitter-prebuilds workflow lands their binaries. (The static-import
degradation smoke is covered by the registry-import-closure regression test
extended in the C lazy-load commit.)

* chore(deps): promote node-gyp-build/node-addon-api to regular dependencies

Every vendored grammar's index.js does `require("node-gyp-build")` at runtime
to load even a prebuilt .node, so node-gyp-build is runtime-load-critical (and
node-addon-api is needed for the source-build fallback). They were
optionalDependencies, surviving `--omit=optional` only via the required
tree-sitter's transitive edge — correct today but fragile. Promote both to
regular dependencies so the contract is explicit (optionalDependencies is now
empty and removed). Lock the contract with a cli-commands assertion.

* chore(vendor): add Windows cflags parity block to tree-sitter-c/binding.gyp

c's binding.gyp used an unconditional `cflags_c: ["-std=c11"]`, while
kotlin/swift gate MSVC flags behind an `OS=='win'` condition (/std:c11 /utf-8).
Inert today (no non-ASCII bytes in c's parser.c, and node-gyp ignores cflags_c
on MSVC anyway), but align the three so a future source-build fallback on
Windows behaves consistently.

* docs(agents): correct stale optional-grammar / postinstall notes

AGENTS.md still said postinstall "patches tree-sitter-swift, builds
tree-sitter-proto" and that only kotlin/swift are "optional". Update to the
vendored-uniform model: postinstall materializes the vendored grammars and
prefers a committed prebuild (source-build only when none matches); c is
required while dart/proto/swift/kotlin are optional + skippable via
GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1, with non-fatal warnings only on a
toolchain-less host with no matching prebuild.

* fix(install): preserve the backup and warn loudly on a failed materialize rollback

If renameSync(partial, dest) failed AND the rollback renameSync(backup, dest)
also failed, the grammar was left unmaterialized (node_modules/<name> missing)
with only a generic "could not materialize" warning — the recoverable backup at
<dest>.materialize-bak was unmentioned. Emit a CRITICAL warning naming the
backup path and the recovery command on that double-failure, and document that
the fail-soft catch removes only the scratch `partial`, never the `backup`
(which may be the sole recoverable copy). Never-throw / exit-0 contract intact.

* fix(publish): make the coverage guard's npm-pack inspection script-safe

The prepack guard shelled out to `npm pack --dry-run --ignore-scripts --json`,
but the `--ignore-scripts` flag is not reliably honored by npm pack's
prepare/prepack lifecycle on the CI npm — so build.js ran, polluted the --json
stdout with `[build] …`, and the guard's JSON.parse threw. That broke every
`npm pack` (packaged-install-smoke on ubuntu+windows) and failed the guard's own
real-repo unit test (the only coverage-job failure). Force script-skipping via
the reliable `npm_config_ignore_scripts` env config (also removes the prepack
re-entry/recursion risk) and parse defensively from the JSON-array start.

* fix(publish): make the coverage guard deterministic — read `files`, not `npm pack`

The npm-pack-based guard timed out in CI: `npm pack`'s prepare/prepack lifecycle
is not skipped by `--ignore-scripts` (flag or env config) on the CI npm, so the
inner pack ran the full build (~20s+) — fine for the slow smoke job, but it blew
past vitest's 30s test timeout in the coverage job (and risked re-entering this
prepack guard).

Replace it with a deterministic, fast (~0.1s) check that needs no subprocess:
since `files: ["vendor"]` OVERRIDES `.npmignore` for the vendored subtree (so
`.npmignore` can never drop vendored source — verified), the ONLY lever that can
exclude source is narrowing the package.json `files` field. The guard now reads
`files` directly: a grammar "ships source" iff `files` includes the vendor
subtree AND the grammar carries a buildable source set on disk. A lean publish
that narrows `files` while a grammar lacks 6/6 prebuilds still fails the gate.

* feat(ci): vendored tree-sitter grammar update monitor

Adds a weekly (+ dispatchable) workflow that checks each vendored grammar against
its source-of-origin (npm for swift/kotlin, the GitHub default branch for
dart/proto; c is excluded — held at 0.21.4 for ABI safety) and opens a PR
re-vendoring any update that is ABI-COMPATIBLE with the pinned tree-sitter@0.21.1
(LANGUAGE_VERSION 13-14).

ABI awareness is the point: most upstreams have moved to ABI 15 (newer
tree-sitter), so a blind "bump to latest" would open PRs that can't build. The
monitor fetches the candidate source, reads its parser.c LANGUAGE_VERSION, and
only re-vendors 13/14 — incompatible updates are reported (notice + job summary),
never applied. (Confirmed live: dart/proto upstreams are ABI 15 today and are
correctly held; swift/kotlin are current.)

The re-vendor refreshes only the source-build inputs + runtime entrypoints,
preserving the GitNexus-hardened binding.gyp / README / prebuilds; the version
bump then triggers build-tree-sitter-prebuilds.yml, whose ABI-validation is the
final safety net so a subtly-wrong re-vendor can't silently ship. PR creation is
gated on the RELEASE_APP secret (skips with a notice if absent), mirroring the
build aggregate. Unit test locks the ABI gate; the script is import-safe.

* feat(ci): monitor tree-sitter-c too (report-only, ABI-pinned)

c was excluded from the update monitor, so an upstream c update went unnoticed.
Include it, but as report-only via a `hold`: c is ABI-pinned at 0.21.4
(#1242/#858) and must not auto-bump without a tree-sitter runtime upgrade, so an
available c update is detected + surfaced (notice + job summary) but never
auto-PR'd — even if it were ABI-13/14. `--apply c` refuses defensively. (Live:
upstream c is 0.24.1 / ABI 15 today, so c is doubly held — reported, not applied.)

* fix(ci): drop the shell in the grammar monitor's github fetch (CodeQL)

CodeQL flagged the GitHub-tarball fetch — it used `bash -c "gh api …/tarball/$ref
> src.tgz && tar xzf src.tgz"`, interpolating the API-derived ref into a shell
command (the shell-command-injection family: "this shell command depends on an
uncontrolled file name"). Replace it with a shell-free path: capture `gh api`'s
binary tarball as a Buffer via execFileSync, write it to a fixed file, and
extract with execFileSync('tar', …). No shell, no injection surface. Verified the
dart/proto fetch + ABI read still work.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 18:16:24 +01:00

54 KiB
Raw Blame History

GitNexus

⚠️ Important Notice: GitNexus has NO official cryptocurrency, token, or coin. Any token/coin using the GitNexus name on Pump.fun or any other platform is not affiliated with, endorsed by, or created by this project or its maintainers. Do not purchase any cryptocurrency claiming association with GitNexus.

abhigyanpatwari%2FGitNexus | Trendshift

Join the official Discord to discuss ideas, issues etc!

Discord npm version License: PolyForm Noncommercial OpenSSF Scorecard CI Workflows

Enterprise (SaaS & Self-hosted) - akonlabs.com

Building nervous system for agent context.

Indexes any codebase into a knowledge graph — every dependency, call chain, cluster, and execution flow — then exposes it through smart tools so AI agents never miss code.

https://github.com/user-attachments/assets/172685ba-8e54-4ea7-9ad1-e31a3398da72

Like DeepWiki, but deeper. DeepWiki helps you understand code. GitNexus lets you analyze it — because a knowledge graph tracks every relationship, not just descriptions.

TL;DR: The Web UI is a quick way to chat with any repo. The CLI + MCP is how you make your AI agent actually reliable — it gives Cursor, Claude Code, Antigravity, Codex, and friends a deep architectural view of your codebase so they stop missing dependencies, breaking call chains, and shipping blind edits. Even smaller models get full architectural clarity, making it compete with Goliath models.


Star History

Star History Chart

Two Ways to Use GitNexus

CLI + MCP Web UI
What Index repos locally, connect AI agents via MCP Visual graph explorer + AI chat in browser
For Daily development with Cursor, Claude Code, Antigravity, Codex, Windsurf, OpenCode Quick exploration, demos, one-off analysis
Scale Full repos, any size Limited by browser memory (~5k files), or unlimited via backend mode
Install npm install -g gitnexus No install — gitnexus.vercel.app
Storage LadybugDB native (fast, persistent) LadybugDB WASM (in-memory, per session)
Parsing Tree-sitter native bindings Tree-sitter WASM
Privacy Everything local, no network Everything in-browser, no server

Bridge mode: gitnexus serve connects the two — the web UI auto-detects the local server and can browse all your CLI-indexed repos without re-uploading or re-indexing.


Enterprise

GitNexus is available as an enterprise offering - either as a fully managed SaaS or a self-hosted deployment. Also available for commercial use of the OSS version with proper licensing.

Enterprise includes:

  • PR Review - automated blast radius analysis on pull requests
  • Auto-updating Code Wiki - always up-to-date documentation (Code Wiki is also available in OSS)
  • Auto-reindexing - knowledge graph stays fresh automatically
  • Multi-repo support - unified graph across repositories
  • OCaml support - additional language coverage
  • Priority feature/language support - request new languages or features

Upcoming:

  • Auto regression forensics
  • End-to-end test generation

👉 Learn more at akonlabs.com

💬 For commercial licensing or enterprise inquiries, ping us on Discord or drop an email at founders@akonlabs.com


Development

  • ARCHITECTURE.md — packages, index → graph → MCP flow, where to change code
  • RUNBOOK.md — analyze, embeddings, stale index, MCP recovery, CI snippets
  • GUARDRAILS.md — safety rules and operational “Signs” for contributors and agents
  • CONTRIBUTING.md — license, setup, commits, and pull requests
  • TESTING.md — test commands for gitnexus and gitnexus-web

The CLI indexes your repository and runs an MCP server that gives AI agents deep codebase awareness.

Quick Start

# Index your repo (run from repo root)
npx gitnexus analyze

That's it. This indexes the codebase, installs agent skills, registers Claude Code hooks, and creates AGENTS.md / CLAUDE.md context files — all in one command.

On npm 11.x? npx can crash during install with Cannot destructure property 'package' of 'node.target' (an npm/arborist bug, before GitNexus runs). Use pnpm instead — it builds the native deps explicitly:

pnpm --allow-build=@ladybugdb/core --allow-build=gitnexus --allow-build=tree-sitter dlx gitnexus@latest analyze

Or install globally (npm install -g gitnexus@latest) and run gitnexus analyze. See #1939.

To configure MCP for your editor, run npx gitnexus setup once — or set it up manually below.

Faster install (no C++ toolchain needed): set GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1 before npm install -g gitnexus to skip the vendored grammar materialize/build for tree-sitter-dart, tree-sitter-proto, tree-sitter-swift, and tree-sitter-kotlin — those four won't be parsed, but install completes in seconds without python3/make/g++. Strict =1 only — any other value falls through to the rebuild. See the tree-sitter-kotlin note below.

About tree-sitter-kotlin: like Dart/Proto/Swift, Kotlin is a vendored grammar (under gitnexus/vendor/tree-sitter-kotlin). Upstream tree-sitter-kotlin ships source only (no prebuilt binaries), so GitNexus builds the Kotlin platform prebuilds itself (via the build-tree-sitter-prebuilds GitHub Actions workflow) and vendors them — the same uniform pipeline now used for Dart, Proto, and Swift (Swift's prebuilds were originally copied from upstream; they're now GitNexus-cross-built too). node-gyp-build selects the right .node at require time, so no C/C++ toolchain is needed. If no prebuild matches your platform-arch, only Kotlin (.kt/.kts) parsing is unavailable; the rest of gitnexus is unaffected.

MCP Setup

gitnexus setup auto-detects your editors and writes the correct global MCP config. You only need to run it once.

Editor Support

Editor MCP Skills Hooks (auto-augment) Support
Claude Code Yes Yes Yes (PreToolUse + PostToolUse) Full
Cursor Yes Yes Yes (postToolUse, manual install) Full
Antigravity (Google) Yes Yes Yes (AfterTool, Gemini CLI hooks schema)¹ Full
Codex Yes Yes MCP + Skills
Windsurf Yes MCP
OpenCode Yes Yes MCP + Skills

Claude Code gets the deepest integration: MCP tools + agent skills + PreToolUse hooks that enrich searches with graph context + PostToolUse hooks that detect a stale index after commits and prompt the agent to reindex.

¹ Antigravity hooks follow the Gemini CLI hooks reference (Antigravity 2.0 is the documented successor to Gemini CLI). Augmentation runs in AfterTool because BeforeTool has no context-injection channel in the Gemini contract — the agent sees graph context appended to the tool result via hookSpecificOutput.additionalContext. Stale-index hints land in the same channel after a successful git commit/merge/rebase/cherry-pick/pull. The schema may evolve if Antigravity-specific hook docs diverge from Gemini CLI's; the implementation will track those changes.

Community Integrations

Built by the community — not officially maintained, but worth checking out.

Project Author Description
pi-gitnexus @tintinweb GitNexus plugin for pipi install npm:pi-gitnexus
gitnexus-stable-ops @ShunsukeHayashi Stable ops & deployment workflows (Miyabi ecosystem)

Have a project built on GitNexus? Open a PR to add it here!

If you prefer manual configuration:

Recommended for fastest startup: install gitnexus globally (npm i -g gitnexus) and run gitnexus setup — this writes an absolute-path MCP config that bypasses npx entirely. The pinned-npx snippets below are a quickstart fallback; on a cold cache the npx install can exceed Claude Code's MCP_TIMEOUT default (~30s).

Claude Code (full support — MCP + skills + hooks):

# macOS / Linux
claude mcp add gitnexus -- npx -y gitnexus@latest mcp

# Windows
claude mcp add gitnexus -- cmd /c npx -y gitnexus@latest mcp

Codex (full support — MCP + skills):

codex mcp add gitnexus -- npx -y gitnexus@latest mcp

Cursor (~/.cursor/mcp.json — global, works for all projects):

{
  "mcpServers": {
    "gitnexus": {
      "command": "npx",
      "args": ["-y", "gitnexus@latest", "mcp"]
    }
  }
}

Antigravity (Google) — ~/.gemini/antigravity/mcp_config.json:

{
  "mcpServers": {
    "gitnexus": {
      "command": "npx",
      "args": ["-y", "gitnexus@latest", "mcp"]
    }
  }
}

gitnexus setup also merges an AfterTool entry into ~/.gemini/settings.json (under the canonical Gemini CLI hooks schema) and installs skills to ~/.gemini/antigravity/skills/. Existing user hooks are preserved. The hook adapter's path is rewritten at install time, so run gitnexus setup rather than hand-editing.

OpenCode (~/.config/opencode/config.json):

{
  "mcp": {
    "gitnexus": {
      "type": "local",
      "command": ["gitnexus", "mcp"]
    }
  }
}

Codex (~/.codex/config.toml for system scope, or .codex/config.toml for project scope):

[mcp_servers.gitnexus]
command = "npx"
args = ["-y", "gitnexus@latest", "mcp"]

CLI Commands

gitnexus setup                   # Configure MCP for your editors (one-time)
gitnexus uninstall               # Preview removal of GitNexus MCP/skills/hooks (add --force to apply)
gitnexus analyze [path]          # Index a repository (or update stale index)
gitnexus analyze --repair-fts    # Fast path: rebuild/verify only FTS indexes on existing index data
gitnexus analyze --force         # Full rebuild: re-parse + graph rebuild + FTS rebuild
gitnexus analyze --skills        # Generate repo-specific skill files from detected communities
gitnexus analyze --skip-embeddings  # Skip embedding generation (faster)
gitnexus analyze --skip-agents-md  # Preserve custom AGENTS.md/CLAUDE.md gitnexus section edits
gitnexus analyze --skip-skills     # Skip installing .claude/skills/gitnexus/ skill files
gitnexus analyze --default-branch develop  # Branch used in the generated regression-compare example (base_ref)
gitnexus analyze --skip-git        # Index folders that are not Git repositories
gitnexus analyze --embeddings [limit]  # Enable embedding generation (slower, better search)
gitnexus analyze --verbose       # Log skipped files when parsers are unavailable
gitnexus analyze --worker-timeout 60  # Increase worker idle timeout for slow parses
gitnexus analyze --wal-checkpoint-threshold 67108864  # 64 MiB. Control LadybugDB WAL auto-checkpoint threshold (default: 67108864 = 64 MiB; -1 keeps Ladybug stock ~16 MiB)
gitnexus analyze --workers <n>        # Parse worker pool size (>=1; default: cores-1, capped at 16, auto-sized to the repo). 0 is rejected — there is no sequential mode.
gitnexus mcp                     # Start MCP server (stdio) — serves all indexed repos
gitnexus serve                   # Start local HTTP server (multi-repo) for web UI connection
gitnexus list                    # List all indexed repositories
gitnexus status                  # Show index status for current repo
gitnexus clean                   # Delete index for current repo
gitnexus clean --all --force     # Delete all indexes
gitnexus wiki [path]             # Generate repository wiki from knowledge graph
gitnexus wiki --model <model>    # Wiki with custom LLM model (default: gpt-4o-mini)
gitnexus wiki --base-url <url>   # Wiki with custom LLM API base URL
gitnexus publish                 # Notify the understand-quickly registry (opt-in, see below)

# Repository groups (multi-repo / monorepo service tracking)
gitnexus group create <name>                                   # Create a repository group
gitnexus group add <group> <groupPath> <registryName>          # Add a repo to a group. <groupPath> is a hierarchy path (e.g. hr/hiring/backend); <registryName> is the repo's name from the registry (see `gitnexus list`)
gitnexus group remove <group> <groupPath>                      # Remove a repo from a group by its hierarchy path
gitnexus group list [name]                                     # List groups, or show one group's config
gitnexus group sync <name>                                     # Extract contracts and match across repos/services
gitnexus group contracts <name>  # Inspect extracted contracts and cross-links
gitnexus group query <name> <q>  # Search execution flows across all repos in a group
gitnexus group status <name>     # Check staleness of repos in a group

gitnexus uninstall reverses gitnexus setup — it removes the GitNexus MCP entries, hooks, and skill directories it added to each detected editor. Skill directories are identified by bundled gitnexus skill name (e.g. gitnexus-cli/), so if you customized files inside an installed skill directory, back them up first. It is a dry-run preview by default and prints the exact paths it would remove; pass --force to apply. Per-repo indexes (gitnexus clean --all) and the global npm package (npm uninstall -g gitnexus) are left for you to remove.

If analyze reports a worker parse timeout on a large or unusual repository, it keeps running and falls back safely. To give slow worker jobs more time, use gitnexus analyze --worker-timeout 60 or set GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS=60000. For very large files, GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES controls the worker job byte budget.

Embeddings node limit

gitnexus analyze --embeddings generates semantic search vectors with a default 50,000-node safety cap to protect memory on large repositories. Override the cap when you know the host has enough memory for a larger graph, or disable it entirely for a one-off full embeddings run.

# Generate embeddings with the default 50,000 node safety cap
gitnexus analyze --embeddings

# Disable the safety cap entirely
gitnexus analyze --embeddings 0

# Use a custom cap
gitnexus analyze --embeddings 100000

If embeddings are skipped on a large repository, the indexed graph likely exceeds the default safety cap. Re-run with gitnexus analyze --embeddings 0 to remove the cap, or gitnexus analyze --embeddings <n> to choose a higher limit while still keeping memory bounded.

Project config (.gitnexusrc)

Commit a .gitnexusrc JSON file at the repo root to preconfigure recurring analyze options per project, instead of re-passing the same flags every run. It is read from the resolved repo root (not .gitnexus/, which is gitignored index storage). CLI flags always override .gitnexusrc.

{
  // Default branch used in the generated regression-compare example (base_ref).
  // Use this so a project on `develop`/`master` doesn't get "main" rewritten
  // over its fix on every analyze. (Alias: "branch".)
  "defaultBranch": "develop",
  "skipContextFiles": true, // alias of skipAgentsMd: keep your own AGENTS.md/CLAUDE.md
  "skipSkills": true, // don't install .claude/skills/gitnexus/
  "embeddings": true, // generate embeddings by default
  "workerTimeout": 60
}

A nested analyze block is also accepted (and overrides flat keys for the same option):

{ "analyze": { "defaultBranch": "develop", "skipSkills": true } }

Notes:

  • The default branch is resolved as: --default-branch > .gitnexusrc defaultBranch/branch > auto-detected origin/HEAD > main.
  • skipContextFiles / skipAiContext are aliases for skipAgentsMd — they skip the AGENTS.md / CLAUDE.md block only. They do not imply skipSkills. indexOnly is the stronger option that skips all file injection.
  • Supported keys: defaultBranch (branch), skipAgentsMd (skipContextFiles, skipAiContext), skipSkills, indexOnly, stats/noStats, embeddings, dropEmbeddings, name, allowDuplicateName, maxFileSize, workerTimeout, walCheckpointThreshold, workers, embeddingThreads, embeddingBatchSize, embeddingSubBatchSize, embeddingDevice.
  • The file is JSON only. Unknown keys and invalid values fail fast with an actionable error before analysis starts.

Environment variables

Most analyze knobs are also CLI flags (--workers, --worker-timeout, --max-file-size, --verbose). Use the env-var form when you'd otherwise repeat the same flag every run, or when invoking GitNexus from a long-running host (MCP server, eval-server, CI shell) that already manages its own environment. CLI flags take precedence over env vars; env vars take precedence over built-in defaults.

Variable Default Effect Tune when…
GITNEXUS_WORKER_POOL_SIZE cores - 1, capped at 16 Parse worker pool size (must be ≥ 1). Equivalent to --workers <n>. The worker pool is the sole parse path — there is no sequential parser, so 0 is rejected with an actionable error (the pool self-heals via quarantine + respawn). Constrained containers (cgroup CPU limits) or CI runners with explicit quotas. To narrow down a worker crash set 1 for a single-worker pool — not 0.
GITNEXUS_PARSE_CHUNK_CONCURRENCY 2 Number of chunks whose file contents may be read into memory in parallel while the pool dispatches the current chunk. Worker dispatch itself stays serial. Repos large enough to chunk (multi-MB total source) where disk I/O is a measurable fraction of analyze wall-clock.
GITNEXUS_VERBOSE unset When 1, enables verbose ingestion logs (skipped-file warnings, per-chunk throughput, parse-cache stats). Equivalent to --verbose. Debugging an analyze that "completed" but seems to have missed files; tuning --workers / chunk concurrency against observable throughput.
GITNEXUS_PROFILE_DEFERRED unset When 1, emits [deferred-profile] timing/progress logs for the post-chunk deferred resolution band (imports → heritage → buildHeritageMap → legacy call resolution). Implied by GITNEXUS_VERBOSE. Diagnosing analyze stalls in "Resolving calls (all chunks)" on large Java/Kotlin repos (issue #1741) without the full verbose ingestion noise.
GITNEXUS_PROFILE_DEFERRED_SLOW_MS 3000 (verbose) / 5000 Per-file threshold in ms above which processCallsFromExtracted emits a slow file … log line. Parsed via Number(): accepts integers (5000), scientific notation (2.5e3), decimals (.5), and hex (0x10). Non-finite or non-positive values fall back to the default. Hunting a few outlier files dominating the deferred call-resolution stage; lower to surface more, raise to focus only on the worst.
GITNEXUS_MAX_FILE_SIZE 512 (KB) Walker skip threshold in KB. Hard cap is 32768 (tree-sitter buffer ceiling). Equivalent to --max-file-size <kb>. Indexing repos with intentionally-large source files (generated parsers, vendored bundles) that should still be parsed.
GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS 30000 Worker idle timeout in milliseconds before retry/fallback. Equivalent to --worker-timeout <seconds> × 1000. Slow-parsing files (large minified JS, deeply-nested TS types) that legitimately need more than 30s.
GITNEXUS_WAL_CHECKPOINT_THRESHOLD 67108864 (64 MiB) LadybugDB WAL auto-checkpoint threshold in bytes. Equivalent to --wal-checkpoint-threshold <bytes>. -1 keeps LadybugDB's stock threshold (~16 MiB). Larger thresholds reduce checkpoint frequency but increase the WAL size at rotation time — choose a smaller value on disk-constrained environments. You need a larger or smaller WAL auto-checkpoint threshold for your analyze workload.
GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES 8388608 (8 MB) Per-job byte budget the pool will send to a worker in one postMessage. Very large individual files; mostly diagnostic — bumping past 8 MB risks structured-clone memory pressure.
GITNEXUS_WORKER_MAX_RESPAWNS_PER_SLOT 3 Max replacement spawns per worker slot before the slot is dropped from the active rotation. Bounds respawn loops on a chronically-crashing slot. Hosts where a flaky worker should retry more (raise) or fail-fast (lower) before the slot is dropped.
GITNEXUS_WORKER_MAX_CUMULATIVE_TIMEOUT_MS 5 × subBatchTimeoutMs Total retry wall-time budget per job before quarantining. Combined with timeoutBackoffFactor, prevents exponentially-growing retries from stalling for hours. Slow files that legitimately need long total retry windows; lower to fail-fast on stalls.
GITNEXUS_WORKER_CONSECUTIVE_FAILURE_THRESHOLD max(3, poolSize) Per-slot consecutive deaths before the pool's circuit breaker trips. After tripping, every subsequent dispatch rejects until a fresh pool is created. Hosts where a SIGSEGV-prone native grammar should trip the breaker sooner; CI runners that should fail loudly.
GITNEXUS_CHUNK_BYTE_BUDGET 2097152 (2 MB) Chunk boundary used for cache-key composition and dispatch. Smaller = finer-grained cache hits but more dispatch overhead. Tuning incremental-analyze cache behavior on monorepos.
GITNEXUS_NO_GITIGNORE unset When set, skips .gitignore parsing. .gitnexusignore is still honored. Indexing a repo whose .gitignore excludes files you actually want indexed (e.g., generated code committed for cross-repo lookup).
GITNEXUS_SKIP_OPTIONAL_GRAMMARS unset When =1 strictly, skips the vendored grammar materialize for tree-sitter-dart, tree-sitter-proto, tree-sitter-swift, and tree-sitter-kotlin at install time (and the Dart/Proto source builds). Those four won't be parsed; the install still succeeds. Installing on a host without a C++ toolchain or where the vendored prebuilds don't match; willing to skip Dart/Proto/Swift/Kotlin parsing.

Publishing to understand-quickly (opt-in)

looptech-ai/understand-quickly is a public registry of code-knowledge graphs that lists gitnexus@1 as a first-class format. After registering your repo once (npx @understand-quickly/cli add or the wizard), gitnexus publish fires a single repository_dispatch event so the registry resyncs your entry on demand instead of waiting for the nightly job.

It is opt-in and a no-op without UNDERSTAND_QUICKLY_TOKEN — a fine-grained GitHub PAT with Repository dispatches: write on the registry repo. Nothing else happens; no graph file is uploaded. See the protocol spec for the full contract.

What Your AI Agent Gets

16 tools exposed via MCP (11 per-repo + 5 group):

Tool What It Does repo Param
list_repos Discover all indexed repositories
query Process-grouped hybrid search (BM25 + semantic + RRF) Optional
context 360-degree symbol view — categorized refs, process participation Optional
impact Blast radius analysis with depth grouping and confidence Optional
detect_changes Git-diff impact — maps changed lines to affected processes Optional
rename Multi-file coordinated rename with graph + text search Optional
cypher Raw Cypher graph queries Optional
group_list List configured repository groups
group_sync Extract contracts and match across repos/services
group_contracts Inspect extracted contracts and cross-links
group_query Search execution flows across all repos in a group
group_status Check staleness of repos in a group

When only one repo is indexed, the repo parameter is optional. With multiple repos, specify which one: query({query: "auth", repo: "my-app"}).

Resources for instant context:

Resource Purpose
gitnexus://repos List all indexed repositories (read this first)
gitnexus://repo/{name}/context Codebase stats, staleness check, and available tools
gitnexus://repo/{name}/clusters All functional clusters with cohesion scores
gitnexus://repo/{name}/cluster/{name} Cluster members and details
gitnexus://repo/{name}/processes All execution flows
gitnexus://repo/{name}/process/{name} Full process trace with steps
gitnexus://repo/{name}/schema Graph schema for Cypher queries

2 MCP prompts for guided workflows:

Prompt What It Does
detect_impact Pre-commit change analysis — scope, affected processes, risk level
generate_map Architecture documentation from the knowledge graph with mermaid diagrams

4 agent skills installed to .claude/skills/ automatically:

  • Exploring — Navigate unfamiliar code using the knowledge graph
  • Debugging — Trace bugs through call chains
  • Impact Analysis — Analyze blast radius before changes
  • Refactoring — Plan safe refactors using dependency mapping

Repo-specific skills generated with --skills:

When you run gitnexus analyze --skills, GitNexus detects the functional areas of your codebase (via Leiden community detection) and generates a SKILL.md file for each one under .claude/skills/generated/. Each skill describes a module's key files, entry points, execution flows, and cross-area connections — so your AI agent gets targeted context for the exact area of code you're working in. Skills are regenerated on each --skills run to stay current with the codebase.


Multi-Repo MCP Architecture

GitNexus uses a global registry so one MCP server can serve multiple indexed repos. No per-project MCP config needed — set it up once and it works everywhere.

flowchart TD
    subgraph CLI [CLI Commands]
        Setup["gitnexus setup"]
        Analyze["gitnexus analyze"]
        Clean["gitnexus clean"]
        List["gitnexus list"]
    end

    subgraph Registry ["~/.gitnexus/"]
        RegFile["registry.json"]
    end

    subgraph Repos [Project Repos]
        RepoA[".gitnexus/ in repo A"]
        RepoB[".gitnexus/ in repo B"]
    end

    subgraph MCP [MCP Server]
        Server["server.ts"]
        Backend["LocalBackend"]
        Pool["Connection Pool"]
        ConnA["LadybugDB conn A"]
        ConnB["LadybugDB conn B"]
    end

    Setup -->|"writes global MCP config"| CursorConfig["~/.cursor/mcp.json"]
    Analyze -->|"registers repo"| RegFile
    Analyze -->|"stores index"| RepoA
    Clean -->|"unregisters repo"| RegFile
    List -->|"reads"| RegFile
    Server -->|"reads registry"| RegFile
    Server --> Backend
    Backend --> Pool
    Pool -->|"lazy open"| ConnA
    Pool -->|"lazy open"| ConnB
    ConnA -->|"queries"| RepoA
    ConnB -->|"queries"| RepoB

How it works: Each gitnexus analyze stores the index in .gitnexus/ inside the repo (portable, gitignored) and registers a pointer in ~/.gitnexus/registry.json. When an AI agent starts, the MCP server reads the registry and can serve any indexed repo. LadybugDB connections are opened lazily on first query and evicted after 5 minutes of inactivity (max 5 concurrent). If only one repo is indexed, the repo parameter is optional on all tools — agents don't need to change anything.


Web UI (browser-based)

A client-side graph explorer and AI chat — your code never leaves your machine.

Try it now: gitnexus.vercel.app — run npx gitnexus@latest serve locally and the page auto-connects to your local backend.

gitnexus_img

Or run the frontend locally:

git clone https://github.com/abhigyanpatwari/gitnexus.git
cd gitnexus/gitnexus-shared && npm install && npm run build
cd ../gitnexus-web && npm install
npm run dev
# Then in another terminal, start the backend the frontend connects to:
npx gitnexus@latest serve

Docker

The official Docker setup ships two signed images orchestrated by docker-compose.yaml. Each image is published to both GitHub Container Registry (GHCR) and Docker Hub — same build, same digest, same Cosign signature — so pick whichever registry you prefer:

Purpose GHCR (default in docker-compose.yaml) Docker Hub mirror
CLI / gitnexus serve backend (HTTP API on port 4747, MCP, indexer) ghcr.io/abhigyanpatwari/gitnexus:latest akonlabs/gitnexus:latest
Static web UI (port 4173) ghcr.io/abhigyanpatwari/gitnexus-web:latest akonlabs/gitnexus-web:latest

Heads-up — image rename. Earlier releases published the web UI under ghcr.io/abhigyanpatwari/gitnexus. Starting with the introduction of the bundled backend, that slug now hosts the CLI/server image and the UI moved to ghcr.io/abhigyanpatwari/gitnexus-web. The previous tags remain available for pulling, but new versions are only published under the new slugs. Update your docker run / compose files accordingly (or just adopt the bundled compose).

One-command setup

docker compose up -d

This starts the server on http://localhost:4747 and the web UI on http://localhost:4173. The UI auto-detects the server because the browser runs on the host and reaches the container via the mapped port.

A named volume (gitnexus-data) persists the global registry, indexes, and cloned repos at /data/gitnexus inside the server container. To make repos on your host machine indexable, set WORKSPACE_DIR before bringing the stack up:

WORKSPACE_DIR=$HOME/code docker compose up -d
# Inside the server container the directory is mounted read-only at /workspace.
docker compose exec gitnexus-server gitnexus index /workspace/my-repo

Direct docker run

# Server
docker run --rm -d \
  --name gitnexus-server \
  -p 4747:4747 \
  -v gitnexus-data:/data/gitnexus \
  ghcr.io/abhigyanpatwari/gitnexus:latest

# Web UI
docker run --rm -d \
  --name gitnexus-web \
  -p 4173:4173 \
  ghcr.io/abhigyanpatwari/gitnexus-web:latest

Optional env file (override image tags, container names, ports, workspace dir):

cp .env.example .env
docker compose --env-file .env up -d

Versioning & supply-chain protection

The Docker images are version-locked to the npm package:

  • Stable images are only published from vX.Y.Z git tags (via docker.yml triggered directly by the tag push), and the workflow refuses to build unless the tag exactly matches gitnexus/package.json's version. So ghcr.io/abhigyanpatwari/gitnexus:1.6.2 (and its Docker Hub mirror akonlabs/gitnexus:1.6.2) is byte-for-byte the same release as npm install gitnexus@1.6.2 — no drift, no floating builds from main. Both registries receive the same digest from a single build step, so you can pull from either and the signature verifies identically.
  • Release-candidate images (e.g. :1.7.0-rc.1) are published alongside each RC npm release. They are built by publish.yml calling docker.yml as a reusable workflow after the RC tag is created and pushed.
  • :latest is auto-promoted only from non-prerelease tags by the Docker metadata action, so it always points at a real, npm-published version.

Both images are signed with Cosign keyless signing using the workflow's GitHub OIDC identity, and shipped with build provenance and SBOM attestations. This is your protection against supply-chain attacks: even if an attacker republishes a same-named image elsewhere (or somehow pushes to a typo-squatted registry), they cannot forge a Cosign signature tied to abhigyanpatwari/GitNexus's docker.yml. Always verify before pulling into sensitive environments:

Stable releases — signed from the v* tag ref:

cosign verify ghcr.io/abhigyanpatwari/gitnexus:1.6.2 \
  --certificate-identity-regexp '^https://github\.com/abhigyanpatwari/GitNexus/\.github/workflows/docker\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

# Same signature verifies the Docker Hub mirror (identical digest):
cosign verify docker.io/akonlabs/gitnexus:1.6.2 \
  --certificate-identity-regexp '^https://github\.com/abhigyanpatwari/GitNexus/\.github/workflows/docker\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

The regex pins the certificate identity to this repo's docker.yml workflow run from a v* tag — rejecting unsigned images, images signed by other workflows, and images signed from unprotected refs. It is identical for both registries because both sets of tags were signed at the same digest in one workflow run.

Release candidates — signed from refs/heads/main (the caller's ref when publish.yml invokes docker.yml as a reusable workflow):

cosign verify ghcr.io/abhigyanpatwari/gitnexus:1.7.0-rc.1 \
  --certificate-identity 'https://github.com/abhigyanpatwari/GitNexus/.github/workflows/docker.yml@refs/heads/main' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

You can also inspect the build provenance and SBOM:

cosign download attestation ghcr.io/abhigyanpatwari/gitnexus:1.6.2 \
  --predicate-type https://slsa.dev/provenance/v1

Kubernetes: enforce signatures at admission

For Kubernetes deployments, ship the bundled ClusterImagePolicy so the Sigstore policy-controller rejects any GitNexus pod whose image is not signed by this repo's docker.yml running from a vX.Y.Z tag — the same identity the cosign verify snippet above pins.

# 1. Install the controller (one-time, cluster-wide)
helm repo add sigstore https://sigstore.github.io/helm-charts && helm repo update
helm install policy-controller -n cosign-system --create-namespace \
  sigstore/policy-controller

# 2. Opt your namespace in
kubectl label namespace <your-ns> policy.sigstore.dev/include=true

# 3. Apply the policy
kubectl apply -f deploy/kubernetes/cluster-image-policy.yaml

After this, attempting to deploy an unsigned image — or one signed by anything other than abhigyanpatwari/GitNexus's docker.yml at a v* tag — fails the admission webhook before a pod is ever created. This turns the verifiable signature into an enforced policy, which is the supply-chain control most clusters actually need.

Files

  • Dockerfile.web — builds gitnexus-shared and gitnexus-web, then serves the production frontend.
  • Dockerfile.cli — builds the CLI/server (with its native deps) and runs gitnexus serve --host 0.0.0.0.
  • docker-compose.yaml — starts both signed images side by side.
  • .env.example — overrides for image names, container names, ports, and the workspace mount.

The web UI uses the same indexing pipeline as the CLI but runs entirely in WebAssembly (Tree-sitter WASM, LadybugDB WASM, in-browser embeddings). It's great for quick exploration but limited by browser memory for larger repos.

Local Backend Mode: Run gitnexus serve and open the web UI locally — it auto-detects the server and shows all your indexed repos, with full AI chat support. No need to re-upload or re-index. The agent's tools (Cypher queries, search, code navigation) route through the backend HTTP API automatically.


The Problem GitNexus Solves

Tools like Cursor, Claude Code, Codex, Cline, Roo Code, and Windsurf are powerful — but they don't truly know your codebase structure.

What happens:

  1. AI edits UserService.validate()
  2. Doesn't know 47 functions depend on its return type
  3. Breaking changes ship

Traditional Graph RAG vs GitNexus

Traditional approaches give the LLM raw graph edges and hope it explores enough. GitNexus precomputes structure at index time — clustering, tracing, scoring — so tools return complete context in one call:

flowchart TB
    subgraph Traditional["Traditional Graph RAG"]
        direction TB
        U1["User: What depends on UserService?"]
        U1 --> LLM1["LLM receives raw graph"]
        LLM1 --> Q1["Query 1: Find callers"]
        Q1 --> Q2["Query 2: What files?"]
        Q2 --> Q3["Query 3: Filter tests?"]
        Q3 --> Q4["Query 4: High-risk?"]
        Q4 --> OUT1["Answer after 4+ queries"]
    end

    subgraph GN["GitNexus Smart Tools"]
        direction TB
        U2["User: What depends on UserService?"]
        U2 --> TOOL["impact UserService upstream"]
        TOOL --> PRECOMP["Pre-structured response:
        8 callers, 3 clusters, all 90%+ confidence"]
        PRECOMP --> OUT2["Complete answer, 1 query"]
    end

Core innovation: Precomputed Relational Intelligence

  • Reliability — LLM can't miss context, it's already in the tool response
  • Token efficiency — No 10-query chains to understand one function
  • Model democratization — Smaller LLMs work because tools do the heavy lifting

How It Works

GitNexus builds a complete knowledge graph of your codebase through a multi-phase indexing pipeline:

  1. Structure — Walks the file tree and maps folder/file relationships
  2. Parsing — Extracts functions, classes, methods, and interfaces using Tree-sitter ASTs
  3. Resolution — Resolves imports, function calls, heritage, constructor inference, and self/this receiver types across files with language-aware logic
  4. Clustering — Groups related symbols into functional communities
  5. Processes — Traces execution flows from entry points through call chains
  6. Search — Builds hybrid search indexes for fast retrieval

Supported Languages

Language Imports Named Bindings Exports Heritage Type Annotations Constructor Inference Config Frameworks Entry Points
TypeScript
JavaScript
Python
Java
Kotlin
C#
Go
Rust
PHP
Ruby
Swift
C
C++
Dart

Imports — cross-file import resolution · Named Bindingsimport { X as Y } / re-export tracking · Exports — public/exported symbol detection · Heritage — class inheritance, interfaces, mixins · Type Annotations — explicit type extraction for receiver resolution · Constructor Inference — infer receiver type from constructor calls (self/this resolution included for all languages) · Config — language toolchain config parsing (tsconfig, go.mod, etc.) · Frameworks — AST-based framework pattern detection · Entry Points — entry point scoring heuristics


Tool Examples

Impact Analysis

impact({target: "UserService", direction: "upstream", minConfidence: 0.8})

TARGET: Class UserService (src/services/user.ts)

UPSTREAM (what depends on this):
  Depth 1 (WILL BREAK):
    handleLogin [CALLS 90%] -> src/api/auth.ts:45
    handleRegister [CALLS 90%] -> src/api/auth.ts:78
    UserController [CALLS 85%] -> src/controllers/user.ts:12
  Depth 2 (LIKELY AFFECTED):
    authRouter [IMPORTS] -> src/routes/auth.ts

Options: maxDepth, minConfidence, relationTypes (CALLS, IMPORTS, EXTENDS, IMPLEMENTS), includeTests, limit (max symbols per depth, default 100), offset (pagination start per depth), summaryOnly (counts and risk only, omits symbol list)

Disambiguation — when several symbols share the target name, impact returns a ranked ambiguous candidate list instead of guessing. Narrow it with target_uid (exact, zero-ambiguity), file_path, or kind (Function, Class, Method, …). From the CLI these are --uid, --file, and --kind, matching gitnexus context:

gitnexus impact get_embeddings                       # → ambiguous: lists ranked candidates
gitnexus impact get_embeddings --file src/embed.py   # → resolves to the one in that file
gitnexus impact get_embeddings --uid "Function:src/embed.py:get_embeddings"  # exact
query({query: "authentication middleware"})

processes:
  - summary: "LoginFlow"
    priority: 0.042
    symbol_count: 4
    process_type: cross_community
    step_count: 7

process_symbols:
  - name: validateUser
    type: Function
    filePath: src/auth/validate.ts
    process_id: proc_login
    step_index: 2

definitions:
  - name: AuthConfig
    type: Interface
    filePath: src/types/auth.ts

Context (360-degree Symbol View)

context({name: "validateUser"})

symbol:
  uid: "Function:validateUser"
  kind: Function
  filePath: src/auth/validate.ts
  startLine: 15

incoming:
  calls: [handleLogin, handleRegister, UserController]
  imports: [authRouter]

outgoing:
  calls: [checkPassword, createSession]

processes:
  - name: LoginFlow (step 2/7)
  - name: RegistrationFlow (step 3/5)

Detect Changes (Pre-Commit)

detect_changes({scope: "all"})

summary:
  changed_count: 12
  affected_count: 3
  changed_files: 4
  risk_level: medium

changed_symbols: [validateUser, AuthService, ...]
affected_processes: [LoginFlow, RegistrationFlow, ...]

Rename (Multi-File)

rename({symbol_name: "validateUser", new_name: "verifyUser", dry_run: true})

status: success
files_affected: 5
total_edits: 8
graph_edits: 6     (high confidence)
text_search_edits: 2  (review carefully)
changes: [...]

Cypher Queries

-- Find what calls auth functions with high confidence
MATCH (c:Community {heuristicLabel: 'Authentication'})<-[:CodeRelation {type: 'MEMBER_OF'}]-(fn)
MATCH (caller)-[r:CodeRelation {type: 'CALLS'}]->(fn)
WHERE r.confidence > 0.8
RETURN caller.name, fn.name, r.confidence
ORDER BY r.confidence DESC

Wiki Generation

Generate LLM-powered documentation from your knowledge graph:

# Requires an LLM API key (OPENAI_API_KEY, etc.)
gitnexus wiki

# Use a custom model or provider
gitnexus wiki --model gpt-4o
gitnexus wiki --base-url https://api.anthropic.com/v1

# Force full regeneration
gitnexus wiki --force


# Increase the timeout or retries for large codebase or slow LLM providers
gitnexus wiki --timeout <seconds> # LLM request timeout in seconds (default: disabled)
gitnexus wiki --retries <n>      # Max LLM retry attempts per request (default: 3)

# Change the language generation for wiki
gitnexus wiki --lang <lang>  # Output language for generated documentation (e.g. english, chinese, spanish, japanese)

The wiki generator reads the indexed graph structure, groups files into modules via LLM, generates per-module documentation pages, and creates an overview page — all with cross-references to the knowledge graph.


Tech Stack

Layer CLI Web
Runtime Node.js (native) Browser (WASM)
Parsing Tree-sitter native bindings Tree-sitter WASM
Database LadybugDB native LadybugDB WASM
Embeddings HuggingFace transformers.js (GPU/CPU) transformers.js (WebGPU/WASM)
Search BM25 + semantic + RRF BM25 + semantic + RRF
Agent Interface MCP (stdio) LangChain ReAct agent
Visualization Sigma.js + Graphology (WebGL)
Frontend React 18, TypeScript, Vite, Tailwind v4
Clustering Graphology Graphology
Concurrency Worker threads + async Web Workers + Comlink

Roadmap

Actively Building

  • LLM Cluster Enrichment — Semantic cluster names via LLM API
  • AST Decorator Detection — Parse @Controller, @Get, etc.
  • Incremental Indexing — Only re-index changed files

Recently Completed

  • Constructor-Inferred Type Resolution, self/this Receiver Mapping
  • Wiki Generation, Multi-File Rename, Git-Diff Impact Analysis
  • Process-Grouped Search, 360-Degree Context, Claude Code Hooks
  • Multi-Repo MCP, Zero-Config Setup, 14 Language Support
  • Community Detection, Process Detection, Confidence Scoring
  • Hybrid Search, Vector Index

Security & Privacy

  • CLI: Everything runs locally on your machine. No network calls. Index stored in .gitnexus/ (gitignored). Global registry at ~/.gitnexus/ stores only paths and metadata.
  • Web: Everything runs in your browser. No code uploaded to any server. API keys stored in localStorage only.
  • Open source — audit the code yourself.

Acknowledgments