After v0.14.3 npm-publish failed again with 401 Unauthorized despite
path-scoped _authToken. Direct curl probe to keigit confirmed BOTH Bearer
and Basic auth schemes work — so the issue is npm 10 not sending the
auth header in CI. Likely cause: deprecated `always-auth=true` interfered
with token resolution.
== Publish auth fix ==
- Drop `always-auth=true` (deprecated in npm 10+; warns in logs)
- Keep path-scoped `_authToken` (npm 10 canonical)
- Add legacy Basic-auth fallback rows (username/_password/email) — Forgejo
accepts both schemes per direct probe; if one resolution path fails,
npm tries the other
- chmod 600 on $HOME/.npmrc and project .npmrc (defense-in-depth)
- Bump 0.14.3 → 0.14.4
== Slice A — TS server hardening (Sonnet code-implementer-typescript) ==
File: _ts_packages/packages/mcp-server/src/server.ts (+3/-1)
File: _ts_packages/packages/mcp-server/src/index.ts (+14/-4)
- safeEqual constant-time path on length mismatch (timing oracle close)
- HTTP server defaults to 127.0.0.1 bind; --bind <addr> opt-in for 0.0.0.0
- Body cap 1 MiB with 413 response (DoS prevention)
- VERIFIED: tsc -b --noEmit exit 0
== Slice B — Outcome-only profile hardening (Sonnet code-implementer) ==
Files: install.sh, install/lib-args.sh, install/lib-profile-outcome-only.sh
- Confirm-screen gate before destructive install (skips on --dry-run / --yes)
- _outcome_install_ledger return value tracked → summary reflects reality
(was: false-success "ledger: ..." when init failed)
- --dry-run silent-ignored on non-outcome profiles → now warns
- VERIFIED: end-to-end smoke against fake $HOME with `<<< "y"` — all 5
files installed, schema v9 + 2 triggers, summary correct
== Slice D — jq-merge dedup tuple (Sonnet code-implementer) ==
File: install/lib-hooks.sh
- Replaced `unique_by(.command)` with reduce-into-object keyed on
norm-ed command (tilde-vs-absolute path collision fix)
- Snippet-wins precedence on collision
- 3 manual scenario traces pass: tilde+tilde, absolute+tilde, idempotency
== Slice E — Doc honesty pass (Sonnet code-implementer, selective-merged) ==
Files: README.md, docs/{INSTALL,ARCHITECTURE,PROFILE-OUTCOME-ONLY}.md
Note: Slice E worktree was based on an older main commit; merged
selectively to preserve current-main values (565 DNAs, not worktree's 518)
- README:62 plugin marketplace URL: KeiSei84/KeiSeiKit → KeiSei84/KeiSeiKit-1.0
(consistent with line 66 git clone URL + Cargo.toml repository field)
- README:9-15: per-claim [REAL: <command>] markers on all 8 numerics
- README:124-132 + PROFILE-OUTCOME-ONLY.md:43-55 + ARCHITECTURE.md:288-302:
rephrase 100-row router claim — now describes Wilson lower-bound
(δ=0.10, q*=0.70) continuous metric with file:line pointer to select.rs
- INSTALL.md: ESTIMATE-HTC marker covering all install-time / disk-size
numerics in profile table (RULE 0.18 compliance)
- PROFILE-OUTCOME-ONLY.md privacy section: discloses agent-toolstats.jsonl
sidecar (was undocumented per W3 finding)
- PROFILE-OUTCOME-ONLY.md uninstall: added 6th rm -f for .bak-* cleanup
(closes orphan-accumulation per W3+W4 audits)
[FROM-JOURNAL: tasks.jsonl this session — 12 audit agents waves 5+6 +
4 parallel fix-implementer worktrees ran ~25 min wall-time]
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
120 lines
5.5 KiB
Markdown
120 lines
5.5 KiB
Markdown
# `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} /<!-- outcome-only profile \(KeiSeiKit\) -->/ {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-<epoch> 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.
|