Back to docs
Exports

Take your memory anywhere.

Export any subset of your memories — by namespace, by conversation, or all of it at once — to Markdown, HTML, JSON, NDJSON, or CSV. Drop the file into Claude, Cursor, Cline, ChatGPT, a spreadsheet, or your own pipeline. Your memory belongs to you, in whatever format helps you reuse it.

Why exports matter

Memory in mnueron is a database, but the tools you use day to day expect files. When you want to brief a new chat session on the last six months of work, you don't want to retype a summary — you want to drop in your saved notes. When you want a human collaborator to see how a decision evolved, you want a single document, not access to a dashboard. Exports bridge those use cases:

  • Reuse as agent context. Drop the markdown into Claude Desktop, Cursor, Cline, or any chat that accepts file attachments. The agent grounds its responses in your actual history instead of starting fresh.
  • Share with humans. HTML opens in any browser; Print → Save as PDF gives you a polished read-only document you can email or attach to a ticket.
  • Back up or migrate. JSON / NDJSON are round-trip safe — re-import into another mnueron instance to restore your namespace exactly. Useful before destructive operations or when moving between local-first and hosted modes.
  • Analyze. Open the CSV in a spreadsheet, query the NDJSON with jq or DuckDB, or pipe it into your own data warehouse. Your memory is just rows you have first-class access to.

Five formats, one click each

Pick the format that matches where you're taking your data.

Markdown

.md

Best for

Reusing memories as context in Claude, Cursor, Cline, ChatGPT, or any LLM chat surface

Each memory becomes a heading with timestamp + role + namespace metadata, then the content body, then any tags as inline code chips. Threads render as transcripts when you turn on conversation grouping. This is the format LLM chat tools ingest most cleanly via drag-and-drop or paste.

HTML

.html

Best for

Sharing a polished read-only view, or producing a PDF via your browser's Print dialog

Single self-contained HTML document with inline CSS — no external assets, opens in any browser. Each memory becomes a card with a meta bar (role, timestamp, source), the content as preformatted text, and tags as chips. A print stylesheet keeps cards intact across page breaks so Print → Save as PDF produces a clean multi-page document without you adding any PDF library to the deploy.

JSON

.json

Best for

Programmatic re-import or analysis pipelines

A single JSON array of memory rows, each row preserving every column the API exposes: id, content, namespace, tags, source, source_ref, metadata, created_at, updated_at. Round-trip safe — you can POST this back to mnueron's import endpoint to restore the exact same memories on another instance.

NDJSON

.ndjson

Best for

Streaming or processing a large export line by line

Same shape as JSON, but each memory is on its own line as a standalone JSON object. Process it without loading the whole file into memory — useful for very large exports where a 200MB JSON array would be impractical. Most data tools (jq, DuckDB, BigQuery, ClickHouse) read NDJSON natively.

CSV

.csv

Best for

Opening in Excel / Google Sheets, or feeding a data warehouse

RFC-4180 compliant CSV with the columns id, content, namespace, tags, source, source_ref, created_at, updated_at. Multi-line content is properly quoted; embedded quotes are doubled. Tags collapse to a single column with the array stringified. Use when you need flat tabular data for a spreadsheet or BI tool.

Group by conversation, namespace, or not at all

The group_by option controls how memories are clustered in the output. Picking the right grouping mode turns a raw memory dump into a document that actually reads well.

Flat

group_by: "none"

All memories appear in chronological order, oldest first. No section headers between them.

Use when: You want one continuous timeline — e.g. exporting a single namespace to study your own usage, or producing a flat CSV for a spreadsheet.

By conversation

group_by: "thread"

Memories are grouped by metadata.parent_ref so chat turns from the same thread cluster together as a transcript. Each conversation gets a section header derived from its first line.

Use when: You're exporting imported chat history (claude-cowork, web-claude, web-chatgpt) and want it to read like discrete conversations rather than a fire-hose of unrelated turns. This is what most users want when they say 'export by conversation'.

By namespace

group_by: "namespace"

Memories grouped by their namespace, with a heading for each section. Inside each section, rows are chronological.

Use when: You have many namespaces and want a single document organized by project — for example, exporting both work and personal namespaces to one HTML file to share with a teammate.

Exporting from the dashboard

The fastest way to export — no command line, no scripts.

  1. 1

    Sign in and open /dashboard. The memory list appears with the usual three-pane layout.

  2. 2

    Click the Export button in the header (next to Import). A dialog opens.

  3. 3

    Pick a format. Markdown is the best default if you're reusing the file as agent context; HTML if you're sharing it; JSON if you're going to re-import it later.

  4. 4

    Pick a grouping mode. By conversation is what you want for chat-history exports; By namespace if you have many projects and want a single organized document; Flat if you want raw chronological order.

  5. 5

    Optionally narrow the export to a single namespace using the dropdown. Leaving it blank exports across every namespace you have access to.

  6. 6

    Click Export. Your browser downloads the file directly. The success line tells you how many memories were included.

