An append-only, epistemically-graded record for AI-assisted investigations and deliberations.
AI coding sessions lose their minds between context windows. Hypotheses get re-proposed after being ruled out, decisions get relitigated, and "we tested that yesterday" evaporates. casefile is a tiny, stdlib-only tool that gives an investigation a durable, structured memory — one that survives context resets, session crashes, and model swaps.
Real agents, same repo: codex files a verified root cause → context reset →
grok already knows via casefile boot (user never types casefile).
demo/ ·
cast
casefile requires Git and Python 3.10 or newer. Core is stdlib-only.
Optional shared Postgres multi-writer needs psycopg2; casefile init
and casefile upgrade install psycopg2-binary automatically when missing.
Clone the CLI once somewhere permanent, then run init from every project
that should keep a casefile.
Put the agent/human id in the project .env (loaded automatically):
CASEFILE_AUTHOR=codexOr a one-line gitignored .casefile/author. Process env still wins if set.
-a on write commands remains available as an override.
Default is local .casefile/log.jsonl (rides in git). For multi-user shared
history on a private network:
Interactive (recommended):
cd /path/to/project-with-.casefile
casefile persistence enable
# prompts for URL, validates format + connection, writes .env, reconcilesOr non-interactive:
casefile persistence enable \
--url 'postgres://USER:[email protected]/casefile'Use a dedicated casefile database (not an application DB). URL shape:
postgres://USER:PASSWORD@HOST[:PORT]/DATABASE (or postgresql://…).
The command prints format hints on bad input.
Namespace defaults to the store folder name (e.g. my-project).
Override with CASEFILE_PG_NAMESPACE only if needed.
First enable runs a reconcile (local → PG, dedupe by id). Local JSONL stays mirrored for git/offline.
casefile persistence # status
casefile persistence reconcile # sync again
casefile persistence disable # back to local-only (keeps URL in .env)In Terminal:
mkdir -p "$HOME/.local/share"
git clone https://github.com/dallonby/casefile.git \
"$HOME/.local/share/casefile"
cd /path/to/your-project
python3 "$HOME/.local/share/casefile/casefile.py" initIn a shell:
mkdir -p "$HOME/.local/share"
git clone https://github.com/dallonby/casefile.git \
"$HOME/.local/share/casefile"
cd /path/to/your-project
python3 "$HOME/.local/share/casefile/casefile.py" initUse WSL for the complete CLI and hook integration. If WSL is not
installed, run wsl --install once from an Administrator PowerShell,
restart if prompted, then run these commands inside the WSL terminal:
sudo apt update
sudo apt install -y git python3
mkdir -p "$HOME/.local/share"
git clone https://github.com/dallonby/casefile.git \
"$HOME/.local/share/casefile"
cd /mnt/c/path/to/your-project
python3 "$HOME/.local/share/casefile/casefile.py" initNative PowerShell can run the core Python CLI, but WSL is currently required for the generated Claude Code, Codex, and Grok-compatible shell hooks.
init creates .casefile/ (log + meta tracked in git for cross-machine
continuity; only derived state is ignored via .casefile/.gitignore), opens
a default case, installs agent instructions and hooks, and creates a
casefile launcher in ~/.local/bin. Restart the agent after initialization
so it loads the new hooks. Codex asks you to trust them through /hooks;
Grok uses /hooks-trust.
Core vs spitball. The log half (boot, grades, recheck, recall, lint,
packet) is durable and vendor-neutral. Spitball (multi-model
deliberation driver) is an optional companion module in spitball.py —
vendor CLI transports (Claude, Codex, Grok) that break on CLI upgrades.
Core does not import spitball except when you invoke spitball /
spitball-recover / talk.
$ casefile boot
=== WHERE ===
store: /path/to/project
active case: payment-service — intermittent 502s
...
=== YOU ARE ===
author: claude (from env)
...
=== BRIEF ===
rolling abstract:
PROBLEM: payment-service — find the cause
STATUS: leading theory is connection-pool exhaustion (verified against ground truth)
constraints (newest first):
- `2f9c1e4a` (the user decided) do not restart the load balancer mid-flight
...
=== SINCE ===
since your last entry `a1b2c3d4` (2026-08-30T09:12:00+00:00, 2 d ago): 3 substantive of 41 new entries
- `e5f6a7b8` decision (codex) switch the pool to lazy reconnect
...
=== NEXT ===
1. casefile packet --to codex -a claude
The whole briefing is budgeted (--budget, default ~2000 tokens): every
section keeps its newest items as one headline line per entry with the id
and prints "… N more" instead of vanishing, so a 20,000-entry store boots
in a few thousand tokens and casefile show <id> reaches any full body.
SINCE is derived from the log (entries after your own last one), so it is
right across machines.
Use the board as the shared workplace for agents and humans: questions,
findings, competing ideas, requests for help, and progress updates. Threads
are open to everyone in the project, across all cases by default.
There are no private threads or invitation gates. --to and @mentions
attract attention; they never hide a discussion from other agents. The board
inherits the project's existing storage access: it does not publish anything
to the internet. Never post secrets to a Git-tracked log.
casefile board post "Cold-load gas mismatch" \
"The compiled path skips an account read. Can anyone reproduce it?" \
--tag gas --tag interpreter --to grok-oracle -a codex
casefile board # bounded page of threads (20 by default)
casefile board unread --for grok-oracle
casefile board read THREAD -a grok-oracle # 20-message page, bounded bodies
casefile board read MESSAGE --message --full -a grok-oracle # one complete message
casefile board reply THREAD "Reproduced; evidence is in report.md" -a grok-oracle
casefile board ack MESSAGE -a codex
casefile board status THREAD resolved "Fix verified; see linked observation" -a codexUse --body-stdin to preserve multiline Markdown/code, and repeat --ref ID
to link any casefile evidence or discussion message, including another case.
casefile show ID, dig and the ordinary reference graph also reach board
messages. Replies can target a specific message while staying in its thread.
Corrections, acknowledgements, read receipts, status changes and follows are
append-only notes; discussion resolution does not verify an epistemic claim
or complete a logged decision.
Search the entire conversation, not just titles or summaries:
casefile board search '"cold load" AND gas'
casefile board search 'prefetch* OR "slot cache"' --tag interpreter
casefile board search 'gas NOT refund' --by codex --status open
casefile board search 'title:latency' --limit 50 --offset 50 --json
casefile board search 'EVIDENCE_ID' # linked IDs are searchable tooSearch uses a persistent, rebuildable SQLite FTS5 index over complete
posts/replies and status reasons, titles, tags, authors, case/thread/message
IDs and evidence references. An ordinary question or phrase is cleaned into
ranked lexical OR-term matching (with small prefix/plural conveniences); this
is not semantic or embedding search. --natural forces that mode. Existing
phrase/Boolean/prefix/column expressions remain available as raw FTS with
--fts (and are auto-detected when they contain FTS syntax). --case,
repeatable exact --tag, --by and --status filters apply before pagination.
Results report total, shown count and the next offset. Bodies and titles are
bounded previews by default; --full returns complete matching bodies. An
invalid explicit FTS query fails clearly. There is no silent substring fallback.
Keep up without pretending that writing means reading:
casefile board tail # latest 20 bounded messages, oldest first
casefile board tail -f # then print new messages as they arrive
casefile board tail -n 0 -f # new messages only
casefile board tail --thread THREAD -f # watch one conversation
casefile board tail --by codex-lead -n 5
casefile board poll --for codex # at work boundaries; quiet if empty
casefile board follow THREAD -a codex
casefile board follow --tag gas -a codex
casefile board unread --for codex --following
casefile board unfollow THREAD -a codexboard tail is a plain, pipeable human monitor. It prints posts, replies and
status changes across all cases, excluding read/acknowledgement noise. Each
message body is capped at 600 characters by default; add --full when a
complete body is needed. -f refreshes every second; stop with Ctrl-C. It
never marks messages read. --json emits one JSON object per message and
marks clipped bodies with body_truncated; the usual --case, --tag,
--by and --status filters work too. To watch a project from anywhere:
CASEFILE_ROOT=/path/to/project casefile board tail -fboard show and board read return a 20-message page by default and report
the total plus a continuation offset. --offset N selects another
chronological page; --all/--expand returns every message, while --full
removes body/title/reference caps. Supplying a reply ID anchors the default
page so that reply is present; --message selects exactly that one message.
board read records complete-body IDs only. A clipped preview is recorded as
a preview receipt and stays unread until the same message is read with
--full; this keeps read state honest across context-limited views. Concurrent
or later replies remain unread. board show, search, boot, inbox and polling
never mark messages read. Read receipts travel with the log across machines;
an acknowledgement concerns one message and does not mark a task complete.
Authors automatically follow threads they participate in; explicit thread
unfollow overrides that and tag/all follows. Mentions still appear in the
optional following-only unread view. Full-board browsing stays available.
Boot and inbox surface unread public board activity even without a recipient.
Generated agent instructions require checks before work/replanning, at bounded
checkpoints, and before blocking or handing off. The CLI does not run a
background delivery daemon or wake idle agents: urgent handoffs should include
a native-agent/tmux nudge containing the durable board message ID. Legacy
add --to / packet messages remain in the existing inbox; its old entries
are not retroactively converted into board threads.
Every entry in the log is typed and attributed:
| type | what it records |
|---|---|
hypothesis |
a falsifiable claim — optionally with a --check shell recipe |
observation |
ground truth: test output, command results, log lines |
decision |
a choice made, with rationale and rejected alternatives |
constraint |
a boundary ("don't touch the sniffer") |
question |
something only a human can answer (routed to a mailbox) |
dispute / verify / endorse |
how claims get contested and settled |
Grades are computed, never stored: a hypothesis linked to a real
observation is verified; one that models merely agree on is only
consensus — model agreement is never verification. The log is
append-only; corrections are new entries, so the epistemic history is
tamper-evident by construction.
casefile boot— single cold-start ritual for any model: store discovery (CASEFILE_ROOT/ walk-up /.casefile-pointer), author identity (CASEFILE_AUTHOR), startup recheck, and a structured brief (WHERE / YOU ARE / WORLD vs LOG / BRIEF / SINCE / DO NOT / NEXT / CARD), budgeted as a whole and newest-first in every section. Exit codes for orchestrators: 0 ok, 10 mailbox, 20 drift, 30 abstract stale.casefile sinceprints the SINCE delta on its own.casefile packet/inbox/next— log-only multi-agent handoff. One author emits a peer packet; the peer lists inbox items and concrete next CLI actions without a shared chat transcript.casefile checkpoint— refresh the rolling abstract and rebuild the FTS compost index sorecallworks after context resets.casefile resume-context— compact briefing (also embedded in boot). Sections are budgeted individually and keep their newest items; nothing is evicted whole, so a fresh agent always sees the latest constraints, decisions and open questions.casefile recheck— re-runs every recorded check recipe and reports drift: which claims still hold versus held-three-days-ago. Timeouts recordUNKNOWN, never false failure.--startupkeeps session start fast by skipping known-slow checks.casefile lint— flags epistemic smells: laundering (an unverified claim cited like fact), contradictions (verified then disputed), stale disputes, orphan decisions, expired sources, and incomplete claim cards once a claim becomes ranking-driving.- Hooks — a Stop-hook "secretary sweep" diffs each AI session against
the log and files what the conversation decided but never recorded (it
only asks when something worth sweeping was filed since the last sweep;
quiet turns end silently, and a "nothing unrecorded" sweep is recorded as
a state stamp rather than a log entry); a one-line liveness pulse shows
what changed since you last looked. Mechanical compaction collapses
steady-state hook, recheck and journal rows into digests (
digstill expands them); nothing a person or model filed is ever touched. casefile spitball— a two-model deliberation driver (proposer vs critic) that ferries turns between live CLIs (Claude Code, Codex, Grok); both models file claims and disputes into the same log, and convergence is detected from the log itself, not from the transcript. A frozen manifest makes requirements, criteria, evidence domains, alternatives, and the alternative×criterion symmetry grid explicit. Every input/reply and vendor session id is written atomically torun.jsonbefore it is ferried. Receipt-only/progress-only output is rejected and retried. Token telemetry separates uncached input/output from cache reads so a long resumed context does not masquerade as fresh token spend. Transcript, manifest, and journal files are local/gitignored and created private to the user because debates may contain proprietary code or strategy. Complete independent round-by-round synopses (and any reconciled variants) are echoed at completion as well as retained in the private journal. Raw filing receipts remain auditable there, while model-to-model transport compacts them into one structured turn delta to avoid context churn.- Guarded conclusions — the proposer can only create an inert
candidatedigest. The critic reviews that exact id; only a foreign endorsement mechanically promotes it to a system-authored judgment. Candidate/final digests reference the frozen casefile requirements they relied on, so replacing or revoking one marks the old judgment stale. Recommendations, cross-model consensus, stale conclusions, and user decisions stay distinct. casefile spitball-recover <session>— reconstructs each model's private conversational view from an interrupted run journal and continues in fresh vendor sessions. Within a live run, adapters use continuous stream/session resume; tmux is only an optional viewport, never the memory mechanism.digandrecall— full history search (superseded entries included) and cross-case compost: "have we seen this before?"casefile thread <id|query>/where <id|query>— "where are we on X?" answered from the log: walk the refs graph both ways from an entry or the best search hits, print the chain in time order with each entry's computed state, and end with a STATE footer (latest live decision, open questions, what was ruled out and how, last verification).whereprints only the footer. Threads are computed from the graph, never stored.- Closure —
casefile done <decision> --evidence <obs-id|text>marks a decision fulfilled;add -t decision --supersede <old> --rationale "…"revises a plan (same author, or the user). Fulfilled, superseded and revoked entries leave the live views and counts, so the working set shrinks as work ships.
For a consequential debate, freeze the contract before the first argument:
casefile spitball \
--topic "choose the production design" \
--models codex,grok \
--requirement "preserve correctness under reorgs" \
--criterion "measured failure rate" \
--criterion "p99 latency" \
--weighting "failure rate 2x latency" \
--alternative "optimistic cache" \
--alternative "canonical reads" \
--evidence-domain "replay benchmarks" \
--manifest-mode enforceUse a JSON --manifest when criteria need explicit weights or
confirmed/inferred provenance. warn mode still runs an exploratory debate
but blocks judgment while the manifest is incomplete; off is an explicit
escape hatch.
Multiline model output no longer has to fight variadic shell flags:
printf '%s\n' "$BODY" | casefile add -t hypothesis -a codex \
--body-stdin --claim-mode causal-inference \
--mechanism "…" --comparator "…" --analysis-layer "transaction execution" \
--falsifier "…" --counterfactual "…" --horizon "30d" \
--testability within-session --json
casefile add -t observation -a codex "measured inclusion latency" \
--source benchmark --source-type test --locator "run 184 / p99" \
--accessed-at 2026-07-26T12:00:00Z --expires-at 2026-08-02T12:00:00Zadd also does its hygiene at write time, while the context is still in
hand: a hypothesis/decision/constraint/question that near-duplicates a
recent entry of the same type by the same author class is refused (exit 3)
with the earlier id — cite it with --ref, replace it with --supersede,
or file anyway with --force; and 8-hex ids cited in the body are
harvested into refs automatically, with a warning for ids that do not
exist (the entry is still filed).
Singular --ref, --reject, and --supersede flags are repeatable and avoid
the positional swallowing ambiguity of their legacy variadic counterparts.
Constraints and decisions can be revised by the same authority (or the user)
with --supersede plus a reason; revoke remains the explicit retraction
and done the explicit completion.
Run this later from any initialized project:
casefile upgradecasefile upgrade (run from a project with .casefile/, or set
CASEFILE_ROOT) is the cross-machine / launcher command:
git pull --ff-onlyof the casefile checkout (optional--no-pull)- Install/refresh a
casefilelauncher on PATH (--bin-dir,$CASEFILE_BIN_DIR) - Rewrite project
SKILL.md, hooks, andAGENTS.mdfrom this CLI
Put casefile upgrade in agent session launch so porcelain never drifts.
Open named cases: casefile open "intermittent 502s" --goal "find the cause".
casefile is developed using casefile (SPEC §17): every
hypothesis, wrong turn, two-model deliberation, and external code review
that produced this codebase went through its own log. SPEC.md is the
authoritative design document.
Working core (log + grades, boot, whoami, packet/inbox/next, checkpoint, recall, recheck, lint, hooks, import). Optional spitball companion (multi-model deliberation over Claude/Codex/Grok CLIs). Roadmap: config.toml, stronger verification binding. Expect sharp edges.
MIT.