Practical patterns for integrating codegraph into your development workflow.
Keep your graph up to date automatically. Add this to your git hooks so the database is always fresh before you commit.
With husky (recommended):
npm install -D husky
npx husky init
echo "codegraph build" > .husky/pre-commitWith a plain git hook:
echo '#!/bin/sh
codegraph build' > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commitSee what your branch will affect before pushing:
# .husky/pre-push
codegraph build
codegraph diff-impact --ref origin/main --no-testsThis prints a summary like:
3 functions changed → 12 callers affected across 7 files
If you want to block pushes that exceed a threshold, add a check:
# .husky/pre-push
codegraph build
IMPACT=$(codegraph diff-impact --ref origin/main --no-tests --json)
AFFECTED=$(echo "$IMPACT" | node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
console.log(d.summary?.callersAffected || 0)
")
if [ "$AFFECTED" -gt 50 ]; then
echo "WARNING: $AFFECTED callers affected. Review with 'codegraph diff-impact' before pushing."
exit 1
fiAutomatically append impact info to commit messages:
# .husky/prepare-commit-msg
IMPACT=$(codegraph diff-impact --staged --no-tests --json 2>/dev/null)
SUMMARY=$(echo "$IMPACT" | node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
if (d.summary) console.log('Impact: ' + d.summary.functionsChanged + ' functions changed, ' + d.summary.callersAffected + ' callers affected');
" 2>/dev/null)
if [ -n "$SUMMARY" ]; then
echo "" >> "$1"
echo "$SUMMARY" >> "$1"
fiCopy the included workflow to your repo:
cp node_modules/@optave/codegraph/.github/workflows/codegraph-impact.yml .github/workflows/Every PR gets a comment:
3 functions changed -> 12 callers affected across 7 files
Add a threshold check to your CI pipeline:
- name: Check impact threshold
run: |
npx codegraph build
IMPACT=$(npx codegraph diff-impact --ref origin/${{ github.base_ref }} --json)
AFFECTED=$(echo "$IMPACT" | node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
console.log(d.summary?.callersAffected || 0)
")
echo "Callers affected: $AFFECTED"
if [ "$AFFECTED" -gt 100 ]; then
echo "::error::High impact PR — $AFFECTED callers affected. Requires additional review."
exit 1
fiSpeed up CI by caching .codegraph/:
- uses: actions/cache@v4
with:
path: .codegraph
key: codegraph-${{ hashFiles('src/**', 'lib/**') }}
restore-keys: codegraph-
- run: npx codegraph build # incremental — only re-parses changed filesStart the MCP server so AI assistants can query your graph:
codegraph mcp # Single-repo mode (default) — only local project
codegraph mcp --multi-repo # Multi-repo — all registered repos accessible
codegraph mcp --repos a,b # Multi-repo with allowlistBy default, the MCP server runs in single-repo mode — the AI agent can only query the current project's graph. The repo parameter and list_repos tool are not exposed, preventing agents from silently accessing other codebases.
Enable --multi-repo to let the agent query any registered repository, or use --repos to restrict access to a specific set of repos.
The server exposes tools for query_function, file_deps, impact_analysis, find_cycles, module_map, fn_deps, fn_impact, diff_impact, semantic_search, export_graph, list_functions, structure, and hotspots.
Add this to your project's CLAUDE.md so AI agents know codegraph is available:
## Code Navigation
This project uses codegraph. The database is at `.codegraph/graph.db`.
- **Before modifying a function**: `codegraph fn <name> --no-tests`
- **Before modifying a file**: `codegraph deps <file>`
- **To assess PR impact**: `codegraph diff-impact --no-tests`
- **To find entry points**: `codegraph map`
- **To trace breakage**: `codegraph fn-impact <name> --no-tests`
Rebuild after major structural changes: `codegraph build`
### Semantic search
Use `codegraph search` to find functions by intent rather than exact name.
When a single query might miss results, combine multiple angles with `;`:
codegraph search "validate auth; check token; verify JWT"
codegraph search "parse config; load settings" --kind function
Multi-query search uses Reciprocal Rank Fusion — functions that rank
highly across several queries surface first. This is especially useful
when you're not sure what naming convention the codebase uses.
When writing multi-queries, use 2-4 sub-queries (2-4 words each) that
attack the problem from different angles. Pick from these strategies:
- **Naming variants**: cover synonyms the author might have used
("send email; notify user; deliver message")
- **Abstraction levels**: pair high-level intent with low-level operation
("handle payment; charge credit card")
- **Input/output sides**: cover the read half and write half
("parse config; apply settings")
- **Domain + technical**: bridge business language and implementation
("onboard tenant; create organization; provision workspace")
Use `--kind function` to cut noise. Use `--file <pattern>` to scope.You can configure Claude Code hooks to automatically rebuild the graph after file edits:
// .claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "codegraph build",
"timeout": 30
}
]
}
]
}
}This ensures the graph stays fresh as the AI agent modifies files. Incremental builds are automatic — only changed files are re-parsed.
When multiple AI agents work on the same repo concurrently, add hooks to prevent cross-session interference:
- Edit tracker (PostToolUse on Edit|Write): log every file path touched to
.claude/session-edits.log - Git guard (PreToolUse on Bash): block
git add .,git reset,git restore,git clean,git stash, and validate thatgit commitonly includes files from the session edit log
See this repo's .claude/hooks/track-edits.sh and guard-git.sh for a working implementation. Pair with the /worktree command so each session gets an isolated copy of the repo.
Keep the graph updating in the background while you code:
codegraph watchChanges are picked up incrementally — no manual rebuilds needed.
Before touching a function, check its blast radius:
codegraph fn myFunction --no-tests # callers, callees, call chain
codegraph fn-impact myFunction --no-tests # what breaks if this changesBefore touching a file:
codegraph deps src/utils/auth.ts # imports and importers
codegraph impact src/utils/auth.ts # transitive reverse depscodegraph cycles # file-level cycles
codegraph cycles --functions # function-level cyclesWhen you're not sure where something lives:
codegraph search "handle authentication"
codegraph search "parse config file" --min-score 0.4Build embeddings first (one-time):
codegraph embed # ~23 MB model, fast
codegraph embed --model jina-code # ~137 MB, best for code search
codegraph embed --model bge-large # ~335 MB, best general retrievalWhen a single query doesn't capture what you're looking for, combine multiple angles with ;. Results are ranked using Reciprocal Rank Fusion (RRF) — functions that score well across multiple queries rise to the top.
Use 2-4 sub-queries. Each sub-query should attack the problem from a different angle. The framework below covers the four most effective angles — pick 2-3 that fit your situation:
Codebases are inconsistent. The function you want might be called authenticate, checkAuth, verifyUser, or ensureLoggedIn. Cover the likely naming variations:
# You think "validate input" — but the author might have written "sanitize", "check", or "parse"
codegraph search "validate input; sanitize request; check params"
# You think "send email" — but it could be "notify", "mail", or "deliver"
codegraph search "send email; notify user; deliver message"A high-level description ("handle payment") and a low-level one ("charge credit card") often match different but related functions. Combining them surfaces the full chain:
# High-level intent + low-level implementation
codegraph search "handle payment; charge credit card; create Stripe session"
# Architecture concept + concrete operation
codegraph search "rate limiting; count requests per window; throttle API"Many operations have a clear "read" half and a "write" half. Querying both surfaces the full pipeline:
# Reading config + applying config
codegraph search "parse config file; apply settings; load environment"
# Receiving data + transforming data
codegraph search "deserialize JSON payload; map response to model"Business logic often uses domain language that differs from the technical implementation. Bridge both:
# Domain language + implementation pattern
codegraph search "onboard new tenant; create organization; provision workspace"
# User-facing concept + internal mechanism
codegraph search "user permissions; role-based access; check authorization"A real-world search typically mixes 2-3 of these angles:
# Refactoring a caching layer — synonyms + abstraction levels + domain terms
codegraph search "cache invalidation; expire stale entries; TTL cleanup" --kind function
# Finding all auth-related code before a security review
codegraph search "authenticate request; verify JWT; check session token" --file "src/api/*"
# Understanding how errors propagate — input/output + abstraction
codegraph search "catch exception; format error response; report failure to client"Additional tips:
- Keep each sub-query to 2-4 words — embedding models work best on short, focused phrases
- Use
--kind functionor--kind methodto cut noise from class/type matches - Use
--file <pattern>to scope to a directory when you roughly know where the code lives - Lower
--rrf-k(e.g.,--rrf-k 30) to make top-ranked results dominate more sharply
Codegraph's LLM features (semantic search with LLM-generated descriptions, future codegraph ask) require an API key. Use apiKeyCommand to fetch it from a secret manager at runtime instead of hardcoding it in config files or leaking it through environment variables.
Environment variables are better than plaintext in config files, but they still leak via ps e, /proc/<pid>/environ, child processes, shell history, and CI logs. apiKeyCommand keeps the secret in your vault and only materializes it in process memory for the duration of the call.
1Password CLI:
{
"llm": {
"provider": "openai",
"apiKeyCommand": "op read op://Development/openai/api-key"
}
}Bitwarden CLI:
{
"llm": {
"provider": "anthropic",
"apiKeyCommand": "bw get password anthropic-api-key"
}
}macOS Keychain:
{
"llm": {
"provider": "openai",
"apiKeyCommand": "security find-generic-password -s codegraph-llm -w"
}
}HashiCorp Vault:
{
"llm": {
"provider": "openai",
"apiKeyCommand": "vault kv get -field=api_key secret/codegraph/openai"
}
}pass (GPG-encrypted):
{
"llm": {
"provider": "openai",
"apiKeyCommand": "pass show codegraph/openai-key"
}
}The resolution order is:
apiKeyCommandoutput (highest priority)CODEGRAPH_LLM_API_KEYenvironment variablellm.apiKeyin config filenull(default)
If the command fails (timeout, not found, non-zero exit), codegraph logs a warning and falls back to the next available source. The command has a 10-second timeout.
- The command is split on whitespace and executed with
execFileSync(array args, no shell) — no shell injection risk - stdout is captured; stderr is discarded
- The resolved key is held only in process memory, never written to disk
- Keep
.codegraphrc.jsonout of version control if it containsapiKeyCommandpaths specific to your vault layout, or use a shared command that works across the team
Add the codegraph database to .gitignore — it's a build artifact:
# codegraph
.codegraph/
The database is rebuilt from source with codegraph build. Don't commit it.
# 1. Install codegraph
npm install -g @optave/codegraph
# 2. Build the graph
codegraph build
# 3. Add to .gitignore
echo ".codegraph/" >> .gitignore
# 4. Set up pre-commit hook (with husky)
npm install -D husky
npx husky init
echo "codegraph build" > .husky/pre-commit
# 5. Copy CI workflow
mkdir -p .github/workflows
cp node_modules/@optave/codegraph/.github/workflows/codegraph-impact.yml .github/workflows/
# 6. (Optional) Build embeddings for semantic search
codegraph embed
# 7. (Optional) Add CLAUDE.md for AI agents
# See the AI Agent Integration section above