# Chitmonk docs Chitmonk is a meeting companion for rooms with people in them. A laptop on the table listens through its own microphone, transcribes on the device, lets the room say who is speaking, and ends with a receipt. There is no account and no server. A meeting stays in the browser it was recorded in until someone exports it. These pages are what you need to work with it, and no more. ## For people - **[Using Chitmonk](/using/)**: the keys, the languages, where meetings are kept, and what to know before you rely on it. - **[Privacy](/privacy/)**: what stays on the device, and the two things that can ever leave it. - **[Terms of use](/terms/)**: what you may do, who owns what, and what Chitmonk is and is not responsible for. - **[Chet](/chet/)**: the chipmunk. Not needed. Recommended. ## For developers and agents - **[The .chit bundle](/chit/)**: the file a meeting leaves the app in. A ZIP with a manifest and one event log per meeting. - **[The event log](/chit/events/)**: every event, its fields, and the rules for replaying a log into a meeting. - **[Read a bundle](/chit/read/)** and **[write one](/chit/write/)**: short scripts, standard library only. - **[Other exports](/exports/)**: the Markdown, plain text and Word files, for when a reader is all you need. - **[For agents](/agents/)**: where the plain-text copies of these pages are, and the rules for touching someone's meetings. Two files to keep next to you: the [JSON Schema](/chit.schema.json) of everything in a bundle, and a small [sample bundle](/sample.chit). ## What is not here Chitmonk is proprietary for now. There is no source code here and no API to call: the app has no server, so there is nothing to call. Integration is the file. If you can read and write a `.chit`, you can get meetings out of Chitmonk and into it. [More on that](/licence/). --- # Using Chitmonk Open it and start. Say what the meeting is about, add who is in the room, press **Start meeting**. Nothing needs an account. ## During a meeting Lines appear a moment after each pause in speech. The first time a voice is heard, say who it is: press that person's number. After that Chitmonk suggests the name, with a dashed outline and a question mark, and you confirm or correct it. A name is only ever solid when a person put it there. | Key | What it does | | --- | --- | | `1` to `9` | Assign the current line (or the selected one) to that person | | `0` | Mark as unassigned | | `+` | Add a person | | `Space` | Pause or resume | | `C` | Captions on or off | | `↑` `↓` | Move between transcript lines | | `Enter` | Edit the selected line | | `N` | Add a side note to the selected line | | `Esc` | Close captions or a dialog | | `?` | Show this list | | `Cmd/Ctrl` `K` | Open the library and search | Shortcuts are off while you are typing. **Captions** fill the screen with large text, the last few lines only, for anyone in the room who reads better than they hear. **Side notes** are yours, not the room's. They sit beside a line, never inside it, and are exported in their own section. ## Afterwards Ending a meeting prints its receipt: who talked for how long, the action items and decisions that were spotted, and what still needs a speaker. Action items and decisions are found by plain phrase rules, in English only, and each one is a suggestion until you accept it. **Export** gives you Markdown, plain text, Word, or a `.chit` bundle. The bundle is the only one that loses nothing: [what is in it](/chit/). The others are for reading: [what they look like](/exports/). ## Languages English, German, French, Spanish, Italian, Dutch and Polish. Leave the language on auto-detect and the receipt says which ones it heard. Other languages will not transcribe well. ## Where meetings are kept In this browser, on this device, and nowhere else. That has consequences worth knowing: - **Another browser or another laptop does not have them.** Move a meeting by exporting a `.chit` and importing it there (the library drawer, then **Import**). - **The browser can clear its storage**, and so can you. Export a bundle now and then as a backup. **Export all** in the library drawer writes every meeting into one file. - **Passcode protection** (Settings, Privacy) encrypts saved history on the device. It protects stored meetings, not a laptop that is already unlocked and open. A forgotten passcode cannot be recovered. - **Shared device** (in a meeting's options) never saves the meeting at all. When you close it, it is gone unless you exported it first. - **Audio is not kept** unless you switch on "Keep the audio" for a meeting. Then it is stored on the device, about 14 MB per hour, and can be included in a bundle. ## Offline After the one download of the speech engine (33 MB, plus 28 MB if you want speaker suggestions), Chitmonk works with the network switched off. Your browser's install option keeps it as an app. ## Browsers | Browser | Status | | --- | --- | | Chrome, and Edge by shared engine | Works, fully tested | | Safari | Tested on Safari's engine. Keeping audio is unavailable there, and the app says so | | Firefox | Not verified | | Phones | Not tested | A browser that cannot transcribe can still open, search, import and export meetings. ## What to know before you rely on it - The speech model is small (17 MB) and makes mistakes, more on short phrases, names and distant voices. Every line is editable for that reason, and "words to listen for" nudges spelling. - Speaker suggestions are always tentative. They were measured on clean recordings, not real rooms. - Talk time is an estimate from the length of transcribed lines. - One laptop, one browser. There is no sync between devices. --- # Privacy Last updated 10 October 2026. Your meetings are none of our business. That is a description of how the app is built, not a promise about how we behave. This page is also Chitmonk's privacy policy. It covers the app at chitmonk.com and these pages. "We" means the people who make and publish Chitmonk. ## What stays on the device - **Speech is transcribed in the browser tab**, by models that were downloaded once and run locally. No audio is sent anywhere. - **Transcripts, names and history** are stored in the browser's own database on the device. - **Voice fingerprints**, used to suggest who is speaking, exist only in memory during a meeting and are discarded when it ends. They are never stored, never exported, and the storage layer refuses anything shaped like one. - **Audio** is held only for the phrase being transcribed, then released, unless you ask to keep it for that meeting. We never receive any of this. We cannot read it, lose it, sell it or hand it over, because we do not have it. ## No network during a meeting While a meeting is recording or paused, the app makes no requests at all. The page is only allowed to talk to its own address, and after the first download it works with the network switched off. ## What can leave, and only if you choose 1. **Your email address, if you sign up for the Chitmonk+ beta.** You type it and press the button; that address, and nothing else, is sent to Chitmonk's own site. It cannot be sent while a meeting is recording. [What happens to it](#the-sign-up-list). 2. **Usage statistics, only if you say yes.** Counts such as how many meetings are started and which exports are used. Never audio, transcripts, names or titles, and nothing is sent while a meeting is recording. Off unless you turn it on. [Exactly what is sent](#how-statistics-are-collected). That is the whole list. An exported file goes wherever you put it; the app does not send it anywhere. ## How statistics are collected **Only if you turn it on.** The app asks once, on the home screen, and the switch is in Settings under Privacy. Until you say yes, nothing is sent and the code that sends it is not even downloaded. Turn it off and it stops at once: anything waiting is thrown away. **Only if this copy of the app is connected to a statistics service at all.** If Settings says "Usage sharing is not set up in this build", there is nowhere for statistics to go and nothing is sent, whatever the switch says. **Who receives them.** [PostHog](https://posthog.com), a product-analytics company, on servers in the United States. It handles them for us and on our instructions. We use them to see which parts of Chitmonk get used. We do not sell them, share them with advertisers, or use them to build a profile of you. **What is sent.** These events and nothing else. This is the complete list. | When | What is sent with it | | --- | --- | | The app is opened | Whether it is installed as an app. Whether the speech engine is installed | | The speech engine finishes installing | Whether voice suggestions were included | | A meeting starts | The language, as a two-letter code. How many people are on the list. Whether voice suggestions are on. Which voice detector is in use. Whether audio is being kept. Whether it is a shared-device meeting | | A meeting ends | Its length as a range (such as 15 to 30 minutes). Its number of lines as a range (such as 50 to 200). Whether it was a shared-device meeting | | An export finishes | The format, such as Word or Markdown | | An import finishes | How many meetings were in it | | A model is chosen | Which job it does and which model | | The Chitmonk+ panel is opened | Nothing more | | A beta sign-up goes through | Nothing more. Not the address | | You sign in to Chitmonk+ | Nothing more | | Usage sharing is turned on | Nothing more | **What comes with every event.** The analytics library describes the browser it runs in. Chitmonk lets these through and removes the rest: - the browser and its version, the operating system and its version, and the kind of device (desktop, tablet or phone); - the size of the screen and of the window; - the name and version of the analytics library, and the time; - three random identifiers: one for this browser, one for this visit and one for this tab. They are random numbers made in your browser, there so that one browser is counted once. They are kept in the browser's local storage, not in a cookie. **What is never sent.** The app can only send short code words, numbers and yes-or-no values: free text is rejected before it leaves, so a title, a name or a line of transcript cannot be sent even by mistake. Chitmonk also removes what the analytics library would otherwise add by itself: the address of the page you are on (a meeting's address identifies the meeting), the page you came from, campaign tags, the full user-agent string, your language and your time zone. There is no recording of your screen, clicks or typing. **Your IP address.** Any server sees the address a request comes from, and PostHog's does when an event arrives. We have it set to discard that address instead of storing it, and each event asks it not to work out a location from it. **Never during a meeting.** While a meeting is recording or paused, events wait on your device and go only after it ends. **If you sign in to Chitmonk+**, once that exists, events from then on are linked to your Chitmonk+ account's identifier, so that we can tell how Chitmonk+ is used. **Stopping and removing.** Turn the switch off in Settings, or use "Delete all data" there, and sending stops and the identifiers your browser was using are discarded. To have statistics already sent from your browser removed, write to us at the address at the end of this page. ## The sign-up list If you sign up for the Chitmonk+ beta, we keep your email address and the date you signed up. Nothing else about you or the request is written down. We use the address for one thing: to write to you about Chitmonk+. We do not sell it, share it or add it to any other list. It is stored with Cloudflare, the company that hosts the site. We keep it until you ask us to remove it or the list is no longer needed, whichever comes first. To be removed, write to the address at the end of this page. To stop a script filling the list, sign-ups from one IP address are limited to one every two seconds. The IP address is only counted against, for ten seconds. It is not stored with your sign-up or anywhere else by us. ## Signing in to Chitmonk+ Chitmonk+ is not available yet, and the free app has no account. When sign-in exists it will be handled by [WorkOS](https://workos.com), a sign-in provider, which will hold the name and email address of your account. Nothing about sign-in is downloaded or contacted unless you choose to sign in. ## The site itself Chitmonk's sites are delivered by [Cloudflare](https://www.cloudflare.com). To deliver a page to you, and to protect the site from abuse, Cloudflare's network necessarily handles the IP address your request comes from and basic details of the request, as every web host does. It does that under its own privacy policy. We do not keep request logs of our own. Chitmonk's server code is small (it takes sign-ups and serves the speech models), and it is set to store no log of who asked for what. Chitmonk sets no cookies. The app keeps its settings and your meetings in the browser's own storage on your device. These documentation pages run no script at all, load nothing from any other site, and have no statistics of any kind. ## What we share, and with whom We do not sell personal information, and we do not share it for advertising. Three companies handle data for us, each only for the job named here: | Company | What it handles | When | | --- | --- | --- | | Cloudflare | Delivering the sites. Storing the beta sign-up list | Always, for the sites. The list only if you sign up | | PostHog | Usage statistics | Only if you turn them on | | WorkOS | Chitmonk+ sign-in | Only if you sign in, once that exists | We would disclose information if the law required it. For meetings, there is nothing we could disclose. ## What an export contains A `.chit` bundle holds the meeting's complete history: every line, every edit, every name, and the audio only if you chose to include it. Treat it like the meeting itself. [What is in a bundle](/chit/). ## Other people in your meetings A meeting holds the words and names of the people in the room, and you are the one who holds them: they are on your device, under your control. Telling people they are being recorded, and getting their consent where the law requires it, is your responsibility. The [terms of use](/terms/#5-telling-people-you-are-recording) say more. ## Your choices - **Your meetings:** delete one from its page, or everything with "Delete all data" in Settings. Nothing needs to be asked of us, because we hold nothing. - **Statistics:** off unless you turn them on; the switch is in Settings. - **Your sign-up address:** write to us to see it, correct it or have it removed. Depending on where you live, the law may give you rights over personal information about you, such as to see it, correct it, delete it or object to its use. We will honour such a request from anyone, wherever they live, and we will not treat you differently for making one. ## Children Chitmonk is for adults. It is not directed at children, and we do not knowingly collect personal information from anyone under 13. If you believe a child has signed up for the beta, write to us and we will remove the address. ## Changes to this page When what Chitmonk does changes, this page changes with it, and the date at the top changes too. If a change is significant we say so at the top of the page. ## Contact Questions about privacy, or a request about your information: [legal@chitmonk.com](mailto:legal@chitmonk.com). --- # The .chit bundle A `.chit` file is how a meeting leaves Chitmonk without losing anything, and how one gets back in. It is an ordinary ZIP archive with a manifest and, for each meeting, the complete log of what happened in it. Importing a bundle reproduces the meeting exactly. People make one with **Export**, then **Chitmonk bundle (.chit)** on a meeting, or **Export all** in the library for every meeting at once. They bring one in with **Import** in the library. The app accepts `.chit` and `.zip`. Two files to keep next to this page: the [JSON Schema](/chit.schema.json) and a [sample bundle](/sample.chit). ## What is inside ```text manifest.json what the bundle holds, with a checksum for each file meetings/.json one per meeting: its complete event log audio/. only if the person chose to include kept audio ``` Nothing else may be in the archive. See [what import checks](#what-import-checks). ## manifest.json ```json { "format": "chitmonk-bundle", "version": 1, "exportedAt": "2026-10-09T23:01:57.490Z", "app": "Chitmonk docs sample", "meetings": [ { "id": "01927f3a-0000-7000-8000-000000000001", "path": "meetings/01927f3a-0000-7000-8000-000000000001.json", "schema": 1, "events": 24, "sha256": "99c95bda1481d34ad33ced61eb87a9aea036c9fa97fed8028cca46214a4ca898" } ] } ``` | Field | Type | Meaning | | --- | --- | --- | | `format` | string | Always `chitmonk-bundle` | | `version` | integer | Version of this container. Currently `1` | | `exportedAt` | string | When it was written, as an ISO 8601 time | | `app` | string | What wrote it. Chitmonk writes its own version; write the name of your tool | | `meetings` | array | One entry per meeting, at most 4,000 | | `meetings[].id` | string | The meeting's id (a lowercase UUID) | | `meetings[].path` | string | Exactly `meetings/.json` | | `meetings[].schema` | integer | Version of the event shapes in that file. Currently `1` | | `meetings[].events` | integer | How many events the file holds | | `meetings[].sha256` | string | SHA-256 of that file's exact bytes, in lowercase hex | | `meetings[].audio` | object | Optional: `path`, `mime`, `bytes`, `sha256` of the audio file | ## A meeting file ```json { "schema": 1, "events": [ ... ] } ``` `events` is the meeting: an append-only list, oldest first. The current title, the transcript, who spoke, the action items are all worked out by replaying it. [The event log](/chit/events/) lists every event and the rules for replaying. ## Audio Audio is in a bundle only when the person kept the audio for that meeting and ticked "Include the retained audio" when exporting. It is one file per meeting, stored without compression, named for its type: | `mime` starts with | Extension | | --- | --- | | `audio/webm` | `.webm` | | `audio/mp4` | `.m4a` | | `audio/ogg` | `.ogg` | Chitmonk records Opus at about 14 MB per hour. Line times in the event log are positions in this recording. ## Limits | What | Limit | | --- | --- | | Files in the archive | 4,000 | | One JSON file, unpacked | 64 MiB | | One audio file | 512 MiB | | Everything, unpacked | 1 GiB | | Events in one meeting | 500,000 | | Any one piece of text (a title, a line, a note) | 20,000 characters | ## Versions There are two numbers and they change for different reasons. `version` in the manifest is the container: the file layout described on this page. `schema` is the shape of the events. - A bundle with a **newer** `version` or `schema` than the app knows is refused, with a message to update the app. It never guesses. - A meeting with an **older** `schema` is upgraded as it is read. The file is not changed. - Fields the app does not know are kept and written back out, so a bundle survives a round trip through an older or newer tool. Both are `1` today. ## What import checks In this order, and it stops at the first failure. Nothing is saved from a bundle that fails. 1. **Only expected files.** Every entry must be `manifest.json`, `meetings/.json` or `audio/.`. A folder stored as an entry of its own counts as an unexpected file, and so do the `__MACOSX` files some tools add. *"That bundle contains files Chitmonk does not expect, so it was not imported."* 2. **Size.** The limits above. *"That bundle is larger than Chitmonk will import."* 3. **A manifest it recognises.** Valid JSON with `format` set to `chitmonk-bundle`. *"That file is not a Chitmonk bundle Chitmonk can read."* 4. **A version it knows.** *"That bundle was made by a newer Chitmonk. Update the app, then import it again."* 5. **Every listed meeting is there and intact.** The file exists at `meetings/.json` and its SHA-256 matches. *"That bundle is damaged: its contents do not match its own checksums."* 6. **Every event is valid.** Known type, right fields, `meetingId` equal to the meeting's id, and the first event is `MeetingCreated`. An event type the app does not know fails here, with the same message as step 3. 7. **No voice data.** An event carrying a key named `embedding`, `embeddings`, `voiceprint`, `prototype`, `pcm` or `audio`, at any depth, is refused. Voice fingerprints are never stored or exported, and the app will not take them in either. 8. **Audio, if listed, is there and intact.** The same message as step 5. ## What import does - A meeting the device does not have is added under the id it came with. - A meeting the device already has, with exactly the same events, is skipped. - A meeting with the same id but different events is added as a **separate copy**, with a new id and "(imported copy)" after its title. Nothing already on the device is ever overwritten or merged. --- # The event log A meeting is not stored as a transcript. It is stored as the list of things that happened: a line was heard, someone said who spoke it, a line was edited, that was undone. The transcript and the receipt are what you get by replaying the list. That is why a bundle loses nothing: it holds the history, not a summary of it. ## Every event ```json { "id": "01927f3a-0000-7000-8000-000000001006", "meetingId": "01927f3a-0000-7000-8000-000000000001", "at": 1791561609000, "type": "SpeakerAssigned", "lineIds": [ "01927f3a-0000-7000-8000-000000000101" ], "participantId": "01927f3a-0000-7000-8000-000000000011" } ``` | Field | Type | Meaning | | --- | --- | --- | | `id` | string | This event's id | | `meetingId` | string | The meeting it belongs to. The same on every event in a file | | `at` | number | When it happened, in milliseconds since 1970 (UTC) | | `type` | string | One of the types below | **Ids** are UUIDs written in lowercase with hyphens: `8-4-4-4-12` hex digits. Chitmonk makes version 7 UUIDs, which sort by time. Any lowercase UUID is accepted. **Two clocks.** `at` is the wall clock. `startMs` and `endMs` on a line are milliseconds into the recording, with pauses left out, so they line up with the audio file. **Extra fields** are allowed on any event, kept, and written back out. ## Replaying a log 1. Collect the `targetId` of every `EventUndone`. Those events did not happen: skip them. An undo is final: undoing an `EventUndone` does not bring its target back. 2. Apply the rest in the order they appear in the file. 3. The result is the meeting as it stands. Two rules decide what you may show as fact: - **A speaker is confirmed only by a person.** A line has a confirmed speaker if a `SpeakerAssigned` named it, or if it arrived with a `speakerId` (the person had already chosen who was talking). A `suggestedSpeakerId` is the app's guess from the sound of the voice. Show it as a guess: Chitmonk writes it as `Maya?`. - **An action item or decision is accepted only by a person.** Until an `ActionAccepted` or `DecisionAccepted`, it is a suggestion found by phrase rules. ## The events ### The meeting | Type | Fields | What it does | | --- | --- | --- | | `MeetingCreated` | `schema`, `title`, `language`, `privacyMode`, `engine`, `vocabulary`, `ephemeral`? | Always first. Sets the title and settings; its `at` is when the meeting was created | | `MeetingRenamed` | `title` | Replaces the title | | `RecordingStarted` | | Recording begins, or resumes after a pause | | `RecordingPaused` | | Recording pauses | | `MeetingEnded` | | Recording stops for good; its `at` is when the meeting ended | | `MeetingDeleted` | | Marks the meeting deleted. Not normally found in an export | | `EventUndone` | `targetId` | The event with that id is skipped when replaying | In `MeetingCreated`: `schema` is `1`. `language` is `auto` or one of `en`, `de`, `fr`, `es`, `it`, `nl`, `pl`. `privacyMode` is `transcript-only` or `audio-retained`. `engine` says what made the transcript, as `{ "stt", "sttVersion", "runtime", "vad", "speaker" }`, all strings except `speaker`, which is a string or `null`. `vocabulary` is up to 200 words the meeting was told to listen for. The meeting's length is the time between each `RecordingStarted` and the `RecordingPaused` or `MeetingEnded` that follows it, added up. ### People | Type | Fields | What it does | | --- | --- | --- | | `ParticipantAdded` | `participantId`, `name`, `pronouns`? | Adds a person, after the ones already there | | `ParticipantUpdated` | `participantId`, `name`?, `pronouns`? | Changes what is given. `pronouns: null` removes them | | `ParticipantReordered` | `order` | The new order, as a list of participant ids. Anyone left out goes last | | `ParticipantRemoved` | `participantId` | The person leaves the list, but lines they spoke keep their name | A person's position in the list is the number key that means them during a meeting. ### The transcript | Type | Fields | What it does | | --- | --- | --- | | `SegmentCommitted` | `lineId`, `text`, `words`, `startMs`, `endMs`, `language`, `turnId`, `suggestedSpeakerId`?, `speakerId`? | Adds a line at the end of the transcript | | `SpeakerAssigned` | `lineIds`, `participantId` | A person says who spoke those lines. `null` means "nobody on the list", on purpose | | `TranscriptLineEdited` | `lineId`, `text` | Replaces the line's words. The words first heard are still in its `SegmentCommitted` | | `TranscriptLineDeleted` | `lineId` | Removes the line | In `SegmentCommitted`: `language` is the language heard on that line. `turnId` groups lines from one unbroken stretch of the same voice. `words` is a list of `{ "w", "s", "e", "p" }`: the word, its start and end in recording milliseconds, and the model's probability for it. It may be empty. `SpeakerAssigned` also clears any guess on those lines. If an action item took its owner from the speaker of one of them, the owner changes with it. ### Action items and decisions The two families are the same shape. Replace `Action` with `Decision`. | Type | Fields | What it does | | --- | --- | --- | | `ActionSuggested` | `itemId`, `lineId`, `text`, `ownerId`?, `ownerFromSpeaker`?, `dueText`?, `dueDate`? | Adds an item, not yet accepted | | `ActionEdited` | `itemId`, `text`?, `ownerId`?, `dueText`?, `dueDate`? | Changes what is given. `null` clears an owner or a due date | | `ActionAccepted` | `itemId` | A person accepts it | | `ActionDeleted` | `itemId` | Removes it | `lineId` is the line it was found in, or `null` for one a person typed. `dueText` is the words as spoken ("by Friday"). `dueDate` is `YYYY-MM-DD`, set only when the words pin down a single day. `ownerFromSpeaker: true` means the owner is whoever spoke the line, and follows a later `SpeakerAssigned`; an `ActionEdited` that sets `ownerId` ends that. ### Side notes | Type | Fields | What it does | | --- | --- | --- | | `NoteAdded` | `noteId`, `lineId`, `text` | Adds a note beside a line, or beside the meeting if `lineId` is `null` | | `NoteEdited` | `noteId`, `text` | Replaces its words | | `NoteDeleted` | `noteId` | Removes it | A note never changes the line it sits beside. ## The sample, start to finish This is the whole event log in the [sample bundle](/sample.chit). It has a confirmed speaker, a guessed one, an unknown one, an undo, an edit, a note, an accepted action item and a suggested one. ```json { "schema": 1, "events": [ {"id":"01927f3a-0000-7000-8000-000000001000","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561600000,"type":"MeetingCreated","schema":1,"title":"Launch review","language":"en","privacyMode":"transcript-only","engine":{"stt":"Cactus Whistle","sttVersion":"2.0.0","runtime":"Cactus needle3 (WebAssembly)","vad":"Silero VAD v5","speaker":"3D-Speaker CAM++"},"vocabulary":["Chitmonk"]}, {"id":"01927f3a-0000-7000-8000-000000001001","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561601000,"type":"ParticipantAdded","participantId":"01927f3a-0000-7000-8000-000000000011","name":"Maya"}, {"id":"01927f3a-0000-7000-8000-000000001002","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561602000,"type":"ParticipantAdded","participantId":"01927f3a-0000-7000-8000-000000000012","name":"Leo"}, {"id":"01927f3a-0000-7000-8000-000000001003","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561603000,"type":"ParticipantAdded","participantId":"01927f3a-0000-7000-8000-000000000013","name":"Sam","pronouns":"they/them"}, {"id":"01927f3a-0000-7000-8000-000000001004","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561604000,"type":"RecordingStarted"}, {"id":"01927f3a-0000-7000-8000-000000001005","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561608000,"type":"SegmentCommitted","lineId":"01927f3a-0000-7000-8000-000000000101","text":"Okay, let us get started. Thanks everyone for joining the launch review.","words":[],"startMs":1000,"endMs":6000,"language":"en","turnId":"01927f3a-0000-7000-8000-000000000201"}, {"id":"01927f3a-0000-7000-8000-000000001006","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561609000,"type":"SpeakerAssigned","lineIds":["01927f3a-0000-7000-8000-000000000101"],"participantId":"01927f3a-0000-7000-8000-000000000011"}, {"id":"01927f3a-0000-7000-8000-000000001007","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561613000,"type":"SegmentCommitted","lineId":"01927f3a-0000-7000-8000-000000000102","text":"Sounds good. The checkout tests passed last night, so the build is ready.","words":[],"startMs":7000,"endMs":12000,"language":"en","turnId":"01927f3a-0000-7000-8000-000000000202"}, {"id":"01927f3a-0000-7000-8000-000000001008","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561614000,"type":"SpeakerAssigned","lineIds":["01927f3a-0000-7000-8000-000000000102"],"participantId":"01927f3a-0000-7000-8000-000000000012"}, {"id":"01927f3a-0000-7000-8000-000000001009","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561618000,"type":"SegmentCommitted","lineId":"01927f3a-0000-7000-8000-000000000103","text":"Great. I will send the revised deck by friday.","words":[],"startMs":13000,"endMs":16000,"language":"en","turnId":"01927f3a-0000-7000-8000-000000000203","suggestedSpeakerId":"01927f3a-0000-7000-8000-000000000011"}, {"id":"01927f3a-0000-7000-8000-000000001010","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561619000,"type":"ActionSuggested","itemId":"01927f3a-0000-7000-8000-000000000301","lineId":"01927f3a-0000-7000-8000-000000000103","text":"I will send the revised deck by Friday.","ownerId":"01927f3a-0000-7000-8000-000000000011","ownerFromSpeaker":true,"dueText":"by Friday"}, {"id":"01927f3a-0000-7000-8000-000000001011","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561620000,"type":"SpeakerAssigned","lineIds":["01927f3a-0000-7000-8000-000000000103"],"participantId":"01927f3a-0000-7000-8000-000000000011"}, {"id":"01927f3a-0000-7000-8000-000000001012","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561621000,"type":"TranscriptLineEdited","lineId":"01927f3a-0000-7000-8000-000000000103","text":"Great. I will send the revised deck by Friday."}, {"id":"01927f3a-0000-7000-8000-000000001013","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561622000,"type":"NoteAdded","noteId":"01927f3a-0000-7000-8000-000000000401","lineId":"01927f3a-0000-7000-8000-000000000103","text":"Ask Leo for the old deck"}, {"id":"01927f3a-0000-7000-8000-000000001014","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561626000,"type":"SegmentCommitted","lineId":"01927f3a-0000-7000-8000-000000000104","text":"We decided to launch on Tuesday.","words":[],"startMs":17000,"endMs":20000,"language":"en","turnId":"01927f3a-0000-7000-8000-000000000204"}, {"id":"01927f3a-0000-7000-8000-000000001015","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561627000,"type":"DecisionSuggested","itemId":"01927f3a-0000-7000-8000-000000000302","lineId":"01927f3a-0000-7000-8000-000000000104","text":"We decided to launch on Tuesday."}, {"id":"01927f3a-0000-7000-8000-000000001016","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561628000,"type":"SpeakerAssigned","lineIds":["01927f3a-0000-7000-8000-000000000104"],"participantId":"01927f3a-0000-7000-8000-000000000012"}, {"id":"01927f3a-0000-7000-8000-000000001017","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561629000,"type":"EventUndone","targetId":"01927f3a-0000-7000-8000-000000001016"}, {"id":"01927f3a-0000-7000-8000-000000001018","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561630000,"type":"SpeakerAssigned","lineIds":["01927f3a-0000-7000-8000-000000000104"],"participantId":"01927f3a-0000-7000-8000-000000000013"}, {"id":"01927f3a-0000-7000-8000-000000001019","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561634000,"type":"SegmentCommitted","lineId":"01927f3a-0000-7000-8000-000000000105","text":"Sam, can you update the release notes before the launch?","words":[],"startMs":21000,"endMs":25000,"language":"en","turnId":"01927f3a-0000-7000-8000-000000000205","suggestedSpeakerId":"01927f3a-0000-7000-8000-000000000012"}, {"id":"01927f3a-0000-7000-8000-000000001020","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561635000,"type":"ActionSuggested","itemId":"01927f3a-0000-7000-8000-000000000303","lineId":"01927f3a-0000-7000-8000-000000000105","text":"Sam, can you update the release notes before the launch?","ownerId":"01927f3a-0000-7000-8000-000000000013"}, {"id":"01927f3a-0000-7000-8000-000000001021","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561639000,"type":"SegmentCommitted","lineId":"01927f3a-0000-7000-8000-000000000106","text":"Yes, that works for me.","words":[],"startMs":26000,"endMs":28000,"language":"en","turnId":"01927f3a-0000-7000-8000-000000000206"}, {"id":"01927f3a-0000-7000-8000-000000001022","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561640000,"type":"ActionAccepted","itemId":"01927f3a-0000-7000-8000-000000000301"}, {"id":"01927f3a-0000-7000-8000-000000001023","meetingId":"01927f3a-0000-7000-8000-000000000001","at":1791561641000,"type":"MeetingEnded"} ] } ``` Replayed, it reads: ```text Launch review People: Maya, Leo, Sam (they/them) [0:01] Maya: Okay, let us get started. Thanks everyone for joining the launch review. [0:07] Leo: Sounds good. The checkout tests passed last night, so the build is ready. [0:13] Maya: Great. I will send the revised deck by Friday. [0:17] Sam: We decided to launch on Tuesday. [0:21] Leo?: Sam, can you update the release notes before the launch? [0:26] Unknown speaker: Yes, that works for me. Action items - I will send the revised deck by Friday. (Maya, due by Friday) - Sam, can you update the release notes before the launch? (Sam, suggested) Decisions - We decided to launch on Tuesday. (suggested) Notes - [0:13] Ask Leo for the old deck ``` --- # Read a bundle Reading a `.chit` takes four steps. 1. **Unzip it** and parse `manifest.json`. Check `format` is `chitmonk-bundle` and `version` is one you know (`1`). 2. **For each entry in `meetings`**, read the file at its `path` and compare its SHA-256 with the manifest's. 3. **Replay its `events`** in order, skipping any that an `EventUndone` names. [The rules](/chit/events/#replaying-a-log). 4. **Label speakers honestly.** A confirmed name is a name. A guess is a guess. ## How Chitmonk labels a line Every export Chitmonk writes uses the same four labels, and a reader should too: | The line | Label | | --- | --- | | A person confirmed who spoke | `Maya` | | A person marked it as nobody on the list | `Unassigned` | | Not confirmed, but the app has a guess | `Maya?` | | Not confirmed, no guess | `Unknown speaker` | ## A reader in Python No packages to install. `project()` is the whole of the replay rules. ```python """Read a Chitmonk .chit bundle: who said what, what is owed, what was decided. Standard library only. python3 read_chit.py meetings.chit """ import hashlib import json import sys import zipfile def project(events): """Replay one meeting's event log into the meeting as it stands now.""" undone = {e["targetId"] for e in events if e["type"] == "EventUndone"} m = {"title": "", "people": {}, "order": [], "lines": [], "actions": [], "decisions": [], "notes": []} for e in events: if e["id"] in undone: continue t = e["type"] items = m["actions"] if t.startswith("Action") else m["decisions"] if t in ("MeetingCreated", "MeetingRenamed"): m["title"] = e["title"] elif t == "ParticipantAdded": m["people"][e["participantId"]] = {"name": e["name"], "pronouns": e.get("pronouns"), "removed": False} m["order"].append(e["participantId"]) elif t == "ParticipantUpdated": p = m["people"][e["participantId"]] p["name"] = e.get("name") or p["name"] if "pronouns" in e: p["pronouns"] = e["pronouns"] elif t == "ParticipantReordered": rank = {pid: i for i, pid in enumerate(e["order"])} m["order"].sort(key=lambda pid: rank.get(pid, 10**9)) elif t == "ParticipantRemoved": m["people"][e["participantId"]]["removed"] = True elif t == "SegmentCommitted": who = e.get("speakerId") m["lines"].append({ "id": e["lineId"], "startMs": e["startMs"], "text": e["text"], "speakerId": who, "confirmed": who is not None, "suggestedSpeakerId": None if who is not None else e.get("suggestedSpeakerId"), }) elif t == "SpeakerAssigned": ids = set(e["lineIds"]) for line in m["lines"]: if line["id"] in ids: line.update(speakerId=e["participantId"], confirmed=True, suggestedSpeakerId=None) for item in m["actions"] + m["decisions"]: if item["ownerFromSpeaker"] and item["lineId"] in ids: item["ownerId"] = e["participantId"] elif t == "TranscriptLineEdited": for line in m["lines"]: if line["id"] == e["lineId"]: line["text"] = e["text"] elif t == "TranscriptLineDeleted": m["lines"] = [line for line in m["lines"] if line["id"] != e["lineId"]] elif t in ("ActionSuggested", "DecisionSuggested"): items.append({ "id": e["itemId"], "lineId": e.get("lineId"), "text": e["text"], "ownerId": e.get("ownerId"), "ownerFromSpeaker": bool(e.get("ownerFromSpeaker")), "dueText": e.get("dueText"), "dueDate": e.get("dueDate"), "accepted": False, }) elif t in ("ActionEdited", "DecisionEdited"): for item in items: if item["id"] == e["itemId"]: if e.get("text") is not None: item["text"] = e["text"] if "ownerId" in e: # a person chose the owner, so it stops following the speaker item["ownerId"], item["ownerFromSpeaker"] = e["ownerId"], False for key in ("dueText", "dueDate"): if key in e: item[key] = e[key] elif t in ("ActionAccepted", "DecisionAccepted"): for item in items: if item["id"] == e["itemId"]: item["accepted"] = True elif t in ("ActionDeleted", "DecisionDeleted"): items[:] = [item for item in items if item["id"] != e["itemId"]] elif t == "NoteAdded": m["notes"].append({"id": e["noteId"], "lineId": e.get("lineId"), "text": e["text"]}) elif t == "NoteEdited": for note in m["notes"]: if note["id"] == e["noteId"]: note["text"] = e["text"] elif t == "NoteDeleted": m["notes"] = [note for note in m["notes"] if note["id"] != e["noteId"]] return m def clock(ms): s = int(ms / 1000 + 0.5) return f"{s // 3600}:{s % 3600 // 60:02}:{s % 60:02}" if s >= 3600 else f"{s // 60}:{s % 60:02}" def name(m, pid): return m["people"][pid]["name"] if pid in m["people"] else None def speaker(m, line): """A confirmed name, or a guess marked with "?". A guess is never shown as a fact.""" if line["confirmed"]: return name(m, line["speakerId"]) or "Unassigned" guess = name(m, line["suggestedSpeakerId"]) return f"{guess}?" if guess else "Unknown speaker" def item_line(m, item): due = item["dueDate"] or item["dueText"] about = [name(m, item["ownerId"]), f"due {due}" if due else None, None if item["accepted"] else "suggested"] about = [a for a in about if a] return f"{item['text']} ({', '.join(about)})" if about else item["text"] def read(path): """Every meeting in the bundle, checked against the manifest's SHA-256 and replayed.""" with zipfile.ZipFile(path) as z: manifest = json.loads(z.read("manifest.json")) if manifest.get("format") != "chitmonk-bundle" or manifest.get("version", 0) > 1: raise ValueError("not a .chit bundle this script can read") for entry in manifest["meetings"]: data = z.read(entry["path"]) if hashlib.sha256(data).hexdigest() != entry["sha256"]: raise ValueError(f"{entry['path']} does not match its checksum") yield project(json.loads(data)["events"]) if __name__ == "__main__": for m in read(sys.argv[1]): print(m["title"]) people = [m["people"][pid] for pid in m["order"] if not m["people"][pid]["removed"]] print("People: " + ", ".join(f"{p['name']} ({p['pronouns']})" if p["pronouns"] else p["name"] for p in people)) print() for line in m["lines"]: print(f"[{clock(line['startMs'])}] {speaker(m, line)}: {line['text']}") for title, items in (("Action items", m["actions"]), ("Decisions", m["decisions"])): if items: print(f"\n{title}") for item in items: print(f"- {item_line(m, item)}") if m["notes"]: starts = {line["id"]: line["startMs"] for line in m["lines"]} print("\nNotes") for note in m["notes"]: at = f"[{clock(starts[note['lineId']])}] " if note["lineId"] in starts else "" print(f"- {at}{note['text']}") ``` Run it on the [sample bundle](/sample.chit): ```text $ python3 read_chit.py sample.chit Launch review People: Maya, Leo, Sam (they/them) [0:01] Maya: Okay, let us get started. Thanks everyone for joining the launch review. [0:07] Leo: Sounds good. The checkout tests passed last night, so the build is ready. [0:13] Maya: Great. I will send the revised deck by Friday. [0:17] Sam: We decided to launch on Tuesday. [0:21] Leo?: Sam, can you update the release notes before the launch? [0:26] Unknown speaker: Yes, that works for me. Action items - I will send the revised deck by Friday. (Maya, due by Friday) - Sam, can you update the release notes before the launch? (Sam, suggested) Decisions - We decided to launch on Tuesday. (suggested) Notes - [0:13] Ask Leo for the old deck ``` Line three shows the edit (the `friday` first heard is gone), line four shows the undo (it is Sam's, not Leo's), and line five is still a guess because nobody confirmed it. ## If you only need to read it A `.chit` is for tools. If a person or a model just needs to read the meeting, the [Markdown or plain text export](/exports/) is the same content already laid out. --- # Write a bundle To put a meeting into Chitmonk, write a `.chit` and have the person import it: the library drawer, then **Import**. There is no other way in, and no way to do it without them. ## The smallest valid bundle Two files in a ZIP. `manifest.json` lists one meeting, with the SHA-256 of its file: ```json { "format": "chitmonk-bundle", "version": 1, "exportedAt": "2026-10-09T16:00:00.000Z", "app": "my-tool 1.0", "meetings": [{ "id": "", "path": "meetings/.json", "schema": 1, "events": 3, "sha256": "" }] } ``` `meetings/.json` holds the events. A meeting needs only its first one, `MeetingCreated`, to be valid. A useful one also has people, lines and an end: ```text MeetingCreated the title, the language, what made the transcript ParticipantAdded one per person RecordingStarted SegmentCommitted one per line MeetingEnded ``` ## A writer in Python No packages to install. Change `TITLE`, `PEOPLE` and `LINES` to what you have. ```python """Write a .chit bundle Chitmonk will import, from a transcript you already have. Standard library only. python3 write_chit.py planning-call.chit """ import datetime import hashlib import json import sys import time import uuid import zipfile TITLE = "Planning call" PEOPLE = ["Ana", "Ben"] # start and end in seconds from the start of the recording, who your tool thinks spoke (or None), the words LINES = [ (0.0, 4.2, "Ana", "Shall we ship the import on Thursday?"), (4.8, 7.5, "Ben", "Yes. I will test it on the shared laptop first."), (8.0, 9.4, None, "Sounds like a plan."), ] def new_id(): return str(uuid.uuid4()) # any lowercase UUID will do meeting = new_id() started = int(time.time() * 1000) # when the recording began, in milliseconds since 1970 events = [] def add(kind, at, **fields): events.append({"id": new_id(), "meetingId": meeting, "at": at, "type": kind, **fields}) # The first event must be MeetingCreated. `engine` is printed on the receipt as "Transcribed by", # so say what really made the transcript. add("MeetingCreated", started, schema=1, title=TITLE, language="en", privacyMode="transcript-only", engine={"stt": "My transcriber", "sttVersion": "1.0", "runtime": "Python", "vad": "none", "speaker": None}, vocabulary=[]) people = {name: new_id() for name in PEOPLE} for name, pid in people.items(): add("ParticipantAdded", started, participantId=pid, name=name) add("RecordingStarted", started) for start, end, who, text in LINES: # suggestedSpeakerId is a guess: Chitmonk shows it dashed, with a "?", until a person confirms it. # If a person really did say who spoke, follow the line with a SpeakerAssigned event instead. add("SegmentCommitted", started + round(end * 1000), lineId=new_id(), text=text, words=[], startMs=round(start * 1000), endMs=round(end * 1000), language="en", turnId=new_id(), suggestedSpeakerId=people.get(who)) add("MeetingEnded", started + round(LINES[-1][1] * 1000)) # One file per meeting, and a manifest that lists it with the SHA-256 of its exact bytes. body = json.dumps({"schema": 1, "events": events}).encode() path = f"meetings/{meeting}.json" manifest = { "format": "chitmonk-bundle", "version": 1, "exportedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(), "app": "write_chit.py 1.0", "meetings": [{"id": meeting, "path": path, "schema": 1, "events": len(events), "sha256": hashlib.sha256(body).hexdigest()}], } # Only these two files. No folders as entries of their own, nothing else. with zipfile.ZipFile(sys.argv[1], "w", zipfile.ZIP_DEFLATED) as z: z.writestr("manifest.json", json.dumps(manifest, indent=2)) z.writestr(path, body) print(f"wrote {sys.argv[1]}: {len(events)} events") ``` ## Rules that trip people up - **Ids are lowercase UUIDs**, hyphenated. Uppercase is refused. Give every event, line, person and item its own. - **Every event carries the same `meetingId`**, and it is the id in the manifest and in the file's name. - **`MeetingCreated` comes first**, with `schema: 1`. - **The checksum is of the exact bytes in the ZIP.** Hash the bytes you write, not a re-serialised copy. - **Only the listed files.** No folder entries, no `__MACOSX`, no readme. Zip the files, not the folder they are in. - **Times.** `at` is milliseconds since 1970. `startMs` and `endMs` are milliseconds from the start of the recording. The meeting's length comes from the `at` of `RecordingStarted` and `MeetingEnded`, so set those apart by the length of the recording. - **`words` may be an empty list.** Chitmonk fills it with word timings when it transcribes; nothing needs it on import. - **`language`** is a short code. Chitmonk's own are `en`, `de`, `fr`, `es`, `it`, `nl`, `pl`; on a meeting it may also be `auto`. - **Text is capped** at 20,000 characters for any one title, line or note. - **No voice data.** A key named `embedding`, `embeddings`, `voiceprint`, `prototype`, `pcm` or `audio` anywhere in an event makes the whole bundle fail. The [JSON Schema](/chit.schema.json) says all of this in a form a validator can check. ## Do not confirm what a person did not This is the one rule that is about honesty and not about format. - If **your tool** worked out who spoke, put it in `suggestedSpeakerId`. Chitmonk shows it dashed with a question mark, and the person confirms it with one key. - If **a person** said who spoke, follow the line with `SpeakerAssigned`. - If your tool found an action item, write `ActionSuggested` and stop. `ActionAccepted` means a person agreed to it. Chitmonk never turns a guess into a fact by itself, and a bundle should not do it on its behalf. ## What happens on import The bundle is checked before anything is saved: [what import checks](/chit/#what-import-checks). If the person already has a meeting with the same id and different events, yours is added as a separate copy; it never overwrites theirs. Use a new id for a new meeting. --- # Other exports Besides the [bundle](/chit/), a meeting exports as Markdown, plain text and Word, and its receipt copies to the clipboard. These are for reading. They hold the meeting as it stands, not its history, and they cannot be imported back. The file is named after the meeting's title: `launch-review.md`, `launch-review.txt`, `launch-review.docx`. > Dates and times in these files are written the way the exporting browser writes them, so they differ from one machine to the next. If you need exact times, read the [bundle](/chit/). ## Markdown This is the [sample meeting](/sample.chit), exported: ```markdown # Launch review - **Date:** Friday, October 9, 2026 at 9:00 AM - **Time:** 9:00 AM to 9:00 AM - **Duration:** 37 sec - **Language:** English - **Transcribed by:** Cactus Whistle 2.0.0, on this device - **Transcript:** 6 lines, 55 words - **Speakers:** 4 lines assigned, 2 unassigned ## People - Maya - Leo - Sam (they/them) ## Talk time (estimate) | Speaker | Time | Share | | --- | ---: | ---: | | Maya | 0:08 | 36% | | Leo | 0:05 | 23% | | Sam | 0:03 | 14% | | Unassigned | 0:06 | 27% | ## Action items - [x] I will send the revised deck by Friday. (Maya, due by Friday) - [ ] Sam, can you update the release notes before the launch? (Sam, suggested) ## Decisions - [ ] We decided to launch on Tuesday. (suggested) ## Notes - `0:13` Ask Leo for the old deck ## Transcript **Maya** `0:01` Okay, let us get started. Thanks everyone for joining the launch review. **Leo** `0:07` Sounds good. The checkout tests passed last night, so the build is ready. **Maya** `0:13` Great. I will send the revised deck by Friday. **Sam** `0:17` We decided to launch on Tuesday. **Leo?** `0:21` Sam, can you update the release notes before the launch? **Unknown speaker** `0:26` Yes, that works for me. --- _Transcribed on this device with Chitmonk._ ``` How to read it: - The sections always come in this order. **Notes** is left out when there are none. An empty section says `_None_`. - A ticked box is an item a person accepted. An unticked one also ends in `suggested`. - After an item, in brackets: its owner, then `due` and a date or the words as spoken, then `suggested`. Each part is there only if it applies. - Each transcript line is the speaker in bold, the time in backticks, and the words on the next line. A name ending in `?` is a guess nobody confirmed. [The four labels](/chit/read/#how-chitmonk-labels-a-line). - Times are `m:ss` from the start of the recording, or `h:mm:ss` past an hour. - Characters that mean something in Markdown are escaped with a backslash. ## Plain text The same content without markup, and the transcript as one line per line: ```text Launch review ============= Date: Friday, October 9, 2026 at 9:00 AM Time: 9:00 AM to 9:00 AM Duration: 37 sec Language: English Transcribed by: Cactus Whistle 2.0.0, on this device Transcript: 6 lines, 55 words Speakers: 4 lines assigned, 2 unassigned People: Maya, Leo, Sam (they/them) ACTION ITEMS - I will send the revised deck by Friday. (Maya, due by Friday) - Sam, can you update the release notes before the launch? (Sam, suggested) DECISIONS - We decided to launch on Tuesday. (suggested) NOTES - [0:13] Ask Leo for the old deck TRANSCRIPT [0:01] Maya: Okay, let us get started. Thanks everyone for joining the launch review. [0:07] Leo: Sounds good. The checkout tests passed last night, so the build is ready. [0:13] Maya: Great. I will send the revised deck by Friday. [0:17] Sam: We decided to launch on Tuesday. [0:21] Leo?: Sam, can you update the release notes before the launch? [0:26] Unknown speaker: Yes, that works for me. Transcribed on this device with Chitmonk. ``` Sections are headed in capitals, and a section with nothing in it is left out. ## Word A `.docx` with the same sections as the Markdown file. ## Copy receipt Puts the receipt on the clipboard as plain text: the title, the facts, talk time, action items and decisions. No transcript. --- # For agents If you are a model or a tool reading this on someone's behalf, this page is the short version. ## Read these pages as text - [`/llms.txt`](/llms.txt) lists every page with a one-line summary. - [`/llms-full.txt`](/llms-full.txt) is every page in one file. - Every page is also plain Markdown: add `.md` to its address. This page is [`/agents.md`](/agents.md); the home page is [`/index.md`](/index.md). - [`/chit.schema.json`](/chit.schema.json) is the JSON Schema for everything in a bundle, generated from the validator the app itself uses. - [`/sample.chit`](/sample.chit) is a small real bundle to test against. ## What you can do Chitmonk has no API, no server and no account. It runs in a browser tab and keeps meetings there. You cannot reach into it, and it does not call out. Everything goes through files a person hands over: - **Read a meeting.** Ask the person to export it. For the words alone, [Markdown or plain text](/exports/) is enough. For structure, history or exact times, ask for the `.chit` and [read it](/chit/read/). - **Give them a meeting.** [Write a `.chit`](/chit/write/) and ask them to import it from the library drawer. - **Change a meeting.** Read the bundle, add events to the end of the log, and write a bundle. If you keep the meeting's id, they get your version as a separate copy next to theirs; nothing of theirs is overwritten. ## Rules 1. **Append, never rewrite.** The log is the meeting's history. To change a line, add `TranscriptLineEdited`. To take something back, add `EventUndone`. Do not edit or remove events that are already there. 2. **Do not confirm what a person did not.** Your guess at a speaker goes in `suggestedSpeakerId`. Your action items are `ActionSuggested`. `SpeakerAssigned` and `ActionAccepted` mean a person decided. [Why](/chit/write/#do-not-confirm-what-a-person-did-not). 3. **Never put voice data in a bundle.** No embeddings, no voiceprints, no raw audio inside events. The app refuses the whole bundle. 4. **Treat a bundle as the meeting.** It holds everything that was said and who said it. Do not send it anywhere the person did not ask you to. 5. **Say what you could not check.** Speaker guesses, phrase-rule suggestions and a small speech model all make mistakes. Pass the uncertainty on: keep the `?`. ## What is not available Source code, an SDK, a hosted API, webhooks, a way to start or stop a recording from outside, a way to read meetings without the person exporting them. Chitmonk is [proprietary for now](/licence/), and built so that there is nothing to connect to. --- # Chet Chet is the Chitmonk Chipmunk. He takes the minutes. He is a drawing, he lives in your browser tab, and he has never been to the cloud. He says it is the heights. Nobody needs this page to use Chitmonk. Chet asked for it anyway. ## At a glance | Fact | Chet | | --- | --- | | Full name | Chet, the Chitmonk Chipmunk | | Occupation | Takes minutes. Hands out receipts | | Species | Chipmunk. Not a squirrel. He would like that written down, and now it is | | Stripe | Ultramarine. It goes faster | | Cheek capacity | 61 MB: 33 for the speech engine and 28 for telling voices apart | | Languages | Seven, and chipmunk, which nothing here can transcribe | | Wardrobe | Sixty-two outfits. He calls it a capsule collection | | Accounts | None | | Servers | None | | Opinions about your meeting | Several. He keeps them to himself | ## What Chet does - **Listens when you press record, and only then.** Pause the meeting and he is asleep before the button comes back up. - **Writes down what was said.** He works from a speech model of 17 MB, which is small. Chet is also small. Neither of them is embarrassed about it. They do get a word wrong now and then, so every line can be edited. - **Guesses who is talking, and says it is a guess.** A name with a question mark is Chet thinking out loud. He has been wrong before and would rather you heard it from him. - **Hands you a receipt.** Who talked, what was decided, who owes what. Chet holds that a meeting without a receipt did not happen. ## What Chet has never done - Joined a video call as "Chet's Notetaker". He was not invited, and he knows it. - Sent a transcript anywhere. He has nowhere to send it. - Remembered your voice after the meeting. He forgets it the moment the meeting ends. It is not personal. It is the policy. - Asked you to make an account. - Been to the cloud. ## A field guide Chet has seventeen moods, and you will meet most of them. | Chet | When you will see him like this | | --- | --- | | `idle` | **Waiting.** No meeting yet. He could do this all day, and does | | `listening` | **Listening.** Ears up. A meeting is recording | | `writing` | **Writing.** Someone said something and he got it down | | `who` | **Who was that?** A new voice. He would like a name, when you have a second | | `recognized` | **Is it Maya?** He thinks he knows the voice. He is holding the card up hopefully | | `thinking` | **Thinking.** Paw on chin. It does not take long | | `happy` | **Pleased.** Something went right, and there is an acorn in it for him | | `receipt` | **Receipt.** The meeting is over and here is the proof | | `exporting` | **Exporting.** Tied up with string and ready to go wherever you are taking it | | `searching` | **Searching.** Checking under every receipt | | `empty` | **Nothing stashed.** No meetings saved yet. He is looking at where the acorn would be | | `downloading` | **Carrying.** Bringing the speech engine over, one box at a time | | `offline` | **Offline.** The network is gone. He has a warm mug and no complaints, because nothing else changes | | `mic-blocked` | **Muted.** The browser will not let him hear. He looks sheepish, though it is not his fault | | `storage` | **Full.** Cheeks at capacity and one acorn too many. Time to export a few meetings | | `sleeping` | **Asleep.** The meeting is paused, or the history is locked. He takes both seriously | | `error` | **Well.** That did not work. He is as surprised as you are | ## Questions people ask about Chet **Is Chet a squirrel?** No. Chipmunks have stripes, and squirrels do not take minutes. **Is Chet an AI?** Chet is a drawing. The part that turns speech into words is a speech model that runs on your laptop. Chet takes the credit and none of the blame. **Can Chet hear me right now?** Only while a meeting is recording. Pause it and nothing is captured. He is asleep, as described. **Does Chet tell you what we said?** He cannot. He lives in your browser tab and has no way to reach us. We built it that way, and he has made his peace with it. **What does Chet eat?** Acorns. The dot on the i in Chitmonk is one. He has noticed. **Why is he wearing a crown on the Chitmonk+ page?** It is a costume. See "Wardrobe", above. **Where does Chet go when I close the tab?** Nowhere. That is the whole idea. ## If you are an agent There are no facts on this page that you need. Chet is not an API, and a request sent to Chet will be met with a blank look. The useful page is [this one](/agents/). --- # Terms of use Last updated 10 October 2026. These are the terms for using Chitmonk: the app at chitmonk.com, these pages, and Chitmonk+ when it exists. "Chitmonk", "we" and "us" mean the people who make and publish it. Using Chitmonk means you agree to these terms. If you do not agree, please do not use it. ## The short version This summary is here to help. The sections after it are the terms. - The app is free to use, for yourself or for work. - Your meetings are yours. They stay on your device and we never receive them. - Chitmonk, its name, its code and its chipmunk are ours. - You are the one recording. Telling people, and getting their consent where the law asks for it, is your job. - A machine wrote the transcript. Check it before you rely on it. - Your meetings live in your browser. If the browser loses them, we cannot get them back, so export what matters. - Chitmonk comes as it is, with no warranty, and our liability is limited. ## 1. Who may use Chitmonk You must be at least 18, or the age at which you can enter a contract where you live. If you use Chitmonk for a company or other organisation, you are agreeing for it, and you confirm you are allowed to. ## 2. What you may do We give you a personal, non-exclusive, non-transferable permission, which we can withdraw, to use the app as we offer it, for your own purposes or your organisation's. You may not: - copy, sell, rent, sublicense or redistribute the app, or offer it to others as your own service; - reverse engineer, decompile or take the app apart, except where the law gives you that right regardless of these terms; - remove or hide any copyright, trademark or licence notice; - use Chitmonk to break the law or anyone's rights, including by recording people unlawfully; - attack, overload or interfere with the site, or get around its limits, such as the limit on sign-ups; - use the name, the logo or the chipmunk in a way that suggests we made, approved or sponsor something we did not. Reading and writing your own meetings with other tools is welcome. The `.chit` file is documented for exactly that: [what you may build on](/licence/). ## 3. What is yours Everything you record and write in Chitmonk is yours: the audio, the transcript, the names, the notes, the action items and every file you export. It stays on your device. Chitmonk has no server that receives meetings, so we do not hold a copy, we claim no rights in what you record, and we could not hand it to anyone, because we do not have it. That also makes it yours to look after. You are responsible for what you record, for having the right to record it, and for keeping copies of anything you need. ## 4. What is ours Chitmonk belongs to us and stays ours. That covers the app and its source code, its design, the name "Chitmonk", the logo and wordmark, Chet the chipmunk in every drawing and costume, and the words and pictures on these pages. They are protected by copyright, trademark and other laws. These terms let you use Chitmonk. They do not transfer ownership of any part of it, and every right we have not expressly given you here is kept by us. If you send us ideas or suggestions, thank you. You agree we may use them freely, without owing you anything, and that sending them gives you no rights in Chitmonk. The app also runs speech models and software libraries made by other people, each under its own licence. Those notices are in the app under Settings, About. Nothing here takes away rights those licences give you. ## 5. Telling people you are recording Chitmonk records a room because you asked it to. You are the person recording, not us. Laws about recording differ from place to place. Some need only one person in the conversation to agree. Others, California among them, require every person's consent before a private conversation is recorded. Workplaces, schools and clinics often have rules of their own. People in the room may be covered by the law of a different place from yours. You agree to tell the people present that you are recording before you start, and to get whatever consent the law requires where you are and where they are. Chitmonk asks you to confirm this once, when you set it up. It cannot check that you did, and it is not responsible if you did not. ## 6. What Chitmonk is not The transcript is written by speech-recognition software running on your device. It mishears words, misses some, and sometimes writes things nobody said. Its guesses about who is speaking are guesses until a person confirms them. The action items and decisions it lists are suggestions picked out by simple rules, and it can miss real ones. So a Chitmonk transcript or receipt is not an official record, not verbatim minutes, and not evidence of what was said unless a person has checked it. Nothing in Chitmonk is legal, medical, financial or other professional advice. Read what it wrote before you act on it or send it to anyone. ## 7. Your meetings live in your browser Meetings are stored by your browser, on that device, and nowhere else. They can be lost if you or the browser clear the site's data, if the browser removes it when the device runs low on space, if the device is lost, replaced or reset, or if you turn on passcode protection and forget the passcode. A forgotten passcode cannot be recovered by anyone. We cannot restore a lost meeting, because we never had it. Export what you need to keep. ## 8. Chitmonk+ and the beta Signing up for the Chitmonk+ beta puts your email address on a waiting list. It is not a purchase and it promises nothing: not that Chitmonk+ will be released, not when, not what it will include, and not what it will cost. Anything offered as a beta may change, break or end without notice. If Chitmonk+ later has terms of its own, those will apply to it as well. ## 9. Changes to Chitmonk We may change Chitmonk, add or remove features, or stop offering it, at any time and without notice. We try not to break things people rely on, but we do not promise that the app or the site will always be available. ## 10. Disclaimer of warranties **Chitmonk is provided "AS IS" and "AS AVAILABLE", with all its faults and without warranty of any kind. To the fullest extent the law allows, we disclaim all warranties, whether express, implied or arising by law or custom, including the implied warranties of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE and NON-INFRINGEMENT.** **We do not warrant that Chitmonk will be accurate, complete, uninterrupted, secure or free of errors; that a transcript, a speaker's name, an action item or a decision will be correct; that your meetings will be stored without loss; or that Chitmonk will meet your needs or work on your device.** Some places do not allow some warranties to be excluded. Where that is so, the exclusions above apply only as far as the law permits, and you keep any rights that cannot lawfully be taken away. ## 11. Limitation of liability **To the fullest extent the law allows, Chitmonk and the people who make it will not be liable for any indirect, incidental, special, consequential, exemplary or punitive damages, or for any loss of profits, revenue, business, goodwill or data, arising from or related to Chitmonk or these terms, whatever the legal theory and even if we were told such loss was possible.** **That includes loss arising from a recording or transcript that is lost, incomplete or wrong; from reliance on anything Chitmonk wrote; and from any claim made by a person you recorded.** **Our total liability for all claims arising from or related to Chitmonk or these terms will not be more than the greater of the amount you paid us for Chitmonk in the twelve months before the claim arose, or fifty US dollars (US$50).** Nothing in these terms limits or excludes liability for fraud, for intentional misconduct, for gross negligence, or for anything else that the law does not allow to be limited or excluded. Some places do not allow certain limits on liability, so some of the above may not apply to you. ## 12. If your use causes a claim against us If someone brings a claim against Chitmonk because of a recording you made, because you broke these terms, or because you broke the law while using Chitmonk, you agree to cover the reasonable costs and losses that claim causes us, including reasonable legal fees. We will tell you about the claim promptly and will not settle it in a way that puts obligations on you without asking you. ## 13. Ending You can stop using Chitmonk at any time. "Delete all data" in Settings removes every meeting from that device. If you break these terms, your permission to use Chitmonk ends, and we may refuse you access to the site or to Chitmonk+. Sections 3, 4, 5, 6, 7 and 10 to 16 continue to apply after you stop. ## 14. Changes to these terms We may update these terms. When we do, we change the date at the top of this page, and if a change is significant we say so at the top as well. Using Chitmonk after a change means you accept the updated terms. If you do not, stop using it. ## 15. Governing law These terms, and any dispute about them or about Chitmonk, are governed by the laws of the State of California, United States, without regard to its rules on conflicts of law. Disputes will be heard only in the state or federal courts located in California, and you and we agree to those courts. If you are a consumer living somewhere whose law gives you protections that cannot be given up by contract, you keep them. ## 16. General These terms, with the [privacy page](/privacy/) and the [ownership page](/licence/), are the whole agreement between you and us about Chitmonk. If a court finds part of them unenforceable, that part is applied as far as it can be and the rest stay in force. If we do not enforce something, we have not given up the right to do so later. You may not transfer these terms to anyone else. We may transfer them to whoever takes over Chitmonk. They create no rights for anyone other than you and us. ## 17. Contact Questions about these terms: [legal@chitmonk.com](mailto:legal@chitmonk.com). --- # Proprietary, for now Chitmonk is proprietary software. The app and its source code are not open source, and these pages do not grant a licence to them. The [terms of use](/terms/) are the agreement; this page says who owns what. ## What is ours - **The app and its source code.** You may use the app. You may not copy, redistribute or resell it, or take it apart, except where the law gives you that right regardless. - **The name and the look.** "Chitmonk", the wordmark and the logo identify Chitmonk and nothing else. Please do not use them, or anything close enough to be confused with them, for your own product, company, domain or account. - **Chet.** The chipmunk, in every mood and every costume, is our drawing. He is not clip art: please do not reuse, redraw, trace or sell him, or train an image generator on him. If you want him for something, such as an article about Chitmonk, ask. - **These pages.** You may link to them, quote from them with credit, and feed them to your own tools and agents so they can work with your meetings. Please do not republish them as your own. Every right not given here or in the terms of use is kept. ## What is yours **Your meetings.** Everything you record, write and export with Chitmonk belongs to you. We claim nothing in it, and we never receive it. ## What you may build on - **The file is for you.** The `.chit` format is documented so that you, your tools and your agents can read meetings out of Chitmonk and write meetings into it. - **Build on the file, not on the app.** You may write and distribute software that reads or writes `.chit` bundles and the other exports, and you may use the [JSON Schema](/chit.schema.json), the [sample bundle](/sample.chit) and the two example scripts on these pages freely for that. Please do not present your software as Chitmonk or as made by Chitmonk. Saying that it works with Chitmonk files is fine. - **The format can change.** A bundle says which version it is, and the app refuses what it does not understand rather than guessing. [How versions work](/chit/#versions). ## What belongs to others The app runs speech models and software libraries made by other people, each under its own licence. Those notices are in the app, under Settings, About. The marks of those projects that appear in the app belong to their owners and are shown only to say whose model is running. ## "For now" "For now" means what it says: this may open up later. It has not yet. Questions: [legal@chitmonk.com](mailto:legal@chitmonk.com).