update_memory
Atomically edit a memory in-place to correct facts, update deadlines, or re-score importance. Preserves memory_id for referential integrity.
Instructions
Atomically edit an existing memory in-place. Preferred over forget+remember because it preserves memory_id, which matters for session_file_edits links and referential integrity. Use to correct facts, update deadlines in goal entries, refine caveats, or re-score importance. Caveat-layer memories can be updated but cannot have their protected flag removed.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| memory_id | Yes | The memory.id to update | |
| content | No | New content (plain text or JSON). If omitted, content is kept. | |
| layer | No | Move to a different layer (aliases accepted). If omitted, layer is kept. | |
| importance | No | New importance 0-1. Set to 0.9 or higher to pin. |
Implementation Reference
- src/mcp/server.ts:606-659 (handler)The core handler function `handleUpdateMemory` that executes the update_memory tool logic. It looks up the memory by ID, patches content/layer/importance fields (with validation for caveat protection and layer aliases), runs the SQL UPDATE, records an audit event, and returns the result.
function handleUpdateMemory(args: any): string { const memoryId = Number(args.memory_id); if (!Number.isFinite(memoryId)) { return JSON.stringify({ ok: false, error: 'memory_id (number) required' }); } const existing = db.prepare('SELECT id, entity_id, layer, content, importance, protected FROM memories WHERE id = ?').get(memoryId) as any; if (!existing) { return JSON.stringify({ ok: false, error: `memory_id ${memoryId} not found` }); } const patch: Record<string, any> = {}; if (typeof args.content === 'string') patch.content = args.content; if (typeof args.layer === 'string') { const resolved = resolveLayer(args.layer); if (!resolved || !(LAYER_ENUM as readonly string[]).includes(resolved)) { return JSON.stringify({ ok: false, error: `unknown layer "${args.layer}"` }); } // Cannot demote a caveat out of caveat (caveat is auto-protected by trigger) if (existing.layer === 'caveat' && resolved !== 'caveat' && existing.protected === 1) { return JSON.stringify({ ok: false, error: 'Cannot move a protected caveat memory to another layer. Create a new memory in the target layer instead.', }); } patch.layer = resolved; } if (args.importance !== undefined) { const imp = Math.min(1, Math.max(0, Number(args.importance))); patch.importance = imp; patch.protected = imp >= 0.9 || existing.protected === 1 ? 1 : 0; } const keys = Object.keys(patch); if (keys.length === 0) { return JSON.stringify({ ok: false, error: 'no fields to update (provide content, layer, or importance)' }); } const setClause = keys.map((k) => `${k} = ?`).join(', '); const values = keys.map((k) => patch[k]); db.prepare(`UPDATE memories SET ${setClause} WHERE id = ?`).run(...values, memoryId); // Record the update as an event for audit trail db.prepare('INSERT INTO events (entity_id, kind, payload) VALUES (?, ?, ?)').run( existing.entity_id, 'memory_updated', JSON.stringify({ memory_id: memoryId, changed: keys }) ); return JSON.stringify({ ok: true, memory_id: memoryId, updated_fields: keys, pinned: (patch.importance ?? existing.importance) >= 0.9, }); } - src/mcp/server.ts:100-114 (schema)The input schema definition for the update_memory tool — declares parameters (memory_id required, content/layer/importance optional) with descriptions and constraints.
{ name: 'update_memory', description: 'Atomically edit an existing memory in-place. Preferred over forget+remember because it preserves memory_id, which matters for session_file_edits links and referential integrity. Use to correct facts, update deadlines in goal entries, refine caveats, or re-score importance. Caveat-layer memories can be updated but cannot have their protected flag removed.', inputSchema: { type: 'object', properties: { memory_id: { type: 'number', description: 'The memory.id to update' }, content: { type: 'string', description: 'New content (plain text or JSON). If omitted, content is kept.' }, layer: { type: 'string', description: 'Move to a different layer (aliases accepted). If omitted, layer is kept.' }, importance: { type: 'number', minimum: 0, maximum: 1, description: 'New importance 0-1. Set to 0.9 or higher to pin.' }, }, required: ['memory_id'], }, }, - src/mcp/server.ts:806-806 (registration)The dispatch switch-case that routes the 'update_memory' tool name to the handleUpdateMemory handler in the CallToolRequestSchema handler.
case 'update_memory': text = handleUpdateMemory(args); break; - src/mcp/server.ts:47-51 (helper)The resolveLayer helper function used by handleUpdateMemory to resolve layer aliases (e.g., 'decisions' to 'learning') before updating.
function resolveLayer(input: string | undefined): string | undefined { if (!input) return undefined; const k = String(input).toLowerCase().trim(); return LAYER_ALIASES[k] ?? k; }