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

Terminal and platforms3 of 10

The nineteen slash commands

About 8 minutes to read

On this page

Type / at the prompt and the completion list shows all nineteen, with no … N more — a list that hides the last command turns / from everything I can do into some of it.

A command is the machine answering, not her: it writes at column 0, takes no nameplate, and returns you to the prompt. A word typed after a command that takes none is answered rather than dropped — /calm off with motion already off used to turn motion on.

/exit is a twentieth name and deliberately not in the list: it is folded to /quit on the way in.


Looking at what she is doing

/work [N]

The long job's receipt so far: the opening bracket with a clock where the start time was, then every tool step and every helper under it, drawn still.

▸ ▏WORK ▕ 01  compare the three release notes and write it up           3m 34s
✓  TOOL   release notes 2.4 · 7 results                                   4.0s
▸ ▏BASH ▕ npm test                                                       30.0s
▸  言 01  ( •ω• )   research read the changelogs             ▪▪ 2 steps 100.0s
what she's thinking isn't kept — this is what she's done, not how she got there

With no argument it opens the running job, or the last one if none is running. /work 2 opens the second job of this session; the numbers are the session's, assigned by the terminal, because the backend keeps one record per session and overwrites it. A finished job also prints its closing bracket and its summary.

The listing is fitted to your window and both brackets are outside the budget, so a job that ended never reads as one still going — what is cut is the middle, and it is counted: +4 tools and 3 helpers not drawn — a taller window opens more of it.

With nothing running and nothing finished: nothing of hers is running out here — /work is for the long job, and there isn't one.

/helpers [N]

The full log of the line-up that is out right now, or of the last one back — nameplate, every step, and the summary each helper came home with.

1 helper last time — /helpers 2 for just that one
▸  言 01  ( •ω• )   research read the changelogs             ▪▪ 2 steps 100.0s
     · opening the changelog
     ✓ read 3 pages

/helpers 2 opens just that one. The number is the same number the roster and /work N print. Bounded twice — by how many helpers the window holds and by how many steps one of them did — and a helper's summary is bought before its steps, because that is where the outcome is stated in words.

/plan

The open plan, on demand — the one place the whole thing still prints while the band carries it live:

▸ ▏PLAN ▕ compare the releases                                         3 steps
   ✓  1  read the changelogs
   ▸  2  compare the two releases
   ·  3  write it up

It takes no argument — a plan is hers to open, so /plan do the thing answers rather than pretending to be a way of making one. Head first, and if the tail is cut it names the step she is on, so the row you opened /plan to find is never simply missing.

With nothing open: no plan open right now. When the list closes, its receipt goes into the transcript once, with 3 of 3 in place of 3 steps.

/last

The last tool result, printed whole. The row in the transcript only had space for a phrase — 7 results, exit 1 — and this is the rest of it. nothing has run yet this session before anything has.

/stop

Calls off the long job, and only ever that. It names what would die before it asks, on a single-keypress rail with its own two labels:

▄▄▄▄▄▄▄▄▄▄▄▄
█   NEEDS YOU  stop the long job? 3m 34s in
█
█  2 steps so far, on: compare the three release notes. None of
█  it is kept if you stop it now
█
█  y stop it   n let it run

A turn owns the terminal for as long as it lasts, so /stop can only ever reach the background job — there is nothing else out here to stop. It takes no argument: /stop 2 reads as "stop job 2", and job 2 need not be the one running, so the number is answered instead of acted on.


What she is configured with

/settings [section]

Everything she is configured with, in the same twelve sections the web panel uses: BRAIN, VOICE, WORK, SECURITY, HER, MCP, SKILLS, MEMORY, REMINDERS, TOOLSETS, KEYS, PLUGINS.

 B R A I N  ──────────────────────────────────────────────────────────────
