fixed resource count multiplying issue ( using resource templates now )

This commit is contained in:
abhigyanpatwari 2026-02-13 21:28:36 +05:30
parent 96e1d799c8
commit eca55aacd7
44 changed files with 3422 additions and 541 deletions

View file

@ -0,0 +1,23 @@
{
"permissions": {
"allow": [
"WebSearch",
"WebFetch(domain:cursor.com)",
"WebFetch(domain:composio.dev)",
"Bash(npx tsc:*)",
"Bash(claude rename:*)",
"Bash(npm run build:*)",
"Bash(npm link:*)",
"Bash(gitnexus --version:*)",
"Bash(gitnexus --help:*)",
"Bash(npm ls:*)",
"Bash(gitnexus augment:*)",
"Bash(node -e \"\nconst { augment } = await import\\(''./gitnexus/dist/core/augmentation/engine.js''\\);\ntry {\n const r = await augment\\(''setup'', process.cwd\\(\\)\\);\n console.log\\(''Result:'', r ? r.substring\\(0, 200\\) : ''null''\\);\n} catch\\(e\\) { console.error\\(''Error:'', e.message\\); }\nprocess.exit\\(0\\);\n\")",
"Bash(cmd.exe /c \"cd /d D:\\\\Projects\\\\GitnexusV2 && gitnexus augment setup\")",
"Bash(cmd.exe /c \"cd /d D:\\\\Projects\\\\GitnexusV2 && gitnexus status\")",
"Bash(gh repo clone:*)",
"Bash(claude mcp:*)",
"Bash(gh issue view:*)"
]
}
}

View file

@ -15,8 +15,8 @@ description: Trace bugs through call chains using knowledge graph
## Workflow
```
1. gitnexus_search({query: "<error or symptom>"}) → Find related code
2. gitnexus_explore({name: "<suspect>", type: "symbol"}) → See callers/callees
1. gitnexus_query({query: "<error or symptom>"}) → Find related execution flows
2. gitnexus_context({name: "<suspect>"}) → See callers/callees/processes
3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow
4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed
```
@ -27,9 +27,9 @@ description: Trace bugs through call chains using knowledge graph
```
- [ ] Understand the symptom (error message, unexpected behavior)
- [ ] gitnexus_search for error text or related code
- [ ] Identify the suspect function
- [ ] gitnexus_explore to see callers and callees
- [ ] gitnexus_query for error text or related code
- [ ] Identify the suspect function from returned processes
- [ ] gitnexus_context to see callers and callees
- [ ] Trace execution flow via process resource if applicable
- [ ] gitnexus_cypher for custom call chain traces if needed
- [ ] Read source files to confirm root cause
@ -39,26 +39,27 @@ description: Trace bugs through call chains using knowledge graph
| Symptom | GitNexus Approach |
|---------|-------------------|
| Error message | `gitnexus_search` for error text → `explore` throw sites |
| Wrong return value | `explore` the function → trace callees for data flow |
| Intermittent failure | `explore` → look for external calls, async deps |
| Performance issue | `explore` → find symbols with many callers (hot paths) |
| Recent regression | `gitnexus_impact` on recently changed symbols |
| Error message | `gitnexus_query` for error text → `context` on throw sites |
| Wrong return value | `context` on the function → trace callees for data flow |
| Intermittent failure | `context` → look for external calls, async deps |
| Performance issue | `context` → find symbols with many callers (hot paths) |
| Recent regression | `detect_changes` to see what your changes affect |
## Tools
**gitnexus_search** — find code related to error:
**gitnexus_query** — find code related to error:
```
gitnexus_search({query: "payment validation error", depth: "full"})
→ validatePayment, handlePaymentError, PaymentException
gitnexus_query({query: "payment validation error"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError, PaymentException
```
**gitnexus_explore** — full context for a suspect:
**gitnexus_context** — full context for a suspect:
```
gitnexus_explore({name: "validatePayment", type: "symbol"})
Callers: processCheckout, webhookHandler
Callees: verifyCard, fetchRates (external API!)
Cluster: Payment
gitnexus_context({name: "validatePayment"})
Incoming calls: processCheckout, webhookHandler
Outgoing calls: verifyCard, fetchRates (external API!)
Processes: CheckoutFlow (step 3/7)
```
**gitnexus_cypher** — custom call chain traces:
@ -70,11 +71,12 @@ RETURN [n IN nodes(path) | n.name] AS chain
## Example: "Payment endpoint returns 500 intermittently"
```
1. gitnexus_search({query: "payment error handling"})
→ validatePayment, handlePaymentError, PaymentException
1. gitnexus_query({query: "payment error handling"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError
2. gitnexus_explore({name: "validatePayment", type: "symbol"})
Callees: verifyCard, fetchRates (external API!)
2. gitnexus_context({name: "validatePayment"})
Outgoing calls: verifyCard, fetchRates (external API!)
3. READ gitnexus://repo/my-app/process/CheckoutFlow
→ Step 3: validatePayment → calls fetchRates (external)

View file

@ -17,9 +17,9 @@ description: Navigate unfamiliar code using GitNexus knowledge graph
```
1. READ gitnexus://repos → Discover indexed repos
2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness
3. READ gitnexus://repo/{name}/clusters → See all functional areas
4. READ gitnexus://repo/{name}/cluster/{name} → Drill into relevant cluster
5. gitnexus_explore({name, type: "symbol"}) → Deep dive on specific symbol
3. gitnexus_query({query: "<what you want to understand>"}) → Find related execution flows
4. gitnexus_context({name: "<symbol>"}) → Deep dive on specific symbol
5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow
```
> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal.
@ -27,12 +27,11 @@ description: Navigate unfamiliar code using GitNexus knowledge graph
## Checklist
```
- [ ] READ gitnexus://repos
- [ ] READ gitnexus://repo/{name}/context
- [ ] READ gitnexus://repo/{name}/clusters
- [ ] Identify the relevant cluster
- [ ] READ gitnexus://repo/{name}/cluster/{name}
- [ ] gitnexus_explore for key symbols
- [ ] gitnexus_query for the concept you want to understand
- [ ] Review returned processes (execution flows)
- [ ] gitnexus_context on key symbols for callers/callees
- [ ] READ process resource for full execution traces
- [ ] Read source files for implementation details
```
@ -41,33 +40,36 @@ description: Navigate unfamiliar code using GitNexus knowledge graph
| Resource | What you get |
|----------|-------------|
| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) |
| `gitnexus://repo/{name}/clusters` | All clusters with cohesion scores (~300 tokens) |
| `gitnexus://repo/{name}/cluster/{name}` | Cluster members with file paths (~500 tokens) |
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) |
| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) |
| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) |
## Tools
**gitnexus_explore** — symbol context with callers/callees:
**gitnexus_query** — find execution flows related to a concept:
```
gitnexus_explore({name: "validateUser", type: "symbol"})
→ Callers: loginHandler, apiMiddleware
→ Callees: checkToken, getUserById
→ Cluster: Auth (92% cohesion)
gitnexus_query({query: "payment processing"})
→ Processes: CheckoutFlow, RefundFlow, WebhookHandler
→ Symbols grouped by flow with file locations
```
**gitnexus_search** — find code by query when you don't know the cluster:
**gitnexus_context** — 360-degree view of a symbol:
```
gitnexus_search({query: "payment validation", depth: "full"})
gitnexus_context({name: "validateUser"})
→ Incoming calls: loginHandler, apiMiddleware
→ Outgoing calls: checkToken, getUserById
→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3)
```
## Example: "How does payment processing work?"
```
1. READ gitnexus://repo/my-app/context → 918 symbols, 12 clusters
2. READ gitnexus://repo/my-app/clusters → Auth, Payment, Database, API...
3. READ gitnexus://repo/my-app/cluster/Payment → processPayment, validateCard, PaymentService
4. gitnexus_explore({name: "processPayment", type: "symbol"})
→ Callers: checkoutHandler, webhookHandler
→ Callees: validateCard, chargeStripe, saveTransaction
5. Read src/payments/processor.ts for implementation details
1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes
2. gitnexus_query({query: "payment processing"})
→ CheckoutFlow: processPayment → validateCard → chargeStripe
→ RefundFlow: initiateRefund → calculateRefund → processRefund
3. gitnexus_context({name: "processPayment"})
→ Incoming: checkoutHandler, webhookHandler
→ Outgoing: validateCard, chargeStripe, saveTransaction
4. Read src/payments/processor.ts for implementation details
```

View file

