The .curt format.
.curt is an open, single-file format for AI chat conversations:
one file, one conversation, full fidelity — images and tool calls ride
verbatim. Born in Curtis AI Chat, specified openly so any app can
read and write it. Your history is files, not hostages.
File shape.
A .curt file is UTF-8 JSON (tab-indented by convention). The
generator field lets your app sign what it wrote — readers
must ignore it.
{
"curt": "curtis-conversation",
"version": 1,
"generator": "[email protected]",
"conversation": { ... }
} Writers may attach extra fields anywhere — tokens, images, tool-call linkage — and readers must preserve them on round-trip and never fail on them. The full field tables live in the spec.
Validation, version 1.
A reader accepts a file as .curt v1 when, and only when, the
body parses as JSON, the magic field is exactly
"curtis-conversation" with version 1, and the
conversation carries its id, title, timestamps,
and a messages array in which every entry passes message
validation. Anything else is a rejection — whole-file, not a best-effort
parse.
Multiple conversations travel as a zip of .curt files.
Versions change rarely and only additively within a version; version-1
files stay readable forever.
Read and write it.
The reference implementation is TypeScript, zero dependencies, MIT:
npm install curt-format import { serializeCurt, parseCurt } from 'curt-format';
const body = serializeCurt(conversation, '[email protected]');
const back = parseCurt(body); // CurtConversation | null — null means invalid curt-format on npm · dot_curt repository · SPEC.md · round-trip fixtures
Third-party writers are welcome. PRs for bindings in other languages too — keep the reference implementation and the spec in lockstep.