provider            openai                                      openai · xai
base_url            (openai's own)                    http(s)://… or nothing
model               gpt-5.4-mini                                    any name
...
 S E C U R I T Y  ────────────────────────────────────────────────────────
sandbox             local                              local · docker · none
trust               workspace
browser_cdp

Not an accordion: a browser hides sections because it has one screenful and a mouse, and a terminal has scrollback. Every section open is the accordion, and /settings brain is the one you clicked.

A row's third column is what /set will take. A row with no third column is read-only — the absence is the signal, the same way the web shows it. Whole sections are drawn while they fit, head first, and the ones that do not fit are named by the name you would type.

/set <key> <value>

The write behind every settable row.

$ /set                       → /set <key> <value> — /settings lists every key and what it takes
$ /set sandbox               → prints that one row
$ /set sandbox rocket        → sandbox takes local · docker · none — 'rocket' isn't one of them
$ /set work_timeout 5        → work_timeout can't go under 30 — that's the floor
$ /set banana 3              → I don't have a setting called banana — /settings lists every one of mine
$ /set name Aiko             → name isn't something /set reaches — it's what she's got, and it
                               changes where it was made

Nothing invalid is stored: the tables here decide only the message, and the write itself goes through the same validator. A value that is already set says so instead of reporting a change. A home that will not take a write is answered in her words and the session goes on.

/set model <name> is taken on your word — an OpenAI-compatible base_url can be pointed at anything — but a name the provider does not publish gets one clause on the line reporting the write, and never on the read-back:

$ /set model grok-4.3
model → grok-4.3 — xAI (Grok) is the one that serves that name — /set provider xai goes with it

Two settings change the trust model, and only those two are gated behind a confirmation: sandbox and provider. The rail states the consequence rather than asking "are you sure":

█   NEEDS YOU  sandbox local → docker
█  that moves everything I run into a container that sees only my
█  workdir — and I stop asking before anything that isn't dangerous
█  y change it   n leave it as it is
█   NEEDS YOU  provider openai → xai
█  that sends everything you say to xai instead of openai — a different
█  company, a different privacy policy, and the keys are kept apart

There is deliberately no --force twin. A flag people learn to type reflexively is a gate that has already been passed. The only other route to these two keys is the --settings picker, which runs the same command and therefore hits the same rail.

/model [name]

With no argument, the one fact the bar's right slot also carries, and how to change it:

gpt-5.4-mini · OpenAI — /model <name> switches it

It answers OpenAI · no key yet when no client could be built, and OpenAI · wrong model when the provider does not serve the model that is set. It never calls the provider. /model x is /set model x, so the header, the bar and this listing cannot disagree.

/approvals and /approvals rm <name-or-number>

What she runs without asking, and how to take any of it back. Each row says what the grant buys now, not what it bought when you gave it:

 A L W A Y S   A L L O W E D  ────────────────────────────────────────────
1.  curl
    asks every time — this no longer grants anything
2.  cat
    runs inside her workdir without asking
3.  execute_code
    runs code without asking — still asks for anything risky

these run without a card — /approvals rm <name-or-number> makes her ask again

A grant goes by name or by number, because an exact grant can be a whole command line and asking somebody to retype it is asking them to leave it there. Two rows that would draw the same elided text are drawn whole instead, so the number you read always points at the grant printed beside it.

Revoking needs no confirmation: it only makes her ask more. The friction is for turning a gate off.

With nothing saved, it says so and names what still runs unasked on this machine: nothing is always-allowed — only a plain read in her workdir runs without a card.


What she has handed you, and what you hand her

/attach <path>

Sends her a file. An image or a PDF rides the next turn's context — the line lands in the box as [Image #1], or [File #1] for a PDF, and waits for enter, so you can say what to look for. Anything else that decodes as UTF-8 text is copied into her workdir where read_file can find it, and the line becomes read <name>.

  • Recognised as something she can see: .png .jpg .jpeg .webp .gif .pdf.
  • A file that is neither text nor a picture is refused: I'd only see bytes.
  • One file must be under 14 MB, and one message carries at most 4 of them. Over either, she says so and no row claims she is carrying it.
  • A shared image is also saved into her library, so "what was in that picture?" three turns later still has somewhere to go.

The path is not jailed — /attach ~/Downloads/trace.png is a path you typed out in full, knowingly. That is exactly why @ is jailed and this is not.

/open [N]

Opens something she handed you — a report, a file she kept, a link — through your desktop's own opener (xdg-open, macOS open, os.startfile on Windows). With no number, or a number that is not one of hers, it lists what there is to open.

A path is refused if it leaves her file library; a URL is not a path and skips that check. The number is bounded on both sides, so /open 0 and /open -1 reach nothing rather than silently launching the last row. If nothing could be spawned it says so and prints the path, rather than printing opening → and doing nothing.

/sessions

The last 20 conversations, newest first, with when each one started and how much is in it.

None of them reopens, and the command says so rather than letting a numbered list imply otherwise: these don't reopen — say what you're after and she'll go and find it in them. That is the thing that actually works — she can search every turn in the table. To replay one, launch with kotoba --sessions, which opens the picker that does.


Her face and the screen

/emotions

All fourteen faces at once, as many to a row as the window holds:

( ・ω・ )    neutral      ( ^ω^ )    happy        ( ★ω★ )!   excited
( ・︵・ )   sad          ( ╥ω╥ )    crying       ( `Д´ )    angry
( ⊙O⊙ )!   surprised    ( >ω< )    embarrassed  (  ̄_ ̄ )? thinking
( -ω- )z sleepy       ( ♡ω♡ )~   affectionate ( ・ω? )    confused
( ゚Д゚ )    scared       ( •ω• )    determined

/face <name>

Sets one of those fourteen by name, folded so /face EXCITED works. A name she does not have is refused by name — and her face is not changed, because setting confused on a miss would be answering a failed command by doing the thing it asked for.

/plate

Flips the nameplate between turn — a plate on every reply — and quiet, which plates her only when her mood changes.

/calm

Flips reduced motion. Nothing on screen moves while it is on: the spinner is a still frame, the chip is solid, her face does not blink.

/clear

Wipes the screen and reprints the header. The session is untouched — the command says so, because /clear history reads as clearing the history and used to clear only the screen, in silence. The word is refused before the glass is wiped, so the refusal is not printed under a screen that just went blank.

/help [part]

Four parts — commands, launch, keys, try. Together they are 45 rows, so on a classic 80×24 what fits is drawn head first and the rest is named:

+5 commands not drawn — / lists every one of them, and scrolls
also /help launch · keys · try

/help keys opens one part. A part that does not exist names the four that do.

/quit

Leaves. ctrl-d and /exit do the same.