@ -11,13 +11,14 @@ description: Analyze blast radius before making code changes
- "Show me the blast radius"
- "Who uses this code?"
- Before making non-trivial code changes
- Before committing — to understand what your changes affect
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this
2. READ gitnexus://repo/{name}/clusters → Check which areas are affected
3. READ gitnexus://repo/{name}/processes → Check affected execution flows
2. READ gitnexus://repo/{name}/processes → Check affected execution flows
3. gitnexus_detect_changes() → Map current git changes to affected flows
4. Assess risk and report to user
```
@ -29,9 +30,8 @@ description: Analyze blast radius before making code changes
- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents
- [ ] Review d=1 items first (these WILL BREAK)
- [ ] Check high-confidence (>0.8) dependencies
- [ ] READ clusters to understand which areas are affected
- [ ] Count affected clusters (cross-cutting = higher risk)
- [ ] READ processes to check affected execution flows
- [ ] gitnexus_detect_changes() for pre-commit check
- [ ] Assess risk level and report to user
```
@ -47,14 +47,14 @@ description: Analyze blast radius before making code changes
| Affected | Risk |
|----------|------|
| <5 symbols, 1 cluster | LOW |
| 5-15 symbols, 1-2 clusters | MEDIUM |
| >15 symbols or 3+ clusters | HIGH |
| <5 symbols, few processes | LOW |
| 5-15 symbols, 2-5 processes | MEDIUM |
| >15 symbols or many processes | HIGH |
| Critical path (auth, payments) | CRITICAL |
## Tools
**gitnexus_impact** — the primary tool:
**gitnexus_impact** — the primary tool for symbol blast radius:
```
gitnexus_impact({
target: "validateUser",
@ -69,9 +69,15 @@ gitnexus_impact({
→ d=2 (LIKELY AFFECTED):
- authRouter (src/routes/auth.ts:22) [CALLS, 95%]
```
→ Affected Processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM (3 processes)
**gitnexus_detect_changes** — git-diff based impact analysis:
```
gitnexus_detect_changes({scope: "staged"})
→ Changed: 5 symbols in 3 files
→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline
→ Risk: MEDIUM
```
## Example: "What breaks if I change validateUser?"
@ -81,8 +87,8 @@ gitnexus_impact({
→ d=1: loginHandler, apiMiddleware (WILL BREAK)
→ d=2: authRouter, sessionManager (LIKELY AFFECTED)
2. READ gitnexus://repo/my-app/clusters
Auth and API clusters affected (2 clusters)
2. READ gitnexus://repo/my-app/processes
LoginFlow and TokenRefresh touch validateUser
3. Risk: 2 direct callers, 2 clusters = MEDIUM
3. Risk: 2 direct callers, 2 processes = MEDIUM
```

View file

@ -16,8 +16,8 @@ description: Plan safe refactors using blast radius and dependency mapping
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents
2. gitnexus_search({query: "X"}) → Find string/dynamic references
3. READ gitnexus://repo/{name}/cluster/{name} → Check cohesion impact
2. gitnexus_query({query: "X"}) → Find execution flows involving X
3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs
4. Plan update order: interfaces → implementations → callers → tests
```
@ -27,36 +27,44 @@ description: Plan safe refactors using blast radius and dependency mapping
### Rename Symbol
```
- [ ] gitnexus_impact({target: oldName, direction: "upstream"}) — find all callers
- [ ] gitnexus_search({query: oldName}) — find string literals and dynamic references
- [ ] Check for reflection/dynamic invocation patterns
- [ ] Plan update order: interface → implementation → callers → tests
- [ ] Update all d=1 (WILL BREAK) items
- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits
- [ ] Review graph edits (high confidence) and ast_search edits (review carefully)
- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits
- [ ] gitnexus_detect_changes() — verify only expected files changed
- [ ] Run tests for affected processes
```
### Extract Module
```
- [ ] gitnexus_explore({name: target, type: "symbol"}) — map internal dependencies
- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs
- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers
- [ ] READ cluster resource — check if extraction preserves cohesion
- [ ] Define new module interface
- [ ] Extract code, update imports
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
### Split Function/Service
```
- [ ] gitnexus_explore({name: target, type: "symbol"}) — understand all callees
- [ ] Group callees by responsibility/domain
- [ ] gitnexus_context({name: target}) — understand all callees
- [ ] Group callees by responsibility
- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update
- [ ] Create new functions/services
- [ ] Update callers
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
## Tools
**gitnexus_rename** — automated multi-file rename:
```
gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits across 8 files
→ 10 graph edits (high confidence), 2 ast_search edits (review)
→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}]
```
**gitnexus_impact** — map all dependents first:
```
gitnexus_impact({target: "validateUser", direction: "upstream"})
@ -64,10 +72,12 @@ gitnexus_impact({target: "validateUser", direction: "upstream"})
→ Affected Processes: LoginFlow, TokenRefresh
```
**gitnexus_search** — find string/dynamic references impact() might miss:
**gitnexus_detect_changes** — verify your changes after refactoring:
```
gitnexus_search({query: "validateUser"})
→ Found in: config.json (dynamic reference!), test fixtures
gitnexus_detect_changes({scope: "all"})
→ Changed: 8 files, 12 symbols
→ Affected processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM
```
**gitnexus_cypher** — custom reference queries:
@ -80,23 +90,24 @@ RETURN caller.name, caller.filePath ORDER BY caller.filePath
| Risk Factor | Mitigation |
|-------------|------------|
| Many callers (>5) | Update in small batches |
| Cross-cluster refs | Coordinate with affected areas |
| String/dynamic refs | `gitnexus_search` to find them |
| Many callers (>5) | Use gitnexus_rename for automated updates |
| Cross-area refs | Use detect_changes after to verify scope |
| String/dynamic refs | gitnexus_query to find them |
| External/public API | Version and deprecate properly |
## Example: Rename `validateUser` to `authenticateUser`
```
1. gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware, testUtils
1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits: 10 graph (safe), 2 ast_search (review)
→ Files: validator.ts, login.ts, middleware.ts, config.json...
2. gitnexus_search({query: "validateUser"})
→ Found in: config.json (dynamic reference!)
2. Review ast_search edits (config.json: dynamic reference!)
3. Plan update order:
1. Update declaration in src/auth/validator.ts
2. Update config.json string reference
3. Update loginHandler, apiMiddleware, testUtils
4. Run tests for LoginFlow, TokenRefresh
3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false})
→ Applied 12 edits across 8 files
4. gitnexus_detect_changes({scope: "all"})
→ Affected: LoginFlow, TokenRefresh
→ Risk: MEDIUM — run tests for these flows
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

View file

@ -0,0 +1,10 @@
{
"name": "gitnexus",
"description": "Code intelligence powered by a knowledge graph. Provides execution flow tracing, blast radius analysis, and augmented search across your codebase.",
"version": "1.0.0",
"author": {
"name": "GitNexus"
},
"homepage": "https://github.com/nicosxt/gitnexus",
"repository": "https://github.com/nicosxt/gitnexus"
}

View file

@ -0,0 +1,123 @@
#!/usr/bin/env node
/**
* GitNexus Claude Code Hook
*
* PreToolUse handler intercepts Grep/Glob/Bash searches
* and augments with graph context from the GitNexus index.
*
* NOTE: SessionStart hooks are broken on Windows (Claude Code bug).
* Session context is injected via CLAUDE.md / skills instead.
*/
const fs = require('fs');
const path = require('path');
const { execFileSync } = require('child_process');
/**
* Read JSON input from stdin synchronously.
*/
function readInput() {
try {
const data = fs.readFileSync(0, 'utf-8');
return JSON.parse(data);
} catch {
return {};
}
}
/**
* Check if a directory (or ancestor) has a .gitnexus index.
*/
function findGitNexusIndex(startDir) {
let dir = startDir || process.cwd();
for (let i = 0; i < 5; i++) {
if (fs.existsSync(path.join(dir, '.gitnexus'))) {
return true;
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
return false;
}
/**
* Extract search pattern from tool input.
*/
function extractPattern(toolName, toolInput) {
if (toolName === 'Grep') {
return toolInput.pattern || null;
}
if (toolName === 'Glob') {
const raw = toolInput.pattern || '';
const match = raw.match(/[*\/]([a-zA-Z][a-zA-Z0-9_-]{2,})/);
return match ? match[1] : null;
}
if (toolName === 'Bash') {
const cmd = toolInput.command || '';
if (!/\brg\b|\bgrep\b/.test(cmd)) return null;
const tokens = cmd.split(/\s+/);
let foundCmd = false;
let skipNext = false;
const flagsWithValues = new Set(['-e', '-f', '-m', '-A', '-B', '-C', '-g', '--glob', '-t', '--type', '--include', '--exclude']);
for (const token of tokens) {
if (skipNext) { skipNext = false; continue; }
if (!foundCmd) {
if (/\brg$|\bgrep$/.test(token)) foundCmd = true;
continue;
}
if (token.startsWith('-')) {
if (flagsWithValues.has(token)) skipNext = true;
continue;
}
const cleaned = token.replace(/['"]/g, '');
return cleaned.length >= 3 ? cleaned : null;
}
return null;
}
return null;
}
function main() {
try {
const input = readInput();
const hookEvent = input.hook_event_name || '';
if (hookEvent !== 'PreToolUse') return;
const cwd = input.cwd || process.cwd();
if (!findGitNexusIndex(cwd)) return;
const toolName = input.tool_name || '';
const toolInput = input.tool_input || {};
if (toolName !== 'Grep' && toolName !== 'Glob' && toolName !== 'Bash') return;
const pattern = extractPattern(toolName, toolInput);
if (!pattern || pattern.length < 3) return;
const result = execFileSync(
'gitnexus',
['augment', pattern],
{ encoding: 'utf-8', timeout: 8000, cwd, stdio: ['pipe', 'pipe', 'pipe'] }
);
if (result && result.trim()) {
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'PreToolUse',
additionalContext: result.trim()
}
}));
}
} catch {
// Graceful failure
}
}
main();

View file

@ -0,0 +1,17 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Grep|Glob|Bash",
"hooks": [
{
"type": "command",
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/gitnexus-hook.js",
"timeout": 10,
"statusMessage": "Enriching with GitNexus graph context..."
}
]
}
]
}
}

View file

@ -0,0 +1,78 @@
#!/bin/bash
# GitNexus PreToolUse hook for Claude Code
# Intercepts Grep/Glob/Bash searches and augments with graph context.
# Receives JSON on stdin with { tool_name, tool_input, cwd, ... }
# Returns JSON with additionalContext for graph-enriched results.
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
# Extract search pattern based on tool type
PATTERN=""
case "$TOOL_NAME" in
Grep)
PATTERN=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
;;
Glob)
# Glob patterns are file paths, not search terms — extract meaningful part
RAW=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
# Strip glob syntax to get the meaningful name (e.g., "**/*.ts" → skip, "auth*.ts" → "auth")
PATTERN=$(echo "$RAW" | sed -n 's/.*[*\/]\([a-zA-Z][a-zA-Z0-9_-]*\).*/\1/p')
;;
Bash)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
# Only augment grep/rg commands
if echo "$CMD" | grep -qE '\brg\b|\bgrep\b'; then
# Extract pattern from rg/grep
if echo "$CMD" | grep -qE '\brg\b'; then
PATTERN=$(echo "$CMD" | sed -n "s/.*\brg\s\+\(--[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
elif echo "$CMD" | grep -qE '\bgrep\b'; then
PATTERN=$(echo "$CMD" | sed -n "s/.*\bgrep\s\+\(-[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
fi
fi
;;
*)
# Not a search tool — skip
exit 0
;;
esac
# Skip if pattern too short or empty
if [ -z "$PATTERN" ] || [ ${#PATTERN} -lt 3 ]; then
exit 0
fi
# Check if we're in a GitNexus-indexed repo
dir="${CWD:-$PWD}"
found=false
for i in 1 2 3 4 5; do
if [ -d "$dir/.gitnexus" ]; then
found=true
break
fi
parent="$(dirname "$dir")"
[ "$parent" = "$dir" ] && break
dir="$parent"
done
if [ "$found" = false ]; then
exit 0
fi
# Run gitnexus augment — must be fast (<500ms target)
RESULT=$(cd "$CWD" && npx -y gitnexus augment "$PATTERN" 2>/dev/null)
if [ -n "$RESULT" ]; then
ESCAPED=$(echo "$RESULT" | jq -Rs .)
jq -n --argjson ctx "$ESCAPED" '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
additionalContext: $ctx
}
}'
else
exit 0
fi

View file

@ -0,0 +1,41 @@
// GitNexus SessionStart hook for Claude Code
// Fires on session startup. Stdout is injected into Claude's context.
// Checks if the current directory has a GitNexus index.
const fs = require('fs');
const path = require('path');
let dir = process.cwd();
let found = false;
for (let i = 0; i < 5; i++) {
if (fs.existsSync(path.join(dir, '.gitnexus'))) {
found = true;
break;
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
if (!found) {
process.exit(0);
}
process.stdout.write(`## GitNexus Code Intelligence
This codebase is indexed by GitNexus, providing a knowledge graph with execution flows, relationships, and semantic search.
**Available MCP Tools:**
- \`query\` — Process-grouped code intelligence (execution flows related to a concept)
- \`context\` — 360-degree symbol view (categorized refs, process participation)
- \`impact\` — Blast radius analysis (what breaks if you change a symbol)
- \`detect_changes\` — Git-diff impact analysis (what do your changes affect)
- \`rename\` — Multi-file coordinated rename with confidence tags
- \`cypher\` — Raw graph queries
- \`list_repos\` — Discover indexed repos
**Quick Start:** READ \`gitnexus://repo/{name}/context\` for codebase overview, then use \`query\` to find execution flows.
**Resources:** \`gitnexus://repo/{name}/context\` (overview), \`/processes\` (execution flows), \`/schema\` (for Cypher)
`);
process.exit(0);

View file

@ -0,0 +1,42 @@
#!/bin/bash
# GitNexus SessionStart hook for Claude Code
# Fires on session startup. Stdout is injected into Claude's context.
# Checks if the current directory has a GitNexus index.
dir="$PWD"
found=false
for i in 1 2 3 4 5; do
if [ -d "$dir/.gitnexus" ]; then
found=true
break
fi
parent="$(dirname "$dir")"
[ "$parent" = "$dir" ] && break
dir="$parent"
done
if [ "$found" = false ]; then
exit 0
fi
# Inject GitNexus context — this stdout goes directly into Claude's context
cat << 'EOF'
## GitNexus Code Intelligence
This codebase is indexed by GitNexus, providing a knowledge graph with execution flows, relationships, and semantic search.
**Available MCP Tools:**
- `query` — Process-grouped code intelligence (execution flows related to a concept)
- `context` — 360-degree symbol view (categorized refs, process participation)
- `impact` — Blast radius analysis (what breaks if you change a symbol)
- `detect_changes` — Git-diff impact analysis (what do your changes affect)
- `rename` — Multi-file coordinated rename with confidence tags
- `cypher` — Raw graph queries
- `list_repos` — Discover indexed repos
**Quick Start:** READ `gitnexus://repo/{name}/context` for codebase overview, then use `query` to find execution flows.
**Resources:** `gitnexus://repo/{name}/context` (overview), `/processes` (execution flows), `/schema` (for Cypher)
EOF
exit 0

View file

@ -0,0 +1,85 @@
---
name: gitnexus-debugging
description: Trace bugs through call chains using knowledge graph
---
# Debugging with GitNexus
## When to Use
- "Why is this function failing?"
- "Trace where this error comes from"
- "Who calls this method?"
- "This endpoint returns 500"
- Investigating bugs, errors, or unexpected behavior
## Workflow
```
1. gitnexus_query({query: "<error or symptom>"}) → Find related execution flows
2. gitnexus_context({name: "<suspect>"}) → See callers/callees/processes
3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow
4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] Understand the symptom (error message, unexpected behavior)
- [ ] gitnexus_query for error text or related code
- [ ] Identify the suspect function from returned processes
- [ ] gitnexus_context to see callers and callees
- [ ] Trace execution flow via process resource if applicable
- [ ] gitnexus_cypher for custom call chain traces if needed
- [ ] Read source files to confirm root cause
```
## Debugging Patterns
| Symptom | GitNexus Approach |
|---------|-------------------|
| Error message | `gitnexus_query` for error text → `context` on throw sites |
| Wrong return value | `context` on the function → trace callees for data flow |
| Intermittent failure | `context` → look for external calls, async deps |
| Performance issue | `context` → find symbols with many callers (hot paths) |
| Recent regression | `detect_changes` to see what your changes affect |
## Tools
**gitnexus_query** — find code related to error:
```
gitnexus_query({query: "payment validation error"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError, PaymentException
```
**gitnexus_context** — full context for a suspect:
```
gitnexus_context({name: "validatePayment"})
→ Incoming calls: processCheckout, webhookHandler
→ Outgoing calls: verifyCard, fetchRates (external API!)
→ Processes: CheckoutFlow (step 3/7)
```
**gitnexus_cypher** — custom call chain traces:
```cypher
MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"})
RETURN [n IN nodes(path) | n.name] AS chain
```
## Example: "Payment endpoint returns 500 intermittently"
```
1. gitnexus_query({query: "payment error handling"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError
2. gitnexus_context({name: "validatePayment"})
→ Outgoing calls: verifyCard, fetchRates (external API!)
3. READ gitnexus://repo/my-app/process/CheckoutFlow
→ Step 3: validatePayment → calls fetchRates (external)
4. Root cause: fetchRates calls external API without proper timeout
```

View file

@ -0,0 +1,75 @@
---
name: gitnexus-exploring
description: Navigate unfamiliar code using GitNexus knowledge graph
---
# Exploring Codebases with GitNexus
## When to Use
- "How does authentication work?"
- "What's the project structure?"
- "Show me the main components"
- "Where is the database logic?"
- Understanding code you haven't seen before
## Workflow
```
1. READ gitnexus://repos → Discover indexed repos
2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness
3. gitnexus_query({query: "<what you want to understand>"}) → Find related execution flows
4. gitnexus_context({name: "<symbol>"}) → Deep dive on specific symbol
5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow
```
> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] READ gitnexus://repo/{name}/context
- [ ] gitnexus_query for the concept you want to understand
- [ ] Review returned processes (execution flows)
- [ ] gitnexus_context on key symbols for callers/callees
- [ ] READ process resource for full execution traces
- [ ] Read source files for implementation details
```
## Resources
| Resource | What you get |
|----------|-------------|
| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) |
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) |
| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) |
| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) |
## Tools
**gitnexus_query** — find execution flows related to a concept:
```
gitnexus_query({query: "payment processing"})
→ Processes: CheckoutFlow, RefundFlow, WebhookHandler
→ Symbols grouped by flow with file locations
```
**gitnexus_context** — 360-degree view of a symbol:
```
gitnexus_context({name: "validateUser"})
→ Incoming calls: loginHandler, apiMiddleware
→ Outgoing calls: checkToken, getUserById
→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3)
```
## Example: "How does payment processing work?"
```
1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes
2. gitnexus_query({query: "payment processing"})
→ CheckoutFlow: processPayment → validateCard → chargeStripe
→ RefundFlow: initiateRefund → calculateRefund → processRefund
3. gitnexus_context({name: "processPayment"})
→ Incoming: checkoutHandler, webhookHandler
→ Outgoing: validateCard, chargeStripe, saveTransaction
4. Read src/payments/processor.ts for implementation details
```

View file

@ -0,0 +1,94 @@
---
name: gitnexus-impact-analysis
description: Analyze blast radius before making code changes
---
# Impact Analysis with GitNexus
## When to Use
- "Is it safe to change this function?"
- "What will break if I modify X?"
- "Show me the blast radius"
- "Who uses this code?"
- Before making non-trivial code changes
- Before committing — to understand what your changes affect
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this
2. READ gitnexus://repo/{name}/processes → Check affected execution flows
3. gitnexus_detect_changes() → Map current git changes to affected flows
4. Assess risk and report to user
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents
- [ ] Review d=1 items first (these WILL BREAK)
- [ ] Check high-confidence (>0.8) dependencies
- [ ] READ processes to check affected execution flows
- [ ] gitnexus_detect_changes() for pre-commit check
- [ ] Assess risk level and report to user
```
## Understanding Output
| Depth | Risk Level | Meaning |
|-------|-----------|---------|
| d=1 | **WILL BREAK** | Direct callers/importers |
| d=2 | LIKELY AFFECTED | Indirect dependencies |
| d=3 | MAY NEED TESTING | Transitive effects |
## Risk Assessment
| Affected | Risk |
|----------|------|
| <5 symbols, few processes | LOW |
| 5-15 symbols, 2-5 processes | MEDIUM |
| >15 symbols or many processes | HIGH |
| Critical path (auth, payments) | CRITICAL |
## Tools
**gitnexus_impact** — the primary tool for symbol blast radius:
```
gitnexus_impact({
target: "validateUser",
direction: "upstream",
minConfidence: 0.8,
maxDepth: 3
})
→ d=1 (WILL BREAK):
- loginHandler (src/auth/login.ts:42) [CALLS, 100%]
- apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%]
→ d=2 (LIKELY AFFECTED):
- authRouter (src/routes/auth.ts:22) [CALLS, 95%]
```
**gitnexus_detect_changes** — git-diff based impact analysis:
```
gitnexus_detect_changes({scope: "staged"})
→ Changed: 5 symbols in 3 files
→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline
→ Risk: MEDIUM
```
## Example: "What breaks if I change validateUser?"
```
1. gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware (WILL BREAK)
→ d=2: authRouter, sessionManager (LIKELY AFFECTED)
2. READ gitnexus://repo/my-app/processes
→ LoginFlow and TokenRefresh touch validateUser
3. Risk: 2 direct callers, 2 processes = MEDIUM
```

View file

@ -0,0 +1,113 @@
---
name: gitnexus-refactoring
description: Plan safe refactors using blast radius and dependency mapping
---
# Refactoring with GitNexus
## When to Use
- "Rename this function safely"
- "Extract this into a module"
- "Split this service"
- "Move this to a new file"
- Any task involving renaming, extracting, splitting, or restructuring code
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents
2. gitnexus_query({query: "X"}) → Find execution flows involving X
3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs
4. Plan update order: interfaces → implementations → callers → tests
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklists
### Rename Symbol
```
- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits
- [ ] Review graph edits (high confidence) and ast_search edits (review carefully)
- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits
- [ ] gitnexus_detect_changes() — verify only expected files changed
- [ ] Run tests for affected processes
```
### Extract Module
```
- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs
- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers
- [ ] Define new module interface
- [ ] Extract code, update imports
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
### Split Function/Service
```
- [ ] gitnexus_context({name: target}) — understand all callees
- [ ] Group callees by responsibility
- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update
- [ ] Create new functions/services
- [ ] Update callers
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
## Tools
**gitnexus_rename** — automated multi-file rename:
```
gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits across 8 files
→ 10 graph edits (high confidence), 2 ast_search edits (review)
→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}]
```
**gitnexus_impact** — map all dependents first:
```
gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware, testUtils
→ Affected Processes: LoginFlow, TokenRefresh
```
**gitnexus_detect_changes** — verify your changes after refactoring:
```
gitnexus_detect_changes({scope: "all"})
→ Changed: 8 files, 12 symbols
→ Affected processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM
```
**gitnexus_cypher** — custom reference queries:
```cypher
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"})
RETURN caller.name, caller.filePath ORDER BY caller.filePath
```
## Risk Rules
| Risk Factor | Mitigation |
|-------------|------------|
| Many callers (>5) | Use gitnexus_rename for automated updates |
| Cross-area refs | Use detect_changes after to verify scope |
| String/dynamic refs | gitnexus_query to find them |
| External/public API | Version and deprecate properly |
## Example: Rename `validateUser` to `authenticateUser`
```
1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits: 10 graph (safe), 2 ast_search (review)
→ Files: validator.ts, login.ts, middleware.ts, config.json...
2. Review ast_search edits (config.json: dynamic reference!)
3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false})
→ Applied 12 edits across 8 files
4. gitnexus_detect_changes({scope: "all"})
→ Affected: LoginFlow, TokenRefresh
→ Risk: MEDIUM — run tests for these flows
```

