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:PASSWORD@db.example.internal/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.
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.