| type | doc | |
|---|---|---|
| title | Shared State | |
| description | Explains Koan's shared state under instance/ — mostly local files (locking/atomic-write conventions, per-uid temp/scratch dirs, config sources), with mission state in an authoritative SQLite store (missions.db) exported to missions.md. | |
| tags |
|
|
| created | 2026-05-28 | |
| updated | 2026-07-10 |
Koan intentionally keeps most runtime state in local files, which keeps setup
simple and makes state inspectable by humans and agents. Mission state is the
one exception (Constitution v2.0.0): it is authoritative in an SQLite store
(instance/missions.db) behind the MissionStore port, with missions.md as a
generated read-only export. Everything else below remains file-based.
instance/ is gitignored runtime state. Important files and directories include:
missions.db- authoritative SQLite mission store (missions + CI queue + ideas + quarantine).missions.md- generated read-only export of the mission store (edits ignored after the one-time sync).outbox.md- pending outbound messages for the bridge.config.yaml- instance behavior and integration configuration.memory/- global and per-project memory files.journal/- daily logs and reflections.events/- scheduled mission JSON files.hooks/- user-defined lifecycle hooks (see Lifecycle Hooks & Automation Rules).- hidden tracker files for pause, focus, passive mode, usage, CI dispatch, review dispatch, burn rate, and similar daemon state.
instance.example/ documents the expected shape of a fresh instance.
Shared files must be written with existing helpers such as atomic_write() and
file-locking utilities from utils.py or dedicated state modules. Avoid direct
read-modify-write cycles on instance/ files unless the code already owns the
appropriate lock. See specs/components/core.md for the design contract behind
these primitives (why atomic_write() and koan_tmp_dir() are the single
sanctioned path for shared-file writes).
The bridge and runner are separate processes, so bugs that are harmless in a single process can corrupt state when both daemons are active.
Transient scratch files (captured stdout/stderr, prompt files, generated plugin
dirs) and the provider invocation lock do not live in instance/ — they live
under a per-uid temp directory returned by utils.koan_tmp_dir():
$XDG_RUNTIME_DIR/koanwhenXDG_RUNTIME_DIRis set (Linux/systemd), else/tmp/koan-<uid>/, created mode0700. Overridable withKOAN_TMP_DIR.- It is per-uid, not per-instance: provider auth/session state is stored in the user's home directory, so two Kōan instances run by the same user must still serialize on the same provider lock.
This isolation is what lets multiple users run Kōan on one host without colliding
on shared /tmp paths. Code that needs a temp file MUST pass dir=koan_tmp_dir()
to tempfile.*; agent prompts that create scratch files MUST use
mktemp "${TMPDIR:-/tmp}/koan-<purpose>-XXXXXX" rather than a fixed filename or a
bare /tmp path. See Troubleshooting.
Each mission (and each parallel session) is additionally spawned with a private
TMPDIR under koan_tmp_dir() — mission-<pid>-<id>/, created by
utils.create_mission_tmp_dir(). Everything the agent writes via mktemp /
$TMPDIR therefore lands in one directory that is reaped when the mission ends
(utils.cleanup_mission_tmp_dir()). Leftovers from crashed runs are removed at
startup by utils.reap_stale_mission_tmp_dirs(), which skips dirs whose owning
pid is still alive so concurrent Kōan instances sharing a uid don't reap each
other's scratch space.
- Project configuration primarily comes from
projects.yamlatKOAN_ROOT. - Environment configuration comes from
.envandKOAN_*variables. - Instance behavior comes from
instance/config.yaml. - Provider selection uses
KOAN_CLI_PROVIDER, with legacy fallback support.
Prefer existing config helper modules over reading environment variables or YAML directly from new code.