View file

@ -0,0 +1,50 @@
#!/bin/bash
# GitNexus beforeShellExecution hook for Cursor
# Receives JSON on stdin with { command, cwd, timeout }
# Returns JSON on stdout with { permission, agent_message }
#
# Extracts search pattern from grep/rg commands, runs gitnexus augment,
# and injects the enriched context via agent_message.
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.command // empty' 2>/dev/null)
if [ -z "$COMMAND" ]; then
echo '{"permission":"allow"}'
exit 0
fi
# Skip non-search commands
case "$COMMAND" in
cd\ *|npm\ *|yarn\ *|pnpm\ *|git\ commit*|git\ push*|git\ pull*|mkdir\ *|rm\ *|cp\ *|mv\ *|echo\ *|cat\ *)
echo '{"permission":"allow"}'
exit 0
;;
esac
# Extract search pattern from rg/grep commands
PATTERN=""
if echo "$COMMAND" | grep -qE '\brg\b'; then
PATTERN=$(echo "$COMMAND" | sed -n "s/.*\brg\s\+\(--[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
elif echo "$COMMAND" | grep -qE '\bgrep\b'; then
PATTERN=$(echo "$COMMAND" | sed -n "s/.*\bgrep\s\+\(-[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
fi
if [ -z "$PATTERN" ] || [ ${#PATTERN} -lt 3 ]; then
echo '{"permission":"allow"}'
exit 0
fi
# Run gitnexus augment
RESULT=$(npx -y gitnexus augment "$PATTERN" 2>/dev/null)
if [ -n "$RESULT" ]; then
# Escape for JSON
ESCAPED=$(echo "$RESULT" | jq -Rs .)
echo "{\"permission\":\"allow\",\"agent_message\":$ESCAPED}"
else
echo '{"permission":"allow"}'
fi
exit 0

View file

@ -0,0 +1,12 @@
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": "./hooks/augment-shell.sh",
"timeout": 5,
"matcher": "\\brg\\b|\\bgrep\\b"
}
]
}
}

View file

@ -0,0 +1,85 @@
---
name: gitnexus-debugging
description: Trace bugs through call chains using knowledge graph
---
# Debugging with GitNexus
## When to Use
- "Why is this function failing?"
- "Trace where this error comes from"
- "Who calls this method?"
- "This endpoint returns 500"
- Investigating bugs, errors, or unexpected behavior
## Workflow
```
1. gitnexus_query({query: "<error or symptom>"}) → Find related execution flows
2. gitnexus_context({name: "<suspect>"}) → See callers/callees/processes
3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow
4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] Understand the symptom (error message, unexpected behavior)
- [ ] gitnexus_query for error text or related code
- [ ] Identify the suspect function from returned processes
- [ ] gitnexus_context to see callers and callees
- [ ] Trace execution flow via process resource if applicable
- [ ] gitnexus_cypher for custom call chain traces if needed
- [ ] Read source files to confirm root cause
```
## Debugging Patterns
| Symptom | GitNexus Approach |
|---------|-------------------|
| Error message | `gitnexus_query` for error text → `context` on throw sites |
| Wrong return value | `context` on the function → trace callees for data flow |
| Intermittent failure | `context` → look for external calls, async deps |
| Performance issue | `context` → find symbols with many callers (hot paths) |
| Recent regression | `detect_changes` to see what your changes affect |
## Tools
**gitnexus_query** — find code related to error:
```
gitnexus_query({query: "payment validation error"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError, PaymentException
```
**gitnexus_context** — full context for a suspect:
```
gitnexus_context({name: "validatePayment"})
→ Incoming calls: processCheckout, webhookHandler
→ Outgoing calls: verifyCard, fetchRates (external API!)
→ Processes: CheckoutFlow (step 3/7)
```
**gitnexus_cypher** — custom call chain traces:
```cypher
MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"})
RETURN [n IN nodes(path) | n.name] AS chain
```
## Example: "Payment endpoint returns 500 intermittently"
```
1. gitnexus_query({query: "payment error handling"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError
2. gitnexus_context({name: "validatePayment"})
→ Outgoing calls: verifyCard, fetchRates (external API!)
3. READ gitnexus://repo/my-app/process/CheckoutFlow
→ Step 3: validatePayment → calls fetchRates (external)
4. Root cause: fetchRates calls external API without proper timeout
```

View file

@ -0,0 +1,75 @@
---
name: gitnexus-exploring
description: Navigate unfamiliar code using GitNexus knowledge graph
---
# Exploring Codebases with GitNexus
## When to Use
- "How does authentication work?"
- "What's the project structure?"
- "Show me the main components"
- "Where is the database logic?"
- Understanding code you haven't seen before
## Workflow
```
1. READ gitnexus://repos → Discover indexed repos
2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness
3. gitnexus_query({query: "<what you want to understand>"}) → Find related execution flows
4. gitnexus_context({name: "<symbol>"}) → Deep dive on specific symbol
5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow
```
> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] READ gitnexus://repo/{name}/context
- [ ] gitnexus_query for the concept you want to understand
- [ ] Review returned processes (execution flows)
- [ ] gitnexus_context on key symbols for callers/callees
- [ ] READ process resource for full execution traces
- [ ] Read source files for implementation details
```
## Resources
| Resource | What you get |
|----------|-------------|
| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) |
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) |
| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) |
| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) |
## Tools
**gitnexus_query** — find execution flows related to a concept:
```
gitnexus_query({query: "payment processing"})
→ Processes: CheckoutFlow, RefundFlow, WebhookHandler
→ Symbols grouped by flow with file locations
```
**gitnexus_context** — 360-degree view of a symbol:
```
gitnexus_context({name: "validateUser"})
→ Incoming calls: loginHandler, apiMiddleware
→ Outgoing calls: checkToken, getUserById
→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3)
```
## Example: "How does payment processing work?"
```
1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes
2. gitnexus_query({query: "payment processing"})
→ CheckoutFlow: processPayment → validateCard → chargeStripe
→ RefundFlow: initiateRefund → calculateRefund → processRefund
3. gitnexus_context({name: "processPayment"})
→ Incoming: checkoutHandler, webhookHandler
→ Outgoing: validateCard, chargeStripe, saveTransaction
4. Read src/payments/processor.ts for implementation details
```

View file

@ -0,0 +1,94 @@
---
name: gitnexus-impact-analysis
description: Analyze blast radius before making code changes
---
# Impact Analysis with GitNexus
## When to Use
- "Is it safe to change this function?"
- "What will break if I modify X?"
- "Show me the blast radius"
- "Who uses this code?"
- Before making non-trivial code changes
- Before committing — to understand what your changes affect
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this
2. READ gitnexus://repo/{name}/processes → Check affected execution flows
3. gitnexus_detect_changes() → Map current git changes to affected flows
4. Assess risk and report to user
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents
- [ ] Review d=1 items first (these WILL BREAK)
- [ ] Check high-confidence (>0.8) dependencies
- [ ] READ processes to check affected execution flows
- [ ] gitnexus_detect_changes() for pre-commit check
- [ ] Assess risk level and report to user
```
## Understanding Output
| Depth | Risk Level | Meaning |
|-------|-----------|---------|
| d=1 | **WILL BREAK** | Direct callers/importers |
| d=2 | LIKELY AFFECTED | Indirect dependencies |
| d=3 | MAY NEED TESTING | Transitive effects |
## Risk Assessment
| Affected | Risk |
|----------|------|
| <5 symbols, few processes | LOW |
| 5-15 symbols, 2-5 processes | MEDIUM |
| >15 symbols or many processes | HIGH |
| Critical path (auth, payments) | CRITICAL |
## Tools
**gitnexus_impact** — the primary tool for symbol blast radius:
```
gitnexus_impact({
target: "validateUser",
direction: "upstream",
minConfidence: 0.8,
maxDepth: 3
})
→ d=1 (WILL BREAK):
- loginHandler (src/auth/login.ts:42) [CALLS, 100%]
- apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%]
→ d=2 (LIKELY AFFECTED):
- authRouter (src/routes/auth.ts:22) [CALLS, 95%]
```
**gitnexus_detect_changes** — git-diff based impact analysis:
```
gitnexus_detect_changes({scope: "staged"})
→ Changed: 5 symbols in 3 files
→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline
→ Risk: MEDIUM
```
## Example: "What breaks if I change validateUser?"
```
1. gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware (WILL BREAK)
→ d=2: authRouter, sessionManager (LIKELY AFFECTED)
2. READ gitnexus://repo/my-app/processes
→ LoginFlow and TokenRefresh touch validateUser
3. Risk: 2 direct callers, 2 processes = MEDIUM
```

View file

@ -0,0 +1,113 @@
---
name: gitnexus-refactoring
description: Plan safe refactors using blast radius and dependency mapping
---
# Refactoring with GitNexus
## When to Use
- "Rename this function safely"
- "Extract this into a module"
- "Split this service"
- "Move this to a new file"
- Any task involving renaming, extracting, splitting, or restructuring code
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents
2. gitnexus_query({query: "X"}) → Find execution flows involving X
3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs
4. Plan update order: interfaces → implementations → callers → tests
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklists
### Rename Symbol
```
- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits
- [ ] Review graph edits (high confidence) and ast_search edits (review carefully)
- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits
- [ ] gitnexus_detect_changes() — verify only expected files changed
- [ ] Run tests for affected processes
```
### Extract Module
```
- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs
- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers
- [ ] Define new module interface
- [ ] Extract code, update imports
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
### Split Function/Service
```
- [ ] gitnexus_context({name: target}) — understand all callees
- [ ] Group callees by responsibility
- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update
- [ ] Create new functions/services
- [ ] Update callers
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
## Tools
**gitnexus_rename** — automated multi-file rename:
```
gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits across 8 files
→ 10 graph edits (high confidence), 2 ast_search edits (review)
→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}]
```
**gitnexus_impact** — map all dependents first:
```
gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware, testUtils
→ Affected Processes: LoginFlow, TokenRefresh
```
**gitnexus_detect_changes** — verify your changes after refactoring:
```
gitnexus_detect_changes({scope: "all"})
→ Changed: 8 files, 12 symbols
→ Affected processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM
```
**gitnexus_cypher** — custom reference queries:
```cypher
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"})
RETURN caller.name, caller.filePath ORDER BY caller.filePath
```
## Risk Rules
| Risk Factor | Mitigation |
|-------------|------------|
| Many callers (>5) | Use gitnexus_rename for automated updates |
| Cross-area refs | Use detect_changes after to verify scope |
| String/dynamic refs | gitnexus_query to find them |
| External/public API | Version and deprecate properly |
## Example: Rename `validateUser` to `authenticateUser`
```
1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits: 10 graph (safe), 2 ast_search (review)
→ Files: validator.ts, login.ts, middleware.ts, config.json...
2. Review ast_search edits (config.json: dynamic reference!)
3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false})
→ Applied 12 edits across 8 files
4. gitnexus_detect_changes({scope: "all"})
→ Affected: LoginFlow, TokenRefresh
→ Risk: MEDIUM — run tests for these flows
```

339
gitnexus/APPROACH.md Normal file
View file

