Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement β†’
Sign In

code-graph-llm

Package Overview
Dependencies
Maintainers
1
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

code-graph-llm - npm Package Compare versions

Comparing version
5.0.0
to
5.1.0
+3
CLAUDE.md
Stack skills (java-spring, python-backend, frontend, testing) load contextually via `.claude/rules/`.
After loading, create concise implementation plan, state assumptions, then implement requested changes.
+8
-8

@@ -101,3 +101,3 @@ /**

await fsp.mkdir(path.dirname(agentFile), { recursive: true });
const content = `---\nname: code-graph\ndescription: Specialized analyst for codebase mapping and memory persistence.\n---\n# Code-Graph Agent\nRole: Specialized analyst for codebase mapping and memory persistence.\nBefore planning, read \`llm-agent-project-learnings.md\` and apply every relevant lesson as an active constraint.\nCapabilities: Can run \`code-graph generate\` to refresh the project map and \`code-graph reflect\` to save concise reusable lessons after failures, corrections, or non-obvious discoveries.\nUsage: Delegate architectural or environmental analysis to this agent.\n`;
const content = `---\nname: code-graph\ndescription: Use INSTEAD of reading source files for architectural overviews, finding relevant files, refreshing the map (code-graph generate), or persisting lessons after failures (code-graph reflect). Reads llm-code-graph.md and llm-agent-project-learnings.md without consuming source-file context budget.\n---\n# Code-Graph Agent\n\nUse INSTEAD of reading source files when:\n- You need an architectural overview or project structure question answered\n- You want to find relevant files before exploring source\n- You need to refresh the project map after adding/removing files\n- You need to persist a lesson after a failure or non-obvious discovery\n\nProtocol:\n1. Before inspecting any source file, read \`llm-code-graph.md\` β€” canonical index of all files, symbols, and edges.\n2. Before planning, read \`llm-agent-project-learnings.md\` β€” apply every matching lesson as an active constraint.\n3. If the map looks stale or missing, run \`code-graph generate\` to refresh it.\n4. After a failure, correction, or non-obvious discovery, run \`code-graph reflect <category> <one-sentence lesson>\`.\n5. Return concise summaries only β€” no raw source dumps.\n`;
await fsp.writeFile(agentFile, content);

@@ -110,15 +110,15 @@ logInstallTarget(agentFile);

'code-graph': {
description: 'Codebase mapping and memory specialist. Delegate here for architectural overviews, refreshing the project map with `code-graph generate`, or persisting non-obvious lessons via `code-graph reflect`.',
description: 'Use INSTEAD of reading source files when you need an architectural overview, want to understand project structure, need to refresh the map (code-graph generate), or persist a lesson after a failure or non-obvious discovery (code-graph reflect). Reads llm-code-graph.md and llm-agent-project-learnings.md without burning source-file context budget.',
body: `You are the Code-Graph Specialist.\n\nResponsibilities:\n1. Before searching raw files, read \`llm-code-graph.md\` for god nodes and structural context.\n2. Before planning or making changes, read \`llm-agent-project-learnings.md\` and apply every relevant lesson as an active constraint.\n3. If a lesson matches the current file, tool, OS, dependency, or failure mode, mention how it changes your approach.\n4. If the map looks stale or missing, run \`code-graph generate\` to refresh it.\n5. After a failure, correction, repeated mistake, or non-obvious discovery, record a concise reusable lesson via \`code-graph reflect <category> <one-sentence lesson>\`.\n6. Return a concise summary to the main conversation, not raw exploration output.\n`
},
'code-graph-locator': {
description: 'Find the smallest relevant file and symbol set from llm-code-graph.md before raw search.',
description: 'Use INSTEAD of Read/Grep when finding which files are relevant before touching source. Queries llm-code-graph.md to return the smallest useful file set, saving context budget. Trigger: "which files relate to X", "where is Y defined", "what should I read before changing Z".',
body: `Use \`llm-code-graph.md\` first. Return compact outputs only:\n- relevant files\n- symbols\n- why each file matters\n- raw files still worth opening\nDo not implement changes. Do not paste source.\n`
},
'code-graph-tracer': {
description: 'Trace dependency and inheritance paths using llm-code-graph.md EDGES.',
description: 'Use INSTEAD of manual import tracing when assessing change impact. Reads the EDGES section of llm-code-graph.md to map upstream/downstream blast radius before you edit. Trigger: "what depends on X", "what breaks if I change Y", "trace the call path to Z".',
body: `Use the EDGES section in \`llm-code-graph.md\` first. Return compact outputs only:\n- dependency path\n- upstream/downstream impact\n- likely risk files\n- missing edges if map appears stale\nDo not implement changes. Do not paste source.\n`
},
'code-graph-reviewer': {
description: 'Review whether a change kept the map, reflections, and scope discipline intact.',
description: 'Use AFTER making changes to verify Code-Graph protocol compliance β€” not for general code review. Checks map freshness, missing reflections, scope creep, dependency staleness. Trigger: "check code-graph protocol", "is the map stale", "did I miss any reflections".',
body: `Review for Code-Graph protocol gaps. Return compact outputs only:\n- stale or missing \`llm-code-graph.md\` update\n- missing reflection after failure or non-obvious behavior\n- scope creep against Simplicity and SurgicalChanges\n- dependency freshness concern\nDo not repeat generic code review unless it affects these protocol checks.\n`

@@ -145,3 +145,3 @@ }

const agentFile = path.join(agentDir, 'AGENT.md');
await fsp.writeFile(agentFile, `# Code-Graph\nSpecialist in project structure and navigation.\n`);
await fsp.writeFile(agentFile, `# Code-Graph β€” Project Map and Memory Specialist\n\nUse INSTEAD of reading source files for:\n- Architectural overviews and project structure questions\n- Finding relevant files before exploring source (reads llm-code-graph.md)\n- Refreshing the project map after adding/removing files (code-graph generate)\n- Persisting lessons after failures or non-obvious discoveries (code-graph reflect)\n\nProtocol:\n1. Before inspecting any source file, read \`llm-code-graph.md\` β€” canonical index of all files, symbols, and edges.\n2. Before planning, read \`llm-agent-project-learnings.md\` β€” apply every matching lesson as an active constraint.\n3. If map is stale or missing, run \`code-graph generate\`.\n4. After failure, correction, or non-obvious discovery: run \`code-graph reflect <category> <lesson>\`.\n5. Return compact summaries only β€” no raw source dumps.\n`);
logInstallTarget(agentFile);

@@ -158,3 +158,3 @@ }

await fsp.mkdir(skillDir, { recursive: true });
const skillContent = `---\nname: code-graph\ndescription: Specialized analyst for codebase mapping and memory persistence. Use \`code-graph generate\` to refresh the project map and \`code-graph reflect\` to save lessons.\n---\n# Code-Graph Agent\nRole: Specialized analyst for codebase mapping and memory persistence.\nBefore planning, read \`llm-agent-project-learnings.md\` and apply every relevant lesson as an active constraint.\nCapabilities: Run \`code-graph generate\` to refresh the project map and \`code-graph reflect\` to persist lessons after failures, corrections, repeated mistakes, or non-obvious discoveries.\nUsage: Delegate architectural or environmental analysis here.\n`;
const skillContent = `---\nname: code-graph\ndescription: Use INSTEAD of reading source files for architectural overviews, finding relevant files, refreshing the map (code-graph generate), or persisting lessons after failures (code-graph reflect). Reads llm-code-graph.md and llm-agent-project-learnings.md without consuming source-file context budget.\n---\n# Code-Graph Agent\n\nUse INSTEAD of reading source files when:\n- You need an architectural overview or project structure question answered\n- You want to find relevant files before exploring source\n- You need to refresh the project map after adding/removing files\n- You need to persist a lesson after a failure or non-obvious discovery\n\nProtocol:\n1. Before inspecting any source file, read \`llm-code-graph.md\` β€” canonical index of all files, symbols, and edges.\n2. Before planning, read \`llm-agent-project-learnings.md\` β€” apply every matching lesson as an active constraint.\n3. If the map looks stale or missing, run \`code-graph generate\` to refresh it.\n4. After a failure, correction, or non-obvious discovery, run \`code-graph reflect <category> <one-sentence lesson>\`.\n5. Return concise summaries only β€” no raw source dumps.\n`;
const skillPath = path.join(skillDir, 'SKILL.md');

@@ -167,3 +167,3 @@ await fsp.writeFile(skillPath, skillContent);

async installGenericPersona() {
const content = `# SYSTEM PROMPT: Code-Graph Personas\nUse these roles when your agent supports delegation. Return compact outputs and avoid raw source dumps.\n\n## code-graph\nMain mapping and memory specialist.\n1. Use \`llm-code-graph.md\` to provide architectural overviews.\n2. Before planning, read \`llm-agent-project-learnings.md\` and apply every relevant lesson as an active constraint.\n3. Strictly follow the protocol in \`llm-agent-rules.md\`.\n4. After a failure, correction, repeated mistake, or non-obvious discovery, record a concise reusable lesson with \`code-graph reflect <CAT> <LESSON>\`.\n\n## code-graph-locator\nFind smallest relevant file and symbol set from \`llm-code-graph.md\`. Return files, symbols, reasons, and raw files worth opening. Do not implement.\n\n## code-graph-tracer\nTrace dependency and inheritance paths from the EDGES section. Return path, upstream/downstream impact, risk files, and stale-map gaps. Do not implement.\n\n## code-graph-reviewer\nReview Code-Graph protocol health: stale map, missing reflection, scope creep, and dependency freshness. Do not repeat generic review unless tied to these checks.\n`;
const content = `# SYSTEM PROMPT: Code-Graph Personas\nUse these roles when your agent supports delegation. Return compact outputs and avoid raw source dumps.\n\n## code-graph\nUse INSTEAD of reading source files for architectural overviews, project structure questions, refreshing the map, or persisting lessons after failures.\n1. Use \`llm-code-graph.md\` for structure without burning source-file context.\n2. Before planning, read \`llm-agent-project-learnings.md\` and apply every relevant lesson as an active constraint.\n3. Strictly follow the protocol in \`llm-agent-rules.md\`.\n4. After a failure, correction, repeated mistake, or non-obvious discovery, record a concise reusable lesson with \`code-graph reflect <CAT> <LESSON>\`.\n\n## code-graph-locator\nUse INSTEAD of Read/Grep when finding relevant files before exploring source. Trigger: "which files relate to X", "where is Y defined", "what should I read before changing Z". Return files, symbols, reasons, and raw files worth opening. Do not implement.\n\n## code-graph-tracer\nUse INSTEAD of manual import tracing when assessing change impact. Trigger: "what depends on X", "what breaks if I change Y". Trace from the EDGES section. Return path, upstream/downstream impact, risk files, stale-map gaps. Do not implement.\n\n## code-graph-reviewer\nUse AFTER making changes to check Code-Graph protocol compliance β€” not for general code review. Trigger: "check code-graph protocol", "is the map stale", "did I miss reflections". Check: stale map, missing reflections, scope creep, dependency freshness.\n`;
const personaPath = path.join(this.cwd, '.code-graph-agent.md');

@@ -170,0 +170,0 @@ await fsp.writeFile(personaPath, content);

@@ -7,3 +7,3 @@ /**

export const CONFIG = Object.freeze({
VERSION: '5.0.0',
VERSION: '5.1.0',
IGNORE_FILE: '.gitignore',

@@ -10,0 +10,0 @@ MAP_FILE: 'llm-code-graph.md',

@@ -44,2 +44,13 @@ /**

- \`STYLE\`: Project-specific architectural rules.
## πŸ”Œ MCP TOOLS (if code-graph MCP server is configured)
Prefer these tools INSTEAD of CLI commands and raw file reads:
- \`get_project_graph\` β€” read full \`${CONFIG.MAP_FILE}\` (INSTEAD of Read)
- \`search_symbols\` β€” find symbols across all files (INSTEAD of Grep)
- \`trace_dependencies\` β€” map blast radius for a file (INSTEAD of manual EDGES parsing)
- \`generate_graph\` β€” refresh the graph (INSTEAD of \`code-graph generate\` CLI)
- \`get_reflections\` β€” read lessons (INSTEAD of Read on \`${CONFIG.REFLECTIONS_FILE}\`)
- \`add_reflection\` β€” record a lesson (INSTEAD of \`code-graph reflect\` CLI)
- \`get_file_symbols\` β€” get symbols for one specific file
- \`search_graph\` β€” search file paths, symbol names, and descriptions together
`;

@@ -46,0 +57,0 @@

@@ -24,6 +24,99 @@ /**

function mcpError(error_type, message, { retryable = false, suggested_action = null } = {}) {
return { _mcpError: true, error_type, message, retryable, ...(suggested_action && { suggested_action }) };
}
function withTimeout(fn, ms) {
return Promise.race([
fn(),
new Promise((_, reject) =>
setTimeout(() => reject({ _mcpError: true, error_type: 'TOOL_TIMEOUT', message: `Operation exceeded ${ms}ms`, retryable: true, retry_after_seconds: 5 }), ms)
),
]);
}
export async function handleGetProjectGraph({ project_path }) {
try {
const pathErr = validateProjectPath(project_path);
if (pathErr) return mcpError('INVALID_PATH', pathErr);
const content = await fsp.readFile(path.join(project_path, CONFIG.MAP_FILE), 'utf8');
return content; // raw string β€” caller must not JSON.stringify
} catch (err) {
if (err.code === 'ENOENT') return mcpError('GRAPH_NOT_FOUND', `Graph file not found at ${path.join(project_path, CONFIG.MAP_FILE)}`, { retryable: false, suggested_action: 'Run `code-graph generate` to build the graph first' });
return mcpError('INTERNAL_ERROR', err.message);
}
}
export async function handleSearchSymbols({ query, project_path, type }) {
try {
const pathErr = validateProjectPath(project_path);
if (pathErr) return mcpError('INVALID_PATH', pathErr);
const content = await fsp.readFile(path.join(project_path, CONFIG.MAP_FILE), 'utf8');
const lower = query.toLowerCase();
const results = [];
let current = null;
for (const line of content.split('\n')) {
if (line.startsWith('## EDGES')) break;
if (line.startsWith('- ') && !line.startsWith(' ')) {
const fileMatch = line.match(/^- \*?([^\s(|]+)/);
const descMatch = line.match(/d:\s*(.+)/);
current = { file: fileMatch?.[1]?.trim() ?? '', description: descMatch?.[1]?.trim() ?? '', symbols: [] };
} else if (current && line.includes('s: [')) {
const match = line.match(/s:\s*\[([^\]]+)\]/);
if (match) {
const matched = match[1].split(',').map(s => s.trim().split(' ')[0]).filter(s => s && s.toLowerCase().includes(lower));
if (matched.length > 0) results.push({ file: current.file, description: current.description, symbols: matched });
}
current = null;
}
}
return { query, type: type ?? 'all', results, total: results.length };
} catch (err) {
if (err.code === 'ENOENT') return mcpError('GRAPH_NOT_FOUND', `Graph file not found at ${path.join(project_path, CONFIG.MAP_FILE)}`, { retryable: false, suggested_action: 'Run `code-graph generate` to build the graph first' });
return mcpError('INTERNAL_ERROR', err.message);
}
}
export async function handleTraceDependencies({ file_path, project_path }) {
try {
const pathErr = validateProjectPath(project_path);
if (pathErr) return mcpError('INVALID_PATH', pathErr);
let content;
try {
content = await fsp.readFile(path.join(project_path, CONFIG.MAP_FILE), 'utf8');
} catch (e) {
if (e.code === 'ENOENT') return mcpError('GRAPH_NOT_FOUND', `Graph file not found at ${path.join(project_path, CONFIG.MAP_FILE)}`, { retryable: false, suggested_action: 'Run `code-graph generate` to build the graph first' });
throw e;
}
const edgesSection = content.split('## EDGES')[1] ?? '';
const normalized = file_path.replace(/\\/g, '/');
const outgoing = [];
const incoming = [];
for (const line of edgesSection.split('\n')) {
if (!line.trim() || !line.includes('->')) continue;
const inheritMatch = line.match(/^\[(.+?)\] -> \[inherits\] -> \[(.+?)\]$/);
if (inheritMatch) {
if (inheritMatch[1] === normalized) outgoing.push({ file: inheritMatch[2], relation: 'inherits' });
if (inheritMatch[2] === normalized) incoming.push({ file: inheritMatch[1], relation: 'inherits' });
continue;
}
const importMatch = line.match(/^\[(.+?)\] -> \[(.+)\]$/);
if (importMatch) {
const targets = importMatch[2].split(',').map(t => t.trim());
if (importMatch[1] === normalized) targets.forEach(t => outgoing.push({ file: t, relation: 'imports' }));
if (targets.includes(normalized)) incoming.push({ file: importMatch[1], relation: 'imports' });
}
}
return { file: normalized, outgoing, incoming, blast_radius: incoming.length };
} catch (err) {
return mcpError('INTERNAL_ERROR', err.message);
}
}
export async function handleGenerateGraph({ project_path }) {
try {
const pathErr = validateProjectPath(project_path);
if (pathErr) return { error: pathErr };
if (pathErr) return mcpError('INVALID_PATH', pathErr);
const mapper = new ProjectMapper(project_path);

@@ -35,3 +128,3 @@ await mapper.generate();

} catch (err) {
return { error: err.message };
return mcpError('INTERNAL_ERROR', err.message);
}

@@ -43,3 +136,3 @@ }

const pathErr = validateProjectPath(project_path);
if (pathErr) return { error: pathErr };
if (pathErr) return mcpError('INVALID_PATH', pathErr);
const content = await fsp.readFile(path.join(project_path, CONFIG.MAP_FILE), 'utf8');

@@ -59,3 +152,2 @@ let inEntry = false;

}
// New top-level entry started β€” file was found but has no symbols
if (line.startsWith('- ') && !line.startsWith(' ')) {

@@ -66,8 +158,7 @@ return { file: file_path, symbols: [] };

}
// End of file reached
if (inEntry) return { file: file_path, symbols: [] };
return { error: `File not found in graph: ${file_path}. Run generate_graph first.` };
return mcpError('FILE_NOT_IN_GRAPH', `File not found in graph: ${file_path}`, { retryable: true, suggested_action: 'Run `code-graph generate` to refresh the graph, then retry' });
} catch (err) {
if (err.code === 'ENOENT') return { error: 'No graph found. Run generate_graph first.' };
return { error: err.message };
if (err.code === 'ENOENT') return mcpError('GRAPH_NOT_FOUND', `Graph file not found at ${path.join(project_path, CONFIG.MAP_FILE)}`, { retryable: false, suggested_action: 'Run `code-graph generate` to build the graph first' });
return mcpError('INTERNAL_ERROR', err.message);
}

@@ -79,3 +170,3 @@ }

const pathErr = validateProjectPath(project_path);
if (pathErr) return { error: pathErr };
if (pathErr) return mcpError('INVALID_PATH', pathErr);
const content = await fsp.readFile(path.join(project_path, CONFIG.MAP_FILE), 'utf8');

@@ -110,4 +201,4 @@ const lower = query.toLowerCase();

} catch (err) {
if (err.code === 'ENOENT') return { error: 'No graph found. Run generate_graph first.' };
return { error: err.message };
if (err.code === 'ENOENT') return mcpError('GRAPH_NOT_FOUND', `Graph file not found at ${path.join(project_path, CONFIG.MAP_FILE)}`, { retryable: false, suggested_action: 'Run `code-graph generate` to build the graph first' });
return mcpError('INTERNAL_ERROR', err.message);
}

@@ -119,11 +210,10 @@ }

const pathErr = validateProjectPath(project_path);
if (pathErr) return { error: pathErr };
if (pathErr) return mcpError('INVALID_PATH', pathErr);
const cat = String(category ?? 'GENERAL').replace(/[^\w-]/g, '').slice(0, 20).toUpperCase() || 'GENERAL';
const cleanLesson = String(lesson).replace(/[\r\n]+/g, ' ').trim().slice(0, 500);
if (!cleanLesson) return { error: 'lesson cannot be empty' };
// ReflectionManager.add handles dedup and sanitization internally
if (!cleanLesson) return mcpError('INVALID_INPUT', 'lesson cannot be empty after sanitization');
await ReflectionManager.add(cat, cleanLesson, project_path);
return { success: true, entry: `[${cat}] ${cleanLesson}` };
} catch (err) {
return { error: err.message };
return mcpError('INTERNAL_ERROR', err.message);
}

@@ -135,3 +225,3 @@ }

const pathErr = validateProjectPath(project_path);
if (pathErr) return { error: pathErr };
if (pathErr) return mcpError('INVALID_PATH', pathErr);
let content;

@@ -155,3 +245,3 @@ try {

} catch (err) {
return { error: err.message };
return mcpError('INTERNAL_ERROR', err.message);
}

@@ -164,2 +254,38 @@ }

{
name: 'get_project_graph',
description: 'Read the full llm-code-graph.md for a project. Use INSTEAD of Read/Grep when exploring structure or understanding dependencies.',
inputSchema: {
type: 'object',
properties: {
project_path: { type: 'string', description: 'Absolute path to the project directory' }
},
required: ['project_path']
}
},
{
name: 'search_symbols',
description: 'Search for symbol names (functions, classes, variables) across the project graph. Returns matching symbols and their files.',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Symbol name or partial name (case-insensitive)' },
project_path: { type: 'string', description: 'Absolute path to the project directory' },
type: { type: 'string', enum: ['function', 'class', 'variable', 'all'], description: 'Symbol type filter (informational β€” graph does not store type metadata)' }
},
required: ['query', 'project_path']
}
},
{
name: 'trace_dependencies',
description: 'Trace incoming and outgoing dependencies for a file. Use before editing to understand blast radius.',
inputSchema: {
type: 'object',
properties: {
file_path: { type: 'string', description: 'Relative file path as in the graph (e.g. lib/parser.js)' },
project_path: { type: 'string', description: 'Absolute path to the project directory' }
},
required: ['file_path', 'project_path']
}
},
{
name: 'generate_graph',

@@ -227,7 +353,10 @@ description: 'Build or refresh llm-code-graph.md for a project directory.',

const HANDLERS = {
generate_graph: handleGenerateGraph,
get_file_symbols: handleGetFileSymbols,
search_graph: handleSearchGraph,
add_reflection: handleAddReflection,
get_reflections: handleGetReflections
get_project_graph: handleGetProjectGraph,
search_symbols: handleSearchSymbols,
trace_dependencies: handleTraceDependencies,
generate_graph: handleGenerateGraph,
get_file_symbols: handleGetFileSymbols,
search_graph: handleSearchGraph,
add_reflection: handleAddReflection,
get_reflections: handleGetReflections,
};

@@ -249,9 +378,19 @@

if (!handler) {
return { content: [{ type: 'text', text: JSON.stringify({ error: `Unknown tool: ${name}` }) }] };
return { isError: true, content: [{ type: 'text', text: JSON.stringify({ error_type: 'UNKNOWN_TOOL', message: `Unknown tool: ${name}`, retryable: false }) }] };
}
const timeoutMs = name === 'generate_graph' ? 300_000 : 30_000;
try {
const result = await handler(args ?? {});
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
const result = await withTimeout(() => handler(args ?? {}), timeoutMs);
if (result?._mcpError) {
const { _mcpError, ...errData } = result;
return { isError: true, content: [{ type: 'text', text: JSON.stringify(errData) }] };
}
const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
return { content: [{ type: 'text', text }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }] };
if (err?._mcpError) {
const { _mcpError, ...errData } = err;
return { isError: true, content: [{ type: 'text', text: JSON.stringify(errData) }] };
}
return { isError: true, content: [{ type: 'text', text: JSON.stringify({ error_type: 'INTERNAL_ERROR', message: err.message ?? String(err), retryable: false }) }] };
}

@@ -258,0 +397,0 @@ });

@@ -315,3 +315,3 @@ /**

projectMapSection() {
return `\n## πŸ—ΊοΈ Skill: ProjectMap\nMANDATORY: Read \`${CONFIG.MAP_FILE}\` BEFORE calling Read, Grep, Glob, or any file tool. It is the canonical index of all files, symbols, and dependency edges. Use it to identify exactly which files to open. Do not inspect raw files without consulting it first. Refresh with \`code-graph generate\` if stale. Skipping = task failure.\n`;
return `\n## πŸ—ΊοΈ Skill: ProjectMap\nMANDATORY: Read \`${CONFIG.MAP_FILE}\` BEFORE calling Read, Grep, Glob, or any file tool. It is the canonical index of all files, symbols, and dependency edges. Use it to identify exactly which files to open. Do not inspect raw files without consulting it first. Refresh with \`code-graph generate\` if stale. If MCP server configured: prefer \`get_project_graph\` (INSTEAD of Read), \`search_symbols\` (INSTEAD of Grep), \`trace_dependencies\` (INSTEAD of manual EDGES parsing). Skipping = task failure.\n`;
}

@@ -324,3 +324,3 @@

reflectionsProtocolBody() {
return `MANDATORY β€” follow this cycle on every task. Skipping = task failure.\n\nBEFORE planning or writing any code:\n1. Read \`${CONFIG.REFLECTIONS_FILE}\` β€” apply every matching lesson as a hard constraint.\n2. Read \`${CONFIG.RULES_FILE}\` β€” follow the protocol exactly.\n3. If a lesson matches the current file, tool, OS, or failure mode: state explicitly how it changes your approach.\n\nAFTER any failure, correction, or non-obvious fix:\n- Run \`code-graph reflect <CATEGORY> <LESSON>\` with a concise, reusable lesson.\n- You MUST either record a new lesson or explicitly state that none was learned.\n- Do NOT mark a task complete without completing this step.\n\nThe goal: no agent repeats a mistake already recorded in \`${CONFIG.REFLECTIONS_FILE}\`.\n`;
return `MANDATORY β€” follow this cycle on every task. Skipping = task failure.\n\nBEFORE planning or writing any code:\n1. Read \`${CONFIG.REFLECTIONS_FILE}\` β€” apply every matching lesson as a hard constraint.\n2. Read \`${CONFIG.RULES_FILE}\` β€” follow the protocol exactly.\n3. If a lesson matches the current file, tool, OS, or failure mode: state explicitly how it changes your approach.\n\nAFTER any failure, correction, or non-obvious fix:\n- Run \`code-graph reflect <CATEGORY> <LESSON>\` with a concise, reusable lesson.\n- You MUST either record a new lesson or explicitly state that none was learned.\n- Do NOT mark a task complete without completing this step.\n\nIf code-graph MCP server is configured, prefer these INSTEAD of the CLI and direct file reads:\n- \`get_reflections\` β€” reads \`${CONFIG.REFLECTIONS_FILE}\` (INSTEAD of Read on the file)\n- \`add_reflection\` β€” records a lesson (INSTEAD of \`code-graph reflect\` CLI)\n\nThe goal: no agent repeats a mistake already recorded in \`${CONFIG.REFLECTIONS_FILE}\`.\n`;
}

@@ -327,0 +327,0 @@

@@ -192,2 +192,7 @@ /**

If code-graph MCP server is configured, prefer these INSTEAD of raw file tools:
- \`get_project_graph\` β€” reads full \`${CONFIG.MAP_FILE}\` in one call (use INSTEAD of Read)
- \`search_symbols\` β€” finds symbols across all files (use INSTEAD of Grep for symbol lookup)
- \`trace_dependencies\` β€” maps upstream/downstream blast radius for a file (use INSTEAD of manual EDGES parsing)
Inspecting raw files without first reading \`${CONFIG.MAP_FILE}\` = task failure.

@@ -303,3 +308,3 @@ `;

function projectMapSection() {
return `\n## πŸ—ΊοΈ Skill: ProjectMap\nMANDATORY: Read \`${CONFIG.MAP_FILE}\` BEFORE calling Read, Grep, Glob, or any file tool. It is the canonical index of all files, symbols, and dependency edges. Use it to identify exactly which files to open. Do not inspect raw files without consulting it first. Refresh with \`code-graph generate\` if stale. Skipping = task failure.\n`;
return `\n## πŸ—ΊοΈ Skill: ProjectMap\nMANDATORY: Read \`${CONFIG.MAP_FILE}\` BEFORE calling Read, Grep, Glob, or any file tool. It is the canonical index of all files, symbols, and dependency edges. Use it to identify exactly which files to open. Do not inspect raw files without consulting it first. Refresh with \`code-graph generate\` if stale. If MCP server configured: prefer \`get_project_graph\` (INSTEAD of Read), \`search_symbols\` (INSTEAD of Grep), \`trace_dependencies\` (INSTEAD of manual EDGES parsing). Skipping = task failure.\n`;
}

@@ -328,4 +333,8 @@

If code-graph MCP server is configured, prefer these INSTEAD of the CLI and direct file reads:
- \`get_reflections\` β€” reads \`${CONFIG.REFLECTIONS_FILE}\` (use INSTEAD of Read on the file)
- \`add_reflection\` β€” records a lesson (use INSTEAD of \`code-graph reflect\` CLI)
The goal: no agent repeats a mistake already recorded in \`${CONFIG.REFLECTIONS_FILE}\`.
`;
}
{
"name": "code-graph-llm",
"version": "5.0.0",
"version": "5.1.0",
"description": "Compact, language-agnostic codebase mapper for LLM token efficiency.",

@@ -5,0 +5,0 @@ "main": "index.js",

+28
-19

@@ -1,2 +0,2 @@

# CODE-GRAPH (v5.0.0)
# CODE-GRAPH (v5.1.0)

@@ -7,8 +7,12 @@ > Inspired by [Andrej Karpathy skills](https://github.com/forrestchang/andrej-karpathy-skills), [juliusbrussee/caveman](https://github.com/juliusbrussee/caveman), and the community's work building better agent workflows.

## New in v5.0.0
## New in v5.1.0
- **MCP Server (reintroduced):** `code-graph mcp` starts a proper MCP stdio server. All five tools (`generate_graph`, `get_file_symbols`, `search_graph`, `add_reflection`, `get_reflections`) accept `project_path` so one running server handles multiple projects. The previous server (removed in v4.14.0) was replaced with a clean, multi-project implementation.
- **Fix (Git Hook β€” idempotent merge):** `code-graph init` no longer clobbers existing pre-commit hooks. The Code-Graph advisory block is wrapped in `# BEGIN CODE-GRAPH` / `# END CODE-GRAPH` markers and merged or updated in-place on reinstall.
- **Fix (SkillManager β€” corrupt JSON safety):** Inverted `ENOENT` check caused invalid JSON in existing settings files to be silently overwritten. Now: missing file β†’ empty init; parse error β†’ warn and leave file unchanged.
- **Fix (ReflectionManager β€” multi-project):** `ReflectionManager.add()` accepts an optional `cwd` argument so the MCP server can record reflections for any project path.
- **MCP Tools (3 new):** Added `get_project_graph` (reads full `llm-code-graph.md` β€” use instead of Read), `search_symbols` (symbol search across all files β€” use instead of Grep), and `trace_dependencies` (upstream/downstream blast radius for a file β€” use instead of manual EDGES parsing). Server now exposes 8 tools total.
- **MCP Structured Errors:** All tool handlers return `{ isError: true, content: [{ type: "text", text: JSON.stringify({ error_type, message, retryable, suggested_action }) }] }`. Error types: `GRAPH_NOT_FOUND`, `FILE_NOT_IN_GRAPH`, `INVALID_PATH`, `INVALID_INPUT`, `TOOL_TIMEOUT`, `UNKNOWN_TOOL`, `INTERNAL_ERROR`. Agents can branch on `error_type` and use `suggested_action` to self-correct.
- **MCP Timeouts:** All tool calls are wrapped in `Promise.race` with a timeout. Default: 30s. `generate_graph`: 300s (5 min). Timeout returns `TOOL_TIMEOUT` with `retryable: true`.
- **Agent Descriptions (WHEN/INSTEAD):** All sub-agent descriptions for Claude Code, Gemini, Kiro, Antigravity, and generic platforms now follow the WHEN/INSTEAD pattern β€” describing trigger conditions and what they replace (Read, Grep, manual EDGES parsing) rather than abstract capability labels.
- **Skills (MCP awareness):** `ProjectMap` and `Reflections` skills now include conditional MCP tool guidance for all 40+ supported platforms: `get_project_graph` instead of Read, `search_symbols` instead of Grep, `add_reflection`/`get_reflections` instead of CLI and direct file reads.
- **Generated rules (MCP section):** `llm-agent-rules.md` scaffolded by `code-graph init` now includes a full MCP tools section listing all 8 tools with INSTEAD guidance.
- **Gitignore (generated platform files):** Added all generated platform output files to `.gitignore` (`GEMINI.md`, `AGENTS.md`, `.clinerules`, `.roorules`, `.kiro/`, `.opencode/`, `.roo/`, `.cursor/rules/`, `llm-agent-rules.md`, `llm-agent-project-learnings.md`, and others) to prevent machine-specific paths from being committed.
- **Tests:** Fixed 2 broken error tests (new structured error format), added 13 new tests for `handleGetProjectGraph`, `handleSearchSymbols`, `handleTraceDependencies`, `INVALID_PATH` validation, and `GRAPH_NOT_FOUND` with `suggested_action`. 24 tests total in `mcp-server.test.js`.

@@ -131,6 +135,6 @@ See [RELEASE_NOTES.md](RELEASE_NOTES.md) for full history.

- `code-graph`: General project-map and reflection specialist.
- `code-graph-locator`: Finds the smallest relevant file and symbol set before raw source reads.
- `code-graph-tracer`: Traces dependency and inheritance paths from `## EDGES`.
- `code-graph-reviewer`: Checks map freshness, reflection coverage, scope creep, and dependency freshness.
- `code-graph`: Use INSTEAD of reading source files for architectural overviews, refreshing the map, or persisting lessons after failures.
- `code-graph-locator`: Use INSTEAD of Read/Grep when finding relevant files before exploring source. Trigger: "which files relate to X", "where is Y defined".
- `code-graph-tracer`: Use INSTEAD of manual import tracing when assessing change impact. Trigger: "what depends on X", "what breaks if I change Y".
- `code-graph-reviewer`: Use AFTER making changes to verify Code-Graph protocol compliance. Trigger: "check code-graph protocol", "is the map stale".

@@ -306,12 +310,17 @@ ## Supported Platforms

| Tool | Description |
|------|-------------|
| `generate_graph` | Build/refresh `llm-code-graph.md` for any project path |
| `get_file_symbols` | Return symbols for a specific file from the graph |
| `search_graph` | Search file paths, symbols, and descriptions |
| `add_reflection` | Append a lesson to `llm-agent-project-learnings.md` |
| `get_reflections` | Return all lessons, optionally filtered by category |
| Tool | When to use | Description |
|------|-------------|-------------|
| `get_project_graph` | INSTEAD of Read on the graph file | Read full `llm-code-graph.md` β€” fastest way to get project structure |
| `search_symbols` | INSTEAD of Grep for symbol lookup | Search symbol names across all files (case-insensitive) |
| `trace_dependencies` | INSTEAD of manual EDGES parsing | Outgoing + incoming deps for a file, plus `blast_radius` count |
| `generate_graph` | When map is stale or missing | Build/refresh `llm-code-graph.md` for any project path |
| `get_file_symbols` | Targeted file lookup | Return symbols for one specific file from the graph |
| `search_graph` | Broad search | Search file paths, symbols, and descriptions together with scoring |
| `add_reflection` | INSTEAD of `code-graph reflect` CLI | Append a lesson to `llm-agent-project-learnings.md` |
| `get_reflections` | INSTEAD of reading the reflections file | Return all lessons, optionally filtered by category |
All tools accept `project_path` (absolute path) so one running server can serve multiple projects.
All tools require `project_path` (absolute path) β€” one running server handles multiple projects.
**Error format:** All tools return structured errors with `isError: true` and JSON content: `{ error_type, message, retryable, suggested_action? }`. Agents can branch on `error_type` (e.g. `GRAPH_NOT_FOUND` β†’ call `generate_graph` first).
## Implementation Details

@@ -330,3 +339,3 @@

install-log.js Shared versioned install target logging
mcp-server.js MCP stdio server: 5 tools, multi-project via project_path
mcp-server.js MCP stdio server: 8 tools, structured errors, per-tool timeouts
skills.js SkillManager: platform skill installation

@@ -333,0 +342,0 @@ agents.js AgentManager: sub-agent registration

# RELEASE NOTES
### v5.1.0 (2026-05-20)
- **MCP Tools (3 new):** Added `get_project_graph` (reads full `llm-code-graph.md` β€” use INSTEAD of Read), `search_symbols` (symbol search β€” use INSTEAD of Grep), and `trace_dependencies` (upstream/downstream blast radius β€” use INSTEAD of manual EDGES parsing). Server now exposes 8 tools total (`generate_graph`, `get_file_symbols`, `search_graph`, `add_reflection`, `get_reflections` unchanged).
- **MCP Structured Errors:** All tool handlers now return `{ isError: true, content: [{ type: "text", text: JSON.stringify({...}) }] }` with a typed `error_type` field (`GRAPH_NOT_FOUND`, `FILE_NOT_IN_GRAPH`, `INVALID_PATH`, `INVALID_INPUT`, `TOOL_TIMEOUT`, `UNKNOWN_TOOL`, `INTERNAL_ERROR`), a `retryable` boolean, and an optional `suggested_action` string. Agents can branch on `error_type` instead of parsing human-readable messages.
- **MCP Timeouts:** All tool calls wrapped in `Promise.race` against an explicit timeout. Default: 30 000ms. `generate_graph`: 300 000ms (5 min). Timeout surfaces as `TOOL_TIMEOUT` with `retryable: true` and `retry_after_seconds: 5`. Prevents the server from hanging indefinitely on large or broken projects.
- **Agent Descriptions (WHEN/INSTEAD):** All platform-specific agent descriptions (Claude Code 4 sub-agents, Gemini, Kiro, Antigravity, generic) now follow the WHEN/INSTEAD pattern β€” stating trigger conditions and what tools they replace, not abstract capability labels. Skill body descriptions for `ProjectMap` and `Reflections` include conditional MCP tool guidance for all 40+ platforms.
- **Skills (MCP awareness):** `projectMapBody()`, `projectMapSection()` (both `specs.js` and `core.js` uninstall copies), and `reflectionsProtocolBody()` now include conditional MCP tool references so agents on any platform know to prefer `get_project_graph`/`search_symbols`/`trace_dependencies` over Read/Grep when the MCP server is configured.
- **Generated rules (MCP section):** `llm-agent-rules.md` scaffolded by `code-graph init` now includes a full `## πŸ”Œ MCP TOOLS` section listing all 8 tools with INSTEAD guidance.
- **Gitignore (generated platform files):** Added `GEMINI.md`, `AGENTS.md`, `.clinerules`, `.roorules`, `.roomodes`, `.code-graph-agent.md`, `opencode.json`, `/.kiro/`, `/.opencode/`, `/.roo/`, `/.cursor/rules/`, `llm-agent-rules.md`, `llm-agent-project-learnings.md`, and `.github/copilot-instructions.md` to `.gitignore`. Prevents generated files containing machine-specific absolute paths from being committed.
- **Tests:** Fixed 2 broken error-format assertions (`result.error` β†’ `result._mcpError`). Added `assertMcpError()` helper and 13 new tests covering `handleGetProjectGraph`, `handleSearchSymbols`, `handleTraceDependencies`, `INVALID_PATH` for null/relative paths, `GRAPH_NOT_FOUND` with `suggested_action`, Windows backslash path normalization, and `FILE_NOT_IN_GRAPH` with `retryable: true`. `mcp-server.test.js`: 24 tests, all pass.
- **Maintenance:** Bumped version to 5.1.0 in `config.js`, `package.json`, and `package-lock.json`.
### v5.0.0 (2026-05-16)

@@ -4,0 +15,0 @@ - **MCP Server (reintroduced):** `lib/mcp-server.js` re-implements the MCP stdio server from scratch. The previous server (removed in v4.14.0) was broken and triggered unintended install dialogs. The new server is a clean, multi-project implementation: all five tools accept `project_path` (absolute path) so one running server can serve multiple projects simultaneously. Tools: `generate_graph`, `get_file_symbols`, `search_graph`, `add_reflection`, `get_reflections`. Launch via `code-graph mcp`.

@@ -12,5 +12,15 @@ import { test } from 'node:test';

handleAddReflection,
handleGetReflections
handleGetReflections,
handleGetProjectGraph,
handleSearchSymbols,
handleTraceDependencies,
} from '../lib/mcp-server.js';
// Helper: assert result is a structured MCP error with the given error_type
function assertMcpError(result, error_type) {
assert.ok(result._mcpError, `expected _mcpError sentinel, got: ${JSON.stringify(result)}`);
assert.strictEqual(result.error_type, error_type);
assert.ok(typeof result.message === 'string' && result.message.length > 0);
}
const REFLECTIONS_FILE = 'llm-agent-project-learnings.md';

@@ -79,5 +89,5 @@

test('handleGenerateGraph returns error for nonexistent path', async () => {
test('handleGenerateGraph returns structured error for nonexistent path', async () => {
const result = await handleGenerateGraph({ project_path: join(tmpdir(), 'cg-nonexistent-' + Date.now()) });
assert.ok(result.error, 'expected error field');
assertMcpError(result, 'INTERNAL_ERROR');
});

@@ -99,3 +109,3 @@

test('handleGetFileSymbols returns error for unknown file', async () => {
test('handleGetFileSymbols returns structured error for unknown file', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-sym-'));

@@ -105,3 +115,4 @@ try {

const result = await handleGetFileSymbols({ file_path: 'lib/does-not-exist.js', project_path: dir });
assert.ok(result.error, 'expected error field');
assertMcpError(result, 'FILE_NOT_IN_GRAPH');
assert.strictEqual(result.retryable, true);
} finally {

@@ -189,1 +200,154 @@ await rm(dir, { recursive: true, force: true });

});
// ── INVALID_PATH errors (shared across all handlers) ────────────────────────
test('handlers return INVALID_PATH for relative project_path', async () => {
const result = await handleGetProjectGraph({ project_path: 'relative/path' });
assertMcpError(result, 'INVALID_PATH');
});
test('handlers return INVALID_PATH for null project_path', async () => {
const result = await handleSearchSymbols({ query: 'foo', project_path: null });
assertMcpError(result, 'INVALID_PATH');
});
// ── Fixture with edges for dependency tracing ────────────────────────────────
const FIXTURE_GRAPH_EDGES = `# CODE_GRAPH
> Legend: * core, (↑out ↓in deps), s: symbols, d: desc
- *lib/reflections.js (3↑ 1↓) | d: Manages project reflections and lessons learned.
- s: [ReflectionManager, add [(category)]]
- lib/parser.js (1↑ 2↓) | d: Handles extraction of symbols and metadata.
- s: [CodeParser, extract [(content)]]
- lib/config.js (0↑ 3↓) | d: Constants and config.
- s: [CONFIG]
## EDGES
[lib/parser.js] -> [lib/config.js, lib/reflections.js]
[lib/reflections.js] -> [lib/config.js]
`;
// ── handleGetProjectGraph ────────────────────────────────────────────────────
test('handleGetProjectGraph returns raw graph content', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-gpg-'));
try {
await writeFile(join(dir, 'llm-code-graph.md'), FIXTURE_GRAPH_EDGES);
const result = await handleGetProjectGraph({ project_path: dir });
assert.strictEqual(typeof result, 'string', 'expected raw string');
assert.ok(result.includes('CODE_GRAPH'));
assert.ok(result.includes('EDGES'));
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('handleGetProjectGraph returns GRAPH_NOT_FOUND when file missing', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-gpg-'));
try {
const result = await handleGetProjectGraph({ project_path: dir });
assertMcpError(result, 'GRAPH_NOT_FOUND');
assert.strictEqual(result.retryable, false);
assert.ok(result.suggested_action);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('handleGetProjectGraph returns INVALID_PATH for null project_path', async () => {
const result = await handleGetProjectGraph({ project_path: null });
assertMcpError(result, 'INVALID_PATH');
});
// ── handleSearchSymbols ──────────────────────────────────────────────────────
test('handleSearchSymbols finds matching symbols', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-ss-'));
try {
await writeFile(join(dir, 'llm-code-graph.md'), FIXTURE_GRAPH_EDGES);
const result = await handleSearchSymbols({ query: 'reflection', project_path: dir });
assert.ok(Array.isArray(result.results), JSON.stringify(result));
assert.ok(result.results.length > 0);
assert.ok(result.results[0].file);
assert.ok(Array.isArray(result.results[0].symbols));
assert.strictEqual(result.total, result.results.length);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('handleSearchSymbols returns empty results for no match', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-ss-'));
try {
await writeFile(join(dir, 'llm-code-graph.md'), FIXTURE_GRAPH_EDGES);
const result = await handleSearchSymbols({ query: 'xyzzy_nomatch_99999', project_path: dir });
assert.ok(Array.isArray(result.results));
assert.strictEqual(result.total, 0);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('handleSearchSymbols returns GRAPH_NOT_FOUND when graph missing', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-ss-'));
try {
const result = await handleSearchSymbols({ query: 'anything', project_path: dir });
assertMcpError(result, 'GRAPH_NOT_FOUND');
} finally {
await rm(dir, { recursive: true, force: true });
}
});
// ── handleTraceDependencies ──────────────────────────────────────────────────
test('handleTraceDependencies returns outgoing and incoming deps', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-td-'));
try {
await writeFile(join(dir, 'llm-code-graph.md'), FIXTURE_GRAPH_EDGES);
// lib/reflections.js imports config.js (outgoing) and is imported by parser.js (incoming)
const result = await handleTraceDependencies({ file_path: 'lib/reflections.js', project_path: dir });
assert.ok(Array.isArray(result.outgoing), JSON.stringify(result));
assert.ok(Array.isArray(result.incoming));
assert.ok(result.outgoing.some(d => d.file === 'lib/config.js'));
assert.ok(result.incoming.some(d => d.file === 'lib/parser.js'));
assert.strictEqual(result.blast_radius, result.incoming.length);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('handleTraceDependencies returns empty arrays for file with no edges', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-td-'));
try {
await writeFile(join(dir, 'llm-code-graph.md'), FIXTURE_GRAPH_EDGES);
const result = await handleTraceDependencies({ file_path: 'lib/unknown-file.js', project_path: dir });
assert.deepStrictEqual(result.outgoing, []);
assert.deepStrictEqual(result.incoming, []);
assert.strictEqual(result.blast_radius, 0);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('handleTraceDependencies returns GRAPH_NOT_FOUND when graph missing', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-td-'));
try {
const result = await handleTraceDependencies({ file_path: 'lib/any.js', project_path: dir });
assertMcpError(result, 'GRAPH_NOT_FOUND');
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test('handleTraceDependencies normalizes Windows backslash paths', async () => {
const dir = await mkdtemp(join(tmpdir(), 'cg-mcp-td-'));
try {
await writeFile(join(dir, 'llm-code-graph.md'), FIXTURE_GRAPH_EDGES);
// Pass backslash path β€” should normalize to forward slash and still match
const result = await handleTraceDependencies({ file_path: 'lib\\reflections.js', project_path: dir });
assert.ok(result.outgoing.some(d => d.file === 'lib/config.js'), JSON.stringify(result));
} finally {
await rm(dir, { recursive: true, force: true });
}
});
# SYSTEM PROMPT: Code-Graph Persona
Your role is now to act as the Code-Graph Specialist.
1. Use `llm-code-graph.md` to provide architectural overviews.
2. Before planning, read `llm-agent-project-learnings.md` and apply every relevant lesson as an active constraint.
3. Strictly follow the protocol in `llm-agent-rules.md`.
4. After a failure, correction, repeated mistake, or non-obvious discovery, record a concise reusable lesson with `code-graph reflect <CAT> <LESSON>`.
# LLM_AGENT_PROJECT_LEARNINGS
> LLM AGENT MEMORY: READ BEFORE STARTING TASKS. UPDATE ON FAILURES.
## ⚠️ CRITICAL PITFALLS
- [OS: win32] PowerShell script execution is disabled by default; use `cmd /c npm` for all npm commands to ensure compatibility.
- [LOGIC: index.js] `extractSymbolsAndInheritance` regex matches itself if TODO/FIXME strings are present in the code; ensure filters are in place.
## πŸ“¦ DEPENDENCIES & ENVIRONMENT
- [DEP: chokidar] Watcher should be debounced by at least 500ms to avoid race conditions during rapid file saves.
## βœ… BEST PRACTICES
- [STYLE] Always include dependency counts (↑N ↓M) in `llm-code-graph.md` to help prioritize architectural understanding.
- [SKILL] Installed Codex skills require YAML frontmatter delimited by ---; a plain Markdown SKILL.md will be skipped as invalid.
- [VERSION] When bumping package metadata, also update CONFIG.VERSION because CLI banners and MCP serverInfo use the runtime constant rather than package.json.
- [VERSION] Version bump requires 4 files: `package.json`, `package-lock.json` (run `npm install --package-lock-only`), `lib/config.js` (CONFIG.VERSION), and `RELEASE_NOTES.md`. Missing lock file causes stale version in published artifact.
- [VERSION] README.md contains version strings in multiple locations: (1) header `# CODE-GRAPH (vX.Y.Z)`, (2) `## New in vX.Y.Z` section, (3) code block examples like `[Code-Graph vX.Y.Z]`. Always grep README for all version refs after bumping β€” stale inline examples are easy to miss.
- [ENV] Windows sandbox setup can fail before PowerShell runs; retry required reads with approved escalation instead of assuming command failure.
- [LOGIC] Shared reflection prompt text must mention llm-agent-rules.md because platform audit expects Cursor reflections rules to retain the rules-file link.
- [LOGIC] When changing generated skill prompt bodies, add the previous generated section text to upgrade cleanup or reinstall may duplicate prompt blocks.
- [BUG] installMCPServer in AgentManager wrote .mcp.json to project root on install-agent, causing Claude Code to prompt MCP installation in every project. Fix: removed all MCP registration methods; agent install now only creates the platform subagent file.
- [TEST] When adding a default bundled skill, update exhaustive install/uninstall expectations that assert every managed plugin, hook, or artifact.
- [ENV] If command execution is blocked by Windows sandbox and approvals are disabled, continue with filesystem MCP edits and report verification as blocked.
- [LOGIC] explicit cwd lesson
- [STYLE] backward compat test
# LLM_AGENT_RULES (STRICT PROTOCOL)
> This protocol is MANDATORY for all LLM agents. Failure to update memory is a failure of the task.
## 🧩 MANDATORY SKILLS
Every bundled skill is mandatory for every agent. Agents MUST follow ProjectMap, Reflections, ThinkBeforeCoding, Simplicity, SurgicalChanges, GoalDriven, FreshDeps, and ContextBudget together; none are optional preferences.
- **ProjectMap:** Read `llm-code-graph.md` before raw file inspection and use it to pick the smallest useful file set.
- **Reflections:** Read `llm-agent-project-learnings.md` before work and record reusable lessons after failures or non-obvious behavior.
- **ThinkBeforeCoding:** Surface assumptions, ambiguity, tradeoffs, and simpler options before non-trivial work.
- **Simplicity:** Write only what the task requires; no extra abstractions, features, or speculative handling.
- **SurgicalChanges:** Change only the explicitly required files and lines; no unrelated refactors or style churn. Clean up only artifacts introduced by your own change.
- **GoalDriven:** Define verifiable success criteria before implementation and report verification results or blockers.
- **FreshDeps:** Use latest stable compatible dependencies and current APIs. Avoid deprecated packages, methods, functions, flags, and patterns. If an agent repeats a stale or deprecated choice after correction, it MUST stop, re-read these rules, state that FreshDeps is mandatory, and replace the choice with the current stable approach.
- **ContextBudget:** Periodically condense working context into a compact rolling summary after each phase or every 10 tool calls.
## 🎯 GOAL-DRIVEN EXECUTION
For non-trivial tasks:
1. State the goal in verifiable terms.
2. State the smallest plan with a check for each step.
3. Reproduce bugs first when feasible.
4. Report verification result, failed check, or exact blocker before claiming completion.
## 🧠 THE REFLECTION CYCLE
Every execution MUST follow this cycle:
1. **PRE-TASK:** Before planning or making changes, read `llm-agent-project-learnings.md`.
2. **APPLY MEMORY:** Treat every relevant lesson as an active constraint. If a lesson matches the current file, tool, OS, dependency, or failure mode, state how it changes your approach.
3. **EXECUTION:** Monitor for failures, corrections, repeated mistakes, or non-obvious project behavior.
4. **POST-TASK:** Run `code-graph reflect <CAT> <LESSON>` for any new reusable lesson. Do not finish a bug fix, failed-command recovery, or environment workaround without either recording a reflection or explicitly stating that no new reusable lesson was learned.
## ⚠️ CRITICAL MANDATES
- **OS [win32]:** Always prefix npm commands with `cmd /c`.
- **FILE [index.js]:** This is the core engine. Any change here requires immediate `npm test` validation.
- **DOCS:** `llm-code-graph.md` is the "Source of Truth" for your context. Keep it accurate.
## πŸ“ REFLECTION CATEGORIES
- `LOGIC`: Code bugs, better patterns, or complex regex pitfalls.
- `ENV`: OS compatibility, shell behaviors, or CI/CD issues.
- `DEP`: Library bugs, version incompatibilities, or deprecations.
- `STYLE`: Naming conventions or project-specific architectural rules.