API reference

The dashboard dialog is a thin wrapper around the export endpoint. If you want to automate exports (nightly backups, CI workflows, custom UIs), hit the endpoint directly.

POST/api/memories/exports

Request body fields (all optional):

  • format json | ndjson | csv | md | html. Default json.
  • group_by none | thread | namespace. Default none.
  • namespace — restrict to one namespace.
  • tags — array of tag strings; only memories tagged with all of them match.
  • created_after and created_before — unix epoch milliseconds for date range filtering.
  • metadata_filter — object; memories with matching metadata keys via JSONB containment.

curl

curl -X POST https://your-mnueron.app/api/memories/exports \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
    "format": "md",
    "group_by": "thread",
    "namespace": "claude-cowork"
  }' > export.md

JavaScript (browser, logged in)

const resp = await fetch("/api/memories/exports", {
  method: "POST",
  credentials: "same-origin",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    format: "md",
    group_by: "thread",
    namespace: "mnueron-dev",
  }),
});
const data = await resp.json();
const blob = new Blob([data.payload], { type: "text/markdown" });
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "mnueron-dev.md";
a.click();

Response shape

{
  "id":           "export-uuid",
  "status":       "completed" | "pending",
  "format":       "md",
  "row_count":    127,
  "filters":      { /* echo of what you asked for */ },
  "payload":      "# Memory export\n\n...",
  "download_url": null,
  "created_at":   1735503600000,
  "completed_at": 1735503601234
}
10,000+ rows

Large exports go through a queue

The endpoint serves exports of up to 10,000 rows inline — the full payload comes back in the response and the browser triggers a download immediately. Above that threshold, the API instead returns status: "pending" and queues the export for a background worker. This keeps single-request response times reasonable for everyone and prevents accidentally OOM-ing the server with a namespace-wide export of millions of rows.

The dashboard handles this transparently — the success line tells you the export is queued and will appear on your exports list once the worker materializes it. From GET /api/memories/exports you can poll the status of any export. For now, if you can narrow your filter to under the cap (one namespace, a date range, a tag combination), the inline path is faster.

Round-trip: export, then re-import

JSON and NDJSON exports are intentionally round-trip safe. You can POST the file back to /api/memories/batch and every memory is restored with its original namespace, tags, source, source_ref, metadata, and timestamps. This makes exports practical as a backup format or a way to migrate between mnueron instances (e.g. from a hosted prod environment to a local-first SQLite store).

Markdown and HTML are not round-trip safe — they discard some structured fields in the name of human readability. Tag arrays become comma-separated chips, metadata flattens to the visible meta line, and timestamps round to minute precision. Use them as outputs for human / LLM consumption; use JSON / NDJSON for anything that needs to come back as memory.

FAQ

Where do exported files come from? Is anything stored on the server?

When you click Export, the browser POSTs the filter to /api/memories/exports. The server runs the query inside your tenant scope (RLS enforces org isolation), encodes the result in the format you picked, and returns the encoded payload in the response body. The browser then wraps the payload in a Blob and triggers a download — the file never lives on disk anywhere except your machine.

Is there a row limit?

Synchronous exports cap at 10,000 rows. If your filter matches more than that, the API returns status: 'pending' instead of a payload and queues the export for a background worker. Once materialized, the export shows up in your exports list and downloads from there. For most users, even an entire mnueron-dev namespace fits comfortably under the cap.

Can I export just one conversation?

Yes — set the namespace filter to that conversation's namespace and group_by to 'thread'. The export will produce sections per parent_ref, each containing only the turns in that thread. A future Export this thread button on the memory detail page will pre-fill these filters automatically.

How do I make a PDF?

Pick the HTML format, download the file, open it in your browser, then Ctrl+P / Cmd+P and choose Save as PDF. The print stylesheet keeps memory cards intact across page breaks so the result reads cleanly. We deliberately don't bundle a server-side PDF renderer (puppeteer, pdfkit, etc.) — it would add ~150MB to the deploy and produce output no better than your browser already does for free.

Can I re-import an exported file later?

Yes for JSON and NDJSON. POST the file's contents back to /api/memories/batch and every memory is restored with its original namespace, tags, source, and metadata. Markdown and HTML are designed for human / LLM consumption — they're not round-trip safe because tag stringification and the heading layout drop some structured fields.

Are tokens / costs / IDE crashes tracked when I export?

No. Exports are pure read operations against the memory store — they don't fire any recall events or affect your savings dashboard. The metrics on /dashboard/overview track memory_recall calls (LLM-driven reads), not export downloads.

Will my private memories show up in a team or public export?

Visibility ACLs are enforced at the row-level by RLS, so an export only includes memories your session can already SELECT. If a memory has been marked Team or Public in its entity_visibility row, it remains accessible to that audience regardless — visibility is a property of the data, not the export.

Your memory, your file, your move.

Five formats. Three grouping modes. One click. Take what you've saved anywhere it makes sense to land next.