@ -0,0 +1,339 @@
# GitNexus: Architecture & Approach
GitNexus is a code intelligence layer that builds a knowledge graph from your repository's structure — functions, classes, call relationships, execution flows — and delivers that context to AI coding agents through two complementary channels: **MCP tools** for explicit deep dives and **hook-based augmentation** that invisibly enriches every search the agent performs.
## Architecture
```mermaid
graph LR
A[gitnexus analyze] -->|parse + index| B[(KuzuDB Graph)]
B --> C[MCP Server]
B --> D[Hook Augmentation]
C -->|tools + resources| E[AI Agent]
D -->|additionalContext on search| E
```
`gitnexus analyze` walks the repository, extracts symbols and relationships using tree-sitter, detects communities with the Leiden algorithm, traces execution flows into processes, and stores everything in a KuzuDB graph database under `.gitnexus/kuzu/`.
The graph is then queryable through two paths:
1. **MCP tools** — the agent calls `query`, `context`, `impact`, etc. explicitly when it needs structural understanding.
2. **Hook augmentation** — a PreToolUse hook fires on every Grep/Glob/Bash search, runs a fast BM25 lookup against the graph, and injects related symbols, callers, callees, and execution flows as `additionalContext`. The agent never asks for this; it just appears alongside search results.
## The Graph
```mermaid
erDiagram
File ||--o{ Function : DEFINES
File ||--o{ Class : DEFINES
File ||--o{ Interface : DEFINES
Class ||--o{ Method : DEFINES
Function ||--o{ Function : CALLS
Method ||--o{ Function : CALLS
Function ||--o{ File : IMPORTS
Class ||--o{ Class : EXTENDS
Class ||--o{ Interface : IMPLEMENTS
Function }o--|| Community : MEMBER_OF
Function }o--|| Process : STEP_IN_PROCESS
```
**Nodes** represent code symbols: `File`, `Folder`, `Function`, `Class`, `Interface`, `Method`, `CodeElement`. Language-specific nodes include `Struct`, `Enum`, `Trait`, `Impl`, etc.
**Edges** use a single `CodeRelation` table with a `type` property:
- `CALLS` — function/method invocation
- `IMPORTS` — file/module import
- `EXTENDS` / `IMPLEMENTS` — inheritance
- `DEFINES` / `CONTAINS` — structural containment
- `MEMBER_OF` — community membership
- `STEP_IN_PROCESS` — participation in an execution flow (with `step` order)
**Communities** are auto-detected functional areas (Leiden algorithm). Each community has a `heuristicLabel` (e.g., "Authentication", "Database") and a `cohesion` score measuring internal connectivity density. Same-label communities are aggregated for display; clusters with fewer than 5 symbols are filtered out.
**Processes** are execution flow traces — ordered sequences of symbols that represent a call chain from entry point to terminal. Each process has a `heuristicLabel`, `processType`, and `stepCount`. A single symbol can participate in multiple processes.
## MCP Tools
| Tool | Purpose |
|------|---------|
| `list_repos` | Discover indexed repositories and their stats |
| `query` | Search for execution flows related to a concept (hybrid BM25 + semantic, grouped by process) |
| `context` | 360-degree view of a single symbol — callers, callees, imports, process participation |
| `impact` | Blast radius analysis — what breaks if you change a symbol, grouped by depth |
| `detect_changes` | Map uncommitted git changes to affected symbols and execution flows |
| `rename` | Multi-file coordinated rename using graph refs + text search fallback |
| `cypher` | Raw Cypher queries against the knowledge graph |
### query
Returns results grouped by process (execution flow), not by file. Hybrid search combines BM25 keyword matching with semantic vector search, merged via Reciprocal Rank Fusion.
```json
{
"processes": [
{ "summary": "UserAuthentication", "priority": 0.033, "symbol_count": 4, "process_type": "request_handler", "step_count": 7 }
],
"process_symbols": [
{ "name": "validateUser", "type": "Function", "filePath": "src/auth/validator.ts", "startLine": 15, "step_index": 3 }
],
"definitions": [
{ "name": "AuthConfig", "type": "Interface", "filePath": "src/auth/types.ts" }
]
}
```
### context
Categorized 360-degree view with disambiguation for common names.
```json
{
"status": "found",
"symbol": { "uid": "Function:src/auth/validator.ts:validateUser", "name": "validateUser", "kind": "Function", "filePath": "src/auth/validator.ts", "startLine": 15, "endLine": 42 },
"incoming": {
"calls": [
{ "uid": "Function:src/routes/login.ts:handleLogin", "name": "handleLogin", "filePath": "src/routes/login.ts" }
],
"imports": [
{ "uid": "File:src/routes/login.ts", "name": "login.ts", "filePath": "src/routes/login.ts" }
]
},
"outgoing": {
"calls": [
{ "uid": "Function:src/db/users.ts:findByEmail", "name": "findByEmail", "filePath": "src/db/users.ts" }
]
},
"processes": [
{ "id": "proc_auth_login", "name": "UserAuthentication", "step_index": 3, "step_count": 7 }
]
}
```
### impact
Blast radius grouped by depth: d=1 will break, d=2 likely affected, d=3 may need testing.
```json
{
"target": { "name": "validateUser", "type": "Function", "filePath": "src/auth/validator.ts" },
"direction": "upstream",
"impactedCount": 5,
"byDepth": {
"1": [{ "name": "handleLogin", "type": "Function", "filePath": "src/routes/login.ts", "relationType": "CALLS", "confidence": 1.0 }],
"2": [{ "name": "authRouter", "type": "Function", "filePath": "src/routes/index.ts", "relationType": "CALLS", "confidence": 1.0 }]
}
}
```
### detect_changes
Maps git diff to indexed symbols and traces which execution flows are impacted.
```json
{
"summary": { "changed_count": 3, "affected_count": 2, "changed_files": 1, "risk_level": "medium" },
"changed_symbols": [
{ "name": "validateUser", "type": "Function", "filePath": "src/auth/validator.ts", "change_type": "Modified" }
],
"affected_processes": [
{ "name": "UserAuthentication", "process_type": "request_handler", "step_count": 7, "changed_steps": [{ "symbol": "validateUser", "step": 3 }] }
]
}
```
### rename
Graph-based rename with text search fallback. Edits tagged by confidence source.
```json
{
"status": "success",
"old_name": "validateUser",
"new_name": "verifyUser",
"files_affected": 4,
"total_edits": 7,
"graph_edits": 5,
"text_search_edits": 2,
"changes": [
{ "file_path": "src/auth/validator.ts", "edits": [{ "line": 15, "old_text": "function validateUser(", "new_text": "function verifyUser(", "confidence": "graph" }] },
{ "file_path": "src/tests/auth.test.ts", "edits": [{ "line": 8, "old_text": "validateUser(testInput)", "new_text": "verifyUser(testInput)", "confidence": "text_search" }] }
],
"applied": false
}
```
## Hook Augmentation
The hook intercepts every search the agent runs and silently enriches it with graph context. The agent doesn't request this — it just sees richer results.
### Flow
```mermaid
sequenceDiagram
participant Agent
participant Claude Code
participant Hook as gitnexus-hook.js
participant CLI as gitnexus augment
participant Graph as KuzuDB
Agent->>Claude Code: Grep { pattern: "validateUser" }
Claude Code->>Hook: PreToolUse event (stdin JSON)
Hook->>Hook: Extract pattern from tool_input
Hook->>CLI: gitnexus augment "validateUser"
CLI->>Graph: BM25 search → symbol lookup → callers/callees/processes
Graph-->>CLI: enriched results
CLI-->>Hook: structured text (stdout)
Hook-->>Claude Code: { additionalContext: "..." }
Claude Code->>Agent: Grep results + additionalContext
```
### What the hook receives
```json
{
"hook_event_name": "PreToolUse",
"tool_name": "Grep",
"tool_input": { "pattern": "validateUser", "path": "src/" },
"cwd": "/home/user/project"
}
```
### What the hook returns
```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "[GitNexus] 3 related symbols found:\n\nvalidateUser (src/auth/validator.ts)\n Called by: handleLogin, authMiddleware\n Calls: findByEmail, hashPassword\n Flows: UserAuthentication (step 3/7)\n\nauthMiddleware (src/middleware/auth.ts)\n Called by: router.use\n Calls: validateUser, getSession\n Flows: RequestPipeline (step 2/5)"
}
}
```
### Before and after
**Without augmentation** — the agent sees only grep matches:
```
src/auth/validator.ts:15: export function validateUser(email: string, password: string) {
src/routes/login.ts:23: const user = await validateUser(req.body.email, req.body.password);
src/tests/auth.test.ts:8: const result = validateUser("test@example.com", "password123");
```
**With augmentation** — the same grep results arrive with additional context appended:
```
src/auth/validator.ts:15: export function validateUser(email: string, password: string) {
src/routes/login.ts:23: const user = await validateUser(req.body.email, req.body.password);
src/tests/auth.test.ts:8: const result = validateUser("test@example.com", "password123");
[GitNexus] 3 related symbols found:
validateUser (src/auth/validator.ts)
Called by: handleLogin, authMiddleware
Calls: findByEmail, hashPassword
Flows: UserAuthentication (step 3/7)
authMiddleware (src/middleware/auth.ts)
Called by: router.use
Calls: validateUser, getSession
Flows: RequestPipeline (step 2/5)
handleLogin (src/routes/login.ts)
Called by: authRouter
Calls: validateUser, createSession
Flows: UserAuthentication (step 4/7)
```
The agent now knows the call chain, related symbols it hasn't searched for yet, and which execution flows are involved — without making any explicit tool call.
### Pattern extraction
The hook extracts search patterns from different tool types:
- **Grep** → uses `pattern` directly
- **Glob** → extracts meaningful name segments from glob patterns
- **Bash** → detects `rg`/`grep` commands and extracts the pattern argument, skipping flags
Patterns shorter than 3 characters are ignored. If no `.gitnexus` index exists in the working directory ancestry, the hook exits silently.
## Internal Ranking
### Clusters as a hidden signal
Communities (clusters) detected by the Leiden algorithm have a `cohesion` score measuring internal connectivity density. This score is used **exclusively as an internal ranking signal** — it is never exposed in tool output or augmentation text.
In `query`, cluster cohesion provides a subtle ranking boost:
```
priority = aggregate_rrf_score + (cohesion * 0.1)
```
In augmentation, results are sorted by their cluster cohesion before formatting. The effect: symbols from tightly-connected functional areas rank higher, but the agent never sees "cluster" or "cohesion" anywhere — it just gets better-ordered results.
### Processes as result grouping
Processes serve as the primary grouping mechanism for `query` results. Instead of returning a flat list of symbol matches, results are organized by execution flow:
1. Hybrid search finds matching symbols
2. Each symbol is traced to its process(es) via `STEP_IN_PROCESS` edges
3. Processes are ranked by aggregate relevance score (with cohesion boost)
4. Results arrive grouped: "here are the execution flows related to your query, with the symbols in each"
Symbols not belonging to any process fall into a `definitions` bucket (types, interfaces, standalone declarations).
## Platform Integration
```mermaid
graph TD
subgraph "gitnexus setup"
S[setup.ts]
end
subgraph Claude Code
S --> CC_MCP["claude mcp add gitnexus"]
S --> CC_HOOKS["~/.claude/settings.json<br/>(PreToolUse hooks)"]
S --> CC_SKILLS["~/.claude/skills/<br/>(exploring, debugging, etc.)"]
end
subgraph "Claude Code Plugin"
P["--plugin-dir gitnexus-claude-plugin/"]
P --> P_HOOKS["hooks/hooks.json<br/>(PreToolUse)"]
P --> P_SKILLS["skills/<br/>(auto-namespaced)"]
end
subgraph Cursor
S --> CU_MCP["~/.cursor/mcp.json"]
S --> CU_SKILLS["~/.cursor/skills/"]
end
subgraph OpenCode
S --> OC_MCP["~/.config/opencode/config.json"]
S --> OC_SKILLS["~/.config/opencode/skill/"]
end
```
**Two install paths for Claude Code:**
1. **`gitnexus setup`** — copies hook scripts to `~/.claude/hooks/gitnexus/`, merges PreToolUse config into `~/.claude/settings.json`, installs skills to `~/.claude/skills/`. Works globally across all projects.
2. **Plugin mode** (`claude --plugin-dir gitnexus-claude-plugin/`) — self-contained directory with `hooks/hooks.json` and skills. Uses `${CLAUDE_PLUGIN_ROOT}` env var for script paths. Skills are auto-namespaced (e.g., `/gitnexus:exploring`).
Both paths install the same 4 skills: `exploring`, `debugging`, `impact-analysis`, `refactoring`.
**Cursor** gets MCP config at `~/.cursor/mcp.json` and skills at `~/.cursor/skills/`.
**OpenCode** gets MCP config at `~/.config/opencode/config.json` and skills at `~/.config/opencode/skill/`.
All MCP entries point to the same server: `npx -y gitnexus@latest mcp`.
## UX Perspective
From the agent's point of view, GitNexus operates on two levels:
**Invisible enrichment** — Every search the agent runs (grep for a function name, glob for a file pattern, bash with ripgrep) gets silently augmented. The agent sees its normal search results plus a `[GitNexus]` block listing related symbols, their callers/callees, and which execution flows they participate in. This happens on every search without the agent doing anything special. The effect is that the agent naturally discovers related code it wouldn't have found from text search alone.
**Explicit tools for deep dives** — When the agent needs structural understanding (not just "find where X is used" but "what happens if I change X"), it uses the MCP tools directly:
- `query` to find execution flows related to a concept
- `context` to get the full picture of a specific symbol
- `impact` to assess blast radius before making changes
- `detect_changes` to understand what uncommitted work affects
- `rename` to safely rename across the codebase with graph-backed confidence
The invisible layer handles the 80% case (richer search context), while the explicit tools handle the 20% (deep structural questions). The agent doesn't need to decide when to use GitNexus for search enrichment — it just happens.

View file

@ -0,0 +1,123 @@
#!/usr/bin/env node
/**
* GitNexus Claude Code Hook
*
* PreToolUse handler intercepts Grep/Glob/Bash searches
* and augments with graph context from the GitNexus index.
*
* NOTE: SessionStart hooks are broken on Windows (Claude Code bug).
* Session context is injected via CLAUDE.md / skills instead.
*/
const fs = require('fs');
const path = require('path');
const { execFileSync } = require('child_process');
/**
* Read JSON input from stdin synchronously.
*/
function readInput() {
try {
const data = fs.readFileSync(0, 'utf-8');
return JSON.parse(data);
} catch {
return {};
}
}
/**
* Check if a directory (or ancestor) has a .gitnexus index.
*/
function findGitNexusIndex(startDir) {
let dir = startDir || process.cwd();
for (let i = 0; i < 5; i++) {
if (fs.existsSync(path.join(dir, '.gitnexus'))) {
return true;
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
return false;
}
/**
* Extract search pattern from tool input.
*/
function extractPattern(toolName, toolInput) {
if (toolName === 'Grep') {
return toolInput.pattern || null;
}
if (toolName === 'Glob') {
const raw = toolInput.pattern || '';
const match = raw.match(/[*\/]([a-zA-Z][a-zA-Z0-9_-]{2,})/);
return match ? match[1] : null;
}
if (toolName === 'Bash') {
const cmd = toolInput.command || '';
if (!/\brg\b|\bgrep\b/.test(cmd)) return null;
const tokens = cmd.split(/\s+/);
let foundCmd = false;
let skipNext = false;
const flagsWithValues = new Set(['-e', '-f', '-m', '-A', '-B', '-C', '-g', '--glob', '-t', '--type', '--include', '--exclude']);
for (const token of tokens) {
if (skipNext) { skipNext = false; continue; }
if (!foundCmd) {
if (/\brg$|\bgrep$/.test(token)) foundCmd = true;
continue;
}
if (token.startsWith('-')) {
if (flagsWithValues.has(token)) skipNext = true;
continue;
}
const cleaned = token.replace(/['"]/g, '');
return cleaned.length >= 3 ? cleaned : null;
}
return null;
}
return null;
}
function main() {
try {
const input = readInput();
const hookEvent = input.hook_event_name || '';
if (hookEvent !== 'PreToolUse') return;
const cwd = input.cwd || process.cwd();
if (!findGitNexusIndex(cwd)) return;
const toolName = input.tool_name || '';
const toolInput = input.tool_input || {};
if (toolName !== 'Grep' && toolName !== 'Glob' && toolName !== 'Bash') return;
const pattern = extractPattern(toolName, toolInput);
if (!pattern || pattern.length < 3) return;
const result = execFileSync(
'gitnexus',
['augment', pattern],
{ encoding: 'utf-8', timeout: 8000, cwd, stdio: ['pipe', 'pipe', 'pipe'] }
);
if (result && result.trim()) {
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'PreToolUse',
additionalContext: result.trim()
}
}));
}
} catch {
// Graceful failure
}
}
main();

View file

@ -0,0 +1,78 @@
#!/bin/bash
# GitNexus PreToolUse hook for Claude Code
# Intercepts Grep/Glob/Bash searches and augments with graph context.
# Receives JSON on stdin with { tool_name, tool_input, cwd, ... }
# Returns JSON with additionalContext for graph-enriched results.
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
# Extract search pattern based on tool type
PATTERN=""
case "$TOOL_NAME" in
Grep)
PATTERN=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
;;
Glob)
# Glob patterns are file paths, not search terms — extract meaningful part
RAW=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty' 2>/dev/null)
# Strip glob syntax to get the meaningful name (e.g., "**/*.ts" → skip, "auth*.ts" → "auth")
PATTERN=$(echo "$RAW" | sed -n 's/.*[*\/]\([a-zA-Z][a-zA-Z0-9_-]*\).*/\1/p')
;;
Bash)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
# Only augment grep/rg commands
if echo "$CMD" | grep -qE '\brg\b|\bgrep\b'; then
# Extract pattern from rg/grep
if echo "$CMD" | grep -qE '\brg\b'; then
PATTERN=$(echo "$CMD" | sed -n "s/.*\brg\s\+\(--[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
elif echo "$CMD" | grep -qE '\bgrep\b'; then
PATTERN=$(echo "$CMD" | sed -n "s/.*\bgrep\s\+\(-[^ ]*\s\+\)*['\"]\\?\([^'\";\| >]*\\).*/\2/p")
fi
fi
;;
*)
# Not a search tool — skip
exit 0
;;
esac
# Skip if pattern too short or empty
if [ -z "$PATTERN" ] || [ ${#PATTERN} -lt 3 ]; then
exit 0
fi
# Check if we're in a GitNexus-indexed repo
dir="${CWD:-$PWD}"
found=false
for i in 1 2 3 4 5; do
if [ -d "$dir/.gitnexus" ]; then
found=true
break
fi
parent="$(dirname "$dir")"
[ "$parent" = "$dir" ] && break
dir="$parent"
done
if [ "$found" = false ]; then
exit 0
fi
# Run gitnexus augment — must be fast (<500ms target)
RESULT=$(cd "$CWD" && npx -y gitnexus augment "$PATTERN" 2>/dev/null)
if [ -n "$RESULT" ]; then
ESCAPED=$(echo "$RESULT" | jq -Rs .)
jq -n --argjson ctx "$ESCAPED" '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
additionalContext: $ctx
}
}'
else
exit 0
fi

View file

