Skip to content

Latest commit

 

History

History
82 lines (65 loc) · 4.14 KB

shared-state.md

File metadata and controls

82 lines (65 loc) · 4.14 KB
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
architecture
created 2026-05-28
updated 2026-07-10

Shared State

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 Directory

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.

Locking And Atomic Writes

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.

Scratch Files And Provider Locks

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/koan when XDG_RUNTIME_DIR is set (Linux/systemd), else /tmp/koan-<uid>/, created mode 0700. Overridable with KOAN_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.

Configuration Sources

  • Project configuration primarily comes from projects.yaml at KOAN_ROOT.
  • Environment configuration comes from .env and KOAN_* 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.