Kotoba

Where to start

What Kotoba isWho she is and where she runs, in one page
InstallingOne package, two commands
First runA key, a model, her first words
The approval gateHow she asks before she acts
The two voice modesLocal voice, or the agent tunnel
The soul fileChange who she is
RoadmapWhat grows next, and what was cut on purpose

Or a section

↑↓ move openesc close124 pages
All pages

The web app4 of 12

The transcript

About 4 minutes to read

On this page

The transcript is the panel on the right of the stage. It shows what was said in this call, and it is where you type or attach something instead of speaking.

Screenshot placeholder: the transcript panel open — a white header strip reading "Transcript", a column of alternating bubbles (hers white on the left labelled "Kotoba", yours purple on the right), and a composer at the foot with a paperclip, a one-line text box and a send arrow.

Open it with the Toggle transcript button in the dock.

What is in it

Bubbles, oldest first, scrolled to the newest whenever a line arrives (components/TranscriptPanel.tsx:45-47). Hers sit left and carry a small coral Kotoba label; yours sit right (TranscriptPanel.tsx:206-232).

A bubble can carry three things (TranscriptPanel.tsx:21-25):

  • Text.
  • An image — either a thumbnail of what you attached, or a keepsake she recalled, fetched from the backend. A recalled image carries a description of what it is of, because calling it "attachment" would be untrue.
  • A file chip — an attachment with nothing to show. It is drawn as its own row with a document icon, never folded into the message text, so the transcript she is sent stays the words and the filename stays a label.

Before anything is drawn, every line goes through one normalisation funnel that strips invisible and bidirectional control characters (lib/transcript.ts:30-32). Her replies quote web pages and external tool servers, and a transcript line can deceive exactly the way a terminal row can.

Her filler is stripped from the displayed text only, shape-anchored so a real word starting with "m" survives (lib/transcript.ts:41-46).

The two voice transports deliver a turn differently — one hands over a whole utterance as a single event, the other hands over sentence fragments — and the panel reconciles both into one bubble per turn (lib/transcript.ts:1-11, 66-88). When a correction arrives, only the last line is rewritten: walking further back would rewrite a turn you have already read (lib/transcript.ts:50-62).

Typing

The composer only works during a live call. With no call, the box is disabled and reads "Start the call to chat" (TranscriptPanel.tsx:56, 320-322). It works while you are muted — mute stops the microphone, not the conversation.

Enter sends. Shift+Enter makes a new line (TranscriptPanel.tsx:313-318).

Attaching a file

The paperclip takes images, PDFs and text files. The picker's filter, the panel's own check and the rejection message are all built from one list, so a format that is pickable can never be one that is then rejected (lib/attachments.ts):

KindAccepted
Imagesany image/*, plus .png .jpg .jpeg .gif .webp .bmp by extension
Documents.pdf
Text.txt .md .csv .tsv .json .log .yml .yaml, plus text/plain, text/markdown, text/csv, application/json

Anything else is refused in the browser with "Only images, PDF, or text files (…)".

The limits, and where each one is enforced

LimitValueEnforced in
Image or PDF size10 MBTranscriptPanel.tsx:58, 75-76
Text file size1 MBTranscriptPanel.tsx:59, 75-76
Text content actually sentfirst 20 000 characters, then …(truncated)CompanionExperience.tsx:504-505
PDF lengthabout 5 pagesCompanionExperience.tsx:516-524
Encoded upload size14 000 000 characters of data URLapi/src/kotoba/server.py:842-843
Files per message4api/src/kotoba/core/attachments.py:20

The three paths differ, and it is worth knowing which one you are on:

  • A text file is read in the browser and pasted into the message as File "name": …contents. It never leaves as a file (CompanionExperience.tsx:498-513).
  • A PDF is counted in the browser first. The page count is read out of the raw bytes; more than about five and she says so and sends nothing (CompanionExperience.tsx:516-524).
  • Images and PDFs are uploaded, base64, to the session's attachment slot and picked up by the next turn (CompanionExperience.tsx:534-546).

The fifth file in one message is refused by the backend with the sentence that fits — "I can only carry 4 files in one message — send this one and I'll take the next lot after it" — and that sentence is carried out to the transcript rather than replaced with generic advice, because "try again" cannot work when the answer is "send this one first" (server.py:852-857, CompanionExperience.tsx:547-552).

The file is stashed before the turn fires. The other order loses the attachment (CompanionExperience.tsx:527).

A staged attachment shows as a chip above the composer with a thumbnail (images) or an extension badge, and a × to remove it. The filename in that chip is scrubbed before it is drawn: a downloaded file's name came from wherever the file did (TranscriptPanel.tsx:271-296).

What the transcript is not

It is not a history browser. The lines live in the page's own memory for as long as the page is open. Reloading the tab starts an empty transcript, and there is no control anywhere in the app for opening a past conversation. See Sessions and history.