memtrace 0.1.37 → 0.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/memtrace.js +102 -14
- package/install.js +21 -179
- package/installer/dist/commands/doctor.d.ts +16 -0
- package/installer/dist/commands/doctor.js +86 -0
- package/installer/dist/commands/install.d.ts +9 -0
- package/installer/dist/commands/install.js +104 -0
- package/installer/dist/commands/picker.d.ts +6 -0
- package/installer/dist/commands/picker.js +22 -0
- package/installer/dist/fs-safe.d.ts +21 -0
- package/installer/dist/fs-safe.js +35 -0
- package/installer/dist/index.d.ts +2 -0
- package/installer/dist/index.js +52 -0
- package/installer/dist/skills.d.ts +17 -0
- package/installer/dist/skills.js +64 -0
- package/installer/dist/transformers/claude.d.ts +41 -0
- package/installer/dist/transformers/claude.js +400 -0
- package/installer/dist/transformers/cursor.d.ts +7 -0
- package/installer/dist/transformers/cursor.js +84 -0
- package/installer/dist/transformers/index.d.ts +7 -0
- package/installer/dist/transformers/index.js +7 -0
- package/installer/dist/transformers/types.d.ts +39 -0
- package/installer/dist/transformers/types.js +1 -0
- package/installer/dist/utils.d.ts +5 -0
- package/installer/dist/utils.js +22 -0
- package/installer/package.json +49 -0
- package/installer/skills/commands/memtrace-api-topology.md +65 -0
- package/installer/skills/commands/memtrace-cochange.md +76 -0
- package/installer/skills/commands/memtrace-evolution.md +135 -0
- package/installer/skills/commands/memtrace-graph.md +117 -0
- package/installer/skills/commands/memtrace-impact.md +64 -0
- package/installer/skills/commands/memtrace-index.md +66 -0
- package/installer/skills/commands/memtrace-quality.md +69 -0
- package/installer/skills/commands/memtrace-relationships.md +73 -0
- package/installer/skills/commands/memtrace-search.md +67 -0
- package/installer/skills/workflows/memtrace-change-impact-analysis.md +85 -0
- package/installer/skills/workflows/memtrace-codebase-exploration.md +108 -0
- package/installer/skills/workflows/memtrace-episode-replay.md +100 -0
- package/installer/skills/workflows/memtrace-first.md +120 -0
- package/installer/skills/workflows/memtrace-incident-investigation.md +125 -0
- package/installer/skills/workflows/memtrace-refactoring-guide.md +116 -0
- package/installer/skills/workflows/memtrace-session-continuity.md +98 -0
- package/package.json +10 -5
- package/skills/commands/memtrace-api-topology.md +3 -0
- package/skills/commands/memtrace-cochange.md +3 -0
- package/skills/commands/memtrace-evolution.md +3 -0
- package/skills/commands/memtrace-graph.md +54 -4
- package/skills/commands/memtrace-impact.md +3 -0
- package/skills/commands/memtrace-index.md +3 -0
- package/skills/commands/memtrace-quality.md +3 -0
- package/skills/commands/memtrace-relationships.md +3 -0
- package/skills/commands/memtrace-search.md +18 -13
- package/skills/workflows/memtrace-first.md +12 -0
- package/uninstall.js +22 -28
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { safeReadJson, writeJsonAtomic } from '../fs-safe.js';
|
|
5
|
+
function skillsRoot(ctx) {
|
|
6
|
+
const base = ctx.scope === 'global' ? os.homedir() : ctx.cwd;
|
|
7
|
+
return path.join(base, '.cursor', 'skills');
|
|
8
|
+
}
|
|
9
|
+
function mcpPath(ctx) {
|
|
10
|
+
const base = ctx.scope === 'global' ? os.homedir() : ctx.cwd;
|
|
11
|
+
return path.join(base, '.cursor', 'mcp.json');
|
|
12
|
+
}
|
|
13
|
+
function writeSkill(skill, rootDir) {
|
|
14
|
+
const name = skill.filename.replace(/\.md$/, '');
|
|
15
|
+
const outDir = path.join(rootDir, name);
|
|
16
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
17
|
+
const safeDesc = skill.frontmatter.description.replace(/"/g, '\\"').trim();
|
|
18
|
+
// Cursor requires frontmatter `name` matching the folder name.
|
|
19
|
+
const content = `---\nname: ${name}\ndescription: "${safeDesc}"\n---\n\n${skill.body}`;
|
|
20
|
+
fs.writeFileSync(path.join(outDir, 'SKILL.md'), content);
|
|
21
|
+
}
|
|
22
|
+
export function registerCursorMcpAt(mcpFile, binary) {
|
|
23
|
+
const { value, corrupted, backupPath } = safeReadJson(mcpFile);
|
|
24
|
+
if (corrupted) {
|
|
25
|
+
console.warn(`memtrace: ${mcpFile} is malformed; backed up to ${backupPath}. Skipped Cursor MCP registration.`);
|
|
26
|
+
return { registered: false, backupPath };
|
|
27
|
+
}
|
|
28
|
+
const cfg = (value ?? {});
|
|
29
|
+
cfg.mcpServers = cfg.mcpServers ?? {};
|
|
30
|
+
cfg.mcpServers['memtrace'] = {
|
|
31
|
+
command: binary,
|
|
32
|
+
args: ['mcp'],
|
|
33
|
+
env: { MEMGRAPH_URL: 'bolt://localhost:7687' },
|
|
34
|
+
};
|
|
35
|
+
writeJsonAtomic(mcpFile, cfg);
|
|
36
|
+
return { registered: true };
|
|
37
|
+
}
|
|
38
|
+
export const cursorTransformer = {
|
|
39
|
+
name: 'cursor',
|
|
40
|
+
async install(skills, ctx) {
|
|
41
|
+
const rootDir = skillsRoot(ctx);
|
|
42
|
+
for (const s of skills)
|
|
43
|
+
writeSkill(s, rootDir);
|
|
44
|
+
let mcpRegistered = false;
|
|
45
|
+
if (!ctx.skipMcp) {
|
|
46
|
+
const result = registerCursorMcpAt(mcpPath(ctx), ctx.memtraceBinary);
|
|
47
|
+
mcpRegistered = result.registered;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
agent: 'cursor',
|
|
51
|
+
skillsWritten: skills.length,
|
|
52
|
+
skillsDir: rootDir,
|
|
53
|
+
mcpConfigPath: mcpPath(ctx),
|
|
54
|
+
mcpRegistered,
|
|
55
|
+
warnings: [],
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
async uninstall(ctx) {
|
|
59
|
+
// 1. Remove memtrace-* skill dirs
|
|
60
|
+
const rootDir = skillsRoot(ctx);
|
|
61
|
+
if (fs.existsSync(rootDir)) {
|
|
62
|
+
for (const entry of fs.readdirSync(rootDir)) {
|
|
63
|
+
if (entry.startsWith('memtrace-')) {
|
|
64
|
+
fs.rmSync(path.join(rootDir, entry), { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 2. Remove memtrace entry from mcp.json; delete file if empty
|
|
69
|
+
const mcpFile = mcpPath(ctx);
|
|
70
|
+
const { value, corrupted } = safeReadJson(mcpFile);
|
|
71
|
+
if (!corrupted && value?.mcpServers?.['memtrace']) {
|
|
72
|
+
delete value.mcpServers['memtrace'];
|
|
73
|
+
if (Object.keys(value.mcpServers).length === 0) {
|
|
74
|
+
delete value.mcpServers;
|
|
75
|
+
}
|
|
76
|
+
if (Object.keys(value).length === 0) {
|
|
77
|
+
fs.unlinkSync(mcpFile);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
writeJsonAtomic(mcpFile, value);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Transformer } from './types.js';
|
|
2
|
+
import { claudeTransformer } from './claude.js';
|
|
3
|
+
import { cursorTransformer } from './cursor.js';
|
|
4
|
+
export declare const ALL_TRANSFORMERS: Transformer[];
|
|
5
|
+
export declare function findTransformer(name: string): Transformer | undefined;
|
|
6
|
+
export { claudeTransformer, cursorTransformer };
|
|
7
|
+
export type { Transformer, InstallContext, InstallResult, TransformResult } from './types.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { claudeTransformer } from './claude.js';
|
|
2
|
+
import { cursorTransformer } from './cursor.js';
|
|
3
|
+
export const ALL_TRANSFORMERS = [claudeTransformer, cursorTransformer];
|
|
4
|
+
export function findTransformer(name) {
|
|
5
|
+
return ALL_TRANSFORMERS.find(t => t.name === name);
|
|
6
|
+
}
|
|
7
|
+
export { claudeTransformer, cursorTransformer };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Skill } from '../skills.js';
|
|
2
|
+
/**
|
|
3
|
+
* A single file to write for a given agent.
|
|
4
|
+
*/
|
|
5
|
+
export interface TransformResult {
|
|
6
|
+
/** Relative path from the agent's root skill directory. */
|
|
7
|
+
relativePath: string;
|
|
8
|
+
/** File content (UTF-8 text). */
|
|
9
|
+
content: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Runtime context passed to every transformer during install/uninstall.
|
|
13
|
+
*/
|
|
14
|
+
export interface InstallContext {
|
|
15
|
+
/** 'global' = write to ~/.<agent>/; 'local' = write to cwd's .<agent>/ */
|
|
16
|
+
scope: 'global' | 'local';
|
|
17
|
+
/** Used for local scope. Absolute path. */
|
|
18
|
+
cwd: string;
|
|
19
|
+
/** Command or absolute path used as the MCP server command. */
|
|
20
|
+
memtraceBinary: string;
|
|
21
|
+
/** When true, write skills but skip MCP registration. */
|
|
22
|
+
skipMcp?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface InstallResult {
|
|
25
|
+
agent: string;
|
|
26
|
+
skillsWritten: number;
|
|
27
|
+
skillsDir: string;
|
|
28
|
+
mcpConfigPath?: string;
|
|
29
|
+
mcpRegistered: boolean;
|
|
30
|
+
warnings: string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One transformer per supported AI coding agent.
|
|
34
|
+
*/
|
|
35
|
+
export interface Transformer {
|
|
36
|
+
name: 'claude' | 'cursor';
|
|
37
|
+
install(skills: Skill[], ctx: InstallContext): Promise<InstallResult>;
|
|
38
|
+
uninstall(ctx: InstallContext): Promise<void>;
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
export function execCommand(command, opts = {}) {
|
|
3
|
+
const timeout = opts.timeoutMs ?? 30_000;
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
exec(command, { timeout }, (error, stdout, stderr) => {
|
|
6
|
+
if (error)
|
|
7
|
+
reject(new Error(`Command failed: ${command}\n${stderr || error.message}`));
|
|
8
|
+
else
|
|
9
|
+
resolve(stdout.trim());
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export async function commandExists(cmd) {
|
|
14
|
+
try {
|
|
15
|
+
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
16
|
+
await execCommand(`${which} ${cmd}`, { timeoutMs: 5_000 });
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "memtrace-skills",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Memtrace skills for AI coding agents — codebase exploration, temporal evolution, impact analysis, and more.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"memtrace-skills": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"skills/",
|
|
12
|
+
"plugins/",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"prebuild": "node scripts/copy-skills.js",
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"commander": "^12.0.0",
|
|
24
|
+
"fs-extra": "^11.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/fs-extra": "^11.0.0",
|
|
28
|
+
"@types/node": "^20.0.0",
|
|
29
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
30
|
+
"typescript": "^5.4.0",
|
|
31
|
+
"vitest": "^4.1.4"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/syncable-dev/memtrace"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"memtrace",
|
|
43
|
+
"code-intelligence",
|
|
44
|
+
"mcp",
|
|
45
|
+
"skills",
|
|
46
|
+
"claude-code",
|
|
47
|
+
"ai-agent"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memtrace-api-topology
|
|
3
|
+
description: "Use when the user asks about API endpoints, HTTP routes, service-to-service calls, microservice dependencies, API topology, which services call which, cross-repo dependencies, or wants to understand the API surface of a codebase"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- mcp__memtrace__get_api_topology
|
|
6
|
+
- mcp__memtrace__find_api_endpoints
|
|
7
|
+
- mcp__memtrace__find_api_calls
|
|
8
|
+
- mcp__memtrace__get_symbol_context
|
|
9
|
+
- mcp__memtrace__link_repositories
|
|
10
|
+
user-invocable: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Map the HTTP API surface of a codebase — exposed endpoints, outbound HTTP calls, and cross-repo service-to-service dependency graphs. Supports auto-detection for Express, Encore, NestJS, Axum, FastAPI, Flask, Gin, Spring Boot, and more.
|
|
16
|
+
|
|
17
|
+
## Quick Reference
|
|
18
|
+
|
|
19
|
+
| Tool | Purpose |
|
|
20
|
+
|------|---------|
|
|
21
|
+
| `find_api_endpoints` | All exposed HTTP endpoints (GET /users, POST /orders, etc.) |
|
|
22
|
+
| `find_api_calls` | All outbound HTTP calls (fetch, axios, reqwest, etc.) |
|
|
23
|
+
| `get_api_topology` | Cross-repo call graph: which service calls which endpoint |
|
|
24
|
+
| `link_repositories` | Manually link repos for cross-repo edge detection |
|
|
25
|
+
|
|
26
|
+
> **Parameter types:** MCP parameters are strictly typed. Numbers (`limit`, `depth`, `min_size`, `last_n`, etc.) must be JSON numbers — not strings. Use `limit: 20`, never `limit: "20"`. Passing a string yields `MCP error -32602: invalid type: string, expected usize`.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Steps
|
|
30
|
+
|
|
31
|
+
### 1. Discover endpoints
|
|
32
|
+
|
|
33
|
+
Use `find_api_endpoints`:
|
|
34
|
+
- `repo_id` — required
|
|
35
|
+
- Returns: method, path, handler function, framework detected
|
|
36
|
+
|
|
37
|
+
### 2. Discover outbound calls
|
|
38
|
+
|
|
39
|
+
Use `find_api_calls`:
|
|
40
|
+
- `repo_id` — required
|
|
41
|
+
- Returns: target URL/path, HTTP method, calling function, library used (fetch, axios, reqwest, etc.)
|
|
42
|
+
|
|
43
|
+
### 3. Map service topology
|
|
44
|
+
|
|
45
|
+
Use `get_api_topology` to see the cross-repo HTTP call graph:
|
|
46
|
+
- Which services call which endpoints
|
|
47
|
+
- Confidence scores for each detected link
|
|
48
|
+
- Service-to-service dependency direction
|
|
49
|
+
|
|
50
|
+
**Prerequisite:** Multiple repos must be indexed. If cross-repo links aren't appearing, use `link_repositories` to explicitly connect them.
|
|
51
|
+
|
|
52
|
+
### 4. Deep-dive into an endpoint
|
|
53
|
+
|
|
54
|
+
For any specific endpoint, use `get_symbol_context` with the endpoint's symbol ID to see:
|
|
55
|
+
- Which internal functions handle the request
|
|
56
|
+
- Which processes (execution flows) include this endpoint
|
|
57
|
+
- Which external services call this endpoint
|
|
58
|
+
|
|
59
|
+
## Common Mistakes
|
|
60
|
+
|
|
61
|
+
| Mistake | Reality |
|
|
62
|
+
|---------|---------|
|
|
63
|
+
| Expecting cross-repo links with only one repo indexed | Index ALL related services first; cross-repo HTTP edges are linked automatically after indexing |
|
|
64
|
+
| Missing endpoints from custom frameworks | Memtrace auto-detects major frameworks; for custom routers, the endpoints may appear as regular functions |
|
|
65
|
+
| Not using `link_repositories` | If auto-linking missed a connection, use this to manually establish cross-repo edges |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memtrace-cochange
|
|
3
|
+
description: "Use when the user asks what tends to change together with a symbol, what other code moves when this moves, historical coupling, blast awareness before modifying a symbol, or wants to find hidden dependencies not visible in the call graph"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- mcp__memtrace__get_cochange_context
|
|
6
|
+
- mcp__memtrace__find_symbol
|
|
7
|
+
- mcp__memtrace__get_impact
|
|
8
|
+
user-invocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Find symbols that historically co-change with a target symbol — ranked by co-occurrence frequency across all episodes. This surfaces **behavioral coupling** that the static call graph cannot see.
|
|
14
|
+
|
|
15
|
+
`get_impact` answers "who calls this?" (structural).
|
|
16
|
+
`get_cochange_context` answers "what always moves when this moves?" (historical).
|
|
17
|
+
|
|
18
|
+
They are complementary. A symbol with no direct callers can still have strong cochange partners if it's always modified alongside another in every commit.
|
|
19
|
+
|
|
20
|
+
> **Parameter types:** MCP parameters are strictly typed. Numbers (`limit`, `depth`, `min_size`, `last_n`, etc.) must be JSON numbers — not strings. Use `limit: 20`, never `limit: "20"`. Passing a string yields `MCP error -32602: invalid type: string, expected usize`.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Steps
|
|
24
|
+
|
|
25
|
+
### 1. Identify the target symbol
|
|
26
|
+
|
|
27
|
+
Use `find_symbol` if you need the exact name. The tool matches by `name` field.
|
|
28
|
+
|
|
29
|
+
### 2. Call `get_cochange_context`
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
get_cochange_context(
|
|
33
|
+
repo_id: "...",
|
|
34
|
+
symbol: "execute", // exact symbol name
|
|
35
|
+
limit: 20 // default 20, increase for broader view
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 3. Interpret results
|
|
40
|
+
|
|
41
|
+
The response contains `cochanges[]`, each with:
|
|
42
|
+
- `name` — symbol name
|
|
43
|
+
- `kind` — Function / Method / Class / Struct
|
|
44
|
+
- `file_path` — where it lives
|
|
45
|
+
- `cochange_count` — how many episodes it shared with the target
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
High cochange_count = strong historical coupling
|
|
49
|
+
→ If you modify the target, you will likely need to touch this too
|
|
50
|
+
→ Or it may be the real root cause you should investigate first
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 4. Cross-reference with call graph
|
|
54
|
+
|
|
55
|
+
For the top cochange partners, optionally run `get_impact` to see if the coupling is also structural:
|
|
56
|
+
|
|
57
|
+
| Structural coupling | Historical coupling | Interpretation |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| Yes | Yes | Core architectural dependency — highest risk |
|
|
60
|
+
| No | Yes | Hidden coupling — only visible through history |
|
|
61
|
+
| Yes | No | Called frequently but changed independently — lower risk |
|
|
62
|
+
|
|
63
|
+
## When to Use
|
|
64
|
+
|
|
65
|
+
- **Before modifying a symbol** — get blast awareness beyond what `get_impact` shows
|
|
66
|
+
- **Incident investigation** — when `get_impact` doesn't explain the blast radius, check cochange history
|
|
67
|
+
- **Code review** — verify that a PR touched all historically-coupled partners
|
|
68
|
+
- **Refactoring** — discover implicit coupling before extracting a module
|
|
69
|
+
|
|
70
|
+
## Common Mistakes
|
|
71
|
+
|
|
72
|
+
| Mistake | Reality |
|
|
73
|
+
|---------|---------|
|
|
74
|
+
| Only using `get_impact` for blast radius | Structural coupling misses behavioral coupling — always pair with cochange |
|
|
75
|
+
| Ignoring low-`in_degree` cochange partners | A rarely-called utility with high cochange_count is a strong coupling signal |
|
|
76
|
+
| Using cochange as a dependency map | It's not a dependency graph — it's a change correlation. Two symbols can cochange without any direct relationship. |
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memtrace-evolution
|
|
3
|
+
description: "Use when the user asks what changed in the codebase, how code evolved over time, what was recently modified, what's the diff between versions, what changed since a date, incident investigation timeline, unexpected changes, change history, or temporal analysis of any kind"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- mcp__memtrace__get_evolution
|
|
6
|
+
- mcp__memtrace__get_timeline
|
|
7
|
+
- mcp__memtrace__detect_changes
|
|
8
|
+
- mcp__memtrace__list_indexed_repositories
|
|
9
|
+
- mcp__memtrace__get_changes_since
|
|
10
|
+
user-invocable: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Multi-mode temporal analysis engine that answers "what changed and why should I care?" across arbitrary time windows. Uses Structural Significance Budgeting (SSB) to surface the most important changes without overwhelming you with noise.
|
|
16
|
+
|
|
17
|
+
This is memtrace's most powerful analytical tool. It implements six distinct scoring algorithms — choose the right one based on what the user needs.
|
|
18
|
+
|
|
19
|
+
## Query Modes — Choose the Right Algorithm
|
|
20
|
+
|
|
21
|
+
| Mode | Algorithm | Best For |
|
|
22
|
+
|------|-----------|----------|
|
|
23
|
+
| `compound` | Rank-fusion: 0.50×impact + 0.35×novel + 0.15×recent | **Default.** General-purpose "what changed?" — use when unsure |
|
|
24
|
+
| `impact` | Structural Significance: `sig(n) = in_degree^0.7 × (1 + out_degree)^0.3` | "What broke?" — finds changes with the largest blast radius |
|
|
25
|
+
| `novel` | Change Surprise Index: `surprise(n) = (1 + in_degree) / (1 + change_freq_90d)` | "What's unexpected?" — anomaly detection for rarely-changing code |
|
|
26
|
+
| `recent` | Temporal Proximity: `impact × exp(−0.5 × Δhours)` | "What changed near the incident?" — time-weighted for root cause |
|
|
27
|
+
| `directional` | Asymmetric scoring (added→out_degree, removed→in_degree, modified→impact) | "What was added vs removed?" — structural change direction |
|
|
28
|
+
| `overview` | Fast module-level rollup only | Quick summary — no per-symbol scoring, just module counts |
|
|
29
|
+
|
|
30
|
+
> **Parameter types:** MCP parameters are strictly typed. Numbers (`limit`, `depth`, `min_size`, `last_n`, etc.) must be JSON numbers — not strings. Use `limit: 20`, never `limit: "20"`. Passing a string yields `MCP error -32602: invalid type: string, expected usize`.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Steps
|
|
34
|
+
|
|
35
|
+
### 1. Determine the time window
|
|
36
|
+
|
|
37
|
+
Ask the user or infer:
|
|
38
|
+
- `from` — ISO-8601 start timestamp (required)
|
|
39
|
+
- `to` — ISO-8601 end timestamp (defaults to now)
|
|
40
|
+
- `repo_id` — scope to a repo (call `list_indexed_repositories` if unknown)
|
|
41
|
+
|
|
42
|
+
### 2. Choose the mode
|
|
43
|
+
|
|
44
|
+
**Decision tree:**
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
User wants to know...
|
|
48
|
+
├── "what changed?" → compound (default)
|
|
49
|
+
├── "what could have broken?" → impact
|
|
50
|
+
├── "anything unexpected?" → novel
|
|
51
|
+
├── "what changed near X?" → recent (set to to incident time)
|
|
52
|
+
├── "what was added/removed?" → directional
|
|
53
|
+
└── "quick summary?" → overview
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 3. Execute the query
|
|
57
|
+
|
|
58
|
+
Use the `get_evolution` MCP tool with:
|
|
59
|
+
- `repo_id` — required
|
|
60
|
+
- `from` / `to` — the time window
|
|
61
|
+
- `mode` — one of: compound, impact, novel, recent, directional, overview
|
|
62
|
+
|
|
63
|
+
### 4. Interpret results
|
|
64
|
+
|
|
65
|
+
The response contains:
|
|
66
|
+
|
|
67
|
+
- **`added[]`** — new symbols that appeared in the time window
|
|
68
|
+
- **`removed[]`** — symbols that were deleted
|
|
69
|
+
- **`modified[]`** — symbols that changed
|
|
70
|
+
- **`by_module[]`** — module-level rollup (NEVER truncated — always shows all modules)
|
|
71
|
+
- **`significance_coverage`** — fraction of total significance captured (target: ≥0.80)
|
|
72
|
+
- **`budget_exhausted`** — if true, there were more significant changes than the budget allowed
|
|
73
|
+
|
|
74
|
+
Each symbol includes: `name`, `kind`, `file_path`, `scope_path`, `in_degree`, `out_degree`, and all four scores (`impact`, `novel`, `recent`, `compound`).
|
|
75
|
+
|
|
76
|
+
### 5. Drill deeper
|
|
77
|
+
|
|
78
|
+
- **For a single symbol's full history:** Use `get_timeline` with the symbol name
|
|
79
|
+
- **For diff-based change scope:** Use `detect_changes` when you have a specific diff/patch
|
|
80
|
+
- **For blast radius of a specific change:** Use `get_impact` on high-scoring symbols
|
|
81
|
+
|
|
82
|
+
## Scoring Algorithms — Detailed Reference
|
|
83
|
+
|
|
84
|
+
### Impact Score (Structural Significance Budgeting)
|
|
85
|
+
```
|
|
86
|
+
sig(n) = in_degree^0.7 × (1 + out_degree)^0.3
|
|
87
|
+
```
|
|
88
|
+
- Heavily weights callers (in_degree) — symbols called by many others have high blast radius
|
|
89
|
+
- Mild boost for outbound complexity (out_degree) — complex functions that changed are notable
|
|
90
|
+
- SSB selects the minimum set covering ≥80% of total significance mass
|
|
91
|
+
|
|
92
|
+
### Novelty Score (Change Surprise Index)
|
|
93
|
+
```
|
|
94
|
+
surprise(n) = (1 + in_degree) / (1 + change_freq_90d)
|
|
95
|
+
```
|
|
96
|
+
- High in_degree + low change frequency = **maximum surprise**
|
|
97
|
+
- A core utility that hasn't changed in 90 days suddenly changing → likely worth investigating
|
|
98
|
+
- Low in_degree + high frequency = routine churn, deprioritized
|
|
99
|
+
|
|
100
|
+
### Recent Score (Temporal Proximity Weighting)
|
|
101
|
+
```
|
|
102
|
+
recent(n) = impact(n) × exp(−0.5 × |Δhours to reference|)
|
|
103
|
+
```
|
|
104
|
+
- Exponential decay from the reference timestamp (the `to` parameter)
|
|
105
|
+
- Changes close to an incident get amplified; older changes fade
|
|
106
|
+
- Best for incident timelines: set `to` to the incident timestamp
|
|
107
|
+
|
|
108
|
+
### Compound Score (Rank Fusion)
|
|
109
|
+
```
|
|
110
|
+
compound = 0.50×rank(impact) + 0.35×rank(novel) + 0.15×rank(recent)
|
|
111
|
+
```
|
|
112
|
+
- Rank-based fusion avoids scale sensitivity between different score types
|
|
113
|
+
- Impact-dominant but boosted by novelty and recency
|
|
114
|
+
- Best default when you don't have a specific hypothesis
|
|
115
|
+
|
|
116
|
+
## Auto-overview Safety
|
|
117
|
+
|
|
118
|
+
If a time window produces more than 500 candidates and mode is not `overview`, the query **automatically downgrades to overview mode** and returns `auto_overview: true`. This prevents timeouts on wide windows. When you see `auto_overview: true`:
|
|
119
|
+
- Narrow the window, OR
|
|
120
|
+
- Switch to `get_changes_since` (which handles this automatically), OR
|
|
121
|
+
- Use the `by_module` rollup to identify the specific area and query a tighter window
|
|
122
|
+
|
|
123
|
+
## Session-Aware Alternative
|
|
124
|
+
|
|
125
|
+
If you're resuming work after a break and don't know the right `from` timestamp, use `get_changes_since` instead — it accepts a `last_episode_id` anchor and never requires timestamp guessing.
|
|
126
|
+
|
|
127
|
+
## Common Mistakes
|
|
128
|
+
|
|
129
|
+
| Mistake | Reality |
|
|
130
|
+
|---------|---------|
|
|
131
|
+
| Using `overview` when user needs details | Overview only gives module-level counts — use `compound` for symbol-level |
|
|
132
|
+
| Ignoring `budget_exhausted` flag | If true, there are more significant changes beyond what was returned — narrow the time window or use module rollup |
|
|
133
|
+
| Not checking `by_module` first | Module rollup is never truncated — scan it to identify which areas changed before diving into symbol-level |
|
|
134
|
+
| Using `recent` without setting `to` | The `to` timestamp is the reference point for proximity weighting — set it to the incident/event time |
|
|
135
|
+
| Guessing timestamps when resuming work | Use `get_changes_since` with a stored `session_anchor` instead — exact episode boundary, no guessing |
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memtrace-graph
|
|
3
|
+
description: "Use when the user asks about architectural bottlenecks, important symbols, PageRank, centrality, bridge functions, code communities, logical modules, service boundaries, chokepoints, or wants to understand the high-level architecture of a codebase"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- mcp__memtrace__find_bridge_symbols
|
|
6
|
+
- mcp__memtrace__find_central_symbols
|
|
7
|
+
- mcp__memtrace__list_communities
|
|
8
|
+
- mcp__memtrace__list_processes
|
|
9
|
+
- mcp__memtrace__get_process_flow
|
|
10
|
+
- mcp__memtrace__execute_cypher
|
|
11
|
+
user-invocable: true
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
Graph algorithms that reveal the structural architecture of a codebase — community detection (Louvain), centrality ranking (PageRank/degree), bridge symbol identification (betweenness), and execution flow tracing.
|
|
17
|
+
|
|
18
|
+
## Quick Reference
|
|
19
|
+
|
|
20
|
+
| Tool | Purpose |
|
|
21
|
+
|------|---------|
|
|
22
|
+
| `find_bridge_symbols` | Architectural chokepoints — symbols that connect otherwise-separate modules |
|
|
23
|
+
| `find_central_symbols` | Most important symbols by PageRank or degree centrality |
|
|
24
|
+
| `list_communities` | Louvain-detected logical modules/services |
|
|
25
|
+
| `list_processes` | Execution flows: HTTP handlers, background jobs, CLI commands, event handlers |
|
|
26
|
+
| `get_process_flow` | Trace a single process step-by-step |
|
|
27
|
+
| `execute_cypher` | Direct read-only Cypher queries for custom analysis |
|
|
28
|
+
|
|
29
|
+
## Parameter Types — Read This First
|
|
30
|
+
|
|
31
|
+
All memtrace MCP tools are **strictly typed**. Numbers must be JSON numbers, not strings.
|
|
32
|
+
|
|
33
|
+
| Parameter shape | Correct | Wrong (will fail deserialization) |
|
|
34
|
+
|-----------------|---------|-----------------------------------|
|
|
35
|
+
| Integer/count (`limit`, `min_size`, `depth`) | `limit: 20` | `limit: "20"` |
|
|
36
|
+
| String identifier (`repo_id`, `branch`, `name`) | `repo_id: "my-repo"` | `repo_id: my-repo` |
|
|
37
|
+
| Boolean (`fuzzy`, `include_tests`) | `fuzzy: true` | `fuzzy: "true"` |
|
|
38
|
+
|
|
39
|
+
If you see `MCP error -32602: invalid type: string "N", expected usize`, you passed a string where a number was required. Remove the quotes.
|
|
40
|
+
|
|
41
|
+
## Steps
|
|
42
|
+
|
|
43
|
+
### 1. Understand the architecture
|
|
44
|
+
|
|
45
|
+
Start with `list_communities` to see how the codebase is naturally partitioned into logical modules. Each community has a name, member count, and representative symbols.
|
|
46
|
+
|
|
47
|
+
**`list_communities` parameters:**
|
|
48
|
+
- `repo_id` — string, required. Repository ID (from `list_indexed_repositories`).
|
|
49
|
+
- `branch` — string, optional. Defaults to `"main"`.
|
|
50
|
+
- `min_size` — **integer**, optional. Minimum community size to include. Default `3`.
|
|
51
|
+
- `limit` — **integer**, optional. Max communities to return. Default `50`, capped at `200`.
|
|
52
|
+
|
|
53
|
+
Example (correct):
|
|
54
|
+
```json
|
|
55
|
+
{ "repo_id": "Memtrace", "limit": 20 }
|
|
56
|
+
```
|
|
57
|
+
Example (WRONG — will fail):
|
|
58
|
+
```json
|
|
59
|
+
{ "repo_id": "Memtrace", "limit": "20" }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. Find critical infrastructure
|
|
63
|
+
|
|
64
|
+
Use `find_central_symbols` to identify the most important symbols:
|
|
65
|
+
|
|
66
|
+
**`find_central_symbols` parameters:**
|
|
67
|
+
- `repo_id` — string, required.
|
|
68
|
+
- `branch` — string, optional. Defaults to `"main"`.
|
|
69
|
+
- `limit` — **integer**, optional. How many to return. Default `20`, capped at `100`.
|
|
70
|
+
- `algorithm` — string, optional. `"pagerank"` (default, via MAGE — falls back to degree if unavailable) or `"degree"` (simple in-degree count, no MAGE required).
|
|
71
|
+
|
|
72
|
+
### 3. Find architectural chokepoints
|
|
73
|
+
|
|
74
|
+
Use `find_bridge_symbols` to find symbols that, if removed, would disconnect parts of the graph. These are:
|
|
75
|
+
- **Single points of failure** — if they break, cascading failures occur
|
|
76
|
+
- **Integration points** — good places for interfaces/contracts
|
|
77
|
+
- **Refactoring targets** — often too much responsibility concentrated in one place
|
|
78
|
+
|
|
79
|
+
**`find_bridge_symbols` parameters:**
|
|
80
|
+
- `repo_id` — string, required.
|
|
81
|
+
- `branch` — string, optional. Defaults to `"main"`.
|
|
82
|
+
- `limit` — **integer**, optional. Default `15`, capped at `50`.
|
|
83
|
+
|
|
84
|
+
### 4. Trace execution flows
|
|
85
|
+
|
|
86
|
+
Use `list_processes` to see all entry points (HTTP handlers, background jobs, CLI commands, event handlers).
|
|
87
|
+
|
|
88
|
+
**`list_processes` parameters:**
|
|
89
|
+
- `repo_id` — string, required.
|
|
90
|
+
- `branch` — string, optional. Defaults to `"main"`.
|
|
91
|
+
- `limit` — **integer**, optional. Default `50`.
|
|
92
|
+
|
|
93
|
+
Use `get_process_flow` with a process name to trace a specific flow step-by-step — shows the full call chain from entry point through business logic to data access.
|
|
94
|
+
|
|
95
|
+
**`get_process_flow` parameters:**
|
|
96
|
+
- `process` — string, required. Process name or entry-point symbol name (from `list_processes`).
|
|
97
|
+
- `repo_id` — string, required.
|
|
98
|
+
- `branch` — string, optional. Defaults to `"main"`.
|
|
99
|
+
|
|
100
|
+
### 5. Custom queries
|
|
101
|
+
|
|
102
|
+
Use `execute_cypher` for advanced graph queries not covered by built-in tools. This is read-only and runs directly against the knowledge graph.
|
|
103
|
+
|
|
104
|
+
**`execute_cypher` parameters:**
|
|
105
|
+
- `query` — string, required. A read-only Cypher query. Write keywords (CREATE, MERGE, DELETE, SET, etc.) are forbidden. Use `$repo_id` to scope to a repository.
|
|
106
|
+
- `params` — object, optional. JSON object of parameter bindings.
|
|
107
|
+
- `repo_id` — string, optional. If provided, injected as `$repo_id` into `params`.
|
|
108
|
+
|
|
109
|
+
## Decision Points
|
|
110
|
+
|
|
111
|
+
| Question | Tool |
|
|
112
|
+
|----------|------|
|
|
113
|
+
| "What are the main modules?" | `list_communities` |
|
|
114
|
+
| "What are the most important functions?" | `find_central_symbols` with method=pagerank |
|
|
115
|
+
| "Where are the bottlenecks?" | `find_bridge_symbols` |
|
|
116
|
+
| "How does a request flow through the system?" | `list_processes` → `get_process_flow` |
|
|
117
|
+
| "What's the entry point for feature X?" | `list_processes`, then filter by name |
|