Skip to main content

Exporting AI conversations: ChatGPT, Claude, Gemini, and agent logs

A practical guide to getting your AI chat history out of each platform in a form you can keep. Nothing here is proprietary knowledge — the exports are things the platforms already hand you. The problems with them, and what .curt does about each, are stated as they are; the comparison page carries the full adversarial version of the same argument.

Why this is harder than it should be​

Every major AI platform has an export feature, and every one of them hands you a private snapshot of the platform's internal database. The preprint documents the pattern across the landscape (§1–§2): the exports are undocumented (no published schema), unversioned (they change without notice, because nothing external depends on them contractually), and validation-free (there is no rule for detecting a corrupted export — bridge tools typically half-import whatever parses). They are the problem statement, not part of the solution space.

.curt is the counter-proposal: one open, versioned, validated file per conversation, with executable conformance vectors so a claim like "reads .curt" is testable rather than prose.

ChatGPT​

How to export: ChatGPT → Settings → Data controls → Export data. OpenAI emails a download link; the archive is a zip whose centerpiece is conversations.json.

What's inside: an array of conversation objects. Each carries a title, timestamps, and a mapping — a tree of message nodes, not a linear list. The live thread is found by walking from the root to current_node, which is why a regenerated answer stays in its branch instead of corrupting the file. Message content arrives as {text} or {parts: [...]} depending on message age and type.

What breaks: the field names and the mapping shape are undocumented and have shifted before; a consumer has no way to tell a truncated export from a complete one; branch handling is on you.

Converting: drag the zip (or conversations.json itself) onto dotcurt.org/try. The converter walks the mapping from the current node, so the branch you actually see in the UI is the one that lands in the file, then writes conforming .curt files through the reference implementation. It runs entirely in your browser — nothing is uploaded.

Claude​

How to export: Claude → Settings → Privacy → Export data. Anthropic emails a link to a zip containing conversations.json.

What's inside: conversation objects whose chat_messages is a flat list, with threading expressed by parent_uuid chaining rather than a tree. Titles ride in a name field.

What breaks: same class of problem — undocumented, unversioned, no validation rule. The parent-uuid chain means a tool that ignores it flattens edited conversations silently.

Converting: the same dotcurt.org/try page reads Claude exports from their chat-message lists and chains the parent UUIDs correctly. In a terminal, the browser extension (Curt Conversation Exporter) grabs the conversation already open in your tab in one click, locally.

Gemini​

How to export: Google Takeout. Gemini's history arrives as activity logs (HTML or JSON), not as a conversation-first archive.

What breaks: Takeout's logs are an audit trail, not a transcript — there is no per-conversation object with roles and timestamps in the shape the other vendors provide, so no faithful one-click mapping exists. This is the honest limit: the guide's other conversions are lossless at the text level; Gemini's is best-effort at best. The preprint's landscape survey treats this as evidence for the portability argument, not a defect to paper over.

Claude Code and agent session logs​

What's inside: agent frameworks keep session transcripts as local JSONL event logs — Claude Code writes one JSONL file per session; the same pattern shows up in other agent runtimes (OpenClaw, Hermes). These are the most machine-readable exports in the ecosystem, and the least portable: a private event stream with no schema, tied to the tool's internal model of a session.

Converting: curt-convert (npm) maps Claude Code session JSONL to .curt, including the tool-linkage extension for tool-call/result pairs. Agent-framework runtimes have their own converters: curt-openclaw (npm) reads OpenClaw's file-based gateway session store, and curt-hermes (npm) reads Hermes's state.db — and emits Claude Code session JSONL, which Hermes imports natively, closing the loop without any upstream change. curt-codex (npm) bridges OpenAI Codex CLI rollouts both ways. For runtimes without a converter yet, the mapping is small (the .curt envelope has few required fields), and the extension registry is the intended route for agent-specific provenance such as multi-agent context (agent-context). LangChain applications can read .curt directly via langchain-curt (PyPI).

Self-hosted chat UIs​

Open WebUI: curt-openwebui is a TypeScript CLI plus an Open WebUI pipelines filter that exports local chats to .curt — no cloud involved, by construction.

Bulk and research corpora​

WildChat-1M: curt-wildchat converts WildChat-1M records (ODC-BY licensed) to .curt. The bulk evidence run — 1,000 records converted, 100% independent re-parse — is the L3 conformance artifact.

After conversion​

  • Keep the files. A .curt file is UTF-8 JSON, readable in any editor, and version-1 files stay readable forever by rule — the spec freezes v1's meaning.
  • Read them anywhere: dotcurt.org/viewer opens any .curt file in the browser, or double-click with curt-openwith (Windows, macOS, Linux).
  • Validate before you trust an archive: the reader rejects a corrupted file whole — never half-imports it. The JSON Schema covers editor and linter integration.
  • Interop: curt-vcon bridges to the IETF vCon container where a telephony-domain system needs the overlap.

The portability framing​

GDPR Article 20 gives you the right to receive your data "in a structured, commonly used and machine-readable format." A vendor snapshot of a private database satisfies the letter and not the spirit — you cannot build on it, and nothing external can commit to parsing it. A frozen, documented, openly licensed format with executable conformance vectors is what the spirit requires. That is the whole argument of the preprint; the format is the answer.