session_export_memory
Export project memory to local files for data portability and archiving. Supports JSON for machine-readable exports and Markdown for human-readable documentation.
Instructions
Export all of a project's memory to a local file. Fulfills GDPR Article 20 (Right to Data Portability) and the 'local-first' portability promise.
What is exported:
All session ledger entries (summaries, decisions, TODOs, file changes)
Current handoff state (live project context)
System settings (API keys are "REDACTED" for security)
Visual memory index (descriptions, captions, timestamps; not the raw files)
Formats:
json— machine-readable, suitable for import into another Prism instancemarkdown— human-readable, ideal for Obsidian, Notion, or archiving
⚠️ Output directory must exist and be writable. Filenames are auto-generated: prism-export-<project>-<date>.(json|md)
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project | No | Project to export. If omitted, exports ALL projects into separate files. | |
| format | No | Export format: 'json' (machine-readable) or 'markdown' (human-readable). Default: json. | json |
| output_dir | Yes | Absolute path to the directory where the export file(s) will be written. Must exist and be writable. Example: '/Users/admin/Desktop'. |
Implementation Reference
- The handler function `sessionExportMemoryHandler` that executes the `session_export_memory` tool logic. It fetches session data, redacts sensitive settings, and exports the data to a local JSON or Markdown file.
export async function sessionExportMemoryHandler(args: unknown) { if (!isSessionExportMemoryArgs(args)) { return { content: [{ type: "text", text: "Error: output_dir (string) is required." }], isError: true, }; } const { output_dir, format = "json" } = args; const requestedProject = (args as { project?: string }).project; // Validate output directory if (!existsSync(output_dir)) { return { content: [{ type: "text", text: `Error: output_dir does not exist: "${output_dir}". Please create it first.`, }], isError: true, }; } const storage = await getStorage(); const exportedFiles: string[] = []; try { // Determine which projects to export let projects: string[]; if (requestedProject) { projects = [requestedProject]; } else { projects = await storage.listProjects(); if (projects.length === 0) { return { content: [{ type: "text", text: "No projects found in memory — nothing to export." }], isError: false, }; } } // Fetch settings once (shared across all projects) const rawSettings = await getAllSettings(); const safeSettings = redactSettings(rawSettings); const exportedAt = new Date().toISOString(); const dateSuffix = exportedAt.split("T")[0]; // YYYY-MM-DD for (const project of projects) { debugLog(`[session_export_memory] Exporting project "${project}" as ${format}`); // Fetch handoff (live context) const ctx = await storage.loadContext(project, "deep", PRISM_USER_ID) as { metadata?: { visual_memory?: unknown[] }; [key: string]: unknown; } | null; // Fetch full ledger (all non-deleted entries) const ledger = await storage.getLedgerEntries({ project }) as Array<{ id?: string; created_at?: string; event_type?: string; summary: string; todos?: string[]; decisions?: string[]; files_changed?: string[]; embedding?: string | null; // strip from export (large + not human-useful) [key: string]: unknown; }>; // Strip raw embedding vectors from the export (large binary data) const cleanLedger = ledger.map(({ embedding: _emb, ...rest }) => rest); const visualMemory = (ctx?.metadata?.visual_memory as unknown[] | undefined) ?? []; const exportPayload = { prism_export: { version: "4.5", exported_at: exportedAt, project, settings: safeSettings, handoff: ctx ?? null, visual_memory: visualMemory, ledger: cleanLedger, }, }; // Serialize const ext = format === "markdown" ? "md" : "json"; const filename = `prism-export-${project}-${dateSuffix}.${ext}`; const outputPath = join(output_dir, filename); let content: string; if (format === "markdown") { content = toMarkdown(exportPayload); } else { content = JSON.stringify(exportPayload, null, 2); } await writeFile(outputPath, content, "utf-8"); exportedFiles.push(outputPath); debugLog(`[session_export_memory] Wrote ${content.length} bytes to ${outputPath}`); } const plural = exportedFiles.length > 1 ? "files" : "file"; return { content: [{ type: "text", text: `✅ Memory exported successfully (${format.toUpperCase()})\n\n` + `**Project(s):** ${projects.join(", ")}\n` + `**${exportedFiles.length} ${plural} written:**\n` + exportedFiles.map(f => ` \u2022 \`${f}\``).join("\n") + `\n\n⚠️ API keys have been redacted. Vault image files are NOT included — ` + `only metadata and captions. Re-run \`session_save_image\` to re-attach images.`, }], isError: false, }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); console.error(`[session_export_memory] Error: ${msg}`); return { content: [{ type: "text", text: `Export failed: ${msg}` }], isError: true, }; } }