SPECIMEN · .CURT V1 · OPEN FORMAT

One file, one conversation.

.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.

open standardplain textMIT referencezero deps

The file

The shape of a record.

A .curt file is UTF-8 JSON. The generator field lets your app sign what it wrote — readers must ignore it. The agent layer is the point: tokens, cost, memories used, tool linkage — the fields other formats throw away.

Names are derived from immutable fields — date slug id.curt — so renames never orphan or collide, and ids are conv_/msg_ plus timestamp and randomness that readers never validate the shape of. Re-import a file and the title-plus-count fingerprint makes it a no-op. The full field tables live in the spec.

The guarantee

Why the format can be trusted.

01

Full fidelity

One conversation, one file, UTF-8 JSON. Images ride inline as base64, tool calls keep their linkage, and the round-trip is checked, not assumed — the porter's verify command re-serializes every file and compares bytes.

verify, not trust
02

Strict validation

A reader accepts a file as .curt v1 only when the body parses as JSON, the magic field is exactly "curtis-conversation" with version 1, and every message validates. A corrupted file is rejected whole, never half-imported.

whole-file, not best-effort
03

Open by construction

Extra fields ride along on round-trip and never fail a reader. The extension registry tracks which are stable — an entry only goes stable once two independent implementations round-trip it.

stable needs two implementations

Versions change rarely and only additively within a version; version-1 files stay readable forever. Conformance vectors ship in the repository so a second implementation doesn't have to guess.

What survives

Every shape, honestly.

THE GAP IS DELIBERATE

Foreign parsers keep user and assistant turns only — system and tool messages are dropped, and per-message model survives just ChatGPT's model_slug. That isn't loss: foreign exports don't carry the agent layer, and .curt refuses to invent it.

Implement it

Read and write it.

The reference implementation is TypeScript, zero dependencies:

npm install curt-format
import { serializeCurt, parseCurt } from 'curt-format';

const body = serializeCurt(conversation, '[email protected]');
const back = parseCurt(body); // 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.

Stated plainly

No license required.

The format is free for any tool to adopt — plain text, open spec, no permission asked. The reference implementation is MIT licensed; the format itself belongs to whoever needs it.