* fix(lbug): route diagnostic logs to stderr to avoid MCP stdio corruption
Replace console.log/console.warn with console.error in core/lbug so
diagnostic messages reach stderr and never corrupt the JSON-RPC stream
on MCP stdio. Per spec, the server MUST NOT write anything to stdout
that is not a valid MCP message.
- lbug-adapter.ts:367 - schema creation warning (MCP-reachable via lazy
DB init from tool handlers)
- lbug-adapter.ts:1047,1054 - legacy embedding fallback diagnostics
(currently HTTP-only, but covered by upcoming no-console lint rule)
- extension-loader.ts:191 - default warn handler fallback used during
DuckDB extension loading
* feat(mcp): add stdout sentinel via AsyncLocalStorage transport-write tagging
Untagged process.stdout.write calls now redirect to stderr with a
[mcp:stdout-redirect] prefix instead of corrupting the JSON-RPC frame
stream. Identification is correctness-by-construction: the transport
wraps every send() in withMcpWrite() (AsyncLocalStorage) and the
sentinel checks isMcpWrite() per call. A byte-shape heuristic would
have falsely rejected Content-Length frames (start with C, end with })
and misclassified multi-chunk writes.
- gitnexus/src/mcp/stdio-context.ts: AsyncLocalStorage helpers + factory
- gitnexus/src/mcp/server.ts: install sentinel in safeStdout Proxy,
flush summary at process exit
- gitnexus/src/mcp/compatible-stdio-transport.ts: wrap send() write in
withMcpWrite so transport frames pass through cleanly
- gitnexus/test/unit/mcp-stdout-sentinel.test.ts: 17 cases covering
pass-through, redirect, prefix, truncation (default 200 / custom),
rate limit (default 10), one-shot warning, summary, mixed sequences
* feat(eslint): forbid console.log/warn and process.stdout.write in MCP-reachable code
Add a narrow ESLint override for gitnexus/src/mcp/**, gitnexus/src/core/lbug/**,
gitnexus/src/core/embeddings/**, and gitnexus/src/cli/mcp.ts that:
- sets no-console: ['error', { allow: ['error'] }] — only console.error
survives, since stderr is the only spec-safe channel for diagnostics
while the MCP stdio transport owns stdout for JSON-RPC frames
- adds no-restricted-syntax matching MemberExpression and CallExpression
forms of process.stdout.write to close the bypass path that the
AsyncLocalStorage sentinel cannot guarantee
Migrates 18 pre-existing console.log/warn call sites in core/embeddings/
(embedder.ts, embedding-pipeline.ts) to console.error; these are reached
from gitnexus_query semantic search and would have polluted MCP stdio
once a query triggered the embedding pipeline.
Adds eslint-disable-next-line comments in pool-adapter.ts at the four
legitimate process.stdout.write sites — they ARE the captured-real-write
infrastructure used by the sentinel and the silenceStdout/restoreStdout
mechanism.
The override is forward-compatible with feat/pino-logger (PR #1336)
which adds a broader no-console rule for gitnexus/src/; the narrow rule
here is a strict subset and rebases trivially when #1336 lands.
* feat(setup): pin setup-generated MCP config to installed version, keep static configs on @latest
The user-facing MCP config that 'gitnexus setup' writes into editor configs
now references gitnexus@<installed-version> instead of gitnexus@latest, read
dynamically from gitnexus/package.json#version at module load. This skips
the npm-registry metadata roundtrip on every MCP connect and stays
reproducible until the user explicitly upgrades.
Static example configs and quickstart docs intentionally keep @latest:
- .mcp.json, gitnexus-claude-plugin/.mcp.json
- gitnexus-claude-plugin/skills/*/mcp.json (6 files)
- README.md / gitnexus/README.md MCP examples
Pinning these would create per-release version-bump churn for marginal
(~100-500ms) savings. The dominant cold-cache cost is the native rebuild
addressed separately by the GITNEXUS_SKIP_OPTIONAL_GRAMMARS env var.
README adds a one-line steer above the @latest quickstart pointing
repeated users at 'gitnexus setup' for the absolute-path config that
bypasses npx entirely.
Tests refactored to assert against the dynamic version (createRequire of
package.json) so they don't break on every release bump:
- gitnexus/test/unit/setup.test.ts
- gitnexus/test/unit/setup-jsonc.test.ts
- gitnexus/test/unit/setup-codex.test.ts
- gitnexus/test/integration/setup-skills.test.ts (regex match)
* feat(install,mcp): GITNEXUS_SKIP_OPTIONAL_GRAMMARS opt-out + missing-grammar warnings
Postinstall scripts (build-tree-sitter-dart.cjs, build-tree-sitter-proto.cjs)
gain a strict 'process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS === "1"'
early-exit so users without a C++ toolchain (or anyone wanting fast
'npm install gitnexus') can skip the native rebuild. Strict '=1' only —
'true', 'yes', '0' and any other value fall through to the rebuild.
Add gitnexus/src/cli/optional-grammars.ts: cheap require.resolve probe for
each optional grammar, with a stderr warning helper. The warning surfaces:
- At MCP server start (cli/mcp.ts) — unconditional, since the server
serves any indexed repo and we cannot pre-filter by language.
- At 'gitnexus analyze' start (cli/analyze.ts) — conditional on the
target repo containing .dart/.proto files (cheap glob), so users with
no relevant code don't see noise.
README documents the env var with the strict '=1' value and the trade-off
(faster install, no Dart/Proto parsing until reinstalled).
* test(mcp): child-process integration test asserts end-to-end stdout discipline
Spawns 'node dist/cli/index.js mcp' as a child, drives the MCP stdio
handshake (initialize -> initialized -> tools/list), reassembles every
stdout chunk into Content-Length-framed JSON-RPC messages, and asserts
zero stray bytes. Any byte outside a valid header-then-body window is
captured and surfaced in the failure message alongside the server's
stderr — this is the regression gate for U1 (no console.log/warn in
MCP-reachable code) and U3 (AsyncLocalStorage stdout sentinel).
Time budget: 5s local / 15s CI for first frame; 10s/30s total. Asserts
the published GitNexus tool surface (list_repos, query, context, impact,
detect_changes, rename) is reported by tools/list.
Adds 'pretest:integration': 'node scripts/build.js' so 'npm run
test:integration' rebuilds dist before the spawn — closes the
'stale dist masks regression' DX gap.
* fix(mcp): address PR #1383 review — sentinel scope, grammar detection, lint, contract
Blockers:
- B2: detectMissingOptionalGrammars now actually require()s each grammar
instead of require.resolve(). For 'file:' optional dependencies the
package directory is always installed regardless of postinstall outcome,
so resolve() never threw and the missing-grammar warning never fired
for the exact target users (those who set GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1
or whose native rebuild soft-failed). require() loads the entry, which
triggers node-gyp-build and throws if .node is absent. Result memoized.
Should-fix:
- S1: Removed duplicate uncaughtException/unhandledRejection handlers from
cli/mcp.ts. server.ts:startMCPServer already registers handlers with
full stack traces; cli/mcp.ts handlers fired first with worse output and
never got a chance to exit because server.ts shuts down immediately.
- S2: Sentinel is now actually global. New setActiveStdoutWrite() in
pool-adapter so silenceStdout/restoreStdout cycles preserve a
registered wrapper instead of unwinding to raw realStdoutWrite. At
startMCPServer: install sentinel.write as process.stdout.write AND
register it as the active handler. Direct process.stdout.write calls
from anywhere (console.log, dependency banners, etc.) now route through
the sentinel instead of bypassing it. The transport's _safeStdout Proxy
remains as belt-and-suspenders.
- S3: ESLint no-restricted-syntax now also forbids destructuring of
process.stdout (covers both 'const { write } = process.stdout' shapes
and rest patterns).
Minor:
- M1: chunkToBuffer now handles plain Uint8Array (Buffer.from(u8)) instead
of falling through to String(chunk) which produced '1,2,3,...' garbage.
- M2: Untagged-write callbacks are now invoked on next tick per the
Node Writable.write contract — both within and beyond the rate-limit cap.
extractCallback handles the (chunk, cb) and (chunk, encoding, cb) overloads.
- M3: setup.ts throws early if package.json#version is missing/non-string
instead of emitting 'gitnexus@undefined'.
- M4: parser-loader.ts console.warn → console.error; ESLint scope extended
to gitnexus/src/core/tree-sitter/** so future violations are caught.
New tests cover:
- Plain Uint8Array redirect (asserts no String(chunk) garbage).
- Writable callback fired async (next-tick) for both normal and
past-rate-limit redirects.
Validation: cd gitnexus && npx tsc --noEmit clean; vitest run 7863 passed,
11 skipped; eslint clean on MCP-reachable scope; integration test green
against rebuilt dist/.
* fix(mcp): close pre-sentinel stdout window + tighten contracts
Address ce-code-review findings on PR #1383:
P1 — Sentinel install order (was: stdout corruption window during
mcpCommand pre-startup):
- Add idempotent installGlobalStdoutSentinel() to mcp/stdio-context.ts.
It captures realStdoutWrite/realStderrWrite, replaces process.stdout.write,
and registers with pool-adapter's setActiveStdoutWrite — exactly once.
- cli/mcp.ts now installs the sentinel as the FIRST line of mcpCommand,
before warnMissingOptionalGrammars (which after the B2 fix actually
require()s each native grammar binding and could emit node-gyp-build
banners to raw stdout in the pre-sentinel window).
- mcp/server.ts startMCPServer keeps a safety-net call to the same helper;
the second invocation is a no-op.
P1 — WriteFn type erasure:
- WriteFn now declared as instead of
, so the assignment
and the
setActiveStdoutWrite(sentinel.write) call don't silently cross a
type boundary.
P1 — extractCallback fragility:
- Replaced backward-scan-with-undefined-break heuristic with a strict
'last arg if function' check matching the documented Writable.write
contract. No longer breaks on a future (chunk, options, cb) overload.
P2 — _detectionCache premature memoization:
- Removed the explicit cache. Node's module cache already memoizes
require() — calling detectMissingOptionalGrammars multiple times is
cheap. Removing the module-level mutable state makes the helper
trivially testable (no need for a reset hatch).
P2 — Misleading 'reinstall' message on broken (not missing) grammars:
- detectMissingOptionalGrammars now distinguishes MODULE_NOT_FOUND /
node-gyp-build 'no native build' patterns from other errors
(SyntaxError, EACCES, native crash). Broken bindings get an
actionable stderr line naming the real failure instead of the
misleading 'reinstall to enable' hint.
Other:
- mcp/core/lbug-adapter.ts updated with a KEEP-THIS-FILE note. Tests
use the path as a vi.mock seam (calltool-dispatch.test.ts and 7
others); new non-test code may import core/lbug/pool-adapter.js
directly. The maintainability finding flagging the shim as
self-contradictory was incorrect — the shim has a real test purpose.
Validation: tsc clean, vitest 7863 passed (no regressions), eslint
clean on MCP-reachable scope, integration test green against rebuilt
dist/.
* fix(mcp): close import-time stdout corruption window
Codex's adversarial review on PR #1383 found that even though cli/mcp.ts
is loaded lazily by Commander, ITS static imports (startMCPServer,
LocalBackend, installGlobalStdoutSentinel, warnMissingOptionalGrammars)
evaluate synchronously when the module loads — well before mcpCommand's
function body runs. Three of those four imports transitively pulled in
core/lbug/pool-adapter.ts, which imports @ladybugdb/core at module top
level. The native binding's init can write to raw stdout in that
pre-sentinel window and corrupt the JSON-RPC frame stream.
Fix: shrink cli/mcp.ts's static-import closure to a single zero-dep
chain (mcp/stdio-context.js -> mcp/stdio-capture.js, both leaf-clean),
install the sentinel as the first executable statement of mcpCommand,
then dynamically import the heavy backend modules in parallel via
await Promise.all.
Per the plan at docs/plans/2026-05-06-002-fix-import-time-stdout-window-plan.md:
- U1: New leaf module gitnexus/src/mcp/stdio-capture.ts owns the
stdout-capture singleton state (realStdoutWrite, realStderrWrite,
activeStdoutWrite + setActiveStdoutWrite/getActiveStdoutWrite).
Zero non-node: imports — adding any would re-introduce the hazard.
- U2: pool-adapter.ts re-exports the relocated symbols under the
existing names so the test mock seam (8+ files use vi.mock on
mcp/core/lbug-adapter.ts which re-exports * from pool-adapter)
keeps working without churn. restoreStdout and the watchdog now
read the active handler via getActiveStdoutWrite(). stdio-context.ts
imports from stdio-capture directly.
- U3: cli/mcp.ts's static imports collapse to one
(installGlobalStdoutSentinel). startMCPServer / LocalBackend /
warnMissingOptionalGrammars become parallel await import()
inside mcpCommand, after the sentinel install.
- U4: New regression test gitnexus/test/integration/mcp/import-closure.test.ts
spawns a child Node process that imports dist/cli/mcp.js (without
invoking mcpCommand), inspects the CJS module cache via createRequire,
and asserts @ladybugdb/core (and tree-sitter native bindings) are
NOT in the static-import closure. Characterization-first: this test
was authored to fail against the pre-fix code and confirmed to do so
before U1-U3 landed.
Validation: tsc clean; vitest 7865 passed / 11 skipped (2 new U4 cases);
eslint clean on MCP-reachable scope; integration server-startup test
green against rebuilt dist/.
* fix(mcp): drop dead ESLint selector + suppress redundant grammar warning
Two minor PR #1383 review findings:
1. eslint.config.mjs: removed Selector 3 (`Property[key.name='write'].properties:has(...)`).
`.properties` is not a valid attribute on a Property node in the ESTree
AST, so the :has clause never matched — dead code. Selector 4 covers
the canonical `const { write } = process.stdout` shape; tightened its
comment to make that explicit.
2. cli/mcp.ts: removed the unconditional warnMissingOptionalGrammars call
at MCP startup. The analyze path already emits this warning at index
time with relevantExtensions filtered to the repo's actual file types,
and a repo can only be served by MCP after analyze has run. Repeating
the warning unconditionally on every MCP session was pure noise on
machines whose indexed repos don't use .dart/.proto.
* chore(mcp): address PR #1383 review nits
Three minor hygiene findings from the production-readiness review:
- cli/mcp.ts: rewrite stale comment that described
warnMissingOptionalGrammars as living inside mcpCommand. The call was
removed in ca617552 — this path no longer invokes it at all.
- test/integration/mcp/import-closure.test.ts: same comment drift fixed.
Test assertion is unchanged and still passes for the right reason
(cli/mcp.js's static-import closure is leaf-only).
- mcp/server.ts: rename _safeStdout to safeStdout. The leading underscore
conventionally signals "intentionally unused" but the Proxy is passed
to CompatibleStdioServerTransport on the next line.
No behavior change. Typecheck clean; ESLint MCP-reachable scope still 0
errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
35 KiB
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.
Join the official Discord to discuss ideas, issues etc!
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, 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
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, 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 serveconnects 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
gitnexusandgitnexus-web
CLI + MCP (recommended)
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.
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=1beforenpm install -g gitnexusto skip the nativetree-sitter-dartandtree-sitter-protobuilds. Dart/Proto files won't be parsed, but install completes in seconds withoutpython3/make/g++. Strict=1only — any other value falls through to the rebuild.
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 | — | MCP + Skills |
| 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.
Community Integrations
Built by the community — not officially maintained, but worth checking out.
| Project | Author | Description |
|---|---|---|
| pi-gitnexus | @tintinweb | GitNexus plugin for pi — pi 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 rungitnexus setup— this writes an absolute-path MCP config that bypassesnpxentirely. The pinned-npxsnippets below are a quickstart fallback; on a cold cache thenpxinstall can exceed Claude Code'sMCP_TIMEOUTdefault (~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"]
}
}
}
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 analyze [path] # Index a repository (or update stale index)
gitnexus analyze --force # Force full re-index
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-git # Index folders that are not Git repositories
gitnexus analyze --embeddings # 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 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
# 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
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.
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
repoparameter 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.
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 toghcr.io/abhigyanpatwari/gitnexus-web. The previous tags remain available for pulling, but new versions are only published under the new slugs. Update yourdocker 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.Zgit tags (viadocker.ymltriggered directly by the tag push), and the workflow refuses to build unless the tag exactly matchesgitnexus/package.json's version. Soghcr.io/abhigyanpatwari/gitnexus:1.6.2(and its Docker Hub mirrorakonlabs/gitnexus:1.6.2) is byte-for-byte the same release asnpm install gitnexus@1.6.2— no drift, no floating builds frommain. 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 byrelease-candidate.ymlcallingdocker.ymlas a reusable workflow after the RC tag is created and pushed. :latestis 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
release-candidate.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-sharedandgitnexus-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:
- AI edits
UserService.validate() - Doesn't know 47 functions depend on its return type
- 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:
- Structure — Walks the file tree and maps folder/file relationships
- Parsing — Extracts functions, classes, methods, and interfaces using Tree-sitter ASTs
- Resolution — Resolves imports, function calls, heritage, constructor inference, and
self/thisreceiver types across files with language-aware logic - Clustering — Groups related symbols into functional communities
- Processes — Traces execution flows from entry points through call chains
- 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 Bindings — import { 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
Process-Grouped Search
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
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/thisReceiver 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
- Tree-sitter — AST parsing
- LadybugDB — Embedded graph database with vector support (formerly KuzuDB)
- Sigma.js — WebGL graph rendering
- transformers.js — Browser ML
- Graphology — Graph data structures
- MCP — Model Context Protocol