remember
Store structured memories about entities in six layers (goal, context, emotion, implementation, caveat, learning) to preserve non-obvious goals, failures, and decisions.
Instructions
Store a memory about an entity (person/company/project/concept/file) in one of 6 layers: goal (WHY), context (WHY-THIS-NOW), emotion (USER tone), implementation (HOW — success/failure), caveat (PAIN lesson, never forgotten), learning (GROWTH log). Use this when you discover non-obvious goals, unexpected failures, user preferences, or decisions worth preserving. Pasted assistant output or CI logs are rejected (use force=true only if you are sure).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| entity_name | Yes | Name of the entity this memory is about | |
| entity_kind | Yes | ||
| entity_key | No | Optional canonical key (email, domain, file path) | |
| layer | Yes | One of: goal / context / emotion / implementation / caveat / learning. Common aliases (why, decisions, warnings, how, ...) are accepted. | |
| content | Yes | The memory content (plain text or JSON) | |
| importance | No | 0.0-1.0. Set to 0.9 or higher to "pin" a memory (protects from forgetting even outside caveat layer). | |
| force | No | Bypass the paste-back/CI-log quality check. Only set when you are sure the content is original user or agent thought. |
Implementation Reference
- src/mcp/server.ts:206-250 (handler)The handleRemember function executes the 'remember' tool logic: resolves layers, checks for pasted external content, upserts the entity, inserts the memory record, logs an event, refreshes momentum, and returns the result.
function handleRemember(args: any): string { // Layer alias → canonical const layer = resolveLayer(args.layer); if (!layer || !(LAYER_ENUM as readonly string[]).includes(layer)) { return JSON.stringify({ ok: false, error: `unknown layer "${args.layer}". Known: ${LAYER_ENUM.join(', ')} (aliases: decisions, warnings, how, why, ...)`, }); } // Quality check — reject pasted external content unless force=true const rawContent = String(args.content ?? ''); if (!args.force && isPastedExternalContent(rawContent)) { return JSON.stringify({ ok: false, rejected: 'quality_check', reason: 'Content looks like pasted assistant output, CI log, or external paste. Pass force:true if this really is original thought worth keeping.', hint: 'If you meant to save an extracted insight from that paste, summarize it in your own words first.', }); } const entityId = upsertEntity({ name: args.entity_name, kind: args.entity_kind, key: args.entity_key }); const importance = Math.min(1, Math.max(0, Number(args.importance ?? 0.5))); const result = db .prepare('INSERT INTO memories (entity_id, layer, content, importance, protected) VALUES (?, ?, ?, ?, ?)') .run(entityId, layer, rawContent, importance, importance >= 0.9 ? 1 : 0); db.prepare('INSERT INTO events (entity_id, kind, payload) VALUES (?, ?, ?)').run( entityId, 'memory_stored', JSON.stringify({ layer, memory_id: result.lastInsertRowid }) ); const mom = refreshMomentumForEntity(db, entityId); return JSON.stringify({ ok: true, memory_id: Number(result.lastInsertRowid), entity_id: entityId, layer, pinned: importance >= 0.9, momentum: { score: mom.score, band: mom.band }, }); } - src/mcp/server.ts:61-76 (schema)The 'remember' tool schema definition in the TOOLS array: defines name, description, and inputSchema with properties entity_name, entity_kind, entity_key, layer, content, importance, force.
name: 'remember', description: 'Store a memory about an entity (person/company/project/concept/file) in one of 6 layers: goal (WHY), context (WHY-THIS-NOW), emotion (USER tone), implementation (HOW — success/failure), caveat (PAIN lesson, never forgotten), learning (GROWTH log). Use this when you discover non-obvious goals, unexpected failures, user preferences, or decisions worth preserving. Pasted assistant output or CI logs are rejected (use force=true only if you are sure).', inputSchema: { type: 'object', properties: { entity_name: { type: 'string', description: 'Name of the entity this memory is about' }, entity_kind: { type: 'string', enum: ['person', 'company', 'project', 'concept', 'file', 'other'] }, entity_key: { type: 'string', description: 'Optional canonical key (email, domain, file path)' }, layer: { type: 'string', description: 'One of: goal / context / emotion / implementation / caveat / learning. Common aliases (why, decisions, warnings, how, ...) are accepted.' }, content: { type: 'string', description: 'The memory content (plain text or JSON)' }, importance: { type: 'number', minimum: 0, maximum: 1, description: '0.0-1.0. Set to 0.9 or higher to "pin" a memory (protects from forgetting even outside caveat layer).' }, force: { type: 'boolean', default: false, description: 'Bypass the paste-back/CI-log quality check. Only set when you are sure the content is original user or agent thought.' }, }, required: ['entity_name', 'entity_kind', 'layer', 'content'], }, - src/mcp/server.ts:799-821 (registration)The MCP CallToolRequestSchema handler routes the 'remember' tool name to the handleRemember function (line 804).
server.setRequestHandler(CallToolRequestSchema, async (req) => { const { name, arguments: args } = req.params; try { let text: string; switch (name) { case 'remember': text = handleRemember(args); break; case 'recall': text = handleRecall(args); break; case 'update_memory': text = handleUpdateMemory(args); break; case 'list_entities': text = handleListEntities(args); break; case 'forget': text = handleForget(args); break; case 'consolidate': text = handleConsolidate(args); break; case 'recall_file': text = handleRecallFile(args); break; case 'read_smart': text = handleReadSmart(args); break; default: throw new Error(`Unknown tool: ${name}`); } return { content: [{ type: 'text', text }] }; } catch (err: any) { return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message ?? String(err) }) }], isError: true, }; } }); - src/mcp/server.ts:797-797 (registration)The tool is registered with the MCP server via ListToolsRequestSchema, returning the TOOLS array (line 797).
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); - src/mcp/server.ts:186-204 (helper)The upsertEntity helper function is used by handleRemember to find or create an entity by name/kind/key, returning the entity ID.
function upsertEntity(args: { name: string; kind: string; key?: string }): number { if (args.key) { const byKey = db.prepare('SELECT id FROM entities WHERE canonical_key = ?').get(args.key) as { id: number } | undefined; if (byKey) return byKey.id; } const byName = db .prepare('SELECT id FROM entities WHERE kind = ? AND LOWER(name) = LOWER(?)') .get(args.kind, args.name) as { id: number } | undefined; if (byName) { if (args.key) { db.prepare('UPDATE entities SET canonical_key = ?, updated_at = unixepoch() WHERE id = ? AND canonical_key IS NULL').run(args.key, byName.id); } return byName.id; } const result = db .prepare('INSERT INTO entities (kind, name, canonical_key) VALUES (?, ?, ?)') .run(args.kind, args.name, args.key ?? null); return Number(result.lastInsertRowid); }