Everything Kizuki knows about your study lives in one folder on your computer. There is no account, no cloud copy, and no data in the app's own folder. Kizuki runs no server and opens no network port.
kizukiHome picks the folder: KIZUKI_HOME if set, otherwise ~/.kizuki. The kizuki command's --home option takes the place of KIZUKI_HOME (homeFor). The default folder is hidden on purpose: on macOS, ~/Kizuki would be the same folder as a ~/kizuki clone of the repo, because folder names there ignore letter case. homePaths lays out the rest:
| Path | Holds |
|---|---|
files/ |
Copies of the files you added, named <materialId><ending> |
data/*.jsonl |
The logs. They are the truth. |
data/.lock |
The lock file that makes writers take turns |
index.sqlite |
The search file, rebuildable from the logs at any time |
settings.json |
Model settings. API keys are never saved here, only the names of the variables that hold them. |
To back up your study data, copy the folder. A workflow-data/ folder from a version before 1.0.0 is no longer used; Kizuki leaves it alone, and you can delete it.
Each log is a .jsonl file: one event per line, and lines are only ever added. LogName names the logs, and LOG_SCHEMAS holds the shape of every event:
| Log | Events |
|---|---|
courses.jsonl |
courses and exam dates |
materials.jsonl |
each file's progress, from added to done or failed |
passages.jsonl |
every passage of a file, written once after reading |
concepts.jsonl |
proposed, confirmed, renamed, dropped, and merged concepts |
links.jsonl |
proposed, confirmed, and dropped links |
sessions.jsonl |
each session: your explanation, questions, answers, misses, and result |
corrections.jsonl |
your corrections, and "what does this mean?" questions with your answers |
catches.jsonl |
catches you recorded |
appendLog checks every event against its shape before it writes, and writes nothing if one fails. It writes while holding the lock (withLock). A lock left by a process that stopped is taken over; waiting more than 30 seconds for a live one is an error that names the process. withWriteLock holds the lock across a check and a write, so no other write can come between them.
readLog reads a log oldest first. A line that is not valid JSON, or does not match its shape, stops the read with an error naming the file and line number; Kizuki never skips a line. If Kizuki stopped halfway through writing a line, the error says so and tells you to delete that last line. The next write after such a stop starts on a new line, so only the half-written line is lost.
reduceState rebuilds the current state from the logs. It is pure: the same logs always give the same state. Every command reads the logs fresh, so what you see always matches the files.
Kizuki creates files/ and data/ as folders only your user can open (mode 700), and the files it writes there and settings.json as files only your user can read (mode 600).
With the default settings, nothing. A hosted model receives what you send it, and Kizuki asks first; Models explains what goes out and when. The kizuki.dev site is separate from the app and never sees your data.
lib/ids.ts makes ids: stableId for things found in a file, so reading it again gives the same ids, and newId (random) for everything else. Neither holds personal data.