Vision5 of 5
Privacy and deletion
On this page
An image she remembers is a file on your disk. This page says exactly where, who can read it, what leaves the machine, and how to get rid of one.
Where the bytes are
| What | Path | Override |
|---|---|---|
| Keepsakes | ~/.kotoba/visual-memory/images/ | KOTOBA_VISUAL_MEMORY_DIR |
| The keepsake catalog | ~/.kotoba/visual-memory/index.json | same |
| Screenshots she took | ~/.kotoba/files/screenshots/<source>/ | KOTOBA_FILES_DIR |
| Images you shared at the terminal | ~/.kotoba/files/shared/ | same |
| Clipboard pastes, scratch copy | ~/.kotoba/tmp/clips/ | KOTOBA_TMP_DIR |
~/.kotoba moves as a whole with KOTOBA_HOME.
A ctrl-v at the terminal writes twice: the raw clipboard bytes into the scratch directory, then a copy
into files/shared/. The scratch copy is collectable after 24 hours by a background sweep — but only
if the scratch directory was empty when Kotoba was first handed it. Point KOTOBA_TMP_DIR at a folder
that already had files in it and nothing there is ever swept, on purpose, so it cannot eat somebody's
work.
Images you attach in the browser or on Discord are never written to disk. They sit in the
backend's memory for the session and vanish when the process stops — unless she saves one with
remember_image, at which point it becomes a keepsake like any other.
Encryption, and who can read them
None of it is encrypted. Kotoba encrypts your API keys in a keystore; it does not encrypt images, their notes, or your files.
Measured on a Linux install with the usual umask:
| File | Mode |
|---|---|
index.json | 0600 — owner only |
images/<id>.<ext> | 0644 — world-readable |
| The directories | 0755 — world-traversable |
So the catalog is yours alone, and the pictures are readable by any account on the machine that can
reach the path. Any process running as you can read everything. If that matters to you, put
~/.kotoba on an encrypted volume or tighten the mode yourself.
Over HTTP, a keepsake is reachable at GET /api/visual-memory/{id} and a capture at
GET /api/files/open?path=…. Both sit behind the /api/* token gate, which is only on when you set
a password (KOTOBA_WEB_PASSWORD, or its alias KOTOBA_GATE_PASSWORD). With no password set the
gate is open, and what protects those routes is that kotoba serve binds the backend to 127.0.0.1.
Expose the port and you have exposed the pictures. The security section covers the gate in full.
The keepsake route takes an id and never a path, so a caller cannot ask it for an arbitrary file — an
unknown id and a traversal attempt both come back 404, and the filename read from the index is
re-checked against the store before anything opens. A stored SVG is served as
application/octet-stream with nosniff, so it cannot run as a document on your origin.
What is in the database
The database holds no images and no keepsake rows. Visual memory is the JSON catalog above, not a table.
What the database does keep about a picture:
- the turn text. Content is rendered to plain text before it is stored, with an image part
collapsed to the marker
[image]— never base64. A picture sent with no caption is stored as the sentinel__image_only__. Her own words about what she saw are stored in full, because they are her reply. - one audit row per
remember_imagecall: the tool name plus the first 180 characters of its arguments, which isabout,note,kindandsource. If the source was adata:URL, the first characters of that base64 are in the row as well.view_captureandrecall_imageare reads and write no audit row.
What leaves your machine
Everything she looks at goes to your model provider. There is no local vision model.
Three requests carry an image out:
- The turn. Attachments and tool-result images ride the request as
input_imageparts. - The recall.
recall_imageandview_captureread bytes off your disk and put them back into the next request, so a keepsake you saved months ago is uploaded again each time she looks at it. - The caption. A newly filed screenshot is sent once more, at low detail, to be described in one line for the capture log.
The destination is whatever provider you configured — OpenAI or xAI by default, or any endpoint you
point base_url at. When the answering model is a reasoning model and reasoning_effort is not
off, the request carries store=false, asking the provider not to retain it; setting
KOTOBA_LLM_STORE=1 opts back into stored state. With a non-reasoning model no store field is sent
at all and the provider's own default decides. Retention beyond that is the provider's policy and
nothing in this codebase can enforce it.
Nothing else sends an image anywhere. The events channel that tells your browser a keepsake was recalled carries the id only, never the bytes.
Who can ask her to look
On Discord the answer depends on who is speaking. The guest surface is an allow-list, and the memory
family is not on it, so a stranger in a server cannot reach remember_image or recall_image at all.
view_capture is owner-only twice over: withheld from the schema list, and refused in words by the
tool itself if it is called anyway. The refusal is the tool's, not the model's.
In the browser and the terminal, whoever is at the keyboard is you.
To switch the feature off entirely, turn the tool family off under Settings → Capabilities. Disabling
memory removes remember_image and recall_image from every turn; disabling core removes
view_capture, along with much else. The prompt is built from the tools the turn is actually offered,
so she stops claiming she can do it rather than promising and failing.
Deleting things
A screenshot or a shared image
They are ordinary files in her library.
- In the browser: the Files panel, delete button, two clicks (there is no undo).
- Over HTTP:
DELETE /api/files/{path}— jailed, no traversal, and idempotent. - On disk: delete the file.
The in-memory capture log is not updated by any of these. For the rest of that session she may still see the name, try to open it, and honestly report that she could not.
A keepsake
There is no button and no endpoint for this. The store has a delete function and nothing in the
running product calls it. Deleting a keepsake means editing the store by hand:
- Stop the backend and the CLI. Writes to the catalog take a cross-process lock; editing it while she is running risks losing the edit or losing other entries.
- Delete the image from
~/.kotoba/visual-memory/images/. - Delete its object from
~/.kotoba/visual-memory/index.json.
Deleting the whole ~/.kotoba/visual-memory directory empties the store; it is recreated on the next
save.
If you delete the image but leave the row, the result is not a crash and not silence: recall finds the entry, cannot attach the picture, and hands her the note under an instruction to say plainly that she cannot bring it up — and never to describe it as if she were looking. Ask her to save that image again and the orphan row is replaced rather than blocking the save.
Note that the catalog rows are readable text. The about and note you had her write are in plain
JSON, capped at 120 and 300 characters, and a summary of the entity names goes into her prompt on
every turn while the store is non-empty.
