recall_file
Retrieve the complete edit history of any file, with per-edit user-intent context. Understand why a file was modified historically by querying session_file_edits instead of summary memories.
Instructions
Get the COMPLETE edit history of a file across all sessions, with per-edit user-intent context. Returns: total edit count, daily breakdown, list of distinct user intents that drove the edits, and the linked memories. Use this when you need to understand WHY a file was modified historically — far more accurate than recall() for file-centric questions because it queries session_file_edits (every physical edit) instead of summary memories.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path_substring | Yes | Substring to match against file_path (e.g. "search-services.ts" or full absolute path) | |
| max_intents | No | Max distinct user-intent snippets to return. Default 10. |
Implementation Reference
- src/mcp/server.ts:154-166 (registration)Tool registration for 'recall_file' in the TOOLS array, defining its name, description, and inputSchema (path_substring required, max_intents optional with default 10).
{ name: 'recall_file', description: 'Get the COMPLETE edit history of a file across all sessions, with per-edit user-intent context. Returns: total edit count, daily breakdown, list of distinct user intents that drove the edits, and the linked memories. Use this when you need to understand WHY a file was modified historically — far more accurate than recall() for file-centric questions because it queries session_file_edits (every physical edit) instead of summary memories.', inputSchema: { type: 'object', properties: { path_substring: { type: 'string', description: 'Substring to match against file_path (e.g. "search-services.ts" or full absolute path)' }, max_intents: { type: 'number', description: 'Max distinct user-intent snippets to return. Default 10.', default: 10 }, }, required: ['path_substring'], }, }, - src/mcp/server.ts:158-165 (schema)Input schema for recall_file: path_substring (string, required) and max_intents (number, default 10).
inputSchema: { type: 'object', properties: { path_substring: { type: 'string', description: 'Substring to match against file_path (e.g. "search-services.ts" or full absolute path)' }, max_intents: { type: 'number', description: 'Max distinct user-intent snippets to return. Default 10.', default: 10 }, }, required: ['path_substring'], }, - src/mcp/server.ts:722-787 (handler)Main handler function handleRecallFile: queries session_file_edits table for total edit count, daily breakdown, user intents (context_snippets), linked memories, and matched file paths. Returns structured JSON with all results.
function handleRecallFile(args: any): string { const sub = String(args.path_substring ?? '').trim(); if (!sub) return JSON.stringify({ ok: false, error: 'path_substring required' }); const maxIntents = Math.max(1, Math.min(50, args.max_intents ?? 10)); const totalRow = db.prepare(`SELECT COUNT(*) as c, MIN(occurred_at) as first_at, MAX(occurred_at) as last_at, COUNT(DISTINCT session_id) as sessions FROM session_file_edits WHERE file_path LIKE ?`).get(`%${sub}%`) as any; if (!totalRow || totalRow.c === 0) { return JSON.stringify({ ok: true, count: 0, note: 'No edits found for that path substring.' }); } // Daily breakdown const daily = db.prepare(` SELECT DATE(occurred_at, 'unixepoch') as day, operation, COUNT(*) as edits FROM session_file_edits WHERE file_path LIKE ? GROUP BY day, operation ORDER BY day `).all(`%${sub}%`) as any[]; // Distinct context_snippets (intents) — deduped, ordered by recency const intents = db.prepare(` SELECT DISTINCT context_snippet, MAX(occurred_at) as last_at, COUNT(*) as freq FROM session_file_edits WHERE file_path LIKE ? AND context_snippet IS NOT NULL AND LENGTH(context_snippet) > 20 GROUP BY context_snippet ORDER BY last_at DESC LIMIT ? `).all(`%${sub}%`, maxIntents) as any[]; // Linked memories const memories = db.prepare(` SELECT DISTINCT m.id, m.layer, m.content, m.importance, e.name as entity_name FROM session_file_edits sfe JOIN memories m ON m.id = sfe.memory_id JOIN entities e ON e.id = m.entity_id WHERE sfe.file_path LIKE ? ORDER BY m.importance DESC LIMIT 20 `).all(`%${sub}%`) as any[]; // Distinct file paths matched (the substring may match multiple files) const paths = db.prepare(`SELECT file_path, COUNT(*) as edits FROM session_file_edits WHERE file_path LIKE ? GROUP BY file_path ORDER BY edits DESC`).all(`%${sub}%`) as any[]; return JSON.stringify({ ok: true, path_substring: sub, paths_matched: paths, summary: { total_edits: totalRow.c, first_edit_at: new Date(totalRow.first_at * 1000).toISOString(), last_edit_at: new Date(totalRow.last_at * 1000).toISOString(), sessions_involved: totalRow.sessions, }, daily_breakdown: daily, user_intents: intents.map((i) => ({ when: new Date(i.last_at * 1000).toISOString(), occurrences: i.freq, intent: i.context_snippet, })), linked_memories: memories.map((m) => ({ id: m.id, entity: m.entity_name, layer: m.layer, importance: m.importance, preview: m.content.length > 300 ? m.content.slice(0, 300) + '...' : m.content, })), }); } - src/mcp/server.ts:810-810 (registration)MCP CallToolRequestSchema dispatcher: routes 'recall_file' to handleRecallFile function.
case 'recall_file': text = handleRecallFile(args); break; - src/lib/telemetry.ts:81-81 (helper)Telemetry tracking: recall_file_calls field in TelemetryPayload type, initialized to 0 in buildPayload.
recall_file_calls: number;