@ -0,0 +1,42 @@
#!/bin/bash
# GitNexus SessionStart hook for Claude Code
# Fires on session startup. Stdout is injected into Claude's context.
# Checks if the current directory has a GitNexus index.
dir="$PWD"
found=false
for i in 1 2 3 4 5; do
if [ -d "$dir/.gitnexus" ]; then
found=true
break
fi
parent="$(dirname "$dir")"
[ "$parent" = "$dir" ] && break
dir="$parent"
done
if [ "$found" = false ]; then
exit 0
fi
# Inject GitNexus context — this stdout goes directly into Claude's context
cat << 'EOF'
## GitNexus Code Intelligence
This codebase is indexed by GitNexus, providing a knowledge graph with execution flows, relationships, and semantic search.
**Available MCP Tools:**
- `query` — Process-grouped code intelligence (execution flows related to a concept)
- `context` — 360-degree symbol view (categorized refs, process participation)
- `impact` — Blast radius analysis (what breaks if you change a symbol)
- `detect_changes` — Git-diff impact analysis (what do your changes affect)
- `rename` — Multi-file coordinated rename with confidence tags
- `cypher` — Raw graph queries
- `list_repos` — Discover indexed repos
**Quick Start:** READ `gitnexus://repo/{name}/context` for codebase overview, then use `query` to find execution flows.
**Resources:** `gitnexus://repo/{name}/context` (overview), `/processes` (execution flows), `/schema` (for Cypher)
EOF
exit 0

View file

@ -31,6 +31,7 @@
},
"files": [
"dist",
"hooks",
"skills",
"vendor"
],

View file

@ -15,8 +15,8 @@ description: Trace bugs through call chains using knowledge graph
## Workflow
```
1. gitnexus_search({query: "<error or symptom>"}) → Find related code
2. gitnexus_explore({name: "<suspect>", type: "symbol"}) → See callers/callees
1. gitnexus_query({query: "<error or symptom>"}) → Find related execution flows
2. gitnexus_context({name: "<suspect>"}) → See callers/callees/processes
3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow
4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed
```
@ -27,9 +27,9 @@ description: Trace bugs through call chains using knowledge graph
```
- [ ] Understand the symptom (error message, unexpected behavior)
- [ ] gitnexus_search for error text or related code
- [ ] Identify the suspect function
- [ ] gitnexus_explore to see callers and callees
- [ ] gitnexus_query for error text or related code
- [ ] Identify the suspect function from returned processes
- [ ] gitnexus_context to see callers and callees
- [ ] Trace execution flow via process resource if applicable
- [ ] gitnexus_cypher for custom call chain traces if needed
- [ ] Read source files to confirm root cause
@ -39,26 +39,27 @@ description: Trace bugs through call chains using knowledge graph
| Symptom | GitNexus Approach |
|---------|-------------------|
| Error message | `gitnexus_search` for error text → `explore` throw sites |
| Wrong return value | `explore` the function → trace callees for data flow |
| Intermittent failure | `explore` → look for external calls, async deps |
| Performance issue | `explore` → find symbols with many callers (hot paths) |
| Recent regression | `gitnexus_impact` on recently changed symbols |
| Error message | `gitnexus_query` for error text → `context` on throw sites |
| Wrong return value | `context` on the function → trace callees for data flow |
| Intermittent failure | `context` → look for external calls, async deps |
| Performance issue | `context` → find symbols with many callers (hot paths) |
| Recent regression | `detect_changes` to see what your changes affect |
## Tools
**gitnexus_search** — find code related to error:
**gitnexus_query** — find code related to error:
```
gitnexus_search({query: "payment validation error", depth: "full"})
→ validatePayment, handlePaymentError, PaymentException
gitnexus_query({query: "payment validation error"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError, PaymentException
```
**gitnexus_explore** — full context for a suspect:
**gitnexus_context** — full context for a suspect:
```
gitnexus_explore({name: "validatePayment", type: "symbol"})
Callers: processCheckout, webhookHandler
Callees: verifyCard, fetchRates (external API!)
Cluster: Payment
gitnexus_context({name: "validatePayment"})
Incoming calls: processCheckout, webhookHandler
Outgoing calls: verifyCard, fetchRates (external API!)
Processes: CheckoutFlow (step 3/7)
```
**gitnexus_cypher** — custom call chain traces:
@ -70,11 +71,12 @@ RETURN [n IN nodes(path) | n.name] AS chain
## Example: "Payment endpoint returns 500 intermittently"
```
1. gitnexus_search({query: "payment error handling"})
→ validatePayment, handlePaymentError, PaymentException
1. gitnexus_query({query: "payment error handling"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError
2. gitnexus_explore({name: "validatePayment", type: "symbol"})
Callees: verifyCard, fetchRates (external API!)
2. gitnexus_context({name: "validatePayment"})
Outgoing calls: verifyCard, fetchRates (external API!)
3. READ gitnexus://repo/my-app/process/CheckoutFlow
→ Step 3: validatePayment → calls fetchRates (external)

View file

@ -17,9 +17,9 @@ description: Navigate unfamiliar code using GitNexus knowledge graph
```
1. READ gitnexus://repos → Discover indexed repos
2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness
3. READ gitnexus://repo/{name}/clusters → See all functional areas
4. READ gitnexus://repo/{name}/cluster/{name} → Drill into relevant cluster
5. gitnexus_explore({name, type: "symbol"}) → Deep dive on specific symbol
3. gitnexus_query({query: "<what you want to understand>"}) → Find related execution flows
4. gitnexus_context({name: "<symbol>"}) → Deep dive on specific symbol
5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow
```
> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal.
@ -27,12 +27,11 @@ description: Navigate unfamiliar code using GitNexus knowledge graph
## Checklist
```
- [ ] READ gitnexus://repos
- [ ] READ gitnexus://repo/{name}/context
- [ ] READ gitnexus://repo/{name}/clusters
- [ ] Identify the relevant cluster
- [ ] READ gitnexus://repo/{name}/cluster/{name}
- [ ] gitnexus_explore for key symbols
- [ ] gitnexus_query for the concept you want to understand
- [ ] Review returned processes (execution flows)
- [ ] gitnexus_context on key symbols for callers/callees
- [ ] READ process resource for full execution traces
- [ ] Read source files for implementation details
```
@ -41,33 +40,36 @@ description: Navigate unfamiliar code using GitNexus knowledge graph
| Resource | What you get |
|----------|-------------|
| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) |
| `gitnexus://repo/{name}/clusters` | All clusters with cohesion scores (~300 tokens) |
| `gitnexus://repo/{name}/cluster/{name}` | Cluster members with file paths (~500 tokens) |
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) |
| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) |
| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) |
## Tools
**gitnexus_explore** — symbol context with callers/callees:
**gitnexus_query** — find execution flows related to a concept:
```
gitnexus_explore({name: "validateUser", type: "symbol"})
→ Callers: loginHandler, apiMiddleware
→ Callees: checkToken, getUserById
→ Cluster: Auth (92% cohesion)
gitnexus_query({query: "payment processing"})
→ Processes: CheckoutFlow, RefundFlow, WebhookHandler
→ Symbols grouped by flow with file locations
```
**gitnexus_search** — find code by query when you don't know the cluster:
**gitnexus_context** — 360-degree view of a symbol:
```
gitnexus_search({query: "payment validation", depth: "full"})
gitnexus_context({name: "validateUser"})
→ Incoming calls: loginHandler, apiMiddleware
→ Outgoing calls: checkToken, getUserById
→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3)
```
## Example: "How does payment processing work?"
```
1. READ gitnexus://repo/my-app/context → 918 symbols, 12 clusters
2. READ gitnexus://repo/my-app/clusters → Auth, Payment, Database, API...
3. READ gitnexus://repo/my-app/cluster/Payment → processPayment, validateCard, PaymentService
4. gitnexus_explore({name: "processPayment", type: "symbol"})
→ Callers: checkoutHandler, webhookHandler
→ Callees: validateCard, chargeStripe, saveTransaction
5. Read src/payments/processor.ts for implementation details
1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes
2. gitnexus_query({query: "payment processing"})
→ CheckoutFlow: processPayment → validateCard → chargeStripe
→ RefundFlow: initiateRefund → calculateRefund → processRefund
3. gitnexus_context({name: "processPayment"})
→ Incoming: checkoutHandler, webhookHandler
→ Outgoing: validateCard, chargeStripe, saveTransaction
4. Read src/payments/processor.ts for implementation details
```

View file

