Share the whole conversation
A meeting recording, interview or podcast can carry who said what. Copy one file and its transcript comes along.
An ordinary audio file that carries its own transcript.
Cassini keeps audio, word timestamps and speaker labels together in a single .opus file. Send it, save it, build on it. The words travel with the recording.
Standard Ogg Opus. Open specification. No sidecar to lose.
3 speakers · 1:53 · Click a word to seek
Reading Saturday repair café: the rain plan…
Three fictional volunteers, voiced with ElevenLabs v3 on separate speaker tracks. Cassini transcribed the recording and produced this file. About this example
01 / Why keep them together?
A transcript should survive the trip from the tool that made it to the person who needs it.
A meeting recording, interview or podcast can carry who said what. Copy one file and its transcript comes along.
Listen in an Opus player. Read and seek in a Cassini viewer. The format also works for music with synchronized lyrics.
Original words and timings can sit beside display text and additional transcripts, with provenance recording what produced them.
02 / Inside the file
Cassini adds metadata where an audio file already keeps its title and artist: the OpusTags header.
Same extension. Same audio. More to work with.
Transcript
Word timestamps and speaker labels live in the audio file’s comment header. A Cassini reader turns them into a transcript you can navigate. Multiple transcripts can share the same recording.
{
"speaker": "spk_maya_a95db5b0ac159e4384ff55ef",
"startMs": 60,
"endMs": 459,
"text": "So,"
}The manifest and each transcript are UTF-8 JSON, gzipped, base64url-encoded and split across numbered comments. These values come from the downloadable example.
Payload values are shortened for display.
{
"kind": "cassini-portable-meeting",
"version": 1,
"profile": "ogg-opus",
"meeting": {
"id": "mtg_8d28b76a269092cd722ccaee50953dce9de30021c00146f33170c58ab50c0c80",
"title": "Saturday repair café: the rain plan",
"createdAtUtc": "2026-09-07T16:48:00.244576383Z",
"processedAtUtc": "2026-09-07T16:48:00Z",
"durationMs": 113113
},
"audio": {
"container": "ogg",
"codec": "opus",
"sampleRate": 48000,
"channels": 1,
"sampleCount": 5429448,
"durationMs": 113113
},
"integrity": {
"matchPolicy": "exact-opus-audio-v1",
"opusAudioSha256": "8d28b76a269092cd722ccaee50953dce9de30021c00146f33170c58ab50c0c80",
"sampleRate": 48000,
"channels": 1,
"sampleCount": 5429448,
"durationMs": 113113
},
"speakers": [
{
"id": "spk_maya_a95db5b0ac159e4384ff55ef",
"label": "Maya"
},
{
"id": "spk_tess_7134aac53eddcc48c4c90667",
"label": "Tess"
},
{
"id": "spk_jonah_b2d60d92ca43aa51a0c91ba9",
"label": "Jonah"
}
],
"transcripts": [
{
"id": "raw-asr",
"default": true,
"format": "cassini.words.v1",
"wordCount": 331,
"createdAtUtc": "2026-09-07T16:48:00Z",
"payloadRef": {
"prefix": "CASSINI_TX_RAW_ASR_PAYLOAD_",
"chunkCount": 2,
"sha256": "5a51f4c677c5637050a9019ac1c5824eb93891329423e967f941a51e53829505",
"rawBytes": 31850,
"gzipBytes": 4427,
"mime": "application/vnd.cassini.transcript-words+json",
"encoding": "base64url+gzip+utf8json"
}
}
],
"provenance": {
"speechToText": {
"raw-asr": {
"backend": "sherpa-onnx",
"model": "parakeet-tdt-0.6b-v3",
"device": "cpu",
"hints": {
"termCount": 3,
"decodingMethod": "greedy_search",
"applied": false,
"reason": "disabled by configuration (CASSINI_STT_HINTS_DISABLED)"
}
}
},
"attribution": {
"ran": true,
"mode": "annotate",
"wordsMeasured": 28,
"wordsFlagged": 0,
"wordsDropped": 0
},
"wordTimings": {
"endsBoundedByAudio": true
}
}
}In this example, the compressed manifest and transcript total 5.2 KB in a 0.86 MB file. These sizes exclude base64 encoding and tag overhead.
03 / Make something with it
Copy a reader, use the Python producer, or implement the specification in your own stack.
Get the transcript out in Python or JavaScript. Learn how to decode, verify and handle incomplete metadata.
Pack & preserveCombine an Opus recording with a word-timed transcript using a complete producer in standard-library Python.
Implement & validateFind the v1 contract, transcript format, audio digest, JSON Schemas and conformance suite in one place.
Working with a coding assistant?
Give it the complete specification in one text fileBefore you build
Version 1 is published and used by gocassini, the reference implementation. The ecosystem is still small. Read the project status →
The format stores a transcript you already have. Recording and speech recognition happen in a producer such as gocassini. The standalone Python producer takes audio and timed words as input.
They need a player that supports Ogg Opus to hear the audio. A Cassini reader is needed to display the embedded words and speaker labels. The browser reader is one example.
Audio edits can leave the embedded transcript out of date. A reader that checks the audio digest can detect a mismatch and label the transcript as stale. Software may also strip metadata, so check files after editing or converting them.
No. They check that data matches, including whether a transcript refers to the same audio. Anyone rewriting a file can recompute its hashes. Cassini does not provide signatures or proof of who said something.
Yes. The schemas, test vectors and standalone readers and producer are CC0. The specification text is CC BY 4.0. The transcript interface shown here comes from Cassini and is AGPL-3.0, as is the gocassini application. Start with the reference →