# `outcome-only` install profile > Five-file pitch: install the outcome-tracking primitive without > committing to anything else. No daemon, no Forgejo, no launchd, no > hundred Rust crates, no `no-github-push` hook, no agent generation. > If you do not like what `~/.claude/agents/ledger.sqlite` collects, > the uninstall is a four-line shell paste at the bottom. ## What gets installed | # | Path | Source | LOC | |---|--------------------------------------------------------|---------------------------------------|-----| | 1 | `~/.claude/hooks/agent-outcome-backfill.sh` | `hooks/agent-outcome-backfill.sh` | 140 | | 2 | `~/.claude/hooks/error-spike-detector.sh` | `hooks/error-spike-detector.sh` | 89 | | 3 | `~/.claude/agents/ledger.sqlite` | `install/sql/outcome-only-schema.sql` (or `kei-ledger init`) | n/a | | 4 | one appended line in `~/.claude/CLAUDE.md` | the STATUS-TRUTH MARKER instruction | 1 | | 5 | `_primitives/_rust/kei-model-router/target/release/kei-model-router` (deferred) | `_primitives/_rust/kei-model-router/` | n/a | Plus a jq-merge of two hooks into `~/.claude/settings.json`: - `PostToolUse:Agent` → `agent-outcome-backfill.sh` - `PostToolUse:*` → `error-spike-detector.sh` `./install.sh --profile=outcome-only --dry-run` prints exactly this list and exits 0 without writing. ## What does NOT get installed - 105 Rust workspace crates (cortex, frustration-loop, sleep-layer, …) - 68 skills, 38 agent manifests, 85 substrate blocks - `kei-cortex` HTTP / WS daemon - Forgejo, dev hub, Datasette, restic, mdbook, gdrive-import - launchd plists (`disk-reclaim`, sleep-layer cron) - `no-github-push.sh` hook (or any other Bash gate) - substrate PATH wiring (no edits to your shell rc files) If you later want any of those, the kit is incremental: re-run `./install.sh --profile=core` (or heavier) and the outcome-only state is preserved verbatim — both paths share `~/.claude/hooks/` and `~/.claude/agents/ledger.sqlite`. ## How `kei-model-router` activates The router is a posterior decision rule keyed on per-task-class DNA plus a Beta posterior over `(success, total)` in `agents.outcome`. The router uses a Wilson-style lower confidence bound (`δ=0.10`, `q*=0.70`) — it falls back to "behaviour unchanged" (manifest-declared model) UNTIL the per-(task-class, model) lower-bound clears the quality bar. Typically that's tens of successful observations per pair, not a discrete 100-row threshold (see `_primitives/_rust/kei-model-router/src/select.rs:74-124`). Once the posterior dominates the uniform `Beta(1,1)` prior the router starts producing concrete recommendations. You opt in by adding `kei-model-router` to a `PreToolUse:Agent` hook later — that step is **not** done by this profile. You stay in observe-only mode by default. If `cargo` is on PATH at install time the binary is built into `_primitives/_rust/kei-model-router/target/release/`. If `cargo` is missing the build is skipped silently and the install is still considered complete; rebuild later with: ```bash cd _primitives/_rust/kei-model-router && cargo build --release ``` ## Privacy posture All outcome rows live in `~/.claude/agents/ledger.sqlite`. They never leave the machine — no sync hook, no remote-push, no telemetry. Inspect with: ```bash sqlite3 ~/.claude/agents/ledger.sqlite \ "SELECT id, branch, status, outcome, stubs_count, started_ts FROM agents ORDER BY started_ts DESC LIMIT 20;" ``` A sidecar JSONL at `~/.claude/memory/time-metrics/agent-toolstats.jsonl` accumulates per-agent token counts, tool-use stats, and durations — local-only, append-only, no network egress. Same privacy guarantees as the ledger; the uninstall recipe below removes it. Uncomfortable with the file? `rm` it; the next install or agent run recreates an empty schema, no other side effects. ## Uninstall ```bash rm -f ~/.claude/hooks/agent-outcome-backfill.sh rm -f ~/.claude/hooks/error-spike-detector.sh rm -f ~/.claude/agents/ledger.sqlite rm -f ~/.claude/memory/time-metrics/agent-toolstats.jsonl # CLAUDE.md cleanup — portable across BSD (macOS) and GNU sed via awk. # The original line `sed -i.bak '/.../,+1 d'` used the GNU `,+N` address # extension which BSD sed does NOT support; on macOS it silently no-ops, # leaving an orphan instruction. The awk recipe below works on both. awk 'BEGIN{skip=0} // {skip=2; next} skip>0 {skip--; next} {print}' \ ~/.claude/CLAUDE.md > ~/.claude/CLAUDE.md.tmp \ && mv ~/.claude/CLAUDE.md.tmp ~/.claude/CLAUDE.md # Clean .bak- files left by backup_file during install rm -f ~/.claude/hooks/*.bak-* \ ~/.claude/CLAUDE.md.bak-* \ ~/.claude/settings.json.bak-* ``` Both hooks exit 0 immediately when their target script is missing, so the `~/.claude/settings.json` jq-merge entries are harmless after `rm`. To scrub those too, drop `agent-outcome-backfill.sh` / `error-spike-detector.sh` lines from `settings.json` by hand. The 5th `rm` removes the sidecar telemetry JSONL the backfill hook writes (per-agent token counts + tool stats; local-only, no network egress, but worth deleting if you uninstalled for privacy reasons). ## Why this profile exists A kit with 100 crates / Forgejo / launchd plists is too heavy to evaluate. A pitch you can read in four minutes and trial in five is not. This profile is the answer to "what is the smallest version of KeiSeiKit that still demonstrates the outcome loop?" — and nothing more.