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

Discord3 of 10

Installing, the token, and the settings

About 3 minutes to read

On this page

Install

bash
pip install "kotoba-companion[discord]"          # text only
pip install "kotoba-companion[discord,voice]"    # text and voice

From a clone the extra is pip install -e "api/[discord]".

The discord extra brings discord.py[voice], numpy, and the voice extra it depends on. discord.py[voice] brings PyNaCl and the DAVE library with it, and the bot refuses to start unless all three of discord, nacl and davey are importable — even if you never intend to use voice. It prints the install line and exits.

The voice extra carries the WebSocket library her transcriber and her synthesiser are built on. discord pulls it in, so a Discord install is never missing it. If you do manage an install without it — an old environment, a hand-pinned set — she joins the channel and says she could not open a transcriber, in the log, rather than sitting there silently.

The token

bash
kotoba discord --save-token

It asks on the screen and reads the token with the echo off wherever the terminal lets it, so the token never lands in your shell history. It is stored in the same encrypted keystore as your model key — AES-256-GCM, under the name cred:discord_bot — and the command prints saved, encrypted at rest.

If there is no terminal and nothing piped in, it falls back to DISCORD_BOT_TOKEN and says so instead of ending in a traceback.

DISCORD_BOT_TOKEN is honoured at startup too, but the keystore is read first. The environment variable is the escape hatch for a first run with no database yet.

Neither path ever prints the token: anything that looks like a token or a JWT is replaced with <token redacted> in any error the command reports. A transport error can quote the whole failed request, headers included, and that sentence is the kind people paste into a chat to ask what it means.

Run

bash
kotoba discord                              # connect, and stay until Ctrl+C
kotoba discord --guild 000000000000000000   # only this server (repeatable)

This is one more process beside whatever else you run. It starts no cron ticker and does no OAuth token refresh, because two processes doing either would fight: a second ticker would claim a due reminder and announce a private one into whichever channel happened to be listening, and two processes rotating one credential retire each other's.

kotoba discord acts on none of the four rendering flags (--plain, --ascii, --calm, --no-face). Passing one prints a line naming it and exits with status 2, rather than accepting the flag and ignoring it. Everything the command prints belongs to the gateway and the server, not to her.

Settings

All three are environment variables read by the bot process.

VariableWhat it doesUnset
KOTOBA_DISCORD_OWNER_IDYour Discord user id. The one account she treats as her person. It is never inferred from anything anybody types.Nobody is her person: her terminal, files, memory, keystore, reports and background jobs are reachable by nobody on Discord, and nobody can approve a card for anything that runs on the host
KOTOBA_DISCORD_GUILDSComma-separated server ids she may work in. --guild overrides it. Set, a DM is answered only for somebody who is in one of those servers.Every server she was invited to, and every DM from anybody at all
KOTOBA_DISCORD_HOME_CHANNELSComma-separated channel ids where she answers everything, not only what names her.No such channel; she waits to be named

Both id lists accept commas or semicolons and ignore anything that is not a run of digits, so a stray # or a name silently contributes nothing. Copy ids with Discord's Developer Mode enabled.

Two more variables matter here:

VariableEffect on Discord
KOTOBA_TZThe timezone discord_read_history uses to read "14:00", "yesterday" and "this morning", and to stamp each line it reads back. Unset, it uses the machine's local zone
KOTOBA_STT_LANGUAGEPins transcription in voice channels. Unset, she pins it to her own configured language, and only falls back to auto-detection if that is auto

Where her data lives

One SQLite database, kotoba.db, in ~/.kotoba — or beside the code in api/ if you run from a clone that already has one there. It holds the conversation of every channel she has answered in, and her notes about the people she has met. See What she remembers.