@ -11,13 +11,14 @@ description: Analyze blast radius before making code changes
- "Show me the blast radius"
- "Who uses this code?"
- Before making non-trivial code changes
- Before committing — to understand what your changes affect
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this
2. READ gitnexus://repo/{name}/clusters → Check which areas are affected
3. READ gitnexus://repo/{name}/processes → Check affected execution flows
2. READ gitnexus://repo/{name}/processes → Check affected execution flows
3. gitnexus_detect_changes() → Map current git changes to affected flows
4. Assess risk and report to user
```
@ -29,9 +30,8 @@ description: Analyze blast radius before making code changes
- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents
- [ ] Review d=1 items first (these WILL BREAK)
- [ ] Check high-confidence (>0.8) dependencies
- [ ] READ clusters to understand which areas are affected
- [ ] Count affected clusters (cross-cutting = higher risk)
- [ ] READ processes to check affected execution flows
- [ ] gitnexus_detect_changes() for pre-commit check
- [ ] Assess risk level and report to user
```
@ -47,14 +47,14 @@ description: Analyze blast radius before making code changes
| Affected | Risk |
|----------|------|
| <5 symbols, 1 cluster | LOW |
| 5-15 symbols, 1-2 clusters | MEDIUM |
| >15 symbols or 3+ clusters | HIGH |
| <5 symbols, few processes | LOW |
| 5-15 symbols, 2-5 processes | MEDIUM |
| >15 symbols or many processes | HIGH |
| Critical path (auth, payments) | CRITICAL |
## Tools
**gitnexus_impact** — the primary tool:
**gitnexus_impact** — the primary tool for symbol blast radius:
```
gitnexus_impact({
target: "validateUser",
@ -69,9 +69,15 @@ gitnexus_impact({
→ d=2 (LIKELY AFFECTED):
- authRouter (src/routes/auth.ts:22) [CALLS, 95%]
```
→ Affected Processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM (3 processes)
**gitnexus_detect_changes** — git-diff based impact analysis:
```
gitnexus_detect_changes({scope: "staged"})
→ Changed: 5 symbols in 3 files
→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline
→ Risk: MEDIUM
```
## Example: "What breaks if I change validateUser?"
@ -81,8 +87,8 @@ gitnexus_impact({
→ d=1: loginHandler, apiMiddleware (WILL BREAK)
→ d=2: authRouter, sessionManager (LIKELY AFFECTED)
2. READ gitnexus://repo/my-app/clusters
Auth and API clusters affected (2 clusters)
2. READ gitnexus://repo/my-app/processes
LoginFlow and TokenRefresh touch validateUser
3. Risk: 2 direct callers, 2 clusters = MEDIUM
3. Risk: 2 direct callers, 2 processes = MEDIUM
```

View file

@ -16,8 +16,8 @@ description: Plan safe refactors using blast radius and dependency mapping
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents
2. gitnexus_search({query: "X"}) → Find string/dynamic references
3. READ gitnexus://repo/{name}/cluster/{name} → Check cohesion impact
2. gitnexus_query({query: "X"}) → Find execution flows involving X
3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs
4. Plan update order: interfaces → implementations → callers → tests
```
@ -27,36 +27,44 @@ description: Plan safe refactors using blast radius and dependency mapping
### Rename Symbol
```
- [ ] gitnexus_impact({target: oldName, direction: "upstream"}) — find all callers
- [ ] gitnexus_search({query: oldName}) — find string literals and dynamic references
- [ ] Check for reflection/dynamic invocation patterns
- [ ] Plan update order: interface → implementation → callers → tests
- [ ] Update all d=1 (WILL BREAK) items
- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits
- [ ] Review graph edits (high confidence) and ast_search edits (review carefully)
- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits
- [ ] gitnexus_detect_changes() — verify only expected files changed
- [ ] Run tests for affected processes
```
### Extract Module
```
- [ ] gitnexus_explore({name: target, type: "symbol"}) — map internal dependencies
- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs
- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers
- [ ] READ cluster resource — check if extraction preserves cohesion
- [ ] Define new module interface
- [ ] Extract code, update imports
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
### Split Function/Service
```
- [ ] gitnexus_explore({name: target, type: "symbol"}) — understand all callees
- [ ] Group callees by responsibility/domain
- [ ] gitnexus_context({name: target}) — understand all callees
- [ ] Group callees by responsibility
- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update
- [ ] Create new functions/services
- [ ] Update callers
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
## Tools
**gitnexus_rename** — automated multi-file rename:
```
gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits across 8 files
→ 10 graph edits (high confidence), 2 ast_search edits (review)
→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}]
```
**gitnexus_impact** — map all dependents first:
```
gitnexus_impact({target: "validateUser", direction: "upstream"})
@ -64,10 +72,12 @@ gitnexus_impact({target: "validateUser", direction: "upstream"})
→ Affected Processes: LoginFlow, TokenRefresh
```
**gitnexus_search** — find string/dynamic references impact() might miss:
**gitnexus_detect_changes** — verify your changes after refactoring:
```
gitnexus_search({query: "validateUser"})
→ Found in: config.json (dynamic reference!), test fixtures
gitnexus_detect_changes({scope: "all"})
→ Changed: 8 files, 12 symbols
→ Affected processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM
```
**gitnexus_cypher** — custom reference queries:
@ -80,23 +90,24 @@ RETURN caller.name, caller.filePath ORDER BY caller.filePath
| Risk Factor | Mitigation |
|-------------|------------|
| Many callers (>5) | Update in small batches |
| Cross-cluster refs | Coordinate with affected areas |
| String/dynamic refs | `gitnexus_search` to find them |
| Many callers (>5) | Use gitnexus_rename for automated updates |
| Cross-area refs | Use detect_changes after to verify scope |
| String/dynamic refs | gitnexus_query to find them |
| External/public API | Version and deprecate properly |
## Example: Rename `validateUser` to `authenticateUser`
```
1. gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware, testUtils
1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits: 10 graph (safe), 2 ast_search (review)
→ Files: validator.ts, login.ts, middleware.ts, config.json...
2. gitnexus_search({query: "validateUser"})
→ Found in: config.json (dynamic reference!)
2. Review ast_search edits (config.json: dynamic reference!)
3. Plan update order:
1. Update declaration in src/auth/validator.ts
2. Update config.json string reference
3. Update loginHandler, apiMiddleware, testUtils
4. Run tests for LoginFlow, TokenRefresh
3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false})
→ Applied 12 edits across 8 files
4. gitnexus_detect_changes({scope: "all"})
→ Affected: LoginFlow, TokenRefresh
→ Risk: MEDIUM — run tests for these flows
```

View file

@ -37,13 +37,12 @@ const GITNEXUS_END_MARKER = '<!-- gitnexus:end -->';
* - Tools/Resources sections are labeled "Reference" agents treat them as lookup, not workflow
*/
function generateGitNexusContent(projectName: string, stats: RepoStats): string {
const clusterCount = stats.clusters || stats.communities || 0;
return `${GITNEXUS_START_MARKER}
# GitNexus MCP
This project is indexed by GitNexus as **${projectName}** (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${clusterCount} clusters, ${stats.processes || 0} processes).
This project is indexed by GitNexus as **${projectName}** (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${stats.processes || 0} execution flows).
GitNexus provides a knowledge graph over this codebase clusters, call chains, blast radius, execution flows, and semantic search.
GitNexus provides a knowledge graph over this codebase call chains, blast radius, execution flows, and semantic search.
## Always Start Here
@ -68,10 +67,11 @@ For any task involving code understanding, debugging, impact analysis, or refact
| Tool | What it gives you |
|------|-------------------|
| \`search\` | Semantic + keyword code search with cluster context |
| \`explore\` | Symbol deep dive — callers, callees, cluster membership, processes |
| \`impact\` | Blast radius — what breaks at depth 1/2/3 with confidence scores |
| \`overview\` | All clusters and processes at a glance |
| \`query\` | Process-grouped code intelligence — execution flows related to a concept |
| \`context\` | 360-degree symbol view — categorized refs, processes it participates in |
| \`impact\` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |
| \`detect_changes\` | Git-diff impact — what do your current changes affect |
| \`rename\` | Multi-file coordinated rename with confidence-tagged edits |
| \`cypher\` | Raw graph queries (read \`gitnexus://repo/{name}/schema\` first) |
| \`list_repos\` | Discover indexed repos |
@ -82,8 +82,8 @@ Lightweight reads (~100-500 tokens) for navigation:
| Resource | Content |
|----------|---------|
| \`gitnexus://repo/{name}/context\` | Stats, staleness check |
| \`gitnexus://repo/{name}/clusters\` | All clusters with cohesion scores |
| \`gitnexus://repo/{name}/cluster/{clusterName}\` | Cluster members |
| \`gitnexus://repo/{name}/clusters\` | All functional areas with cohesion scores |
| \`gitnexus://repo/{name}/cluster/{clusterName}\` | Area members |
| \`gitnexus://repo/{name}/processes\` | All execution flows |
| \`gitnexus://repo/{name}/process/{processName}\` | Step-by-step trace |
| \`gitnexus://repo/{name}/schema\` | Graph schema for Cypher |

View file

@ -0,0 +1,32 @@
/**
* Augment CLI Command
*
* Fast-path command for platform hooks.
* Shells out from Claude Code PreToolUse / Cursor beforeShellExecution hooks.
*
* Usage: gitnexus augment <pattern>
* Returns enriched text to stdout.
*
* Performance: Must cold-start fast (<500ms).
* Skips unnecessary initialization (no web server, no full DB warmup).
*/
import { augment } from '../core/augmentation/engine.js';
export async function augmentCommand(pattern: string): Promise<void> {
if (!pattern || pattern.length < 3) {
// Too short to be useful — exit silently
process.exit(0);
}
try {
const result = await augment(pattern, process.cwd());
if (result) {
process.stdout.write(result + '\n');
}
} catch {
// Graceful failure — never break the calling hook
process.exit(0);
}
}

View file

@ -7,6 +7,7 @@ import { statusCommand } from './status.js';
import { mcpCommand } from './mcp.js';
import { cleanCommand } from './clean.js';
import { setupCommand } from './setup.js';
import { augmentCommand } from './augment.js';
const program = new Command();
program
@ -54,4 +55,9 @@ program
.option('--all', 'Clean all indexed repos')
.action(cleanCommand);
program
.command('augment <pattern>')
.description('Augment a search pattern with knowledge graph context (used by hooks)')
.action(augmentCommand);
program.parse(process.argv);

View file

@ -9,8 +9,12 @@
import fs from 'fs/promises';
import path from 'path';
import os from 'os';
import { fileURLToPath } from 'url';
import { getGlobalDir } from '../storage/repo-manager.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
interface SetupResult {
configured: string[];
skipped: string[];
@ -95,8 +99,6 @@ async function setupCursor(result: SetupResult): Promise<void> {
}
async function setupClaudeCode(result: SetupResult): Promise<void> {
// Claude Code uses `claude mcp add` — we just print the command
// Check for common Claude Code indicators
const claudeDir = path.join(os.homedir(), '.claude');
const hasClaude = await dirExists(claudeDir);
@ -107,11 +109,90 @@ async function setupClaudeCode(result: SetupResult): Promise<void> {
// Claude Code uses a JSON settings file at ~/.claude.json or claude mcp add
console.log('');
console.log(' Claude Code detected. Run this command to add GitNexus:');
console.log(' Claude Code detected. Run this command to add GitNexus MCP:');
console.log('');
console.log(' claude mcp add gitnexus -- npx -y gitnexus mcp');
console.log('');
result.configured.push('Claude Code (manual step printed)');
result.configured.push('Claude Code (MCP manual step printed)');
}
/**
* Install GitNexus skills to ~/.claude/skills/ for Claude Code.
*/
async function installClaudeCodeSkills(result: SetupResult): Promise<void> {
const claudeDir = path.join(os.homedir(), '.claude');
if (!(await dirExists(claudeDir))) return;
const skillsDir = path.join(claudeDir, 'skills');
try {
const installed = await installSkillsTo(skillsDir);
if (installed.length > 0) {
result.configured.push(`Claude Code skills (${installed.length} skills → ~/.claude/skills/)`);
}
} catch (err: any) {
result.errors.push(`Claude Code skills: ${err.message}`);
}
}
/**
* Install GitNexus hooks to ~/.claude/settings.json for Claude Code.
* Merges hook config without overwriting existing hooks.
*/
async function installClaudeCodeHooks(result: SetupResult): Promise<void> {
const claudeDir = path.join(os.homedir(), '.claude');
if (!(await dirExists(claudeDir))) return;
const settingsPath = path.join(claudeDir, 'settings.json');
// Source hooks bundled within the gitnexus package (hooks/claude/)
const pluginHooksPath = path.join(__dirname, '..', '..', 'hooks', 'claude');
// Copy unified hook script to ~/.claude/hooks/gitnexus/
const destHooksDir = path.join(claudeDir, 'hooks', 'gitnexus');
try {
await fs.mkdir(destHooksDir, { recursive: true });
const src = path.join(pluginHooksPath, 'gitnexus-hook.js');
const dest = path.join(destHooksDir, 'gitnexus-hook.js');
try {
const content = await fs.readFile(src, 'utf-8');
await fs.writeFile(dest, content, 'utf-8');
} catch {
// Script not found in source — skip
}
const hookCmd = `node "${path.join(destHooksDir, 'gitnexus-hook.js').replace(/\\/g, '/')}"`;
// Merge hook config into ~/.claude/settings.json
const existing = await readJsonFile(settingsPath) || {};
if (!existing.hooks) existing.hooks = {};
// NOTE: SessionStart hooks are broken on Windows (Claude Code bug #23576).
// Session context is delivered via CLAUDE.md / skills instead.
// Add PreToolUse hook if not already present
if (!existing.hooks.PreToolUse) existing.hooks.PreToolUse = [];
const hasPreToolHook = existing.hooks.PreToolUse.some(
(h: any) => h.hooks?.some((hh: any) => hh.command?.includes('gitnexus'))
);
if (!hasPreToolHook) {
existing.hooks.PreToolUse.push({
matcher: 'Grep|Glob|Bash',
hooks: [{
type: 'command',
command: hookCmd,
timeout: 10,
statusMessage: 'Enriching with GitNexus graph context...',
}],
});
}
await writeJsonFile(settingsPath, existing);
result.configured.push('Claude Code hooks (PreToolUse)');
} catch (err: any) {
result.errors.push(`Claude Code hooks: ${err.message}`);
}
}
async function setupOpenCode(result: SetupResult): Promise<void> {
@ -134,6 +215,72 @@ async function setupOpenCode(result: SetupResult): Promise<void> {
}
}
// ─── Skill Installation ───────────────────────────────────────────
const SKILL_NAMES = ['exploring', 'debugging', 'impact-analysis', 'refactoring'];
/**
* Install GitNexus skills to a target directory.
* Each skill is installed as {targetDir}/gitnexus-{skillName}/SKILL.md
* following the Agent Skills standard (both Cursor and Claude Code).
*/
async function installSkillsTo(targetDir: string): Promise<string[]> {
const installed: string[] = [];
for (const skillName of SKILL_NAMES) {
const sourcePath = path.join(__dirname, '..', '..', 'skills', `${skillName}.md`);
const skillDir = path.join(targetDir, `gitnexus-${skillName}`);
const destPath = path.join(skillDir, 'SKILL.md');
try {
const content = await fs.readFile(sourcePath, 'utf-8');
await fs.mkdir(skillDir, { recursive: true });
await fs.writeFile(destPath, content, 'utf-8');
installed.push(skillName);
} catch {
// Source skill file not found — skip
}
}
return installed;
}
/**
* Install global Cursor skills to ~/.cursor/skills/gitnexus/
*/
async function installCursorSkills(result: SetupResult): Promise<void> {
const cursorDir = path.join(os.homedir(), '.cursor');
if (!(await dirExists(cursorDir))) return;
const skillsDir = path.join(cursorDir, 'skills');
try {
const installed = await installSkillsTo(skillsDir);
if (installed.length > 0) {
result.configured.push(`Cursor skills (${installed.length} skills → ~/.cursor/skills/)`);
}
} catch (err: any) {
result.errors.push(`Cursor skills: ${err.message}`);
}
}
/**
* Install global OpenCode skills to ~/.config/opencode/skill/gitnexus/
*/
async function installOpenCodeSkills(result: SetupResult): Promise<void> {
const opencodeDir = path.join(os.homedir(), '.config', 'opencode');
if (!(await dirExists(opencodeDir))) return;
const skillsDir = path.join(opencodeDir, 'skill');
try {
const installed = await installSkillsTo(skillsDir);
if (installed.length > 0) {
result.configured.push(`OpenCode skills (${installed.length} skills → ~/.config/opencode/skill/)`);
}
} catch (err: any) {
result.errors.push(`OpenCode skills: ${err.message}`);
}
}
// ─── Main command ──────────────────────────────────────────────────
export const setupCommand = async () => {
@ -152,10 +299,16 @@ export const setupCommand = async () => {
errors: [],
};
// Detect and configure each editor
// Detect and configure each editor's MCP
await setupCursor(result);
await setupClaudeCode(result);
await setupOpenCode(result);
// Install global skills for platforms that support them
await installClaudeCodeSkills(result);
await installClaudeCodeHooks(result);
await installCursorSkills(result);
await installOpenCodeSkills(result);
// Print results
if (result.configured.length > 0) {
@ -181,6 +334,10 @@ export const setupCommand = async () => {
}
}
console.log('');
console.log(' Summary:');
console.log(` MCP configured for: ${result.configured.filter(c => !c.includes('skills')).join(', ') || 'none'}`);
console.log(` Skills installed to: ${result.configured.filter(c => c.includes('skills')).length > 0 ? result.configured.filter(c => c.includes('skills')).join(', ') : 'none'}`);
console.log('');
console.log(' Next steps:');
console.log(' 1. cd into any git repo');

View file

@ -0,0 +1,222 @@
/**
* Augmentation Engine
*
* Lightweight, fast-path enrichment of search patterns with knowledge graph context.
* Designed to be called from platform hooks (Claude Code PreToolUse, Cursor beforeShellExecution)
* when an agent runs grep/glob/search.
*
* Performance target: <500ms cold start, <200ms warm.
*
* Design decisions:
* - Uses only BM25 search (no semantic/embedding) for speed
* - Clusters used internally for ranking, NEVER in output
* - Output is pure relationships: callers, callees, process participation
* - Graceful failure: any error return empty string
*/
import path from 'path';
import { listRegisteredRepos } from '../../storage/repo-manager.js';
/**
* Find the best matching repo for a given working directory.
* Matches by checking if cwd is within the repo's path.
*/
async function findRepoForCwd(cwd: string): Promise<{
name: string;
storagePath: string;
kuzuPath: string;
} | null> {
try {
const entries = await listRegisteredRepos({ validate: true });
const resolved = path.resolve(cwd);
// Find the repo whose path contains (or is) the cwd
for (const entry of entries) {
const repoResolved = path.resolve(entry.path);
if (resolved.startsWith(repoResolved) || repoResolved.startsWith(resolved)) {
return {
name: entry.name,
storagePath: entry.storagePath,
kuzuPath: path.join(entry.storagePath, 'kuzu'),
};
}
}
return null;
} catch {
return null;
}
}
/**
* Augment a search pattern with knowledge graph context.
*
* 1. BM25 search for the pattern
* 2. For top matches, fetch callers/callees/processes
* 3. Rank by internal cluster cohesion (not exposed)
* 4. Format as structured text block
*
* Returns empty string on any error (graceful failure).
*/
export async function augment(pattern: string, cwd?: string): Promise<string> {
if (!pattern || pattern.length < 3) return '';
const workDir = cwd || process.cwd();
try {
const repo = await findRepoForCwd(workDir);
if (!repo) return '';
// Lazy-load kuzu adapter (skip unnecessary init)
const { initKuzu, executeQuery, isKuzuReady } = await import('../../mcp/core/kuzu-adapter.js');
const { searchFTSFromKuzu } = await import('../search/bm25-index.js');
const repoId = repo.name.toLowerCase();
// Init KuzuDB if not already
if (!isKuzuReady(repoId)) {
await initKuzu(repoId, repo.kuzuPath);
}
// Step 1: BM25 search (fast, no embeddings)
const bm25Results = await searchFTSFromKuzu(pattern, 10, repoId);
if (bm25Results.length === 0) return '';
// Step 2: Map BM25 file results to symbols
const symbolMatches: Array<{
nodeId: string;
name: string;
type: string;
filePath: string;
score: number;
}> = [];
for (const result of bm25Results.slice(0, 5)) {
const escaped = result.filePath.replace(/'/g, "''");
try {
const symbols = await executeQuery(repoId, `
MATCH (n) WHERE n.filePath = '${escaped}'
AND n.name CONTAINS '${pattern.replace(/'/g, "''").split(/\s+/)[0]}'
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
LIMIT 3
`);
for (const sym of symbols) {
symbolMatches.push({
nodeId: sym.id || sym[0],
name: sym.name || sym[1],
type: sym.type || sym[2],
filePath: sym.filePath || sym[3],
score: result.score,
});
}
} catch { /* skip */ }
}
if (symbolMatches.length === 0) return '';
// Step 3: For top matches, fetch callers/callees/processes
// Also get cluster cohesion internally for ranking
const enriched: Array<{
name: string;
filePath: string;
callers: string[];
callees: string[];
processes: string[];
cohesion: number;
}> = [];
const seen = new Set<string>();
for (const sym of symbolMatches.slice(0, 5)) {
if (seen.has(sym.nodeId)) continue;
seen.add(sym.nodeId);
const escaped = sym.nodeId.replace(/'/g, "''");
// Callers
let callers: string[] = [];
try {
const rows = await executeQuery(repoId, `
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(n {id: '${escaped}'})
RETURN caller.name AS name
LIMIT 3
`);
callers = rows.map((r: any) => r.name || r[0]).filter(Boolean);
} catch { /* skip */ }
// Callees
let callees: string[] = [];
try {
const rows = await executeQuery(repoId, `
MATCH (n {id: '${escaped}'})-[:CodeRelation {type: 'CALLS'}]->(callee)
RETURN callee.name AS name
LIMIT 3
`);
callees = rows.map((r: any) => r.name || r[0]).filter(Boolean);
} catch { /* skip */ }
// Processes
let processes: string[] = [];
try {
const rows = await executeQuery(repoId, `
MATCH (n {id: '${escaped}'})-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
RETURN p.heuristicLabel AS label, r.step AS step, p.stepCount AS stepCount
`);
processes = rows.map((r: any) => {
const label = r.label || r[0];
const step = r.step || r[1];
const stepCount = r.stepCount || r[2];
return `${label} (step ${step}/${stepCount})`;
}).filter(Boolean);
} catch { /* skip */ }
// Cluster cohesion (internal ranking signal)
let cohesion = 0;
try {
const rows = await executeQuery(repoId, `
MATCH (n {id: '${escaped}'})-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
RETURN c.cohesion AS cohesion
LIMIT 1
`);
if (rows.length > 0) {
cohesion = (rows[0].cohesion ?? rows[0][0]) || 0;
}
} catch { /* skip */ }
enriched.push({
name: sym.name,
filePath: sym.filePath,
callers,
callees,
processes,
cohesion,
});
}
if (enriched.length === 0) return '';
// Step 4: Rank by cohesion (internal signal) and format
enriched.sort((a, b) => b.cohesion - a.cohesion);
const lines: string[] = [`[GitNexus] ${enriched.length} related symbols found:`, ''];
for (const item of enriched) {
lines.push(`${item.name} (${item.filePath})`);
if (item.callers.length > 0) {
lines.push(` Called by: ${item.callers.join(', ')}`);
}
if (item.callees.length > 0) {
lines.push(` Calls: ${item.callees.join(', ')}`);
}
if (item.processes.length > 0) {
lines.push(` Flows: ${item.processes.join(', ')}`);
}
lines.push('');
}
return lines.join('\n').trim();
} catch {
// Graceful failure — never break the original tool
return '';
}
}

File diff suppressed because it is too large Load diff

View file

@ -25,46 +25,21 @@ export interface ResourceTemplate {
/**
* Static resources includes per-repo resources and the global repos list
*/
export function getResourceDefinitions(backend: LocalBackend): ResourceDefinition[] {
const resources: ResourceDefinition[] = [
export function getResourceDefinitions(): ResourceDefinition[] {
return [
{
uri: 'gitnexus://repos',
name: 'All Indexed Repositories',
description: 'List of all indexed repos with stats. Read this first to discover available repos.',
mimeType: 'text/yaml',
},
{
uri: 'gitnexus://setup',
name: 'GitNexus Setup Content',
description: 'Returns AGENTS.md content for all indexed repos. Useful for setup/onboarding.',
mimeType: 'text/markdown',
},
];
// Add per-repo context resources
const repos = backend.listRepos();
for (const repo of repos) {
resources.push({
uri: `gitnexus://repo/${repo.name}/context`,
name: `${repo.name} Overview`,
description: `Codebase stats and available tools for ${repo.name}`,
mimeType: 'text/yaml',
});
resources.push({
uri: `gitnexus://repo/${repo.name}/clusters`,
name: `${repo.name} Clusters`,
description: `All functional clusters for ${repo.name}`,
mimeType: 'text/yaml',
});
resources.push({
uri: `gitnexus://repo/${repo.name}/processes`,
name: `${repo.name} Processes`,
description: `All execution flows for ${repo.name}`,
mimeType: 'text/yaml',
});
resources.push({
uri: `gitnexus://repo/${repo.name}/schema`,
name: `${repo.name} Schema`,
description: `Graph schema for Cypher queries on ${repo.name}`,
mimeType: 'text/yaml',
});
}
return resources;
}
/**
@ -72,10 +47,34 @@ export function getResourceDefinitions(backend: LocalBackend): ResourceDefinitio
*/
export function getResourceTemplates(): ResourceTemplate[] {
return [
{
uriTemplate: 'gitnexus://repo/{name}/context',
name: 'Repo Overview',
description: 'Codebase stats, staleness check, and available tools',
mimeType: 'text/yaml',
},
{
uriTemplate: 'gitnexus://repo/{name}/clusters',
name: 'Repo Modules',
description: 'All functional areas (Leiden clusters)',
mimeType: 'text/yaml',
},
{
uriTemplate: 'gitnexus://repo/{name}/processes',
name: 'Repo Processes',
description: 'All execution flows',
mimeType: 'text/yaml',
},
{
uriTemplate: 'gitnexus://repo/{name}/schema',
name: 'Graph Schema',
description: 'Node/edge schema for Cypher queries',
mimeType: 'text/yaml',
},
{
uriTemplate: 'gitnexus://repo/{name}/cluster/{clusterName}',
name: 'Cluster Detail',
description: 'Deep dive into a specific cluster',
name: 'Module Detail',
description: 'Deep dive into a specific functional area',
mimeType: 'text/yaml',
},
{
@ -92,6 +91,7 @@ export function getResourceTemplates(): ResourceTemplate[] {
*/
function parseUri(uri: string): { repoName?: string; resourceType: string; param?: string } {
if (uri === 'gitnexus://repos') return { resourceType: 'repos' };
if (uri === 'gitnexus://setup') return { resourceType: 'setup' };
// Repo-scoped: gitnexus://repo/{name}/context
const repoMatch = uri.match(/^gitnexus:\/\/repo\/([^/]+)\/(.+)$/);
@ -122,6 +122,11 @@ export async function readResource(uri: string, backend: LocalBackend): Promise<
if (parsed.resourceType === 'repos') {
return getReposResource(backend);
}
// Setup resource — returns AGENTS.md content for all repos
if (parsed.resourceType === 'setup') {
return getSetupResource(backend);
}
const repoName = parsed.repoName;
@ -194,15 +199,6 @@ async function getContextResource(backend: LocalBackend, repoName?: string): Pro
const repoPath = repo.repoPath;
const lastCommit = repo.lastCommit || 'HEAD';
const staleness = repoPath ? checkStaleness(repoPath, lastCommit) : { isStale: false, commitsBehind: 0 };
// Get aggregated cluster count (matches what overview/clusters resource shows)
let clusterCount = context.stats.communityCount;
try {
const overview = await backend.callTool('overview', { showClusters: true, showProcesses: false, limit: 100, repo: repoName });
if (overview.clusters) {
clusterCount = overview.clusters.length;
}
} catch { /* fall back to raw count */ }
const lines: string[] = [
`project: ${context.projectName}`,
@ -217,45 +213,44 @@ async function getContextResource(backend: LocalBackend, repoName?: string): Pro
lines.push('stats:');
lines.push(` files: ${context.stats.fileCount}`);
lines.push(` symbols: ${context.stats.functionCount}`);
lines.push(` clusters: ${clusterCount}`);
lines.push(` processes: ${context.stats.processCount}`);
lines.push('');
lines.push('tools_available:');
lines.push(' - list_repos: Discover all indexed repositories');
lines.push(' - search: Hybrid semantic + keyword search');
lines.push(' - explore: Deep dive on symbol/cluster/process');
lines.push(' - impact: Blast radius analysis');
lines.push(' - overview: List all clusters and processes');
lines.push(' - query: Process-grouped code intelligence (execution flows related to a concept)');
lines.push(' - context: 360-degree symbol view (categorized refs, process participation)');
lines.push(' - impact: Blast radius analysis (what breaks if you change a symbol)');
lines.push(' - detect_changes: Git-diff impact analysis (what do your changes affect)');
lines.push(' - rename: Multi-file coordinated rename with confidence tags');
lines.push(' - cypher: Raw graph queries');
lines.push(' - list_repos: Discover all indexed repositories');
lines.push('');
lines.push('re_index: Run `npx gitnexus analyze` in terminal if data is stale');
lines.push('');
lines.push('resources_available:');
lines.push(' - gitnexus://repos: All indexed repositories');
lines.push(` - gitnexus://repo/${context.projectName}/clusters: All clusters`);
lines.push(` - gitnexus://repo/${context.projectName}/processes: All processes`);
lines.push(` - gitnexus://repo/${context.projectName}/cluster/{name}: Cluster details`);
lines.push(` - gitnexus://repo/${context.projectName}/clusters: All functional areas`);
lines.push(` - gitnexus://repo/${context.projectName}/processes: All execution flows`);
lines.push(` - gitnexus://repo/${context.projectName}/cluster/{name}: Module details`);
lines.push(` - gitnexus://repo/${context.projectName}/process/{name}: Process trace`);
return lines.join('\n');
}
/**
* Clusters resource
* Clusters resource queries graph directly via backend.queryClusters()
*/
async function getClustersResource(backend: LocalBackend, repoName?: string): Promise<string> {
try {
// Request more than we display so aggregation has enough raw data
const result = await backend.callTool('overview', { showClusters: true, showProcesses: false, limit: 100, repo: repoName });
const result = await backend.queryClusters(repoName, 100);
if (!result.clusters || result.clusters.length === 0) {
return 'clusters: []\n# No clusters detected. Run: gitnexus analyze';
return 'modules: []\n# No functional areas detected. Run: gitnexus analyze';
}
const displayLimit = 20;
const lines: string[] = ['clusters:'];
const lines: string[] = ['modules:'];
const toShow = result.clusters.slice(0, displayLimit);
for (const cluster of toShow) {
const label = cluster.heuristicLabel || cluster.label || cluster.id;
lines.push(` - name: "${label}"`);
@ -263,15 +258,12 @@ async function getClustersResource(backend: LocalBackend, repoName?: string): Pr
if (cluster.cohesion) {
lines.push(` cohesion: ${(cluster.cohesion * 100).toFixed(0)}%`);
}
if (cluster.subCommunities && cluster.subCommunities > 1) {
lines.push(` sub_clusters: ${cluster.subCommunities}`);
}
}
if (result.clusters.length > displayLimit) {
lines.push(`\n# Showing top ${displayLimit} of ${result.clusters.length} clusters. Use gitnexus_search or gitnexus_explore for more.`);
lines.push(`\n# Showing top ${displayLimit} of ${result.clusters.length} modules. Use gitnexus_query for deeper search.`);
}
return lines.join('\n');
} catch (err: any) {
return `error: ${err.message}`;
@ -279,31 +271,31 @@ async function getClustersResource(backend: LocalBackend, repoName?: string): Pr
}
/**
* Processes resource
* Processes resource queries graph directly via backend.queryProcesses()
*/
async function getProcessesResource(backend: LocalBackend, repoName?: string): Promise<string> {
try {
const result = await backend.callTool('overview', { showClusters: false, showProcesses: true, limit: 50, repo: repoName });
const result = await backend.queryProcesses(repoName, 50);
if (!result.processes || result.processes.length === 0) {
return 'processes: []\n# No processes detected. Run: gitnexus analyze';
}
const displayLimit = 20;
const lines: string[] = ['processes:'];
const toShow = result.processes.slice(0, displayLimit);
for (const proc of toShow) {
const label = proc.heuristicLabel || proc.label || proc.id;
lines.push(` - name: "${label}"`);
lines.push(` type: ${proc.processType || 'unknown'}`);
lines.push(` steps: ${proc.stepCount || 0}`);
}
if (result.processes.length > displayLimit) {
lines.push(`\n# Showing top ${displayLimit} of ${result.processes.length} processes. Use gitnexus_explore for more.`);
lines.push(`\n# Showing top ${displayLimit} of ${result.processes.length} processes. Use gitnexus_query for deeper search.`);
}
return lines.join('\n');
} catch (err: any) {
return `error: ${err.message}`;
@ -318,22 +310,29 @@ function getSchemaResource(): string {
nodes:
- File: Source code files
- Folder: Directory containers
- Function: Functions and arrow functions
- Class: Class definitions
- Interface: Interface/type definitions
- Method: Class methods
- Community: Functional cluster (Leiden algorithm)
- CodeElement: Catch-all for other code elements
- Community: Auto-detected functional area (Leiden algorithm)
- Process: Execution flow trace
additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Namespace, Trait, Impl, TypeAlias, Const, Static, Property, Record, Delegate, Annotation, Constructor, Template, Module (use backticks in queries: \`Struct\`, \`Enum\`, etc.)"
relationships:
- CONTAINS: File/Folder contains child
- DEFINES: File defines a symbol
- CALLS: Function/method invocation
- IMPORTS: Module imports
- EXTENDS: Class inheritance
- IMPLEMENTS: Interface implementation
- DEFINES: File defines symbol
- MEMBER_OF: Symbol belongs to community
- STEP_IN_PROCESS: Symbol is step N in process
relationship_table: "All relationships use a single CodeRelation table with a 'type' property. Properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)"
example_queries:
find_callers: |
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
@ -353,31 +352,28 @@ example_queries:
}
/**
* Cluster detail resource
* Cluster detail resource queries graph directly via backend.queryClusterDetail()
*/
async function getClusterDetailResource(name: string, backend: LocalBackend, repoName?: string): Promise<string> {
try {
const result = await backend.callTool('explore', { name, type: 'cluster', repo: repoName });
const result = await backend.queryClusterDetail(name, repoName);
if (result.error) {
return `error: ${result.error}`;
}
const cluster = result.cluster;
const members = result.members || [];
const lines: string[] = [
`name: "${cluster.heuristicLabel || cluster.label || cluster.id}"`,
`module: "${cluster.heuristicLabel || cluster.label || cluster.id}"`,
`symbols: ${cluster.symbolCount || members.length}`,
];
if (cluster.cohesion) {
lines.push(`cohesion: ${(cluster.cohesion * 100).toFixed(0)}%`);
}
if (cluster.subCommunities && cluster.subCommunities > 1) {
lines.push(`sub_clusters: ${cluster.subCommunities}`);
}
if (members.length > 0) {
lines.push('');
lines.push('members:');
@ -390,7 +386,7 @@ async function getClusterDetailResource(name: string, backend: LocalBackend, rep
lines.push(` # ... and ${members.length - 20} more`);
}
}
return lines.join('\n');
} catch (err: any) {
return `error: ${err.message}`;
@ -398,25 +394,25 @@ async function getClusterDetailResource(name: string, backend: LocalBackend, rep
}
/**
* Process detail resource
* Process detail resource queries graph directly via backend.queryProcessDetail()
*/
async function getProcessDetailResource(name: string, backend: LocalBackend, repoName?: string): Promise<string> {
try {
const result = await backend.callTool('explore', { name, type: 'process', repo: repoName });
const result = await backend.queryProcessDetail(name, repoName);
if (result.error) {
return `error: ${result.error}`;
}
const proc = result.process;
const steps = result.steps || [];
const lines: string[] = [
`name: "${proc.heuristicLabel || proc.label || proc.id}"`,
`type: ${proc.processType || 'unknown'}`,
`step_count: ${proc.stepCount || steps.length}`,
];
if (steps.length > 0) {
lines.push('');
lines.push('trace:');
@ -424,9 +420,54 @@ async function getProcessDetailResource(name: string, backend: LocalBackend, rep
lines.push(` ${step.step}: ${step.name} (${step.filePath})`);
}
}
return lines.join('\n');
} catch (err: any) {
return `error: ${err.message}`;
}
}
/**
* Setup resource generates AGENTS.md content for all indexed repos.
* Useful for `gitnexus setup` onboarding or dynamic content injection.
*/
async function getSetupResource(backend: LocalBackend): Promise<string> {
const repos = backend.listRepos();
if (repos.length === 0) {
return '# GitNexus\n\nNo repositories indexed. Run: `npx gitnexus analyze` in a repository.';
}
const sections: string[] = [];
for (const repo of repos) {
const stats = repo.stats || {};
const lines = [
`# GitNexus MCP — ${repo.name}`,
'',
`This project is indexed by GitNexus as **${repo.name}** (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${stats.processes || 0} execution flows).`,
'',
'## Tools',
'',
'| Tool | What it gives you |',
'|------|-------------------|',
'| `query` | Process-grouped code intelligence — execution flows related to a concept |',
'| `context` | 360-degree symbol view — categorized refs, processes it participates in |',
'| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |',
'| `detect_changes` | Git-diff impact — what do your current changes affect |',
'| `rename` | Multi-file coordinated rename with confidence-tagged edits |',
'| `cypher` | Raw graph queries |',
'| `list_repos` | Discover indexed repos |',
'',
'## Resources',
'',
`- \`gitnexus://repo/${repo.name}/context\` — Stats, staleness check`,
`- \`gitnexus://repo/${repo.name}/clusters\` — All functional areas`,
`- \`gitnexus://repo/${repo.name}/processes\` — All execution flows`,
`- \`gitnexus://repo/${repo.name}/schema\` — Graph schema for Cypher`,
];
sections.push(lines.join('\n'));
}
return sections.join('\n\n---\n\n');
}

View file

@ -7,7 +7,7 @@
*
* Supports multiple indexed repositories via the global registry.
*
* Tools: list_repos, search, cypher, overview, explore, impact, analyze
* Tools: list_repos, query, cypher, context, impact, detect_changes, rename
* Resources: repos, repo/{name}/context, repo/{name}/clusters, ...
*/
@ -19,6 +19,8 @@ import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
ListResourceTemplatesRequestSchema,
ListPromptsRequestSchema,
GetPromptRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { GITNEXUS_TOOLS } from './tools.js';
import type { LocalBackend } from './local/local-backend.js';
@ -42,31 +44,31 @@ function getNextStepHint(toolName: string, args: Record<string, any> | undefined
case 'list_repos':
return `\n\n---\n**Next:** READ gitnexus://repo/{name}/context for any repo above to get its overview and check staleness.`;
case 'search':
return `\n\n---\n**Next:** To understand a result in context, use explore({name: "<symbol_name>", type: "symbol"${repoParam}}) to see its callers, callees, and cluster membership.`;
case 'query':
return `\n\n---\n**Next:** To understand a specific symbol in depth, use context({name: "<symbol_name>"${repoParam}}) to see categorized refs and process participation.`;
case 'explore': {
const exploreType = args?.type || 'symbol';
if (exploreType === 'symbol') {
return `\n\n---\n**Next:** If planning changes, use impact({target: "${args?.name || '<name>'}", direction: "upstream"${repoParam}}) to check blast radius. To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
}
if (exploreType === 'cluster') {
return `\n\n---\n**Next:** To drill into a specific symbol, use explore({name: "<symbol_name>", type: "symbol"${repoParam}}). To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
}
if (exploreType === 'process') {
return `\n\n---\n**Next:** To explore any step in detail, use explore({name: "<step_name>", type: "symbol"${repoParam}}).`;
}
return '';
}
case 'overview':
return `\n\n---\n**Next:** To drill into a cluster, READ gitnexus://repo/${repoPath}/cluster/{name} or use explore({name: "<cluster_name>", type: "cluster"${repoParam}}).`;
case 'context':
return `\n\n---\n**Next:** If planning changes, use impact({target: "${args?.name || '<name>'}", direction: "upstream"${repoParam}}) to check blast radius. To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
case 'impact':
return `\n\n---\n**Next:** Review d=1 items first (WILL BREAK). To check affected execution flows, READ gitnexus://repo/${repoPath}/processes.`;
case 'detect_changes':
return `\n\n---\n**Next:** Review affected processes. Use context() on high-risk changed symbols. READ gitnexus://repo/${repoPath}/process/{name} for full execution traces.`;
case 'rename':
return `\n\n---\n**Next:** Run detect_changes(${repoParam ? `{repo: "${repo}"}` : ''}) to verify no unexpected side effects from the rename.`;
case 'cypher':
return `\n\n---\n**Next:** To explore a result symbol, use explore({name: "<name>", type: "symbol"${repoParam}}). For schema reference, READ gitnexus://repo/${repoPath}/schema.`;
return `\n\n---\n**Next:** To explore a result symbol, use context({name: "<name>"${repoParam}}). For schema reference, READ gitnexus://repo/${repoPath}/schema.`;
// Legacy tool names — still return useful hints
case 'search':
return `\n\n---\n**Next:** To understand a result in context, use context({name: "<symbol_name>"${repoParam}}).`;
case 'explore':
return `\n\n---\n**Next:** If planning changes, use impact({target: "<name>", direction: "upstream"${repoParam}}).`;
case 'overview':
return `\n\n---\n**Next:** To drill into an area, READ gitnexus://repo/${repoPath}/cluster/{name}. To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
default:
return '';
@ -83,13 +85,14 @@ export async function startMCPServer(backend: LocalBackend): Promise<void> {
capabilities: {
tools: {},
resources: {},
prompts: {},
},
}
);
// Handle list resources request
server.setRequestHandler(ListResourcesRequestSchema, async () => {
const resources = getResourceDefinitions(backend);
const resources = getResourceDefinitions();
return {
resources: resources.map(r => ({
uri: r.uri,
@ -182,6 +185,81 @@ export async function startMCPServer(backend: LocalBackend): Promise<void> {
}
});
// Handle list prompts request
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
prompts: [
{
name: 'detect_impact',
description: 'Analyze the impact of your current changes before committing. Guides through scope selection, change detection, process analysis, and risk assessment.',
arguments: [
{ name: 'scope', description: 'What to analyze: unstaged, staged, all, or compare', required: false },
{ name: 'base_ref', description: 'Branch/commit for compare scope', required: false },
],
},
{
name: 'generate_map',
description: 'Generate architecture documentation from the knowledge graph. Creates a codebase overview with execution flows and mermaid diagrams.',
arguments: [
{ name: 'repo', description: 'Repository name (omit if only one indexed)', required: false },
],
},
],
}));
// Handle get prompt request
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === 'detect_impact') {
const scope = args?.scope || 'all';
const baseRef = args?.base_ref || '';
return {
messages: [
{
role: 'user' as const,
content: {
type: 'text' as const,
text: `Analyze the impact of my current code changes before committing.
Follow these steps:
1. Run \`detect_changes(${JSON.stringify({ scope, ...(baseRef ? { base_ref: baseRef } : {}) })})\` to find what changed and affected processes
2. For each changed symbol in critical processes, run \`context({name: "<symbol>"})\` to see its full reference graph
3. For any high-risk items (many callers or cross-process), run \`impact({target: "<symbol>", direction: "upstream"})\` for blast radius
4. Summarize: changes, affected processes, risk level, and recommended actions
Present the analysis as a clear risk report.`,
},
},
],
};
}
if (name === 'generate_map') {
const repo = args?.repo || '';
return {
messages: [
{
role: 'user' as const,
content: {
type: 'text' as const,
text: `Generate architecture documentation for this codebase using the knowledge graph.
Follow these steps:
1. READ \`gitnexus://repo/${repo || '{name}'}/context\` for codebase stats
2. READ \`gitnexus://repo/${repo || '{name}'}/clusters\` to see all functional areas
3. READ \`gitnexus://repo/${repo || '{name}'}/processes\` to see all execution flows
4. For the top 5 most important processes, READ \`gitnexus://repo/${repo || '{name}'}/process/{name}\` for step-by-step traces
5. Generate a mermaid architecture diagram showing the major areas and their connections
6. Write an ARCHITECTURE.md file with: overview, functional areas, key execution flows, and the mermaid diagram`,
},
},
],
};
}
throw new Error(`Unknown prompt: ${name}`);
});
// Connect to stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);

View file

@ -32,7 +32,7 @@ WHEN TO USE: First step when multiple repos are indexed, or to discover availabl
AFTER THIS: READ gitnexus://repo/{name}/context for the repo you want to work with.
When multiple repos are indexed, you MUST specify the "repo" parameter
on other tools (search, explore, impact, etc.) to target the correct one.`,
on other tools (query, context, impact, etc.) to target the correct one.`,
inputSchema: {
type: 'object',
properties: {},
@ -40,25 +40,28 @@ on other tools (search, explore, impact, etc.) to target the correct one.`,
},
},
{
name: 'search',
description: `Hybrid search (keyword + semantic) across the codebase.
Returns code nodes with cluster context and optional graph connections.
name: 'query',
description: `Query the code knowledge graph for execution flows related to a concept.
Returns processes (call chains) ranked by relevance, each with its symbols and file locations.
WHEN TO USE: Finding code by concept, name, or keyword. Use alongside grep/IDE search for richer results.
AFTER THIS: Use explore() on interesting results to see callers/callees and cluster membership.
WHEN TO USE: Understanding how code works together. Use this when you need execution flows and relationships, not just file matches. Complements grep/IDE search.
AFTER THIS: Use context() on a specific symbol for 360-degree view (callers, callees, categorized refs).
Complements grep/IDE search by adding:
- Cluster context (which functional area each result belongs to)
- Relationship data (callers/callees with depth=full)
- Hybrid ranking (BM25 + semantic via Reciprocal Rank Fusion)
Returns results grouped by process (execution flow):
- processes: ranked execution flows with relevance priority
- process_symbols: all symbols in those flows with file locations
- definitions: standalone types/interfaces not in any process
RETURNS: Array of {name, type, filePath, cluster?, connections[]?, fusedScore, searchSource}`,
Hybrid ranking: BM25 keyword + semantic vector search, ranked by Reciprocal Rank Fusion.`,
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Natural language or keyword search query' },
limit: { type: 'number', description: 'Max results to return', default: 10 },
depth: { type: 'string', description: 'Result detail: "definitions" (symbols only) or "full" (with relationships)', enum: ['definitions', 'full'], default: 'definitions' },
task_context: { type: 'string', description: 'What you are working on (e.g., "adding OAuth support"). Helps ranking.' },
goal: { type: 'string', description: 'What you want to find (e.g., "existing auth validation logic"). Helps ranking.' },
limit: { type: 'number', description: 'Max processes to return (default: 5)', default: 5 },
max_symbols: { type: 'number', description: 'Max symbols per process (default: 10)', default: 10 },
include_content: { type: 'boolean', description: 'Include full symbol source code (default: false)', default: false },
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
},
required: ['query'],
@ -69,26 +72,30 @@ RETURNS: Array of {name, type, filePath, cluster?, connections[]?, fusedScore, s
description: `Execute Cypher query against the code knowledge graph.
WHEN TO USE: Complex structural queries that search/explore can't answer. READ gitnexus://repo/{name}/schema first for the full schema.
AFTER THIS: Use explore() on result symbols for deeper context.
AFTER THIS: Use context() on result symbols for deeper context.
SCHEMA:
- Nodes: File, Folder, Function, Class, Interface, Method, Community, Process
- Edges via CodeRelation.type: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, CONTAINS, DEFINES, MEMBER_OF, STEP_IN_PROCESS
- Nodes: File, Folder, Function, Class, Interface, Method, CodeElement, Community, Process
- Multi-language nodes (use backticks): \`Struct\`, \`Enum\`, \`Trait\`, \`Impl\`, etc.
- All edges via single CodeRelation table with 'type' property
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, MEMBER_OF, STEP_IN_PROCESS
- Edge properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)
EXAMPLES:
Find callers of a function:
MATCH (a)-[:CodeRelation {type: 'CALLS'}]->(b:Function {name: "validateUser"}) RETURN a.name, a.filePath
Find all functions in a community:
MATCH (f:Function)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community {label: "Auth"}) RETURN f.name
Find community members:
MATCH (f)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community) WHERE c.heuristicLabel = "Auth" RETURN f.name
Find steps in a process:
MATCH (s)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process {label: "UserLogin"}) RETURN s.name, r.step ORDER BY r.step
Trace a process:
MATCH (s)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process) WHERE p.heuristicLabel = "UserLogin" RETURN s.name, r.step ORDER BY r.step
TIPS:
- All relationships use CodeRelation table with 'type' property
- Community = functional cluster detected by Leiden algorithm
- Process = execution flow trace from entry point to terminal`,
- All relationships use single CodeRelation table filter with {type: 'CALLS'} etc.
- Community = auto-detected functional area (Leiden algorithm)
- Process = execution flow trace from entry point to terminal
- Use heuristicLabel (not label) for human-readable community/process names`,
inputSchema: {
type: 'object',
properties: {
@ -99,72 +106,84 @@ TIPS:
},
},
{
name: 'explore',
description: `Deep dive on a symbol, cluster, or process.
name: 'context',
description: `360-degree view of a single code symbol.
Shows categorized incoming/outgoing references (calls, imports, extends, implements), process participation, and file location.
WHEN TO USE: After search() to understand context, or to drill into a specific node.
AFTER THIS (symbol): Use impact() if planning changes, or READ process resource to see execution flows.
AFTER THIS (cluster): Use explore() on specific members, or READ processes resource.
AFTER THIS (process): Use explore() on individual steps for detail.
WHEN TO USE: After query() to understand a specific symbol in depth. When you need to know all callers, callees, and what execution flows a symbol participates in.
AFTER THIS: Use impact() if planning changes, or READ gitnexus://repo/{name}/process/{processName} for full execution trace.
TYPE: symbol | cluster | process
For SYMBOL: Shows cluster membership, process participation, callers/callees
For CLUSTER: Shows members, cohesion score, processes touching it
For PROCESS: Shows step-by-step trace, clusters traversed, entry/terminal points`,
Handles disambiguation: if multiple symbols share the same name, returns candidates for you to pick from. Use uid param for zero-ambiguity lookup from prior results.`,
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name of symbol, cluster, or process to explore' },
type: { type: 'string', description: 'Type: symbol, cluster, or process' },
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
},
required: ['name', 'type'],
},
},
{
name: 'overview',
description: `Get codebase map showing all clusters and processes.
WHEN TO USE: Understanding overall architecture. Prefer READ gitnexus://repo/{name}/clusters resource for a lighter-weight alternative.
AFTER THIS: Drill into a specific cluster with explore({type: "cluster"}) or search() for specific code.
Returns:
- All communities (clusters) with member counts and cohesion scores
- All processes with step counts and types (intra/cross-community)
- High-level architectural view`,
inputSchema: {
type: 'object',
properties: {
showProcesses: { type: 'boolean', description: 'Include process list', default: true },
showClusters: { type: 'boolean', description: 'Include cluster list', default: true },
limit: { type: 'number', description: 'Max items per category', default: 20 },
name: { type: 'string', description: 'Symbol name (e.g., "validateUser", "AuthService")' },
uid: { type: 'string', description: 'Direct symbol UID from prior tool results (zero-ambiguity lookup)' },
file_path: { type: 'string', description: 'File path to disambiguate common names' },
include_content: { type: 'boolean', description: 'Include full symbol source code (default: false)', default: false },
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
},
required: [],
},
},
{
name: 'detect_changes',
description: `Analyze uncommitted git changes and find affected execution flows.
Maps git diff hunks to indexed symbols, then traces which processes are impacted.
WHEN TO USE: Before committing to understand what your changes affect. Pre-commit review, PR preparation.
AFTER THIS: Review affected processes. Use context() on high-risk symbols. READ gitnexus://repo/{name}/process/{name} for full traces.
Returns: changed symbols, affected processes, and a risk summary.`,
inputSchema: {
type: 'object',
properties: {
scope: { type: 'string', description: 'What to analyze: "unstaged" (default), "staged", "all", or "compare"', enum: ['unstaged', 'staged', 'all', 'compare'], default: 'unstaged' },
base_ref: { type: 'string', description: 'Branch/commit for "compare" scope (e.g., "main")' },
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
},
required: [],
},
},
{
name: 'rename',
description: `Multi-file coordinated rename using the knowledge graph + text search.
Finds all references via graph (high confidence) and regex text search (lower confidence). Preview by default.
WHEN TO USE: Renaming a function, class, method, or variable across the codebase. Safer than find-and-replace.
AFTER THIS: Run detect_changes() to verify no unexpected side effects.
Each edit is tagged with confidence:
- "graph": found via knowledge graph relationships (high confidence, safe to accept)
- "text_search": found via regex text search (lower confidence, review carefully)`,
inputSchema: {
type: 'object',
properties: {
symbol_name: { type: 'string', description: 'Current symbol name to rename' },
symbol_uid: { type: 'string', description: 'Direct symbol UID from prior tool results (zero-ambiguity)' },
new_name: { type: 'string', description: 'The new name for the symbol' },
file_path: { type: 'string', description: 'File path to disambiguate common names' },
dry_run: { type: 'boolean', description: 'Preview edits without modifying files (default: true)', default: true },
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
},
required: ['new_name'],
},
},
{
name: 'impact',
description: `Analyze the impact of changing a code element.
Returns all nodes affected by modifying the target, with distance, edge type, and confidence.
description: `Analyze the blast radius of changing a code symbol.
Returns all symbols affected by modifying the target, grouped by depth with edge types and confidence.
WHEN TO USE: Before making code changes, especially refactoring, renaming, or modifying shared code. Shows what would be affected.
AFTER THIS: Review d=1 items (WILL BREAK). READ gitnexus://repo/{name}/processes to check affected flows. If risk > MEDIUM, warn the user.
Output includes:
- Affected processes (with step positions)
- Affected clusters (direct/indirect)
- Risk assessment (critical/high/medium/low)
- Callers/dependents grouped by depth
EdgeType: CALLS, IMPORTS, EXTENDS, IMPLEMENTS
Confidence: 100% = certain, <80% = fuzzy match
WHEN TO USE: Before making code changes especially refactoring, renaming, or modifying shared code. Shows what would break.
AFTER THIS: Review d=1 items (WILL BREAK). READ gitnexus://repo/{name}/processes to check affected execution flows.
Depth groups:
- d=1: WILL BREAK (direct callers/importers)
- d=2: LIKELY AFFECTED (indirect)
- d=3: MAY NEED TESTING (transitive)`,
- d=3: MAY NEED TESTING (transitive)
EdgeType: CALLS, IMPORTS, EXTENDS, IMPLEMENTS
Confidence: 1.0 = certain, <0.8 = fuzzy match`,
inputSchema: {
type: 'object',
properties: {