Format
The casebook repository, file by file.
casebook-data is a private git repository written only by the casebook binary. History is linear: no merge commits, no branches. This is format version 2, the version casebook 0.2.0 and later write.
the root
Top-level files.
| path | content |
|---|---|
| casebook.toml | format_version = 2. A binary refuses a repo with a newer version, and upgrades an older one in place with one commit. |
| policy.toml | Attention thresholds in days, shared by every machine: outgoing_pr_stale_days (14), incoming_no_reply_days (7), unpushed_days (3), repo_dormant_days (365). Unknown keys are errors. |
| README.md, CONTRIBUTIONS.md, MACHINES.md | Views rendered at each sync. On a conflict the upstream copy wins and the next sync renders them again. |
The policies are: an open outgoing pull request with no activity past its threshold (outgoing-stale); an undecided incoming pull request or issue whose latest activity is not your reply (incoming-no-reply); an undecided, unarchived repo not pushed for a year (dormant); and a branch or worktree with commits on no remote (unpushed). An item decided ignore is never flagged.
decisions
items/: one file per decision.
Owner and name are lower case; branch names and paths keep their case and are path-escaped in the file name.
| kind | key | file |
|---|---|---|
| repo | repo:<owner>/<name> | items/repo/<owner>/<name>.toml |
| pr | pr:<owner>/<name>#<n> | items/pr/<owner>/<name>/<n>.toml |
| issue | issue:<owner>/<name>#<n> | items/issue/<owner>/<name>/<n>.toml |
| branch | branch:<owner>/<name>@<branch> | items/branch/<owner>/<name>/<escaped branch>.toml |
| worktree | worktree:<machine>:<abs path> | items/worktree/<machine>/<escaped path>.toml |
disposition = "watch" # keep archive close delete merge wait watch ignore note = "retire the fork when this lands" # optional until = "merged(pr:elidickinson/pi-claude-bridge#97)" # optional; required for wait and watch decided_by = "you" # your login, claude:<session>, pi:<session> decided_at = 2026-09-24T10:12:00Z # UTC, second precision proposed_by = "pi:<session>" # optional: who proposed it (a session or rule:<id>) rule = "<rule id>" # optional: the standing rule that proposed it [conflict] # only after a decision race disposition = "archive" decided_by = "you" decided_at = 2026-09-24T10:11:00Z
Each decision is one commit, decide <key> → <disposition>. casebook validate checks every file. The dispositions each kind allows, and the until forms, are on the rules page.
Races. When two machines decide the same item between syncs, the later decided_at wins. The other is kept under [conflict], and the item's status is conflict until someone decides again.
journal
journal/<machine>/<YYYY>/<MM-DD>.jsonl
One JSON object per line, for every git and gh action the hooks and harnesses saw. Each machine writes only its own directory, so journals never conflict.
v,ts, andsrc:git-hook,claudeorpi.- For git hooks:
hook,argsandstdin(whitespace-split lines, at most 200, withtruncatedwhen cut). cwd,git_dir,repo,machine,exit_code.claude_idandagent_id, the raw harness session ids, andchildwhen the process belongs to the agent session.actions:tool,verb,dir,repo,number,refs,flags.
Never stored: command lines, commit or tag messages, titles, bodies, field values, header values, query strings, or credentials in URLs.
snapshots
machines/<machine>.json
This machine's clones under its roots. The file is deterministic and holds no timestamps of its own, so an unchanged machine makes no commit.
- Per clone: its path, its GitHub repo, its remotes (non-GitHub URLs redacted), whether it is bare or dirty, its stash count, its local
core.hooksPath, and whether casebook's shims are adopted there. - Per branch: upstream, ahead count, unpushed count and the oldest unpushed commit's time, tip and tip time, the upstream's tip, and the landed verdict:
landed_state(yes,no,unknown), withlanded(in <default>ormerged #<n>),landed_tipandlanded_howwhen it is yes. - Per linked worktree: path, branch, head, detached, dirty.
rules and restores
rules/ and restores/
rules/<id>.toml holds one standing rule each; the rules page documents the file. Commits read rule <id> → active by <who>, rule <id> edited by <who> and rule <id> deactivated by <who>.
restores/<YYYY-MM-DD>.tsv is appended one line at a time, immediately before each destructive step, under the header key, action, before, restore-command, separated by tabs. Each line is its own commit, restore record for <key> (<action>). A tab or newline in any field is refused, and the step fails before it checks anything. The apply page lists the restore commands.
not in the repo
What stays on the machine.
The GitHub observation cache (github.json), the drift record (seen.json), the event spool and the hook shims are local to each machine. So is casebook serve's working state in ~/.local/state/casebook/casebook.db: agent sessions, threads, messages and deliveries, proposals, evidence, progress, jobs and the live event log.
That database records collaboration, never intent. A proposal becomes intent only when you accept it, as a decision file with proposed_by.
Versions
- 1 (casebook 0.1.x): decisions, journal, snapshots, views.
- 2 (casebook 0.2.0): decisions gain the optional
proposed_byandrule.rules/andrestores/are new directories that older binaries ignore. The upgrade rewrites onlycasebook.toml.