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 app9 of 12

Settings

About 6 minutes to read

On this page

Settings is an accordion of eleven sections, plus one that appears only when it has something to say. Every change is written to the backend as you make it — there is no global Save button — and the panel then re-reads the backend and draws what it got back.

Screenshot placeholder: the Settings panel open on the left of a narrowed stage — a white header strip reading "Settings", and a stack of collapsed section cards each with a coloured square, a title and a small grey summary on the right (Personality "Kotoba", Brain "gpt-5.6-luna", Security "local").

Settings is reachable before a call as well as during one (components/UIOverlay.tsx:150-152).

How a change lands

One writer handles every request. On a refusal it puts the backend's own sentence in a red banner at the top of the panel; on success it re-reads /api/settings, so what you end up looking at is the normalised value the backend kept, not the value you clicked (components/panels/SettingsPanel.tsx:182-203).

The banner clears itself after 5 seconds (SettingsPanel.tsx:268-272).

There are two kinds of write, and they differ in who rolls back:

  • Provider and model are written with nothing optimistic. A refusal leaves the select reading what is really configured (SettingsPanel.tsx:205-215).
  • Every other knob is written optimistically so the control does not flicker for the length of a round trip — and a refusal therefore re-reads, or the panel would keep showing a value the backend never accepted (SettingsPanel.tsx:218-227).

A background re-read cannot clobber a Personality field you are still typing in: the panel marks those three fields dirty on the first keystroke and refuses to overwrite them until you press Save (SettingsPanel.tsx:162-171, 229-235, 274-277).

The sections

SectionWhat is in it
Personalityher name, language, ElevenLabs voice id, avatar model, voice mode, voice engine, agent id
Brainprovider, base URL, API key, five per-role models, reasoning effort, expressive voice, the two setup doors
Capabilitiesone toggle per tool family
MCP serversconnected external tool servers, with a connect control
Needs connectiononly shown when servers are waiting for authentication
Pluginscommunity add-ons, one toggle each
Skillsthe knowledge guides she consults — read-only
Memorywhat she remembers, by topic, each removable
Remindersscheduled reminders, each removable
Saved keyscredentials stored on the server, listed by name and never shown
Securitysandbox, trust level, the standing command grants, Sign out
Advanced (work)the four work-mode limits and the browser CDP address

(SettingsPanel.tsx:317-500.)

A test enumerates every block the panel asks the backend for and fails if any of them is requested but never drawn — dead weight on the wire reads as a control somebody forgot to build (tests/settings-payload-is-drawn.test.mjs).

Personality

Name, Language and Voice ID share one Save button (SettingsPanel.tsx:318-326). The name write is read back, because the backend silently refuses a value that does not look like a name.

The avatar select lists what is installed and applies on reload, which its own label says. With nothing installed it does not draw an empty select — a control with no options reads as a broken control — it names the folder to unpack a model into instead (SettingsPanel.tsx:329-338).

Below a dashed rule sit three voice controls and a guide. Voice mode is labelled "applies to the next call" and it means it: the call shell re-reads this value whenever the phase is offline and the panel is shut, never mid-call, because a live call has its transport latched (SettingsPanel.tsx:340-345, CompanionExperience.tsx:186-189, tests/settings-reach.test.mjs).

How to set up ElevenLabs → opens a Markdown guide in a modal (SettingsPanel.tsx:354).

Brain

Provider and model are one decision, not two keys. Both go through the guarded setup endpoints rather than the raw runtime endpoint, because switching companies while the old model is still set leaves a pair that cannot work — and "Test connection" then reports a perfectly good key as a bad one (SettingsPanel.tsx:205-215, tests/settings-brain-pair.test.mjs).

The model menus list the active provider's models only. A menu mixing both companies offered ids the install could only fail on (SettingsPanel.tsx:620-626). All five menus also accept a typed id the catalogue does not list.

Five roles, each inheriting when left empty (SettingsPanel.tsx:376-388):

RoleFalls back to
Companion model (voice)
Work model (background)companion
Code modelwork
Research modelwork
Utility model (emotion / memory / captions)companion

Save key refuses an empty draft rather than treating it as "erase" — sending an empty value used to delete the stored key (SettingsPanel.tsx:238-245). Remove is the way to erase one, and it asks for confirmation first (SettingsPanel.tsx:247-255). Test connection does a small round trip and never echoes the key (SettingsPanel.tsx:257-265).

At the foot: Run setup again and Give her a face, both full navigations into /setup.

Security

This is the section that changes what she is allowed to do on your machine.

Sandbox has three values (SettingsPanel.tsx:474-477):

ValueMeaning
localcode and shell run on this machine, gated by approvals
dockerthey run in a container
noneexecution is disabled — the select shows a red "Execution disabled." warning

Trust level is displayed, read-only. It comes from KOTOBA_TRUST and defaults to workspace; there is no live setter for it (api/src/kotoba/core/settings.py:127).

Allowed commands lists every standing grant, and each row says which width it is — just this line: …, running code (Python), or any "npm" command. The bin on a row revokes it (SettingsPanel.tsx:479-491). With none saved it says so plainly: "None — she asks before anything that isn't a simple read."

Sign out appears only when a password is configured.

No setting in this panel asks you to confirm. Changing the sandbox from none to local — which is the difference between "she cannot execute anything" and "she executes on this host, gated by approvals" — is a single select, applied immediately, with no second question. The only two confirmations anywhere in Settings are removing a stored API key (SettingsPanel.tsx:249) and, in Files, the two-click delete. Treat the Sandbox select as the serious control it is.

Advanced (work)

Four numbers, each committed on blur or Enter (SettingsPanel.tsx:495-498): work timeout in seconds (minimum 30), max iterations, max tool calls and a fail limit (each minimum 1). A refused value — below its minimum — is rejected by the backend and the panel re-reads rather than keeping what you typed.

The browser CDP address is displayed, read-only.

Where a change lands on disk

Runtime knobs are validated against an allowlist and persisted to ~/.kotoba/settings.yaml; each call site reads its value at request time, so a change applies to the next request rather than needing a restart (api/src/kotoba/server.py:1170-1184).

API keys are a different store: verified before they are saved, encrypted at rest, decrypted only in memory, never logged and never returned (api/src/kotoba/server.py:1187-1199). A refused key is a 400 and nothing is written at all.

What Settings does not do

  • It does not let you rename the app's own labels. Her configured name does not reach the call shell — see The main screen.
  • It does not expose the login password. That is an environment variable on the server.
  • It does not show a conversation history. See Sessions and history.