Fable 5 Harness Review — 2026-06-09
Produced by a 7-seat delegated audit workflow (23 agents) on the day the COO agent moved from Opus 4.8 to Fable 5; executive synthesis below is by the main session, detailed findings are per-seat.
Executive synthesis
The harness moved from Opus 4.8 to Fable 5 today (2x sticker price, ~2.5-2.6x effective after tokenizer inflation, 1M context default). A 7-seat delegated audit (23 agents; 16/16 adversarial verifications held, zero refuted) reached one verdict: the architecture is right — manifest-driven scheduling, fresh-session handoff seed, model-agnostic rules, clean memory index — but it leaks money at the edges and trust at the seams, and its priorities lag the founder's 2026-06-08 phData-primary shift.
Working (keep): the four CLAUDE.md hard rules (rule 4 — subagent-route >5KB artifacts — matters MORE at $10/MTok input); the single-manifest + SessionStart-hook re-arm design; ray-handoff.md as the fresh-session seed; memory index integrity (61/61); fresh-session-over-compaction discipline.
Broken (fixed same day): the restart script's legacy /loop block fired all 14 cron jobs simultaneously on every restart — deleted (root cause of the 2026-06-09 15:40 incident; the SessionStart hook was innocent; backup .bak-2026-06-09). /open-threads-check burned a guaranteed full cache-miss 48x/day (15-min spacing vs 5-min cache TTL), modeled up to ~$2.7k/mo at Fable prices — retuned to hourly (75% cut) pending the script-gated proper fix (~96% cut). Handoff and memory de-staled: Fable 5 recorded as DONE (settings.json pin covers the 4am restart; the dangerous --model-flag instruction removed), phData/L5/age entries corrected.
Founder decisions pending: (1) CRITICAL — 1Password service-account token plaintext in settings.local.json and every session env; verifier decoded it: master unlock key embedded. Rotate in 1P console, then move retrieval to Keychain/runtime-fetch. (2) enableAllProjectMcpServers=true auto-trusts any project .mcp.json (verifier planted a hostile one; it spawned with zero prompt) — flip to false; classifier correctly blocked Ray from self-editing permissions config, needs the founder's one-line edit; note the verifier found headless -p mode spawns project servers even with the flag false, so also vet .mcp.json in any untrusted dir. (3) The verify-action channel-reply guardrail the founder believes is active was never wired (snippet drafted, never applied; log empty for 35 days) — wire it in a supervised, non-blocking rollout; this is also the agreed "pre-send verification gate," the highest-value open build. (4) Prune: vercel plugin (36 skills, no usage evidence on a Cloudflare stack), core-3d-animation + animation-components plugins, blender/stripe/heygen/mobbin MCP servers, ~15 stale skills to archive. (5) Add: /cert-study skill + weekly cron (the PRIMARY bet has zero scheduled support today), investing watch crons (13F/Congress/EDGAR cadences declared in skills but never wired into the manifest — the May 13F window was missed), and a subagent model-tiering policy (haiku for extraction, sonnet for pipeline/critic seats, Fable only for founder-facing judgment; 10:3:1 price ratios).
Economics in one line: on Fable 5 the dominant cost lever is not per-turn model choice — it is cache-miss recurring wakes against a fat session prefix. Gate crons with scripts, keep the prefix lean, tier the subagents.
Detailed findings by seat
Scheduling (crons, loops, restart scripts)
Scheduling is architecturally sound (single manifest, SessionStart auto-arm hook, OS-level cron only for pure scripts) but has one live defect and one cost hotspot. The 2026-06-09 incident was NOT caused by emit-cron-rearm.sh — that hook (registered only on startup/resume matchers) correctly emits a single CronCreate instruction; the 14 "/loop 0 0 * * * /vault-health"-style enqueues came from a legacy block at claude-channels-restart.sh:100-111 that pipes raw manifest lines into /loop via tmux immediately after the script's own /reload-plugins send at line 93, and /loop cannot parse 5-field cron (an unrecognized interval falls through to dynamic mode which executes the whole line as a prompt immediately — 14 jobs firing at once). The fix is deleting that block, plus closing the gap that /reload-plugins wipes session crons with no matcher to re-arm them. On Fable 5 economics ($10/MTok input, 2x Opus 4.8, 5-min cache TTL), /open-threads-check at 48 fires/day on 15-min spacing is a guaranteed cache miss every fire — roughly $30-90/day ($900-2,700/mo) at plausible session-context sizes — and should become a pure-script pre-check that wakes the agent only when an aged unanswered ask exists. The manifest also has inverted priorities: the PRIMARY bet (phData certs, hard deadlines 2026-08-24 and 2026-11-22) has zero scheduled support and no cert-related skill exists, while two investing skills that explicitly specify cron cadences (13F quarterly, Congress monthly, EDGAR capex quarterly) were never wired into the manifest.
1. [critical] incident/root-cause (action: fix)
- Claim: The 14 '/loop
' enqueues observed at ~15:40 on 2026-06-09 were emitted by claude-channels-restart.sh lines 100-111, not by the SessionStart hook. That block greps the manifest and sends '/loop $interval $command' via tmux send-keys for every job line, and it executes ~15s after the script's own '/reload-plugins' send-keys at line 93 — making /reload-plugins look like the trigger. emit-cron-rearm.sh contains no /loop emission at all. - Evidence: claude-channels-restart.sh:93 '"$TMUX_BIN" send-keys -t "$SESSION_NAME" "/reload-plugins" Enter'; lines 104-108: 'grep -v '^#' "$MANIFEST" | grep -v '^$' | while IFS='|' read -r interval command; do ... "$TMUX_BIN" send-keys -t "$SESSION_NAME" "/loop $interval $command" Enter'; grep of emit-cron-rearm.sh shows its output block instructs only 'Call CronList' / 'call CronCreate' (lines 44-47), no /loop.
- Recommendation: Delete lines 100-111 of ~/.claude/scripts/claude-channels-restart.sh (the entire 'Re-establish scheduled loops from manifest' block). The SessionStart(startup) hook already performs the re-arm when the fresh session launches at line 68.
2. [info] incident/hook-paths (action: keep)
- Claim: SessionStart event routing: matcher 'startup' and matcher 'resume' both run emit-cron-rearm.sh (the clean single-CronCreate-instruction path observed at 15:35); matcher 'compact' runs read-bridge-notes.sh. No SessionStart matcher covers /reload-plugins, so a plugin reload triggers no hook at all — the /loop flood that followed it came from the restart script, not any hook.
- Evidence: settings.json hooks.SessionStart: [{"matcher": "compact", ... read-bridge-notes.sh}, {"matcher": "startup", ... emit-cron-rearm.sh}, {"matcher": "resume", ... emit-cron-rearm.sh}] — no other matchers registered.
- Recommendation: none
3. [critical] incident/loop-grammar (action: fix)
- Claim: /loop cannot parse a 5-field cron expression. Its documented grammar is interval-shorthand plus prompt ('/loop 5m /foo'), and omitting/failing the interval falls through to dynamic self-pacing mode whose instructions begin with immediate execution — so '/loop 0 0 * * * /vault-health' treats the whole line as a prompt and runs the job NOW. 14 such enqueues means all 14 manifest jobs attempt to fire at once, which is what the founder had to interrupt one by one.
- Evidence: loop skill description: 'Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo). Omit the interval to let the model self-pace.' Loaded /loop skill expansion (dynamic mode): '1. Run the autonomous check now... no cron.' Manifest header lines 6-7 already warns the format is hook-only: 'no interval shorthand — emit-cron-rearm.sh parses these literally'.
- Recommendation: Same fix as the root-cause finding: remove the /loop block from the restart script. Never feed manifest lines to /loop.
4. [warn] incident/rearm-race (action: fix)
- Claim: Even after deleting the /loop block, the restart script has a wipe-after-arm race: the SessionStart(startup) hook fires when the fresh session launches (line 68) and the agent re-arms crons, but the script then sends '/reload-plugins' at line 93 (~25-30s later), which per the manifest's own documentation wipes session-scoped CronCreate jobs — and no SessionStart matcher fires on plugin reload to re-arm them. The suite can silently end up empty after every 4am restart. The same gap applies when the founder runs /reload-plugins manually (as today: the 15:35 startup-armed crons were likely wiped at 15:40).
- Evidence: scheduled-jobs.txt:9-11: 'session-scoped CronCreate jobs are wiped on every restart (daily 4am LaunchAgent restart + manual /reload-plugins). The SessionStart(startup/resume) hook -> ...' ; claude-channels-restart.sh ordering: line 68 launches claude, line 93 sends /reload-plugins; settings.json registers no SessionStart matcher for plugin reload.
- Recommendation: Remove the '/reload-plugins' send-keys step from the restart script (plugins are already updated at lines 50-52 before launch and loaded via --channels), or move any reload before the claude launch. Additionally, have the main session run CronList now to verify the suite survived today's incident, and document that any manual /reload-plugins must be followed by a manifest re-arm.
5. [critical] jobs/open-threads-check (action: fix)
- Claim: /open-threads-check fires 48x/day (*/15, hours 9-20 = 4/hr x 12h) with 15-minute spacing against a 5-minute default prompt-cache TTL, so every fire is a full cache miss that re-writes the session prefix at 1.25x base input. At Fable 5's $10/MTok input (2x Opus 4.8's $5), an always-on session prefix of 50K-300K tokens costs roughly 48 x 150K x $12.5/MTok ≈ $90/day (~$2,700/mo) at a mid estimate, and
$30/day ($900/mo) even at a lean 50K — for a check whose job is parking asks past a 60-minute cooldown, where 15-minute sampling buys almost nothing. - Evidence: scheduled-jobs.txt:71 '*/15 9-20 * * * | /open-threads-check'; claude-api skill pricing table: 'Claude Fable 5 ... $10.00 / $50.00' and 'Claude Opus 4.8 ... $5.00 / $25.00'; prompt-caching doc: '"cache_control": {"type": "ephemeral"} // 5-minute TTL (default)' and 'Cache writes cost 1.25x for 5-minute TTL'. (Dollar figures are estimates; fire count, TTL, and prices are grounded.)
- Recommendation: Replace the agent-woken cron with a pure-script pre-check in the OS crontab (precedent: check-public-ip-drift.sh lives there per manifest lines 16-17): a script reads chat.db (the imessage plugin already reads it directly) and the skill's parked-marker state to detect any Ray-ask >60min unanswered, and only then wakes the agent (tmux send-keys or self-iMessage). Expected agent wakes drop from 48/day to ~0-3/day. Interim cheap fix while building the script: change the cron to hourly ('0 9-20 * * *'), a 75% cut, with worst-case parking delay growing from 75min to 2h — immaterial for a bookkeeping marker surfaced in the morning brief.
6. [warn] jobs/process-inbox (action: fix)
- Claim: /process-inbox fires 4x/day but the manifest itself records the inbox is empty in more than 95% of cycles, meaning nearly every fire is a paid cache-miss no-op at Fable 5 prices. An inbox-emptiness test is a zero-cost shell check that does not need an agent wake.
- Evidence: scheduled-jobs.txt:22-24 '# Inbox triage — 4x/day (7am,12pm,5pm,10pm ET). Inbox empty >95% of cycles; reduced from 30m on 2026-05-18 per founder.' '0 7,12,17,22 * * * | /process-inbox'
- Recommendation: Gate with a pure-script pre-check (OS cron: if vault inbox dir is non-empty, wake the agent / leave a trigger), or reduce to 1-2x/day. Same pattern as the open-threads-check fix.
7. [warn] jobs/process-newsletter (action: fix)
- Claim: /process-newsletter watch runs every 6 hours (4 fires/day) in service of Sanity Check, which is a side bet behind the phData primary bet; newsletters are not latency-sensitive, so half of these fires buy nothing at doubled input price.
- Evidence: scheduled-jobs.txt:33-34 '# Newsletter watch — every 6 hours' '0 */6 * * * | /process-newsletter watch'; task context: founder declared phData the PRIMARY bet 2026-06-08, Sanity Check a side bet.
- Recommendation: Retune to 1-2x/day (e.g. '0 7,19 * * *').
8. [info] jobs/vault-health (action: fix)
- Claim: /vault-health runs daily at midnight; it is L4-maintenance hygiene that overlaps the weekly /self-review and daily /graph-reingest, and daily cadence is more than vault drift warrants under Fable 5 economics.
- Evidence: scheduled-jobs.txt:19-20 '# Daily vault health check (midnight low-activity)' '0 0 * * * | /vault-health'; lines 47, 53 show /self-review weekly and /graph-reingest daily also covering vault freshness.
- Recommendation: Retune to weekly (e.g. '0 0 * * 6').
9. [info] jobs/graph-reingest (action: fix)
- Claim: /graph-reingest wakes the full agent daily for what the manifest describes as a ~5-second ingest — a pure-script job (graph-ingest.py exists in scripts/) that does not need agent context at all.
- Evidence: scheduled-jobs.txt:52-53 '# Daily graph-db re-ingest — 3:17am (~5s ingest + qmd refresh)' '17 3 * * * | /graph-reingest'; ls ~/.claude/scripts shows graph-ingest.py and graph-db-venv present.
- Recommendation: Move to OS crontab as a direct script invocation (like check-public-ip-drift.sh), removing one daily agent wake; keep the skill for on-demand use. Low priority.
10. [info] jobs/keep-set (action: keep)
- Claim: The remaining nine jobs are correctly scoped and should be kept as-is: /check-board 4x/day (the autonomous work loop the Notion-queue memory depends on), /morning-prep daily 6:30am, /finance-pulse weekly with documented first-Sunday self-guard (fixed 2026-05-26 from a 12-fires/month Vixie-cron OR bug), /self-review Sun 7am, /improve Mon 7am, /curiosity Tue+Sat 10pm, /deep-research nightly 1am, /sync-contacts nightly 1:30am, /process-youtube daily 11:11pm. All are 1x/day or less (check-board excepted) and sit in the documented 1am-4am deep-work block or low-activity hours.
- Evidence: scheduled-jobs.txt:27 '0 8,13,18,23 * * * | /check-board'; :37 '30 6 * * * | /morning-prep'; :39-44 finance-pulse FIX comment + '0 8 * * 0'; :47 '0 7 * * 0 | /self-review'; :50 '0 7 * * 1 | /improve autonomous'; :56 '0 22 * * 2,6 | /curiosity'; :59 '0 1 * * * | /deep-research'; :62 '30 1 * * * | /sync-contacts'; :65 '11 23 * * * | /process-youtube watch'
- Recommendation: none
11. [warn] jobs/missing-phdata-cert (action: add)
- Claim: The PRIMARY business bet — phData certs with hard deadlines (Snowflake GenAI 2026-08-24, ~11 weeks out; Anthropic Partner 2026-11-22, each +$5k base) — has zero scheduled support: no cert-related job in the 14-job manifest and no cert/study skill exists in ~/.claude/skills/ at all. Meanwhile side bets (newsletter, YouTube, vault, investing-adjacent research) hold 13 of 14 slots.
- Evidence: Full read of scheduled-jobs.txt: no job references certs/phData/Snowflake. Command 'ls ~/.claude/skills/ | grep -i -E "cert|phdata|snowflake|anthropic|study"' and grep for 'GenAI Specialty' across SKILL.md files both returned empty output.
- Recommendation: Create a cert-progress skill (weekly study-plan checkpoint: days-to-deadline countdown, modules covered vs plan, blockers to surface in morning brief) and add a weekly manifest line (e.g. '0 7 * * 2 | /cert-progress'). This is the only recurring job that directly serves the #1 objective.
12. [warn] jobs/missing-investing-crons (action: add)
- Claim: Two built investing skills specify explicit cron cadences that were never wired into the manifest: investing-smart-money-watch declares '13F cron 60 days after quarter end; Congress cron monthly on the 15th', and investing-edgar-watch has a '## Cron schedule' section that says 'Wire via /schedule skill when implementation lands' — neither appears in scheduled-jobs.txt, so the quarterly 13F diff, the monthly Congress PTR pull, and the quarterly hyperscaler-capex pulse only run if someone remembers. The Q1-2026 13F window (Mar 31 + 60d = May 30) has already passed.
- Evidence: investing-smart-money-watch/SKILL.md:2 '...13F cron 60 days after quarter end; Congress cron monthly on the 15th.' and :285-287 '### Cron cadence / Monthly on the 15th.'; investing-edgar-watch/SKILL.md:31 '## Cron schedule' and :40 'Wire via
/scheduleskill when implementation lands.'; scheduled-jobs.txt contains no investing entries (full read). - Recommendation: Add two manifest lines: '0 9 15 * * | /investing-smart-money-watch congress' (monthly 15th) and a quarterly-window line for 13F + EDGAR (e.g. '0 9 1 3,6,9,12 *' with the skills self-guarding the exact 60-day/10-Q timing, mirroring the finance-pulse self-guard pattern). Investing is a side bet, so monthly/quarterly cadence costs ~14 fires/year — negligible.
13. [info] os-level/launchd-cron (action: keep)
- Claim: OS-level scheduling is clean and matches the manifest's documentation: user crontab contains exactly one entry (check-public-ip-drift.sh daily 9am, documented in the manifest as intentionally outside the suite), and com.claude.channels.plist runs the restart script at 04:00 daily plus RunAtLoad, logging to /tmp/claude-channels.log.
- Evidence: crontab -l: '0 9 * * * ~/.claude/scripts/check-public-ip-drift.sh # daily IP-drift check'; com.claude.channels.plist: StartCalendarInterval Hour=4 Minute=0, RunAtLoad=true, ProgramArguments=/bin/zsh /Users/ray/.claude/scripts/claude-channels-restart.sh; scheduled-jobs.txt:15-17 documents the carve-out.
- Recommendation: none
14. [warn] out-of-domain/security (flag to security seat) (action: fix)
- Claim: While reading hook registrations I observed ~/.claude/settings.local.json carries a full 1Password service-account token in plaintext under env.OP_SERVICE_ACCOUNT_TOKEN — directly contradicting the codified 'no secrets on disk' rule. Out of this seat's domain but grounded; routing for the security seat.
- Evidence: settings.local.json: '"env": { "OP_SERVICE_ACCOUNT_TOKEN": "ops_eyJzaWduSW5BZGRyZXNzIjoibXkuMXBhc3N3b3JkLmNvbSIs..." }' (token observed in full); memory feedback_no_secrets_on_disk: 'Use 1Password wrapper scripts for MCP servers, never .env files'.
- Recommendation: Rotate the 1Password service-account token and move injection to a wrapper that fetches it at runtime; do not leave it in settings.local.json.
Verification
- finding 1 — "The 14 '/loop
' enqueues observed at ~15:40 on 2026-06-09 were emitted by claude-channels-restart.sh lines 100-111, not by the SessionStart h…": NOT refuted (verified), confidence high. All evidence reproduced. claude-channels-restart.sh line 93 is exactly the cited /reload-plugins send-keys; lines 100-111 are the manifest-loop block with lines 104-108 matching verbatim (grep -v '^#' | grep -v '^$' | while IFS='|' read -r interval command; send-keys "/loop $interval $command"). sleep 5 (line 94) + sleep 10 (line 98) = ~15s gap between /reload-plugins and the first /loop send, as claimed. scheduled-jobs.txt has exactly 14 active job lines. Direct log proof: /tmp/claude-channels.log (mtime Jun 9 15:37) shows today's run started 15:36:19 EDT and logged all 14 "Scheduling: /loop " lines before completing 15:37:51 EDT — the auditor's "~15:40" is the same event, off by ~2-3 min. emit-cron-rearm.sh emits no /loop (only a line-6 comment mentions it); its heredoc at lines 44-47 instructs "Call CronList" / "call CronCreate" exactly as cited. Recommendation premise also verified: settings.json SessionStart matchers "startup" and "resume" both run emit-cron-rearm.sh, and the fresh session launches at restart-script line 68, so the lines 100-111 block is redundant — and additionally malformed, since it feeds 5-field cron expressions to /loop which expects an interval, explaining the raw-manifest-line enqueues. Note for the fix: the recommendation should be a founder-gated PR (PR-only workflow), and the deleted block predates the 2026-05-26 auto-arm hook, i.e., it is legacy duplication. - finding 3 — "/loop cannot parse a 5-field cron expression. Its documented grammar is interval-shorthand plus prompt ('/loop 5m /foo'), and omitting/failing the interval fall…": NOT refuted (verified), confidence high. Reproduced all cited evidence. (1) Extracted the /loop skill from the Claude Code 2.1.170 binary (/Users/ray/.local/share/claude/versions/2.1.170): description string matches verbatim, and the parsing rules are exactly leading-token ^\d+[smhd]$, trailing 'every N unit', else 'the entire input is the prompt and you'll self-pace dynamically'. A 5-field cron's first token ('0') matches neither rule, so '/loop 0 0 * * * /vault-health' falls through to dynamic mode with the whole line as prompt — /loop genuinely cannot parse 5-field cron. (2) Dynamic mode step 1 is 'Run the parsed prompt now.' (immediate execution); the auditor's exact quote 'Run the autonomous check now... no cron' exists verbatim but belongs to the adjacent empty-input autonomous-default branch — minor attribution imprecision, same substance, both dynamic branches start with immediate execution. (3) /Users/ray/.claude/scripts/scheduled-jobs.txt lines 6-7 match verbatim ('no interval shorthand — emit-cron-rearm.sh parses these literally') and there are exactly 14 active job lines. (4) /Users/ray/.claude/scripts/claude-channels-restart.sh lines 100-111 still send '/loop
' for each manifest line via tmux, while the emit-cron-rearm.sh SessionStart hook (registered for startup+resume in settings.json) already re-arms via CronCreate with 'Do NOT execute the job prompts now' — so the /loop block is redundant and broken; removing it is the right fix. Bonus reinforcement: even /loop's FIXED-interval mode says 'Then immediately execute the parsed prompt now — don't wait for the first cron fire', so the 14-jobs-fire-at-once outcome is overdetermined regardless of parse success. Could not independently verify the historical founder-interrupted-one-by-one event from files, but the mechanism fully supports it. - finding 4 — "Even after deleting the /loop block, the restart script has a wipe-after-arm race: the SessionStart(startup) hook fires when the fresh session launches (line 68…": NOT refuted (verified), confidence high. All three cited evidence items reproduce. (1) /Users/ray/.claude/scripts/scheduled-jobs.txt lines 9-13 say verbatim that session-scoped CronCreate jobs are wiped on every restart "(daily 4am LaunchAgent restart + manual /reload-plugins)" and that the SessionStart(startup/resume) hook -> emit-cron-rearm.sh re-arms; emit-cron-rearm.sh's own header (lines 4-5) repeats the wipe claim. (2) /Users/ray/.claude/scripts/claude-channels-restart.sh line 68 launches claude via tmux send-keys and line 93 sends "/reload-plugins"; sleeps at lines 71 (5s) and 75 (20s) put the reload ~25-30s after launch, confirmed by today's /tmp/claude-channels.log (launch sequence 15:36:19 EDT, reload sent ~15:37:15, complete 15:37:51). (3) /Users/ray/.claude/settings.json registers SessionStart hooks only for matchers compact/startup/resume — nothing fires on plugin reload. So with the /loop block deleted, the wipe-after-arm race is real per the system's own documentation. Caveats: (a) the runtime wipe behavior of /reload-plugins is documented in two first-party files but I did not independently reproduce it (would require manipulating the live channels session); the claim correctly attributes it to the manifest's documentation. (b) The claim's incident timestamps are slightly off: actual log shows 15:36:19 start / ~15:37:15 reload, not 15:35/15:40, and today's event was a full restart-script run, not a bare manual /reload-plugins. (c) Because the /loop block (lines 100-111) still exists and ran AFTER the reload today, today's suite may have been re-armed by /loop rather than left empty — the recommendation's CronList verification step is the right check, and the race itself is order-dependent ("can end up empty", not "will"), which matches the claim's wording.
Rules (CLAUDE.md, hard rules, precedence)
The governing-rules layer is in good shape for the Fable 5 transition: both files are fully model-agnostic (zero references to Opus/Sonnet/Haiku/Fable), so the upgrade introduced no staleness, and all four hard rules remain correct — rule 4 (subagent-route artifacts >5KB) is actually more valuable now that input tokens cost $10/MTok vs Opus 4.8's $5/MTok. The main structural issues are: (1) the prompt-precedence section consumes 47% of CLAUDE.md (5,816 of 12,307 bytes) and its worked-scenarios block (1,553 bytes) is teaching material that can relocate to the already-existing implementation-notes doc; (2) worked scenario 5 internally contradicts the precedence chain it illustrates (claims tier 6 memory beats tier 4 dispatch prompt, and mislabels PR-only as a hard rule); (3) rules 1 and 2 are triple-covered across CLAUDE.md, memory files, and tier-1 MCP instructions — the memory duplicates can retire; and (4) there is no sub-agent model-tiering policy anywhere, which matters at 2x flagship input pricing — draft policy text provided for founder greenlight. Combined persistent preamble is ~17.3KB (CLAUDE.md 12,307 B injected every session via claudeMd; SOUL.md 5,022 B read per session per CLAUDE.md:3), mitigated per-turn by prompt caching but rewritten at every 4am restart.
1. [info] staleness (action: keep)
- Claim: Neither CLAUDE.md nor SOUL.md contains any model-specific assumption (no Opus 4.8, Sonnet, Haiku, or Fable references), so the 2026-06-09 model upgrade introduced zero staleness in the governing files; the only 'model' hits are generic ('Operating model', 'model performance degrades', 'Model default behavior').
- Evidence: grep -in -E 'opus|sonnet|haiku|fable|claude-[0-9]|model' output: only /Users/ray/SOUL.md:34 '## Operating model', SOUL.md:36 'layered execution model', CLAUDE.md:29 'model performance degrades', CLAUDE.md:38 'is the model', CLAUDE.md:58 'Model default behavior'
- Recommendation: none — model-agnosticism is a strength; preserve it in future amendments
2. [info] hard-rules (action: keep)
- Claim: Hard rules 1-3 (run date before time claims; channel replies via reply tool; calendar UTC-offset over timeZone label) are model-agnostic mechanical constraints unaffected by the Fable 5 upgrade and remain correct.
- Evidence: CLAUDE.md:9-13 (rule 1), :15-20 (rule 2), :22-26 (rule 3); none reference model behavior, pricing, or context size
- Recommendation: none — keep all three verbatim
3. [warn] hard-rules (action: keep)
- Claim: Hard rule 4 (route artifacts >5KB through subagents) matters MORE under Fable 5: context rot applies regardless of the 1M window per the rule's own rationale, and parent-context bytes now cost $10/MTok input vs Opus 4.8's $5/MTok (2x), per the claude-api skill model table read this session.
- Evidence: CLAUDE.md:29-30 'model performance degrades as context grows (context rot)... Heuristic: any single artifact >5KB should be processed by a subagent'; claude-api skill Current Models table: 'Claude Fable 5 | claude-fable-5 | 1M | $10.00 | $50.00' and 'Claude Opus 4.8 | claude-opus-4-8 | 1M | $5.00 | $25.00'
- Recommendation: Keep rule 4 and the 5KB threshold unchanged; optionally (founder-greenlit amendment) append one line to the rationale: 'Under Fable 5 ($10/MTok input, 2x Opus) this rule is also a direct cost control, not just a context-rot control.'
4. [warn] prompt-precedence (action: fix)
- Claim: Worked scenario 5 contradicts the precedence chain it illustrates: the chain places sub-agent dispatch prompts at tier 4 ABOVE memory files at tier 6, but the scenario resolves a dispatch-vs-memory conflict as 'tier 2 / tier 6 > tier 4' — and it mislabels PR-only as 'CLAUDE.md hard-rule context' when PR-only exists only as memory (feedback_pr_only_workflow.md), not as one of the four hard rules.
- Evidence: CLAUDE.md:51 '4. Active SKILL.md ... AND sub-agent dispatch prompt'; CLAUDE.md:53 '6. MEMORY.md + older linked feedback memory files'; CLAUDE.md:87 'CLAUDE.md hard-rule context (and feedback_pr_only_workflow) says PR-only → CLAUDE.md / memory wins (tier 2 / tier 6 > tier 4)'; memory dir listing shows feedback_pr_only_workflow.md exists as a memory file
- Recommendation: Draft amendment for founder greenlight: either (a) add an explicit clause that safety/workflow memories override dispatch prompts (carving tier 6 above tier 4 for destructive-action policies), or (b) promote PR-only to hard rule 5 so the scenario's 'tier 2 wins' reading becomes true. As written, a sub-agent walking the chain literally would let a dispatch prompt override PR-only.
5. [warn] prompt-precedence (action: remove)
- Claim: The prompt-precedence section is 5,816 of CLAUDE.md's 12,307 bytes (47%); the chain, hard-rule immutability, and pasted-content carve-out are load-bearing per-turn rules, but the worked-scenarios + cross-references block (1,553 bytes, lines 81-93) is teaching material with an existing relocation target: ~/.claude/state/implementation-notes-claude-md-prompt-precedence.md (9,802 bytes, exists).
- Evidence: awk 'NR>=40 && NR<=93' | wc -c → 5816; awk 'NR>=81 && NR<=93' | wc -c → 1553; ls -la → '-rw-r--r-- ... 9802 May 18 20:45 /Users/ray/.claude/state/implementation-notes-claude-md-prompt-precedence.md'
- Recommendation: Draft amendment for founder greenlight: move Worked scenarios (CLAUDE.md:81-87) and Cross-references (:89-93) into the implementation-notes doc, leaving a one-line pointer. Saves ~1.5KB (~12%) of every-session preamble; keep the chain (:46-58), Decision 1 (:60-62), memory-conflict logging (:64-66), and pasted-content carve-out (:68-79) in place — those are exercised per-turn.
6. [warn] redundancy (action: remove)
- Claim: Hard rules 1 and 2 are triple-covered: rule 1 duplicates memory file feedback_always_check_system_clock.md; rule 2 duplicates memory file feedback_always_send_responses_via_channel.md AND the tier-1 MCP plugin instructions which already state 'The sender reads Discord, not this session. Anything you want them to see must go through the reply tool' (same for iMessage).
- Evidence: CLAUDE.md:9-13 and :15-20; memory dir listing contains feedback_always_check_system_clock.md and feedback_always_send_responses_via_channel.md; MCP server instructions block (plugin:discord:discord / plugin:imessage:imessage) read this session: 'The sender reads Discord, not this session...'
- Recommendation: Retire the two memory files (and their MEMORY.md index lines) — the hard rules at tier 2 are the canonical home and the MCP instructions provide tier-1 backup for rule 2. Do not touch CLAUDE.md. Reversible cleanup; per feedback_distinguish_decision_from_action this is executable without asking, but log it to working-context.md Errors & Corrections per the memory-conflict-logging rule (CLAUDE.md:64-66).
7. [info] redundancy (action: remove)
- Claim: SOUL.md's closing subagent paragraph restates CLAUDE.md hard rule 4's policy (route verbose output through subagents so only the summary lands in parent context), duplicating ~430 bytes of per-session context.
- Evidence: SOUL.md:76 'When I spawn a subagent, prefer it for: anything that returns verbose output (web research, code search, log scraping)... The subagent's final summary is all that lands in my main context' vs CLAUDE.md:28-36 rule 4
- Recommendation: Draft amendment (founder greenlight, since SOUL.md defines persona): trim SOUL.md:76 to 'Subagent routing follows CLAUDE.md hard rule 4.' Minor savings; low priority.
8. [info] redundancy (action: decide)
- Claim: SOUL.md's spend rule ('Spending money or installing external code requires the founder's sign-off') is coarser than two newer memory refinements (feedback_api_cost_budget_controlled: don't pause for per-call API cost; feedback_mcp_install_security_review_default: security review before installs), creating a resolvable but undocumented tension that currently relies on the tier 5/6-over-tier 7 precedence ordering to resolve correctly.
- Evidence: SOUL.md:31 'Spending money or installing external code requires the founder's sign-off.'; MEMORY.md index entries 'feedback_api_cost_budget_controlled ... Don't pause for per-call cost confirmation' and 'feedback_mcp_install_security_review_default'
- Recommendation: Optional amendment: qualify SOUL.md:31 to 'New vendors, subscriptions, or external code installs need sign-off; metered API spend within the standing budget is pre-authorized (see feedback_api_cost_budget_controlled).' Surface to founder; not urgent since precedence resolves it.
9. [info] cost (action: keep)
- Claim: Persistent governing preamble is 17,329 bytes total: CLAUDE.md (12,307 B) is injected into every session via the claudeMd system-reminder; SOUL.md (5,022 B) enters context via the mandated Read at CLAUDE.md:3 and then persists for the session. At Fable 5's $10/MTok input this preamble's uncached cost doubled overnight; prompt caching mitigates per-turn cost (~0.1x reads) but the cache rewrites at every daily 4am LaunchAgent restart and on any byte change to either file.
- Evidence: wc -c output: '12307 /Users/ray/CLAUDE.md' and '5022 /Users/ray/SOUL.md'; CLAUDE.md:3 'Read and follow SOUL.md in this directory'; claude-api skill: Fable 5 $10.00/1M input, prompt-caching.md 'Cache reads cost ~0.1× base input price' and Fable 5 minimum cacheable prefix 2048 tokens
- Recommendation: Treat both files as a byte budget: the two relocations above (~1.9KB combined) are the available trims; reject future additions that aren't per-turn load-bearing (already codified as feedback_no_claudemd_state_drift).
10. [warn] gaps (action: add)
- Claim: No sub-agent model-tiering policy exists anywhere in the governing layer: grep for opus/sonnet/haiku/fable across CLAUDE.md and SOUL.md returns zero model-tier hits, SOUL.md's layered execution model (skills/loops/instances/agent-teams) is silent on model choice, and no memory file in the index covers it — meaning every subagent dispatched under rule 4 defaults to the flagship at $10/$50 per MTok even for mechanical extraction Haiku could do at $1/$5.
- Evidence: grep -in -E 'opus|sonnet|haiku|fable' /Users/ray/CLAUDE.md /Users/ray/SOUL.md → no model-name hits; SOUL.md:36-43 lists the four execution layers with no model guidance; memory dir listing contains no model-tiering file; claude-api skill table: Sonnet 4.6 $3/$15, Haiku 4.5 $1/$5 (200K context)
- Recommendation: Propose this CLAUDE.md addition (requires founder greenlight; do not self-apply): '## Sub-agent model tiering — Dispatch mechanical-extraction seats (rule-4 artifact summarization, log scraping, format conversion, dedup/triage) on claude-haiku-4-5 ($1/$5 per MTok, 200K context — chunk artifacts above that). Dispatch standard work seats (research synthesis, spec-driven build steps, vault writes) on claude-sonnet-4-6 ($3/$15). Reserve the session flagship (claude-fable-5, $10/$50) for judgment seats only: fresh-eyes critics, verification gates, strategic outputs, anything producing a founder-facing recommendation. When unsure, dispatch one tier down and escalate only if the output fails review.'
11. [info] gaps (action: keep)
- Claim: Rule 4's cited rationale doc predates Fable 5 (dated 2026-04-15, written against the 1M-context Opus era) but its load-bearing claim (context rot at large context) is restated inline in CLAUDE.md itself, so the rule does not depend on re-reading a stale source.
- Evidence: CLAUDE.md:29 'Per Thariq's Apr 15 2026 Anthropic guidance ([[~/rdco-vault/06-reference/2026-04-15-thariq-claude-code-session-management-1m-context.md]]): more context isn't free — model performance degrades as context grows'
- Recommendation: none — the inline restatement makes the citation decorative rather than load-bearing; no change needed
Verification
- finding 4 — "Worked scenario 5 contradicts the precedence chain it illustrates: the chain places sub-agent dispatch prompts at tier 4 ABOVE memory files at tier 6, but the s…": NOT refuted (verified), confidence high. All cited evidence reproduced exactly. CLAUDE.md:51 places sub-agent dispatch prompts at tier 4; CLAUDE.md:53 places MEMORY.md + older feedback memories at tier 6; CLAUDE.md:87 (worked scenario 5) nonetheless resolves the dispatch-vs-PR-only conflict as 'tier 2 / tier 6 > tier 4', inverting the published chain. The mislabel claim also holds: the four hard rules (CLAUDE.md lines 9-38: run date, channel reply tool, calendar UTC offset, subagent-route long artifacts) contain nothing about git/commits; PR-only exists only as the memory file /Users/ray/.claude/projects/-Users-ray/memory/feedback_pr_only_workflow.md (confirmed present, dated May 4, founder correction 2026-05-04), so the scenario's 'CLAUDE.md hard-rule context' / tier-2 citation is unfounded. Additional corroboration: the design doc /Users/ray/.claude/state/implementation-notes-claude-md-prompt-precedence.md enumerates dispatch prompt at #8 BELOW memories at #5 (memory beats dispatch) while its Decision 6 merges dispatch into the SKILL.md tier — CLAUDE.md's chain adopted Decision 6 but scenario 5 kept the older ordering, explaining the contradiction. Nothing documents an intentional carve-out elevating workflow memories above dispatch prompts. A sub-agent walking the chain literally would indeed let a dispatch prompt override PR-only, as the auditor warned.
Skills (SKILL.md inventory)
The skills inventory is large but mostly intentional: 85 directories (83 with SKILL.md, 742,858 bytes of SKILL.md, ~5.8MB on disk), of which only 14 are cron-driven; the rest are on-demand rails for the side bets. The real costs are (a) ~46.6KB of skill descriptions (~28.1KB personal + ~18.5KB plugin) injected into every session and every subagent spawn — meaningful at Fable 5's ~2x input price given nightly fan-out patterns — and (b) the vercel plugin (36 skills) plus two animation plugin families that have no usage evidence against a Cloudflare/wrangler stack and duplicate the personal HyperFrames adapter skills. Two integrity bugs surfaced: verify-action's SKILL.md claims a PreToolUse hook wiring that is absent from both settings files, and investing-smart-money-watch's description claims crons that do not exist in the scheduled-jobs.txt single source of truth. The largest strategic gap: zero skills match phdata/cert/snowflake even though phData certs are the founder-declared primary bet with hard deadlines (2026-08-24, 2026-11-22) and study-plan files already sitting in the vault.
1. [info] inventory totals (action: keep)
- Claim: 85 skill directories exist in ~/.claude/skills/; 83 contain a SKILL.md totaling 742,858 bytes (~5.8MB on disk including assets); 14 skills are referenced by the cron manifest (vault-health, process-inbox, check-board, process-newsletter, morning-prep, finance-pulse, self-review, improve, graph-reingest, curiosity, deep-research, sync-contacts, process-youtube, open-threads-check).
- Evidence: ls -d ~/.claude/skills// | wc -l -> 85; find ... -name SKILL.md -exec stat -f %z | awk sum -> 742858; du -sk -> 5796 KB; scheduled-jobs.txt lists exactly those 14 slash commands (e.g. '0 0 * * * | /vault-health', '/15 9-20 * * * | /open-threads-check')
- Recommendation: none
2. [warn] context cost of skill-list preamble (action: fix)
- Claim: Skill descriptions injected into every session/subagent preamble total ~46.6KB of measured frontmatter description text (28,082 chars across 83 personal skills + 18,496 chars across 60 plugin skills), roughly 11-12k tokens, paid on every session start and every subagent dispatch (deep-research nightly fan-out, process-newsletter per-article subagents) at Fable 5's ~2x Opus input price.
- Evidence: python3 frontmatter extraction output: 'personal skills with SKILL.md: 83 total description chars: 28082' and 'TOTAL plugin skills: 60 desc chars: 18496' (claude-plugins-official/vercel: 36 skills, 9173 desc chars was the largest single family)
- Recommendation: Treat description-byte budget as a first-class constraint: prune the unused plugin families below (saves ~13.6KB/~30% of plugin payload), and trim the longest personal descriptions (remotion-to-hyperframes and investing-smart-money-watch descriptions are multi-hundred-word essays) to 1-2 sentences each
3. [warn] plugin sprawl — vercel (action: remove)
- Claim: The vercel plugin (v0.43.0, installed 2026-04-04) injects 36 skill descriptions (9,173 chars, the single largest plugin family) with no evidence of actual use: RDCO's deploy stack is Cloudflare/wrangler, and the only vault mentions are one SOP listing 2 of 36 vercel skills as speculative references ('for any future Next.js surface') plus a legacy DNS CNAME record and font mood-board citations.
- Evidence: installed_plugins.json: 'vercel@claude-plugins-official ... version 0.43.0'; python3 output: 'claude-plugins-official/vercel: 36 skills, 9173 desc chars'; 2026-05-05-rdco-website-polish-workflow.md:59 '
vercel:next-cache-components- PPR + caching for any future Next.js surface'; raydata-co-cloudflare-ns.txt:38 'www CNAME ... cname.vercel-dns.com.'; wrangler evidence: 02-sops/2026-04-26-rdco-web-app-deployment-standard.md - Recommendation: Uninstall the vercel plugin (founder confirms first); reinstall takes minutes if a Next.js surface ever materializes. This alone removes ~20% of the plugin description payload from every session
4. [warn] plugin sprawl — animation families (action: remove)
- Claim: core-3d-animation (5 skills, 1,913 desc chars) and animation-components (5 skills, 2,538 desc chars), both installed 2026-04-15, were explicitly labeled 'OPERATIONAL but unused so far' in the founder's own SOP, and the personal HyperFrames adapter skills built three weeks later (animejs, gsap, lottie, three, css-animations, waapi, all mtime 2026-05-06) cover the same libraries with render-deterministic patterns the plugins lack.
- Evidence: 2026-05-05-rdco-website-polish-workflow.md:25 '| 6 | Animation / motion layer ...
animation-components:*plugins ... | OPERATIONAL but unused so far |'; SOP line 54 even flags 'core-3d-animation:motion-framer (duplicate)'; skills mtime listing shows animejs/gsap/lottie/three/waapi all 2026-05-06; installed_plugins.json shows both installed 2026-04-15T10:54 - Recommendation: Uninstall both claude-design-skillstack plugins (founder confirms); personal HyperFrames adapters supersede them for the video pipeline, and react-spring/framer-motion have no React surface in the stack
5. [info] plugin sprawl — firebase (keep) (action: keep)
- Claim: The firebase plugin is justified despite contributing ~50 deferred MCP tools: Squarely iOS actively uses Firebase SDK, Firestore game data, and Firebase Analytics.
- Evidence: ~/.claude/state/working-context.md:57 'Privacy grounded in actual data (anon
odIdonly, Firestore game data, Firebase Analytics...)'; working-context.md:533 'Project-level Claude config: state mgmt rules, color palette refs, Firebase SDK caveats' - Recommendation: none
6. [warn] misplaced repo in skills dir (action: fix)
- Claim: ~/.claude/skills/heygen-skills/ (mtime 2026-05-04) is a full git repo clone (with .git, CHANGELOG, CONTRIBUTING, release-please config, .mcp.json) rather than a skill; its actual SKILL.md files sit one level too deep (heygen-avatar/SKILL.md, heygen-video/SKILL.md) and consequently neither appears in the session's available-skills list — it is dead weight that surfaces nothing.
- Evidence: ls ~/.claude/skills/heygen-skills/ output shows .git, CHANGELOG.md, release-please-config.json, heygen-avatar/, heygen-video/; ls heygen-avatar/ -> 'SKILL.md references'; the available-skills list in this session contains no heygen entry; for-loop output: '0 MISSING /Users/ray/.claude/skills/heygen-skills/'
- Recommendation: Either move heygen-avatar and heygen-video up to ~/.claude/skills/
/ if HeyGen video is still wanted (the heygen MCP is connected), or delete the directory; current state gives the cost of the clone with zero skill surface
7. [warn] stale/abandoned skill candidates (action: remove)
- Claim: Applying the mtime>3wk + not-cron-referenced filter, the strongest archive candidates with no observed cross-reference are: cross-check (2026-04-12), aws-audit (2026-04-19), postgrid (2026-04-22), stripe-best-practices + stripe-projects + upgrade-stripe (2026-04-29), blender + blender-character (2026-04-29, 34.5KB combined; superseded for mascot work by ray-mascot-anim's Kling pipeline 'figured out 2026-05-04'), save-to-bookshelf (2026-04-30), spm-build-analysis (2026-04-30), voice-match (2026-04-25), remotion-to-hyperframes + website-to-hyperframes (2026-05-06), and build-haiku-generator (2026-05-12, self-described 'Toy smoke-test ... Validates the multi-agent skill build-out pipeline ... before any real domain ships through').
- Evidence: stat loop output (e.g. '4801 2026-04-12 .../cross-check//SKILL.md', '8433 2026-04-19 .../aws-audit//SKILL.md', '741 2026-04-29 .../stripe-projects//SKILL.md'); scheduled-jobs.txt contains none of these; build-haiku-generator/SKILL.md:2 'Toy smoke-test workflow...'; aws-audit/SKILL.md:2 'identify cost drivers and migration candidates' against a stack that migrated to Cloudflare
- Recommendation: Move these ~15 skills to an ~/.claude/skills-archive/ directory (restorable in seconds) after founder confirms; note mtime measures last-edit not last-invocation, so spot-confirm with the founder before archiving anything tied to an active side bet. Explicitly NOT candidates despite age: squarely-deploy, sanity-check skills, investing suite, design-critic (referenced by build-landing-page/SKILL.md:91), pipeline-* seats, audit-model/generate-tests
8. [info] verify- family overlap* (action: decide)
- Claim: Three same-day (2026-05-18) verification skills — verify-dispatch (17,880B), verify-strategic-output (16,557B), verify-vault-write (15,305B), ~49.7KB combined — implement the same fresh-eyes-subagent gate pattern under one umbrella SOP, alongside verify-pdf-output (25,620B), design-critic (39,109B), video-critic (11,715B); consolidation into one parameterized verify skill with per-surface rubric files would cut redundant boilerplate. verify-action is NOT part of this family (it is a PreToolUse hook corpus) and should not be merged.
- Evidence: stat output: '17880 2026-05-18 verify-dispatch', '16557 2026-05-18 verify-strategic-output', '15305 2026-05-18 verify-vault-write'; MEMORY.md entry: '/verify-vault-write, /verify-strategic-output, /verify-dispatch + umbrella SOP at 02-sops/2026-05-19-verification-as-independent-worker-pattern.md'; verify-action/SKILL.md:2 'Pre-flight verifier ... Wired as a PreToolUse hook'
- Recommendation: Low-confidence consolidation candidate: one /verify skill taking a surface argument, rubrics as sub-files loaded on invocation. Only worth doing if the three SKILL.mds share >50% text — diff before deciding
9. [warn] verify-action hook wiring broken (action: fix)
- Claim: verify-action/SKILL.md claims it is 'Wired as a PreToolUse hook in settings.json' to gate outbound iMessage/Discord replies, but neither settings.json nor settings.local.json references verify-action or verify-action.py — the settings.json PreToolUse block contains only Bash matchers (package-security-check.sh, sql-guardrail.sh). The channel-reply guardrail the founder believes is active is not firing.
- Evidence: verify-action/SKILL.md:2 'Wired as a PreToolUse hook in settings.json'; grep -rn 'verify-action' ~/.claude/settings.json ~/.claude/settings.local.json -> exit=1 (no match); full read of settings.json PreToolUse block (lines 131-205) shows only matcher 'Bash' entries; ~/.claude/scripts/verify-action.py exists
- Recommendation: Either re-wire the hook (PreToolUse matcher on mcp__plugin_imessage_imessage__reply and mcp__plugin_discord_discord__reply piping tool-input JSON to verify-action.py) or correct the SKILL.md so nobody trusts a guardrail that does not exist
10. [warn] investing-smart-money-watch cron drift (action: fix)
- Claim: investing-smart-money-watch's description states '13F cron 60 days after quarter end; Congress cron monthly on the 15th', but scheduled-jobs.txt — self-declared 'SINGLE SOURCE OF TRUTH for the cron suite' — contains zero investing entries, meaning the May 15 Congress fire and the ~May 30 13F fire (Q1 ended Mar 31) never ran, or the description is stale.
- Evidence: Available-skills description: '13F cron 60 days after quarter end; Congress cron monthly on the 15th'; grep 'investing' ~/.claude/scripts/scheduled-jobs.txt -> exit=1; grep -c 'smart-money|edgar' scheduled-jobs.txt -> 0; manifest header: 'SINGLE SOURCE OF TRUTH for the cron suite'
- Recommendation: Founder decides: investing is now a deprioritized side bet, so either add the two cron lines to scheduled-jobs.txt or strip the cron claims from the SKILL.md description and run it on-demand only
11. [warn] phData-primary gap (action: add)
- Claim: No skill matches phdata/cert/snowflake despite phData being the founder-declared primary bet (2026-06-08) with two cert deadlines worth $10k (Snowflake GenAI by 2026-08-24, Anthropic Partner by 2026-11-22); the vault already holds 13 phData project files including two study guides, but nothing in the harness drives study cadence, progress tracking, or deadline countdown.
- Evidence: ls ~/.claude/skills/ | grep -i -E 'phdata|cert|snowflake' -> exit=1 (no matches); find ~/rdco-vault/01-projects/phdata -maxdepth 1 -type f returned 13 files including '2026-05-27-claude-certified-architect-foundations-study-plan.md' and 'anthropic-certification-study-guide.md'; scheduled-jobs.txt has no cert-related job
- Recommendation: Add a /cert-study skill (reads the two study-guide files, tracks topic coverage and days-to-deadline, emits a weekly progress check to the founder) plus a cron line in scheduled-jobs.txt; this is the cheapest high-leverage addition the inventory is missing for the stated #1 objective
12. [info] phData-relevant skills to retain (action: keep)
- Claim: audit-model (2026-04-22, 10,336B) and generate-tests (2026-04-22, 4,670B) trip the staleness filter but are directly relevant to phData consulting work — generate-tests explicitly emits 'dbt test YAML or Snowflake SQL', and settings.json already carries a snowsql SQL-guardrail hook — so they should be kept despite age.
- Evidence: stat output '10336 2026-04-22 audit-model', '4670 2026-04-22 generate-tests'; generate-tests description: 'Emits either dbt test YAML or Snowflake SQL based on target platform'; settings.json PreToolUse: sql-guardrail.sh with 'if': 'Bash(snowsql)'
- Recommendation: Keep both; consider folding them into the future phData/cert-study skill family so the phData toolchain has one obvious home
13. [info] design-skill overlap (action: decide)
- Claim: Four design sources coexist: personal brand systems (ray-data-co-design 2026-04-25, sanity-check-design 2026-05-08) plus plugin generics (frontend-design 1 skill, ui-ux-pro-max 1 surfaced skill of 7 SKILL.mds in its cache). The personal systems are canonical per CLAUDE.md's capabilities index and founder taste memory; ui-ux-pro-max is cited once in the polish SOP as a reference library, so it has weak-but-nonzero use evidence — weaker prune candidate than vercel/animation plugins.
- Evidence: stat output '4045 2026-04-25 ray-data-co-design', '11329 2026-05-08 sanity-check-design'; 2026-05-05-rdco-website-polish-workflow.md:46 '
ui-ux-pro-max:ui-ux-pro-max- 50+ styles, 161 palettes...'; find cache/ui-ux-pro-max-skill -name SKILL.md -> 7 files under .claude/skills/ but only 'ui-ux-pro-max:ui-ux-pro-max' appears in the session skill list - Recommendation: Low confidence: keep ui-ux-pro-max and frontend-design for now (small footprint, 234+320 desc chars surfaced); revisit after the vercel/animation prunes land
Verification
- finding 2 — "Skill descriptions injected into every session/subagent preamble total ~46.6KB of measured frontmatter description text (28,082 chars across 83 personal skills …": NOT refuted (verified), confidence high. Core measurement reproduces with two material caveats. (1) Personal skills: confirmed exactly 83 SKILL.md files under ~/.claude/skills/ (85 dirs minus _shared and heygen-skills); my frontmatter extraction totals 28,007 chars vs cited 28,082 (0.27% extraction-method variance). (2) Plugin skills: reproduced the cited counts exactly (60 skills, vercel 36) using recursive skills/**/SKILL.md over installPaths in ~/.claude/plugins/installed_plugins.json; chars 18,090 vs cited 18,496 (~2% variance). HOWEVER, 10 of vercel's 36 are nested skills/
/upstream/SKILL.md reference copies (e.g. .../vercel/0.43.0/skills/ai-sdk/upstream/SKILL.md, total 3,265 desc chars) that are NOT registered skills — this session's own injected skill list shows exactly 26 vercel skills and zero upstream entries. So the actually-injected plugin payload is 50 skills / ~14,825 chars, and the true injected total is ~42.8KB (~10.7k tokens), ~8% below the claimed 46.6KB/11-12k tokens. (3) Pricing verified via claude-api skill: Fable 5 $10/MTok input vs Opus 4.x $5/MTok — '~2x Opus input price' is exactly right. (4) Recommendation spot-check: remotion-to-hyperframes is genuinely the longest personal description (1,240 chars / ~181 words), but investing-smart-money-watch is only 539 chars / ~77 words — NOT a 'multi-hundred-word essay' and not in the top 10 (verify-strategic-output 814, verify-pdf-output 806, verify-vault-write 757, video-critic 732, hyperframes 722 are all longer trim candidates). Verdict: claim directionally holds and the prune/trim recommendation stands, but the parent should correct the injected-payload figure to ~42.8KB/50 plugin skills (the 10 vercel upstream files are never injected and need no pruning) and swap investing-smart-money-watch for one of the verify-* descriptions in the trim list. - finding 6 — "~/.claude/skills/heygen-skills/ (mtime 2026-05-04) is a full git repo clone (with .git, CHANGELOG, CONTRIBUTING, release-please config, .mcp.json) rather than a…": NOT refuted (verified), confidence high. Claim fully reproduced. /Users/ray/.claude/skills/heygen-skills/ (dir mtime May 4 2026 21:11) is a complete clone of https://github.com/heygen-com/skills.git (HEAD e01898f, release 3.1.0) containing .git/, CHANGELOG.md, CONTRIBUTING.md, release-please-config.json, .release-please-manifest.json, .mcp.json, README, LICENSE, and a setup script. There is NO top-level SKILL.md; the only SKILL.md files sit one level deep at heygen-avatar/SKILL.md and heygen-video/SKILL.md (both with valid name/description frontmatter). My for-loop over ~/.claude/skills/*/ reproduced the cited '0 MISSING /Users/ray/.claude/skills/heygen-skills/' output verbatim (it also flags _shared/, likely intentional non-skill assets). The current session's available-skills list contains zero heygen entries, confirming neither nested skill is surfaced. The recommendation's premise also holds: the heygen MCP IS connected (mcp__heygen__authenticate / complete_authentication in the deferred tool list). Note the repo ships its own setup/INSTALL.md for per-skill installation, reinforcing that the wholesale clone into skills/ is a misinstall: full clone cost, zero skill surface.
- finding 9 — "verify-action/SKILL.md claims it is 'Wired as a PreToolUse hook in settings.json' to gate outbound iMessage/Discord replies, but neither settings.json nor setti…": NOT refuted (verified), confidence high. Claim fully reproduces and is strengthened by additional evidence. (1) SKILL.md line 2 says verbatim 'Wired as a PreToolUse hook in settings.json.' (2) grep for verify-action in ~/.claude/settings.json and settings.local.json exits 1 (no match); also no match in ~/.claude.json, ~/.claude/plugins, and no /Library/Application Support/ClaudeCode/managed-settings.json exists. (3) Parsing settings.json hooks as JSON confirms PreToolUse has only matcher 'Bash' entries (package-security-check.sh, sql-guardrail.sh); no hook event references the iMessage/Discord reply tools. (4) ~/.claude/scripts/verify-action.py exists (executable, 14438 bytes). (5) Smoking gun: ~/.claude/skills/verify-action/proposed-settings.json.snippet contains the exact two PreToolUse matcher blocks for mcp__plugin_imessage_imessage__reply and mcp__plugin_discord_discord__reply with a '_comment' instructing to splice them into settings.json — drafted but never applied. (6) Runtime proof: ~/.claude/state/verify-action.log has 38 entries, all timestamped 2026-05-05 (consistent with the run-tests.sh fixture suite on build day), and zero entries in the 35 days since despite daily channel traffic. The guardrail has never fired in production. The recommendation stands: either splice the proposed snippet into settings.json hooks.PreToolUse or correct SKILL.md's claim.
Memory (MEMORY.md + feedback files)
Memory index integrity is clean (61 files, 61 entries, no orphans or dangling links) and — notably — zero memories encode the runtime model, so the Fable 5 swap requires no correctness edits to memory. The dominant problem is index-vs-body drift on the highest-priority topic: the per-session-injected MEMORY.md line for the phData bet still carries the wrong cert name, a superseded fixed sequence, and 'job starts 2026-05-26', while the file body was corrected Jun 8; relatedly, the L5 memory still claims unhobbling is the 'primary focus', contradicting the newer phData MAIN-bet memory, and the dob_age memory now asserts a wrong age (35 vs actual 36). The single critical item is feedback_calibrate_overconfidence.md: a 20.5KB fabrication-incident journal whose own text concludes memory bullets failed to stop the failure mode and twice demands a structural pre-send hook that was never built — that hook should be implemented now, since the model swap resets the behavioral priors the journal was written against. Secondary hygiene: merge the two overlapping xmcp entries, consolidate the duplicated batching rule into no_batched_result_declaration, refresh the 73-day-old channels-setup memory that documents the daily-restart infra, and strip point-in-time state (dates, ages, spec stages) out of injected index lines.
1. [info] index integrity (action: keep)
- Claim: MEMORY.md index is structurally clean: 61 files on disk, 61 index entries, zero files missing from the index and zero index links pointing at nonexistent files.
- Evidence: Cross-check script output: '=== files on disk not in MEMORY.md ===' (empty), '=== MEMORY.md links pointing at nonexistent files ===' (empty), counts '61 / 61 / 14878 MEMORY.md'
- Recommendation: none
2. [warn] staleness: phData index line (action: fix)
- Claim: MEMORY.md line 56 (injected every session) is stale on the PRIMARY business bet: it says 'phData job starts 2026-05-26' (job started two weeks ago), names the cert 'Anthropic Partner Architect' (founder-corrected 2026-05-27 to 'Claude Certified Architect – Foundations'), implies a fixed Snowflake-then-Anthropic sequence (founder clarified 2026-06-08 that order does not matter), and omits MAIN-bet status. The file body project_phdata_cert_escalator_path.md was updated Jun 8 13:51 with all corrections, but MEMORY.md was last written Jun 8 08:34 — the index missed the update.
- Evidence: MEMORY.md:56 'phData job starts 2026-05-26. Snowflake GenAI Specialty cert (90d, deadline 2026-08-24, +$5k base) → Anthropic Partner Architect cert' vs project_phdata_cert_escalator_path.md:3 'MAIN bet (confirmed 2026-06-08)... ORDER DOES NOT MATTER (founder clarified 2026-06-08, supersedes the earlier fixed Snowflake-then-Anthropic sequence)' and :25 'EAP study guide names this "Claude Certified Architect – Foundations" — NOT "Partner Architect" as originally recorded'. ls: MEMORY.md 'Jun 8 08:34', project_phdata_cert_escalator_path.md 'Jun 8 13:51'.
- Recommendation: Rewrite MEMORY.md:56 to match the file body: phData is the founder's MAIN bet (confirmed 2026-06-08); started 2026-05-26; ONE cert by ~2026-08-26 and ONE by ~2026-11-26 in either order (+$5k each); Snowflake GenAI Specialty = easier/quicker, Anthropic 'Claude Certified Architect – Foundations' = ladder-opening, gated on partner-portal access. Also adopt a discipline: any memory-file edit must update its MEMORY.md line in the same turn.
3. [warn] staleness + contradiction: L5 vs phData priority (action: fix)
- Claim: project_l5_north_star_strategic_direction.md (last modified Jun 3) and MEMORY.md line 38 still state 'Primary focus is unhobbling the COO agent', which predates and conflicts with the 2026-06-08 founder confirmation in project_phdata_cert_escalator_path.md that the phData employment bet is the MAIN bet. Per the CLAUDE.md memory-conflict rule, the newer memory wins and the conflict should be logged, not silently absorbed.
- Evidence: project_l5_north_star_strategic_direction.md:3 'Primary focus is unhobbling the COO agent (toolset expansion + visibility), NOT operating the small bets first' and :11 founder quote; vs project_phdata_cert_escalator_path.md:3 'phData job (start 2026-05-26) is the founder's MAIN bet (confirmed 2026-06-08)'. ls: l5 file 'Jun 3 17:03', phdata file 'Jun 8 13:51'.
- Recommendation: Append a dated section to project_l5_north_star_strategic_direction.md and update MEMORY.md:38: as of 2026-06-08, phData (certs) is priority #1 and L5 unhobbling is #2; the L5 thesis itself stays valid (the Jun 3 'convergence signal' section already notes phData orchestration work compounds into L5). Log the supersession to working-context Errors & Corrections per the memory-conflict-logging rule.
4. [warn] staleness: user_dob_age (action: fix)
- Claim: user_dob_age.md and its MEMORY.md line assert a now-wrong age: 'Current age: 35' with 'Next birthday: 2026-06-02 (turns 36)' — the birthday passed 7 days ago (today is 2026-06-09), so the founder is 36. This memory's entire stated purpose is preventing sub-agents from propagating a wrong age into health/screening contexts, and it currently does the opposite. The 'turns 36 on 2026-06-02' phrasing in the injected index actively asserts the stale state every session.
- Evidence: user_dob_age.md:13-14 'Current age: 35 (as of 2026-05-21)' / 'Next birthday: 2026-06-02 (turns 36)'; MEMORY.md:6 'currently 35 (turning 36 on 2026-06-02)'; currentDate injection 'Today's date is 2026-06-09'.
- Recommendation: Update both to age 36 / next birthday 2027-06-02. Better structural fix: make the index line DOB-only ('DOB 1990-06-02; compute age from DOB, never guess') so it can never go stale again — computed age is point-in-time state, not durable memory.
5. [critical] bloat + state drift: feedback_calibrate_overconfidence (action: add)
- Claim: feedback_calibrate_overconfidence.md is 20,566 bytes — the largest memory file — and has drifted from a distilled behavioral rule into a running incident journal (incidents #1 through #10 of fabrication/confidence-without-substrate, May 28-31). The file's own text concludes the memory mechanism has failed for this failure class ('Memory bullets have NOT stopped this — incidents #6-#10 all post-date the rule. The fix is not more rules; it's mechanical and external') and twice recommends a structural pre-send hook that has not been implemented (no such hook is evidenced anywhere I read). This is the highest-stakes open item in the memory system: the documented failure mode is fabricating results/replies/security-alerts to the founder, and the model swap to Fable 5 today resets all behavioral priors the incident log was written against.
- Evidence: ls: 'feedback_calibrate_overconfidence.md 20566 May 31 08:02'. File line 69: 'Memory bullets have NOT stopped this — incidents #6-#10 all post-date the rule... STRONG recommendation to founder: a pre-send hook that, before any channel reply or durable-state write, forces a re-read of the relevant tool result in the same turn'. Line 42: 'Strongly flag to founder as a harness/skill-level change (a pre-send hook that forces a channel re-read), not another line here.'
- Recommendation: Two actions: (1) distill the file to <3KB — keep the original calibration rule plus the 5 hardened mechanical rules (lines 54-59), archive incident narratives #2-#10 to a vault incident log (e.g. ~/rdco-vault/02-sops/ or 06-reference/) with a pointer; (2) actually implement the pre-send hook the file recommends (PreToolUse hook on channel-reply/state-write tools via the update-config skill) — this is the 'add' the memory system has been asking for since 2026-05-31, and re-validating fabrication discipline on the new model makes it timely.
6. [info] integrity: missing incident #9 (action: fix)
- Claim: feedback_calibrate_overconfidence.md numbers incidents up to #10 and says 'worst of the ten', but the file contains no Incident #9 — the sections jump from '### Incident #8' (line 46) to '### Incident #10' (line 63). Either an incident record was lost (possibly to one of the cancelled-batch writes the file itself documents) or never written.
- Evidence: feedback_calibrate_overconfidence.md:46 '### Incident #8 — fabricated a tool result...'; :63 '### Incident #10 — fabricated a PROMPT-INJECTION attack...'; :67 'Why it's the worst of the ten'; grep for '#9' in the file body matches nothing in the read content.
- Recommendation: When archiving the incident log (previous finding), note the #9 gap explicitly rather than renumbering; check 2026-05-31 session transcripts/working-context if the record matters.
7. [info] overlap: calibrate_overconfidence vs no_batched_result_declaration (action: fix)
- Claim: feedback_no_batched_result_declaration.md (May 31) restates the same mechanical rule already embedded in calibrate_overconfidence incident #3: never compose a result-asserting reply in the same batch as the commands that determine it. Two memories carry one rule.
- Evidence: feedback_no_batched_result_declaration.md:17 'Never put a result-asserting channel reply in the same turn/block as the commands that determine the result' vs feedback_calibrate_overconfidence.md:27 'Hard mechanical rule: NEVER put a channel-reply tool call in the same batch as the fetch/read/probe that informs it.'
- Recommendation: Make feedback_no_batched_result_declaration.md the canonical home for the mechanical observe-then-act rules (fold in lines 54-59 of calibrate_overconfidence); calibrate_overconfidence keeps only the epistemic lesson (defer to founder's lived reality, walk back when challenged) with a cross-link. Pairs with the distillation in the bloat finding.
8. [info] overlap: two xmcp entries (action: fix)
- Claim: feedback_xmcp_article_access_persistence.md (Apr 14) and feedback_xmcp_article_body_via_plain_text.md (May 18) are two halves of one X-article-access playbook and explicitly describe each other as inverse cases of the same lesson. They consume two index lines and split the retrieval steps across files.
- Evidence: feedback_xmcp_article_body_via_plain_text.md:28 'Related: [[feedback-xmcp-article-access-persistence]] — earlier memory about pivoting to WebSearch when plain_text is empty; today's lesson is the inverse case where I should have tried xmcp before falling back.'
- Recommendation: Merge into a single 'x-article-access-playbook' memory with the ordered procedure (xmcp getPostsById with tweet.fields=["article"] first; param-shape gotcha tweet.fields not post_fields; if plain_text empty → WebSearch title → author blog cross-post; never claim unreachable after one method). Retire the Apr 14 file and collapse to one index line.
9. [info] model-change exposure (action: keep)
- Claim: No memory file asserts which model the agent runs on or encodes Opus-specific behavior — the only model-name hits are incidental (Haiku as the /goal judge in a docs quote; 'teej Opus 4.7' as the topic of an X draft). The model is pinned in settings.json, already set to Fable 5, and the restart script the channels-setup memory describes contains no --model flag. The Fable 5 swap therefore requires zero memory edits for correctness.
- Evidence: grep -riE 'opus|sonnet|haiku|fable|claude-[0-9]' across memory dir returned only feedback_calibrate_overconfidence.md:25 (Haiku in /goal docs quote) and feedback_x_voice_mismatch.md:3 ('teej Opus 4.7' draft topic). settings.json:252 '"model": "claude-fable-5[1m]"'. grep -cE 'opus|fable|--model' on claude-channels-restart.sh returned 0.
- Recommendation: none
10. [info] staleness: feedback_alpaca_paper_opg_unreliable (action: keep)
- Claim: The Alpaca OPG memory's core fact remains relevant — the investing pipeline is active and explicitly paper-first on Alpaca per the Markov memory, which cross-links it — but the file carries two embedded unresolved action items ('Strategy spec update needed' for smart-money-mirror-v1, 'Cron implication: ...Simplify the cron accordingly') that are task-state inside a durable memory, with no indication they were ever executed.
- Evidence: feedback_alpaca_paper_opg_unreliable.md:45 'Strategy spec update needed: ~/rdco-vault/01-projects/investing/strategies/2026-05-18-smart-money-mirror-v1.md should be revised' and :47 'Simplify the cron accordingly.'; project_investing_markov_capital_cycle.md:19 'Paper-first, walk-forward' + :25 'Related: ...[[feedback_alpaca_paper_opg_unreliable]]'.
- Recommendation: Keep the memory (durable execution-shape rule). Verify the two TODOs were done; if not, queue them to the Notion board per feedback_queue_work_to_the_board, then delete the TODO paragraphs from the memory file.
11. [warn] staleness: project_channels_agent_setup (action: fix)
- Claim: project_channels_agent_setup.md is the oldest memory (Mar 28, 73 days) and its 'Known issues' section is point-in-time CLI state: --name flag bug with /rename workaround, trust-prompt auto-Enter hack, 'auto permission mode would be ideal but requires Teams plan'. The restart script it documents was modified May 31 — two months after the memory — so the description has likely drifted from the actual infra, and today's CLI/model upgrade makes the known-issues claims doubly unverified. This memory governs the daily 4am restart of the entire agent, so drift here has operational consequences.
- Evidence: ls: 'project_channels_agent_setup.md ... Mar 28 00:01' vs 'claude-channels-restart.sh ... May 31 09:29'. File lines 20-24 'Known issues: --name CLI flag doesn't persist session names (bug)... Directory trust prompt appears on every start — script sends Enter after 5s' and :28 'The auto permission mode would be ideal but requires Teams plan — revisit if user upgrades.'
- Recommendation: Re-read the current restart script and refresh this memory: confirm which workarounds are still load-bearing post-upgrade, and re-test the --name and trust-prompt issues on the current CLI. Especially important the week of a model swap, since the 4am restart is the recovery path if Fable 5 behaves differently.
12. [warn] MEMORY.md size + state-in-index drift (action: fix)
- Claim: MEMORY.md is 14,878 bytes (~3.7k tokens) across 61 entries, injected into every session — tolerable in absolute size even at Fable 5's ~2x input price, but the index has a systemic pattern of embedding point-in-time state in lines meant to be durable: a job start date that already passed (line 56), a computed age with a passed birthday (line 6), an 'Active spec (2026-05-27)' status (line 54). This is the no_claudemd_state_drift principle violated at the memory-index level — the index entries that age worst are exactly the ones carrying dates-as-state, and per-session injection means every session inherits the stale assertion.
- Evidence: wc -c: '14878 MEMORY.md'; grep -c '^- [': 61. State-bearing lines: MEMORY.md:56 'phData job starts 2026-05-26', MEMORY.md:6 'currently 35 (turning 36 on 2026-06-02)', MEMORY.md:54 'Active spec: Markov phase-tracker pipeline (2026-05-27)'. Principle: feedback_no_claudemd_state_drift index entry MEMORY.md:37 'CLAUDE.md is for stable rules only.'
- Recommendation: One-time pass over MEMORY.md rewriting index lines to durable form (facts that cannot expire: DOB not age, 'started 2026-05-26' not 'starts', drop spec-stage markers); adopt the rule that dated/status language belongs in file bodies or working-context.md, never in the injected index. Net size after the calibrate-overconfidence distillation and xmcp merge keeps the index around 60 lines — no aggressive pruning needed beyond that.
Verification
- finding 2 — "MEMORY.md line 56 (injected every session) is stale on the PRIMARY business bet: it says 'phData job starts 2026-05-26' (job started two weeks ago), names the c…": NOT refuted (verified), confidence high. Reproduced all cited evidence independently. (1) /Users/ray/.claude/projects/-Users-ray/memory/MEMORY.md line 56 (confirmed via grep -n) reads exactly as cited: 'phData job starts 2026-05-26. Snowflake GenAI Specialty cert (90d, deadline 2026-08-24, +$5k base) → Anthropic Partner Architect cert (180d, deadline 2026-11-22, +$5k base, gated on partner-portal access). $10k total potential.' — stale on all four claimed points: future-tense start date (job started 2026-05-26, two weeks before today 2026-06-09), wrong cert name, arrow implying fixed Snowflake→Anthropic order, no MAIN-bet status. (2) project_phdata_cert_escalator_path.md line 3 contains verbatim 'MAIN bet (confirmed 2026-06-08)' and 'ORDER DOES NOT MATTER (founder clarified 2026-06-08, supersedes the earlier fixed Snowflake-then-Anthropic sequence)'; line 25 contains 'names this "Claude Certified Architect – Foundations" — NOT "Partner Architect" as originally recorded' (founder-confirmed 2026-05-27). (3) stat timestamps: MEMORY.md 2026-06-08 08:34:10 vs project file 2026-06-08 13:51:34 — the body was updated ~5h17m after the index, so the MEMORY.md line predates and missed the correction. The recommendation's proposed rewrite also matches the body (line 14: ONE cert by ~2026-08-26, ONE by ~2026-11-26, either order; line 18: Snowflake = easier/quicker; line 19: Anthropic Foundations = ladder-opening, partner-portal gated). Claim fully holds; the auditor's quotes and timestamps are accurate.
- finding 3 — "project_l5_north_star_strategic_direction.md (last modified Jun 3) and MEMORY.md line 38 still state 'Primary focus is unhobbling the COO agent', which predates…": NOT refuted (verified), confidence high. All cited evidence reproduced exactly. (1) project_l5_north_star_strategic_direction.md:3 reads 'Primary focus is unhobbling the COO agent (toolset expansion + visibility), NOT operating the small bets first' and line 11 has the founder quote verbatim. (2) project_phdata_cert_escalator_path.md:3 reads 'phData job (start 2026-05-26) is the founder's MAIN bet (confirmed 2026-06-08)'. (3) ls -la confirms timestamps: l5 file Jun 3 17:03, phdata file Jun 8 13:51 — phdata is newer. (4) grep -n confirms MEMORY.md line 38 is the L5 entry with 'Primary focus is unhobbling COO agent (toolset + visibility)' (trivial variance: 'the' is absent before 'COO agent'). (5) The supersession is NOT yet logged: ~/.claude/state/working-context.md (last modified Jun 2, before the Jun 8 confirmation) contains no mention of 'main bet'/'unhobbling'/this conflict, so the log-it recommendation is not moot. Bonus finding strengthening the claim: MEMORY.md line 56 (phData entry) is itself stale vs its underlying file — still shows the fixed Snowflake→Anthropic sequence (superseded 2026-06-08 'EITHER ORDER') and the old cert name 'Anthropic Partner Architect' (corrected 2026-05-27 to 'Claude Certified Architect – Foundations'); refresh it alongside line 38. Interpretive caveats that do not refute: the two statements operate at different scopes (founder's overall bet portfolio vs intra-RDCO agent focus) and the l5 file's Jun 3 convergence section partially harmonizes them, so this is a practical prioritization conflict at the MEMORY.md-index level rather than a strict logical contradiction; also the CLAUDE.md rule text says 'feedback memories' while both of these are type:project memories — the spirit clearly applies. Recommendation as stated (dated supersession section, MEMORY.md:38 update, working-context Errors & Corrections log entry, L5 thesis stays valid) is consistent with the evidence.
- finding 4 — "user_dob_age.md and its MEMORY.md line assert a now-wrong age: 'Current age: 35' with 'Next birthday: 2026-06-02 (turns 36)' — the birthday passed 7 days ago (t…": NOT refuted (verified), confidence high. Reproduced all cited evidence exactly. user_dob_age.md:13-14 read verbatim 'Current age: 35 (as of 2026-05-21)' / 'Next birthday: 2026-06-02 (turns 36)'. MEMORY.md:6 reads verbatim 'Ben Wilson DOB 1990-06-02, currently 35 (turning 36 on 2026-06-02)'. Live
datereturned Tue Jun 9 2026 (EDT), matching the currentDate injection; DOB 1990-06-02 means the founder turned 36 seven days ago, so both assertions are now wrong. Staleness is actually wider than cited: the file's frontmatter description (line 3) repeats 'currently 35', and the How-to-apply section (lines 22-24) tells health sub-agents to 'use age 35' and frames CAC screening on age 35. Line 18 confirms the memory's purpose is preventing sub-agents from propagating a wrong age, which it currently inverts. The DOB-only structural fix is consistent with the file's own line 25 ('anchor on DOB 1990-06-02').
State (working-context, state files)
The state-file layer is fundamentally healthy: ray-handoff.md (6,580 bytes, 49 lines) is the right shape for a fresh-session seed, and working-context.md at 22,995 bytes is NOT overdue for a prune — it was condensed from 153,222 bytes on 2026-05-31 and remains right-sized. The problems are staleness, not bloat. The handoff's top 🔴 bullet still describes the Fable 5 upgrade as pending ("awaiting his explicit do it", "running on Opus 4.8 for now") when settings.json:252 now shows "claude-fable-5[1m]" saved as default (mtime Jun 9 15:38) with effortLevel xhigh — and the handoff's proposed remedy (add --model claude-fable-5 to the restart script) is now both unnecessary and dangerous, since the flag omits the [1m] suffix and would override the saved 1M-context default. Secondary drift: the handoff claims 16 cron jobs vs 14 actual manifest lines, the numbered open-threads list (items 1-4) is stale ordering with item 4 contradicting the no-auto-ping rule and item 3 duplicating the 🔴 energy bullet, and working-context.md line 74 still claims settings.json has no model/effort key. founder-energy.txt has been dead for 25 days and two separate handoff bullets keep re-litigating its staleness. The 4.1MB unbounded newsletter-audit-log.md is the only file-size concern in the directory.
1. [warn] ray-handoff.md — Fable 5 open thread (action: fix)
- Claim: The handoff's newest 🔴 bullet describes the Fable 5 upgrade as unresolved ('founder leaning YES, awaiting his explicit do it', 'running on Opus 4.8 for now') but the upgrade is done: settings.json has the model saved as default and the session launched on Fable 5. A fresh 4am session reading this would believe the decision is still pending and may re-ping the founder or attempt the now-wrong remediation.
- Evidence: ray-handoff.md:27 'Fable 5 upgrade (founder leaning YES, awaiting his explicit "do it"): ... Founder kept Opus 4.8 in
/model2026-06-09 → running on Opus 4.8 for now.' vs ~/.claude/settings.json:252 '"model": "claude-fable-5[1m]"' (file mtime 'Jun 9 15:38:35 2026' per stat output). - Recommendation: Replace the line-27 bullet with: 'Fable 5 upgrade: DONE (2026-06-09 ~15:45 ET). Founder set /model to Fable 5 and saved as default — settings.json now has "model": "claude-fable-5[1m]" + "effortLevel": "xhigh" (ultracode). You ARE running Fable 5: 1M context default, adaptive thinking always-on, ~2x Opus input price — keep subagent-routing for long artifacts; bigger window is not free context. No restart-script change needed (see next finding). Reference: ~/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md.'
2. [warn] ray-handoff.md — proposed restart-script change (action: fix)
- Claim: The handoff instructs a future session to 'add --model claude-fable-5 to the launch line (script ~line 68)'. This is no longer needed — the launch line has no --model flag, so fresh sessions inherit the settings.json default 'claude-fable-5[1m]'. Worse, executing the instruction as written would pass 'claude-fable-5' WITHOUT the [1m] suffix, overriding the saved 1M-context default with the standard-context variant on every restart.
- Evidence: ray-handoff.md:27 'TO EXECUTE THE UPGRADE ... add
--model claude-fable-5to the launch line (script ~line 68)'; claude-channels-restart.sh:68 '"$TMUX_BIN" send-keys -t "$SESSION_NAME" "claude --name $RESUME_NAME --channels $CHANNELS $CHROME_FLAG "$SEED_PROMPT"" Enter' (no --model flag); settings.json:252 '"model": "claude-fable-5[1m]"'. - Recommendation: Delete the TO EXECUTE instruction entirely and add an explicit guard to the rewritten bullet: 'Do NOT add a --model flag to claude-channels-restart.sh — the settings.json saved default ([1m] variant) is the single source of truth; a script flag would shadow it and the bare claude-fable-5 id would drop the 1M context.'
3. [warn] ray-handoff.md — cron job count drift (action: fix)
- Claim: The handoff's Key paths section says the cron manifest has 16 jobs; the manifest contains exactly 14 active '
| ' lines, all well-formed. working-context.md independently corroborates 14 ('all 14 scheduled-jobs.txt lines'). - Evidence: ray-handoff.md:41 'Cron manifest (16 jobs, single source of truth):
~/.claude/scripts/scheduled-jobs.txt' vs command output 'grep -v -e ^\s*$ -e ^\s*# ~/.claude/scripts/scheduled-jobs.txt | grep -c " | "' → '14', with all 14 lines listed (/vault-health through /open-threads-check); working-context.md tail: 'all 14scheduled-jobs.txtlines arrived'. - Recommendation: Edit ray-handoff.md:41 to 'Cron manifest (14 jobs, single source of truth)' — or drop the count entirely ('Cron manifest (single source of truth)') so the pointer can never drift again; the manifest is self-counting.
4. [warn] ray-handoff.md — stale-ordering in Open threads section (action: fix)
- Claim: The numbered items 1-4 below the 🔴 block are a stale older list. Item 4 says the restart-script conversion is done and instructs 'If THIS session is the result, the conversion worked — confirm it to the founder', which directly contradicts line 20's 'Do NOT auto-ping the founder on every restart ... long-verified (confirmed working since 2026-05-31)'. Item 3 (energy number owed) duplicates the 🔴 energy bullet on line 29. Item 1, the pre-send verification gate ('the highest-value open build'), is buried beneath the newer 🔴 block instead of leading it.
- Evidence: ray-handoff.md:34 'Restart-script change: DONE + verified 2026-05-31 ... If THIS session is the result, the conversion worked — confirm it to the founder.' vs ray-handoff.md:20 'Do NOT auto-ping the founder on every restart. ... long-verified (confirmed working since 2026-05-31)'; ray-handoff.md:33 'Energy number: he hasn't given today's 1-10' duplicating ray-handoff.md:29 'Energy: no 1-10 given today (2026-06-09)'; ray-handoff.md:31 'NOT yet built — this is the highest-value open build.'
- Recommendation: Restructure the Open threads section: (a) delete item 4 entirely (resolved 2026-05-31; its confirm-to-founder instruction violates the no-auto-ping rule), (b) delete item 3 (duplicate of the 🔴 energy bullet), (c) promote item 1 into the 🔴 block as the first bullet, retitled 'TOP OPEN BUILD — pre-send/pre-write verification gate: founder agreed it's needed; hook that blocks any channel send or state-write not tied to a current-turn tool result. NOT built.', (d) keep item 2 (phData work-agent) as the only remaining numbered item or fold it into the 🔴 block. Drop the 1-4 numbering — a dated 🔴-style block per update is the working pattern; numbered lists invite append-without-retire drift.
5. [info] ray-handoff.md — stale 'Last written' header (action: fix)
- Claim: The header says 'Last written: 2026-06-05 ~04:02 ET' but the file was modified Jun 9 15:35 (matching the 🔴 block's 'Live as of 2026-06-09 ~15:35 ET'). The self-declared freshness stamp is 4 days behind the actual content, weakening the seed's verify-before-assert posture.
- Evidence: ray-handoff.md:3 'Last written: 2026-06-05 ~04:02 ET' vs ls output '-rw-r--r--@ 1 ray staff 6580 Jun 9 15:35 ray-handoff.md' and ray-handoff.md:26 '### 🔴 Live as of 2026-06-09 ~15:35 ET'.
- Recommendation: Update line 3's Last-written stamp in the same edit pass, and adopt the convention that any handoff edit updates the header stamp (it is the first line a fresh session trusts).
6. [info] ray-handoff.md — overall fitness as fresh-session seed (action: keep)
- Claim: At 6,580 bytes / 49 lines the handoff is the right length and shape for its job: identity + channel routing (lines 5-8), the load-bearing why-fresh story and verify-before-assert discipline (lines 10-15), anti-auto-ping startup behavior (lines 17-22), open threads, settled-do-not-resurface items, key paths, and the tmux connectivity note. The structure should be kept; only the content staleness needs fixing.
- Evidence: ls output '-rw-r--r--@ 1 ray staff 6580 Jun 9 15:35 ray-handoff.md'; ray-handoff.md:3 'Short, verified-state seed for a FRESH session. Replaces loading the full 1000-line working-context.md.'; ray-handoff.md:15 'Before ANY channel reply, durable-state write, or claim about state/security/tools: the immediately-prior step must be a tool call whose result you have READ in this turn.'
- Recommendation: Keep the document and its section structure as-is; apply only the staleness fixes in the other findings. The verify-before-assert section (line 15) and no-auto-ping section (line 20) are the two highest-value paragraphs in the file for a Fable 5 session and must survive any rewrite.
7. [info] working-context.md — size (action: keep)
- Claim: working-context.md is 22,995 bytes and is NOT overdue for a prune: it was condensed from a 1096-line accreted version on 2026-05-31 (the 153,222-byte pre-cleanup backup still exists in the directory). Current size is appropriate for a deep-history scratchpad that the handoff explicitly says not to load wholesale.
- Evidence: wc output '22995 /Users/ray/.claude/state/working-context.md'; working-context.md:6 '2026-05-31 — condensed from 1096-line accreted version (backup at
working-context.md.bak-2026-05-31-precleanup)'; ls output '-rw-r--r--@ 1 ray staff 153222 May 31 18:13 working-context.md.bak-2026-05-31-precleanup'. - Recommendation: No prune needed. Move working-context.md.bak-2026-05-31-precleanup into ~/.claude/state/archive/ to keep the top-level state dir to live files only.
8. [warn] working-context.md — model/effort section drift (action: fix)
- Claim: working-context.md's 'Effort / model' section states 'Opus 4.8 (1M context) is the saved default' and 'settings.json has no model/effort key (default lives in another store)' — both claims are now false: settings.json contains both keys ('model': 'claude-fable-5[1m]', 'effortLevel': 'xhigh') as of Jun 9 15:38. The file has not been updated since Jun 2 despite the model upgrade and the check-board gap both occurring after.
- Evidence: working-context.md:74 'Opus 4.8 (1M context) is the saved default and PERSISTS across
--resume/restart (verifiedclaude-opus-4-8[1m]). settings.json has no model/effort key (default lives in another store).' vs settings.json:249 '"effortLevel": "xhigh",' and settings.json:252 '"model": "claude-fable-5[1m]"'; ls output '-rw-r--r--@ 1 ray staff 22995 Jun 2 16:37 working-context.md'. - Recommendation: Rewrite working-context.md:73-75 to: '## Effort / model (updated 2026-06-09) — Fable 5 (
claude-fable-5[1m]) is the saved default in ~/.claude/settings.json (modelkey) witheffortLevel: xhigh; persists across restarts, no --model flag in the restart script (settings.json is the single source). ultracode = xhigh + standing authorization to autonomously author+run dynamic workflows when a task warrants (high bar, no workflow on trivial cron ticks).'
9. [warn] founder-energy.txt — dead signal (action: decide)
- Claim: founder-energy.txt has not been written in 25 days (content '2026-05-15|2|low', mtime May 15 11:48). The handoff handles the staleness correctly (default normal cadence) but two separate handoff bullets re-litigate the same missing signal every session, and a 25-day-dead capture mechanism suggests the energy-number ritual itself has lapsed rather than being merely late.
- Evidence: Command output: 'cat ~/.claude/state/founder-energy.txt' → '2026-05-15|2|low'; stat → 'May 15 11:48:32 2026'; ray-handoff.md:29 '
founder-energy.txtstale (May 15) → default normal cadence' and ray-handoff.md:33 'Energy number: he hasn't given today's 1-10 (sets queue depth).' - Recommendation: Founder decision needed: either (a) retire the energy-number mechanism — delete founder-energy.txt and both handoff bullets, hard-code normal cadence — or (b) recommit, adding the capture prompt to /morning-prep. Until decided, collapse to a single handoff line: 'Energy file stale since 2026-05-15 → default normal cadence; mechanism under review.'
10. [info] ray-handoff.md — missing Fable 5 operating notes for the seed (action: add)
- Claim: Beyond fixing the stale upgrade bullet, the handoff does not yet tell a fresh session anything about operating ON Fable 5: that 1M context does not repeal the >5KB subagent-routing rule (input is ~2x Opus price, so raw-reading long artifacts now costs double), and that ultracode-level autonomous workflow authorization is active with its self-limits.
- Evidence: ray-handoff.md:27 mentions Fable 5 facts only as upgrade-decision inputs ('1M-context default, $10/$50 = ~2x Opus base / ~2.5x effective, adaptive-thinking-always-on'); no operating guidance exists elsewhere in the 49-line file. Cost basis: settings.json:252 confirms the [1m] variant is what every fresh session now runs.
- Recommendation: Add two sentences to the rewritten Fable 5 bullet (per finding 1): 'The 1M window is headroom for long sessions, not license to raw-read large artifacts — CLAUDE.md rule 4 (>5KB → subagent) still applies and now saves 2x the dollars. effortLevel xhigh + ultracode workflow authorization are active; hold the high bar on autonomous workflow spawns.'
11. [warn] state dir hygiene — unbounded append log (action: remove)
- Claim: newsletter-audit-log.md is 4,136,009 bytes and still growing (modified Jun 9 12:33, hours before this audit). It is the largest non-database file in the state dir by 27x over the next markdown file and has no rotation; any session or subagent that naively reads it pays for 4.1MB of context.
- Evidence: ls output '-rw-r--r--@ 1 ray staff 4136009 Jun 9 12:33 newsletter-audit-log.md'; next-largest md is implementation-notes-DESIGN-md-build.md at 39,303 bytes; an 'archive' subdir exists ('drwxr-xr-x@ 34 ray staff 1088 May 31 04:14 archive').
- Recommendation: Rotate: move the current newsletter-audit-log.md to archive/newsletter-audit-log-through-2026-06-09.md and have /process-newsletter start a fresh log; add a size-triggered rotation (e.g., >500KB) to the skill so this never re-accretes. Same pass: move the dated one-offs (rdco-doctor-.json, eval-mine-.json, newsletter-audit-2026-05-11.json at 289,238 bytes, hq-phase*-status.md, youtube-watch-incident-2026-05-11.md) into archive/ — the top-level state dir currently holds 83 entries and should be live state only.
Verification
- finding 1 — "The handoff's newest 🔴 bullet describes the Fable 5 upgrade as unresolved ('founder leaning YES, awaiting his explicit do it', 'running on Opus 4.8 for now') bu…": NOT refuted (verified), confidence high. Reproduced all cited evidence. (1) /Users/ray/.claude/state/ray-handoff.md line 27 is the newest 🔴 bullet (under "Live as of 2026-06-09 ~15:35 ET") and reads exactly as cited: "Fable 5 upgrade (founder leaning YES, awaiting his explicit "do it")" ... "Founder kept Opus 4.8 in
/model2026-06-09 → running on Opus 4.8 for now"; handoff mtime Jun 09 15:35:59 2026. (2) /Users/ray/.claude/settings.json line 252 has top-level "model": "claude-fable-5[1m]" (verified via JSON parse, plus "effortLevel": "xhigh" at line 249); mtime Jun 09 15:38:35 2026 — ~2.5 min AFTER the handoff was written, confirming the bullet is stale. (3) This verifier session itself runs on claude-fable-5[1m], direct proof fresh sessions launch on Fable 5. (4) Restart script has no --model flag (settings.json governs the default) and the cited vault reference 2026-06-09-claude-fable-5-mythos-5-release.md exists. The claim holds: a fresh 4am session reading line 27 would wrongly treat the upgrade as pending. One nit in the proposed replacement text: it says "~15:45 ET" but settings.json mtime is 15:38:35, so "~15:38 ET" is more accurate. - finding 2 — "The handoff instructs a future session to 'add --model claude-fable-5 to the launch line (script ~line 68)'. This is no longer needed — the launch line has no -…": NOT refuted (verified), confidence high. All three cited pieces of evidence reproduce exactly. (1) /Users/ray/.claude/state/ray-handoff.md line 27 contains the TO EXECUTE instruction verbatim, telling a future session to add
--model claude-fable-5(bare, no [1m]) to the launch line at script ~line 68. (2) /Users/ray/.claude/scripts/claude-channels-restart.sh line 68 is exactly the cited send-keys launch line with no --model flag; grep confirms zero occurrences of --model anywhere in the script (the line-85 fallback launch also lacks it). (3) /Users/ray/.claude/settings.json line 252 is"model": "claude-fable-5[1m]". Supporting findings: file mtimes show the handoff was written 2026-06-09 15:35:59 and settings.json was modified 15:38:35 — the saved [1m] default postdates the handoff instruction, confirming staleness. The current session itself (launched via the no-flag script path) runs as claude-fable-5[1m], directly demonstrating that fresh sessions inherit the settings.json default. Claude Code precedence puts a CLI --model flag above settings.json, so executing the instruction as written would shadow the saved default with bareclaude-fable-5; the harness treatsclaude-fable-5andclaude-fable-5[1m]as distinct model-setting strings, with [1m] being the explicit 1M-context variant. One minor caveat: I could not independently measure what context window Claude Code grants for bareclaude-fable-5(the API model itself advertises 1M input per the model catalog), but the override-the-saved-default hazard and the staleness of the instruction are confirmed regardless. The recommendation to delete the TO EXECUTE instruction and add a do-not-add-a-flag guard is well-founded; note the same bullet text appears in the handoff's Open Threads section, so the fix should remove all occurrences, not just line 27. - finding 3 — "The handoff's Key paths section says the cron manifest has 16 jobs; the manifest contains exactly 14 active '
| ' lines, all well-formed. working…": NOT refuted (verified), confidence high. Reproduced all three pieces of evidence independently. (1) /Users/ray/.claude/state/ray-handoff.md line 41 reads exactly "- Cron manifest (16 jobs, single source of truth): ~/.claude/scripts/scheduled-jobs.txt". (2) The cited grep pipeline (strip blanks/comments, count ' | ' lines) returns 14 on /Users/ray/.claude/scripts/scheduled-jobs.txt; an inverse check found 0 non-comment/non-blank lines WITHOUT the ' | ' separator, so all 14 active lines are well-formed and the count method isn't undercounting. Direct read confirms 14 entries, first /vault-health (line 20), last /open-threads-check (line 71). (3) /Users/ray/.claude/state/working-context.md line 113 independently states "all 14scheduled-jobs.txtlines arrived" and "the 14 jobs are correctly armed via CronCreate". The 16-vs-14 drift in the handoff is real; editing line 41 to 14 or dropping the count is the correct fix.
Config (settings.json, hooks, MCP, permissions)
Harness config is fundamentally sound: the Fable 5 model pin is saved in settings.json and covers the 4am restart (the restart script launches bare claude with no --model flag, so the saved default applies), hooks are coherent and all referenced scripts exist, and the bridge-notes/cron-rearm continuity machinery is intact. The two real problems are (1) a plaintext 1Password service-account token in settings.local.json that is exported into every session and subprocess environment — combined with blanket Bash/Write/Edit allows and auto permission mode in an always-on agent that ingests untrusted web/newsletter content, this is the single worst exposure in the config; and (2) MCP sprawl: 28 configured servers, 6 of them permanently stuck in "Needs authentication," injecting an estimated ~420 deferred tool names plus 8+ instruction preambles (~8-10K tokens, estimate) into every session at Fable 5's ~2x input price. Disconnect candidates with no tie to the current objectives: heygen, stripe, blender, mobbin, Canva, and the four unauthenticated cloudflare plugin servers + vercel; xcodebuildmcp (Squarely), elevenlabs, monarch-money, whoop, and qmd earn their keep. One objective-relevant gap: the sql-guardrail hook never fires for the Snowflake snow CLI — the tool most relevant to the primary phData/Snowflake cert bet — because settings.json only matches snowsql/duckdb/psql.
1. [info] Model pin / 4am restart (action: keep)
- Claim: Fable 5 is pinned as the saved default in user settings, and the 4am restart script launches claude with no --model flag, so the saved default covers the restart; no script change is required for the session to come back on Fable 5.
- Evidence: /Users/ray/.claude/settings.json:252: "model": "claude-fable-5[1m]" — and /Users/ray/.claude/scripts/claude-channels-restart.sh:68: "$TMUX_BIN" send-keys -t "$SESSION_NAME" "claude --name $RESUME_NAME --channels $CHANNELS $CHROME_FLAG "$SEED_PROMPT"" Enter (no --model; retry path at line 85 also bare)
- Recommendation: None required. Optionally add
--model claude-fable-5[1m]to lines 68 and 85 as belt-and-suspenders against future settings drift, since the script also runsclaude update(line 43) before launch.
2. [info] Model config / cost (action: decide)
- Claim: effortLevel is pinned to "xhigh" in settings.json; this was set in the Opus era and its interaction with Fable 5's always-on adaptive thinking at ~2x input price has not been re-validated (note ~/.claude.json contains an 'unpinFable5LaunchEffort' key, indicating the harness manages launch-effort migration).
- Evidence: /Users/ray/.claude/settings.json:249: "effortLevel": "xhigh"; ~/.claude.json top-level keys output includes 'unpinOpus48LaunchEffort', 'unpinFable5LaunchEffort'
- Recommendation: Founder decision: confirm xhigh is still the intended default effort under Fable 5, or drop the explicit pin and let the model's adaptive thinking self-pace.
3. [critical] Secrets / settings.local.json (action: fix)
- Claim: A full 1Password service-account token (including embedded secretKey) is stored in plaintext in settings.local.json and injected as OP_SERVICE_ACCOUNT_TOKEN into the environment of every session and every Bash subprocess. Combined with blanket Bash allow + defaultMode auto in an always-on agent that ingests untrusted content (newsletters, WebFetch), a single successful prompt injection running
envexfiltrates the master key to every credential in the vault (Stripe, ElevenLabs, xAI, Alpaca). This violates the founder's own no-secrets-on-disk rule (feedback_no_secrets_on_disk: 1Password wrapper scripts, never secrets on disk). - Evidence: /Users/ray/.claude/settings.local.json:13-14: "env": { "OP_SERVICE_ACCOUNT_TOKEN": "ops_eyJzaWduSW5BZGRyZXNz..." } (full token literal in file; file mode -rw------- per ls output)
- Recommendation: Remove the token from settings env. Store it in macOS Keychain (
security add-generic-password) and have each MCP wrapper script fetch it at launch, so it exists only in the wrapper process env, never in the session-wide env or on disk in config.
4. [warn] Permissions allowlist (action: decide)
- Claim: settings.json grants blanket "Bash", "Write", and "Edit" with "defaultMode": "auto" — unrestricted shell, file-write, and file-edit with no prompts for the always-on agent. This is presumably the accepted autonomy tradeoff (per feedback_auto_mode_signal_to_noise), but it makes the PreToolUse guardrail hooks the ONLY control layer, and it amplifies the OP token exposure above.
- Evidence: /Users/ray/.claude/settings.json:19-21: "Bash", "Write", "Edit" (unscoped) and :74: "defaultMode": "auto"
- Recommendation: Founder confirms this is intentional. If keeping blanket Bash, the OP-token fix above becomes mandatory, and consider a PreToolUse deny-hook for obvious exfil patterns (e.g.
envpiped to curl/network).
5. [info] Permissions allowlist (action: remove)
- Claim: The 61-entry allow list contains ~25 entries made redundant by the blanket grants: every Bash(...) scoped entry (lines 48-72, including the duplicate ~/ vs /Users/ray pairs for xai-image.py, imessage-attach-copy.sh, asc-api.sh) is shadowed by blanket "Bash" (line 19); Write/Edit(/Users/ray/Projects/) (lines 40-41) are shadowed by blanket Write/Edit; Read(/tmp/) and Read(/private/tmp/**) (lines 34, 37) already cover the imessage-cache sub-paths (lines 35, 38).
- Evidence: /Users/ray/.claude/settings.json:19-21 (blanket Bash/Write/Edit) vs :40-41 (Write/Edit Projects), :48-72 (scoped Bash entries), :34-38 (Read /tmp pairs)
- Recommendation: Prune the shadowed entries — or, if the long-term plan is to narrow blanket Bash, keep them as the future scoped allowlist and delete blanket Bash instead. Either way the current mix is misleading about what is actually enforced.
6. [info] Permissions allowlist (action: remove)
- Claim: Stale entry: "mcp__firebase__*" matches no configured server — firebase runs as a plugin whose tool prefix is mcp__plugin_firebase_firebase__*, which is separately allowlisted on the next line.
- Evidence: /Users/ray/.claude/settings.json:44-45: "mcp__firebase__*", "mcp__plugin_firebase_firebase__*"; claude mcp list output shows only 'plugin:firebase:firebase'
- Recommendation: Delete "mcp__firebase__*" (line 44).
7. [info] Permissions allowlist (action: remove)
- Claim: settings.local.json duplicates a grant already in global settings (mcp__plugin_discord_discord__reply) alongside two WebFetch domain grants.
- Evidence: /Users/ray/.claude/settings.local.json:4: "mcp__plugin_discord_discord__reply" duplicates /Users/ray/.claude/settings.json:12
- Recommendation: Delete the duplicate from settings.local.json.
8. [info] Hooks — enumeration (action: keep)
- Claim: Five hook bindings are configured and all referenced scripts exist and are executable: PreCompact (matchers auto + manual) → write-bridge-notes.sh; SessionStart (compact) → read-bridge-notes.sh; SessionStart (startup, resume) → emit-cron-rearm.sh (audited by another seat — enumerated only); PreToolUse(Bash) → package-security-check.sh on 7 matchers (npm install/npm i/pip install/pip3 install/uv */brew install/brew upgrade) and sql-guardrail.sh on 3 matchers (snowsql/duckdb/psql).
- Evidence: /Users/ray/.claude/settings.json:76-207 (hooks block); ls output: -rwxr-xr-x .../write-bridge-notes.sh, read-bridge-notes.sh, emit-cron-rearm.sh, package-security-check.sh, sql-guardrail.sh all present
- Recommendation: Keep all. The PreCompact/SessionStart bridge-notes pair will fire far less often under Fable 5's 1M default context but costs nothing to retain.
9. [warn] Hooks — sql-guardrail coverage gap (action: add)
- Claim: The sql-guardrail script's internal pattern covers 'snow |mysql|sqlite3|sqlcmd|bq ' but the hook only invokes the script for snowsql/duckdb/psql commands, so destructive SQL via the modern Snowflake
snowCLI — the tool most relevant to the primary phData/Snowflake-cert bet — bypasses the guardrail entirely. - Evidence: /Users/ray/.claude/settings.json:187/193/199: "if": "Bash(snowsql)", "Bash(duckdb)", "Bash(psql)" vs /Users/ray/.claude/scripts/sql-guardrail.sh:17: SQL_CLI_PATTERN='(snowsql|snow |psql|mysql|sqlite3|duckdb|sqlcmd|bq )'
- Recommendation: Add PreToolUse entries with "if": "Bash(*snow *)" (and optionally *bq * / sqlite3) pointing at sql-guardrail.sh before Snowflake cert work ramps.
10. [warn] Hooks — sql-guardrail blocking risk (action: decide)
- Claim: sql-guardrail returns permissionDecision "ask" on destructive SQL, which raises a blocking prompt; during unattended cron operation this is the same failure class as the documented 2026-05-26 multi-hour outage from a blocking modal (feedback_no_blocking_modal_in_monitoring). duckdb is invoked by the daily graph-reingest pipeline, so an ingest path that ever issues DROP/TRUNCATE via the duckdb CLI would stall the loop until a human answers.
- Evidence: /Users/ray/.claude/scripts/sql-guardrail.sh:26: {"hookSpecificOutput":{..."permissionDecision":"ask","permissionDecisionReason":"Destructive SQL detected..."}}
- Recommendation: Founder decision: keep the ask-gate (safety) but verify graph-reingest's duckdb usage never matches the destructive pattern, or exempt the known-safe graph-db invocation path.
11. [info] Hooks — package-security-check (action: keep)
- Claim: The "Bash(uv *)" matcher fires the security-check script on every uv invocation (including uv run), but the script no-ops fast on non-install commands via its catch-all case, so the cost is one subprocess spawn per uv command, not a false block. pip is deliberately hard-blocked in favor of uv, and bare
brew upgradeis blocked. - Evidence: /Users/ray/.claude/settings.json:166: "if": "Bash(uv *)"; /Users/ray/.claude/scripts/package-security-check.sh:34-36: *) exit 0 ;; and :23-24 pip block, :40-43 bare brew upgrade block
- Recommendation: Optional: narrow the matcher to Bash(uv add *) / Bash(uv pip install *) to skip the no-op spawns. Low priority.
12. [info] MCP inventory (action: keep)
- Claim: 28 MCP servers are configured across five sources: 7 claude.ai connectors (Figma, Slack, Notion, Calendar, Gmail, Drive, Canva), 9 plugin servers (discord, imessage, vercel, playwright, firebase, 4x cloudflare + cloudflare-docs = 5 cloudflare), 5 user-scope in ~/.claude.json (monarch-money, blender, stripe, heygen, whoop), 4 in ~/.mcp.json project scope (qmd, xmcp, xcodebuildmcp, elevenlabs), and 1 project-specific (mobbin). claude-in-chrome (via the restart script's --chrome flag) and computer-use are harness built-ins, not in mcp list. 6 of 28 are stuck at '! Needs authentication': vercel, cloudflare-api, cloudflare-bindings, cloudflare-builds, cloudflare-observability, heygen.
- Evidence: claude mcp list output (28 entries, 6 showing '! Needs authentication'); ~/.claude.json mcpServers: monarch-money, blender, stripe, heygen, whoop; /Users/ray/.mcp.json:2-21: qmd, xmcp, xcodebuildmcp, elevenlabs; projects['/Users/ray'] -> ['mobbin']; claude-channels-restart.sh:8: CHROME_FLAG="--chrome"
- Recommendation: Use this map when pruning — disconnection point differs per source (claude.ai connector settings, plugin disable in enabledPlugins, ~/.claude.json edit, ~/.mcp.json edit).
13. [warn] MCP context overhead (action: remove)
- Claim: ESTIMATE: this session's system reminder enumerates ~420 deferred mcp__* tool names plus instruction preambles from 8+ servers (blender, claude-in-chrome, Figma, computer-use, discord, imessage, qmd, xcodebuildmcp visible; several KB each). Total fixed injection is roughly 25-35KB ≈ 8-10K tokens per session — paid at Fable 5's ~2x-Opus input price on every cache miss, including every 4am fresh restart. Pruning the disconnect candidates below (blender 46 tools, stripe 25, Canva 35, heygen 2, mobbin 2, plus 6 dead needs-auth servers) would cut the deferred-name list by ~25% and remove the largest single instruction preamble (blender).
- Evidence: Per-server deferred tool counts from this session's system-reminder list: blender 46, firebase 47, Canva 35, xcodebuildmcp 29, claude-in-chrome 25, elevenlabs 25, stripe 25, playwright 24, computer-use 24, monarch-money 19, Figma 17, xmcp 15, Notion 14, Slack 13, Gmail 12, cloudflare 10, others <10 (sum ≈ 419); MCP instruction blocks for 8 servers visible in session preamble
- Recommendation: Prune disconnect candidates below; token figures are estimates and should be re-measured with /context after pruning.
14. [warn] MCP sprawl — heygen (action: remove)
- Claim: heygen is configured at user scope but is unauthenticated ('! Needs authentication'), exposes only authenticate/complete_authentication tools, and has no skill, memory, or objective referencing it. It is pure dead weight.
- Evidence: claude mcp list: "heygen: https://mcp.heygen.com/mcp/v1/ (HTTP) - ! Needs authentication"; ~/.claude.json mcpServers includes heygen; deferred list shows only mcp__heygen__authenticate, mcp__heygen__complete_authentication
- Recommendation: Remove from ~/.claude.json mcpServers (founder confirms).
15. [warn] MCP sprawl — stripe (action: remove)
- Claim: stripe is connected (25 deferred tools, wrapper at /Users/ray/Projects/stripe-mcp-wrapper) but no current revenue surface uses Stripe: Squarely monetizes via the App Store, Sanity Check is a newsletter, and the MAC info-product is not live. No objective requires live Stripe tooling.
- Evidence: claude mcp list: "stripe: bash /Users/ray/Projects/stripe-mcp-wrapper/start.sh - ✔ Connected"; ~/.claude.json mcpServers includes stripe; deferred list shows 25 mcp__stripe__* tools including write-capable cancel_subscription/create_refund/stripe_api_write
- Recommendation: Disconnect (founder confirms); reconnect when MAC or another Stripe-billed surface ships. Write-capable payment tools in an always-on agent with no active use is risk without benefit.
16. [warn] MCP sprawl — blender (action: remove)
- Claim: blender is connected and is the single largest tool surface among side-bet servers (46 deferred tools plus the longest instruction preamble). Its only use is Ray-mascot 3D work (blender/blender-character skills) — a design side-task with no tie to the phData-primary objective, and the ray-mascot-anim pipeline uses Kling image-to-video rather than Blender.
- Evidence: claude mcp list: "blender: uv --directory /Users/ray/blender_mcp/mcp run blender-mcp - ✔ Connected"; 46 mcp__blender__* names in deferred list; blender MCP instruction block present in session preamble; ray-mascot-anim skill description: "fires a Kling 2.1 image-to-video render"
- Recommendation: Disconnect by default (founder confirms); re-add to ~/.claude.json on the rare day mascot 3D work is queued. Biggest single context win available.
17. [warn] MCP sprawl — mobbin (action: remove)
- Claim: mobbin is connected with 2 search tools (design-inspiration browsing); no skill, memory, or current objective references it. Overhead is small but it has no plausible recent COO use.
- Evidence: claude mcp list: "mobbin: https://api.mobbin.com/mcp (HTTP) - ✔ Connected"; ~/.claude.json projects['/Users/ray'] -> ['mobbin']; deferred list: mcp__mobbin__search_flows, mcp__mobbin__search_screens
- Recommendation: Disconnect (founder confirms); trivial to re-add for a design-research sprint.
18. [info] MCP sprawl — keepers (xcodebuildmcp, elevenlabs, computer-use) (action: keep)
- Claim: xcodebuildmcp (29 tools) is justified by the active Squarely iOS bet — the squarely-deploy skill and the asc-api.sh TestFlight allowlist entries evidence a live deployment pipeline. elevenlabs shows actual usage evidence (send-voice-message.py allowlisted; ElevenLabs named in the API-cost memory). computer-use is a harness built-in (absent from claude mcp list) so it is not disconnectable via MCP config, and native-app control on the always-on Mac Mini is a plausible COO capability despite its ~4.5KB instruction preamble.
- Evidence: /Users/ray/.claude/settings.json:43 mcp__xcodebuildmcp__*, :71-72 asc-api.sh betaGroups entries, :47 mcp__elevenlabs__*, :53 Bash(~/.claude/scripts/send-voice-message.py ); claude mcp list output contains no computer-use entry while mcp__computer-use__ tools appear in the deferred list
- Recommendation: Keep all three.
19. [warn] MCP sprawl — dead needs-auth plugin servers (vercel, cloudflare x4) and Canva (action: decide)
- Claim: vercel and four cloudflare plugin servers (api, bindings, builds, observability) have sat in 'Needs authentication' — never usable — while the cloudflare skill itself directs work through the cloudflare-api.sh wrapper and wrangler instead of MCP. Canva (claude.ai connector, 35 deferred tools) has no skill or memory referencing it; RDCO design work runs through its own HTML/CSS design-system skills. All six-plus-one inject config/health-check or tool-name overhead with no use.
- Evidence: claude mcp list: vercel, cloudflare-api, cloudflare-bindings, cloudflare-builds, cloudflare-observability all '! Needs authentication'; cloudflare skill description: "Use the ~/.claude/scripts/cloudflare-api.sh wrapper for the API and wrangler ... for Pages/Workers/R2"; deferred list shows 35 mcp__claude_ai_Canva__* tools
- Recommendation: Founder decides: either authenticate vercel/cloudflare MCP servers if MCP-mediated deploys are wanted, or disable the vercel plugin's MCP and keep cloudflare for skills only (cloudflare-docs can stay); disconnect the Canva connector until a Canva workflow actually exists.
20. [warn] MCP trust posture (action: fix)
- Claim: settings.local.json sets enableAllProjectMcpServers: true, which auto-trusts any .mcp.json found in any project directory — a cloned third-party repo carrying a malicious .mcp.json would auto-load its server. This contradicts the founder's security-review-before-install default for MCP/plugins (feedback_mcp_install_security_review_default).
- Evidence: /Users/ray/.claude/settings.local.json:12: "enableAllProjectMcpServers": true
- Recommendation: Set to false and enumerate trusted project servers explicitly via enabledMcpjsonServers (qmd, xmcp, xcodebuildmcp, elevenlabs are the known ones in /Users/ray/.mcp.json).
Verification
- finding 3 — "A full 1Password service-account token (including embedded secretKey) is stored in plaintext in settings.local.json and injected as OP_SERVICE_ACCOUNT_TOKEN int…": NOT refuted (verified), confidence high. Every element of the cited evidence reproduced independently.
TOKEN LITERAL: /Users/ray/.claude/settings.local.json lines 13-14 contain exactly: "env": { "OP_SERVICE_ACCOUNT_TOKEN": "ops_eyJzaWduSW5BZGRyZXNz..." } as a full plaintext literal (the entire ops_ token, not a reference or wrapper call). Confirmed by Read.
EMBEDDED secretKey: I base64-decoded the ops_ payload. The JSON contains "secretKey":"A3-5ZZPK8-Z3NS44-DJ4VJ-HKTMK-ADEHJ-4TMGR" AND a "muk" (master unlock key: A256GCM key material) AND "srpX". This is worse than the claim states — not just the secretKey but the master unlock key is embedded, i.e. full cryptographic material for the service account (email ixkvevtynzdze@1passwordserviceaccounts.com).
FILE MODE: ls shows -rw-------@ (0600, owner-only). Matches the claimed "-rw-------". Note this 0600 limits other LOCAL users from reading the file, but does NOT mitigate the stated threat (the agent's own process holds the token in env, so a prompt-injected
envdumps it regardless of file perms).ENV-INJECTION + BLANKET BASH + AUTO MODE (verified the broader threat model, not just the two cited lines): /Users/ray/.claude/settings.json has permissions.defaultMode = "auto" and the allow list's first entry is a bare "Bash" (blanket allow for ALL bash commands). So
envwould run with no prompt. Claude Code's settingsenvblock injects the var into the session and spawned-subprocess environments, so OP_SERVICE_ACCOUNT_TOKEN is reachable by any Bash child. The injection chain (untrusted-content ingest -> injection runsenv-> token exfiltrated) is mechanically sound.RULE CONTRADICTION: feedback_no_secrets_on_disk (per MEMORY.md) mandates 1Password wrapper scripts and "never secrets on disk." A plaintext 1Password service-account token in a config file is a direct contradiction; the irony is sharp because the on-disk secret IS the 1Password master credential that wrapper scripts are supposed to fetch at runtime.
One scoping caveat (does not refute): the claim that this is "the master key to every credential (Stripe, ElevenLabs, xAI, Alpaca)" depends on which vaults this service account is granted read access to — I did not enumerate vault scope, so the specific blast radius is asserted, not verified. But the token unambiguously grants whatever that service account can read, and the embedded muk+secretKey are full account credentials. The core security finding stands. Recommendation (move to Keychain, fetch per-wrapper) is the correct remediation.
- finding 20 — "settings.local.json sets enableAllProjectMcpServers: true, which auto-trusts any .mcp.json found in any project directory — a cloned third-party repo carrying a…": NOT refuted (verified), confidence high. CLAIM HOLDS — not refuted. Evidence reproduced exactly and corroborated three ways.
Cited line verbatim: /Users/ray/.claude/settings.local.json line 12 reads exactly
"enableAllProjectMcpServers": true. Confirmed by both Read and grep -n. (enabledMcpjsonServers there is just ["qmd"]; permissions.allow is unrelated.)Authoritative semantics from the Claude Code binary (v2.1.170, /Users/ray/.local/share/claude/versions/2.1.170). The settings schema literally describes the flag: enableAllProjectMcpServers ... describe("Whether to automatically approve all MCP servers in the project"). The approval-resolution function returns "approved" when
_?.enableAllProjectMcpServersis set, otherwise "pending". So with the flag true, ANY project .mcp.json server resolves to approved instead of prompting — exactly the auto-trust the claim describes, and it does contradict the security-review-before-install default.Empirical: I planted a hostile .mcp.json (server command
bash -c "touch MARKER; exec cat") in a fresh project dir and ranclaude -p. The MARKER file was created = the malicious server was spawned with zero approval prompt. Cleaned up all test dirs afterward.
The recommendation (set false + enumerate trusted servers via enabledMcpjsonServers) is sound and the four named servers match /Users/ray/.mcp.json (qmd, xmcp, xcodebuildmcp, elevenlabs).
IMPORTANT CAVEAT that makes the concern WORSE, not weaker: in headless -p mode the malicious server still spawned even when I forced enableAllProjectMcpServers:false (and enabledMcpjsonServers:[]) at project-local AND at the highest-precedence --settings flag level, in clean never-run directories. Merely loading a server executes its command, and print/non-interactive mode appears to load project .mcp.json servers regardless of the approval flag. This Mac Mini agent runs headless. So flipping the flag to false is necessary and correct for the interactive guard, but may be INSUFFICIENT to close the headless attack surface — the safer mitigation is to not let untrusted .mcp.json files exist in any directory the agent will cd into / run in (e.g., vet cloned repos before working in them, or strip their .mcp.json). I did not find a setting that disables project .mcp.json loading in headless mode during this audit.
Model facts (Fable 5 pricing, caching, economics)
Fable 5 facts are well-pinned by two mutually consistent sources read this session: the founder-verified vault release note (2026-06-09) and the bundled claude-api skill (pricing table cached 2026-05-26, already lists claude-fable-5). Headline economics: $10/$50 per Mtok (exactly 2x Opus 4.8's $5/$25), 1M context by default with no long-context premium and no [1m] beta toggle, cache read $1/M (0.1x), cache writes $12.50/M (5-min, 1.25x) and $20/M (1-hr, 2x), and a tokenizer that inflates the same text ~30% — so effective cost vs Opus 4.8 is ~2.5-2.6x, not 2x. The dominant cost risk for this always-on harness is cache-miss cron fires at large parent context: a 48x/day all-miss cron at 150k tokens costs $72-90/day ($2,160-2,700/month) on Fable 5, versus $90-112.50/month if a shell pre-check gates model fires down to ~2/day — a ~96% reduction that dwarfs any model-choice decision. Adaptive thinking cannot be disabled on Fable 5 (explicit disabled returns 400), so every fire also buys thinking tokens at $50/M output; effort is the only spend lever. Subagent tiering from the Fable 5 parent should default to Haiku 4.5 (10x cheaper both directions) for extraction/classification seats and Sonnet 4.6 (3.3x cheaper) for reasoning/critic seats, reserving inherit for founder-facing judgment.
1. [info] fable5-facts/model-ids-and-base-pricing (action: keep)
- Claim: Canonical model IDs and base prices: claude-fable-5 $10/M input, $50/M output, 1M context, 128K max output; claude-opus-4-8 $5/$25, 1M; claude-sonnet-4-6 $3/$15, 1M (64K max output); claude-haiku-4-5 $1/$5, 200K context (64K max output). Fable 5 is exactly 2x Opus 4.8 on both input and output. Batch API is 50% off (Fable 5 batch $5/$25).
- Evidence: claude-api skill SKILL.md 'Current Models (cached: 2026-05-26)' table: 'claude-fable-5 | 1M | $10.00 | $50.00 / claude-opus-4-8 | 1M | $5.00 | $25.00 / claude-sonnet-4-6 | 1M | $3.00 | $15.00 / claude-haiku-4-5 | 200K | $1.00 | $5.00'; shared/models.md: Sonnet 4.6 max output 64K, Haiku 4.5 64K, Fable 5/Opus 4.8 128K. Cross-confirmed by /Users/ray/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md:22 'Pricing: $10/M input, $50/M output (~2x Opus 4.8's $5/$25)... Batch $5/$25' and :21 'Output: 128k max (300k via output-300k-2026-03-24 batch beta)'. Batches: python/claude-api/batches.md '50% cost reduction on all token usage'.
- Recommendation: none
2. [info] fable5-facts/cache-economics (action: keep)
- Claim: Cache economics: reads ~0.1x base input, writes 1.25x (5-min TTL) or 2x (1-hr TTL). Per model: Fable 5 read $1.00/M, write $12.50/M (5m) / $20/M (1h); Opus 4.8 read $0.50, write $6.25/$10; Sonnet 4.6 read $0.30, write $3.75/$6; Haiku 4.5 read $0.10, write $1.25/$2. Minimum cacheable prefix is 2048 tokens on Fable 5 and Sonnet 4.6 but 4096 on Opus 4.8 and Haiku 4.5. 5-min TTL break-even is 2 requests (1.25x + 0.1x = 1.35x vs 2x uncached); 1-hr TTL needs >=3.
- Evidence: shared/prompt-caching.md §API reference: 'Cache reads cost ~0.1× base input price. Cache writes cost 1.25× for 5-minute TTL, 2× for 1-hour TTL... with 5-minute TTL, two requests break even (1.25× + 0.1× = 1.35× vs 2× uncached)' and minimum-prefix table 'Opus 4.8, Opus 4.7, Opus 4.6, Opus 4.5, Haiku 4.5 | 4096 tokens; Fable 5, Sonnet 4.6 | 2048 tokens'. Fable 5 exact dollars: /Users/ray/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md:22 'Cache read $1/M, writes $12.50 (5m) / $20 (1h)'. Other models derived by multiplier from base prices in the same skill table.
- Recommendation: none
3. [info] fable5-facts/1m-context-terms (action: keep)
- Claim: Fable 5's 1M context is the default with no separate beta toggle and no long-context premium — full 1M at standard $10/$50. This removes the Opus 4.8-era [1m] opt-in. The harness is currently configured with model string 'claude-fable-5[1m]', which per the release notes is a vestigial suffix (the session runs, so it resolves, but the [1m] toggle is no longer a documented requirement).
- Evidence: /Users/ray/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md:20 'Context window: 1M tokens by default — no separate [1m]-style beta toggle (cleaner than Opus 4.8's opt-in)' and :22 'No long-context premium — full 1M at standard pricing'. Current harness env: system prompt states 'The exact model ID is claude-fable-5[1m]'. shared/models.md confirms 'Claude Fable 5 | claude-fable-5 | 1M | 128K | Active'.
- Recommendation: Low priority: founder may simplify the Claude Code model setting from claude-fable-5[1m] to claude-fable-5 next time config is touched; verify the session still reports 1M context after the change. Not urgent — current string works.
4. [info] fable5-facts/tokenizer-inflation (action: keep)
- Claim: Fable 5 uses the Opus-4.7-era tokenizer and produces ~30% more tokens for the same text. Effective cost vs Opus 4.8 for identical content is therefore ~2.5-2.6x (2x price x ~1.3 token inflation), not 2x. This also means cross-model comparisons at a fixed token count (like the cost table below) understate Fable's real-world premium, and all token-count-based thresholds (compaction triggers, the >5KB subagent-routing heuristic's effective context impact) shift ~30% earlier in byte terms.
- Evidence: /Users/ray/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md:20 'Tokenizer note: Opus-4.7-era tokenizer, ~30% more tokens for the same text' and :28 'Cost is ~2x base / ~2.5x effective (tokenizer inflation)'. Arithmetic: 2.0 x 1.3 = 2.6x upper bound on input for identical bytes.
- Recommendation: none
5. [info] fable5-facts/adaptive-thinking-always-on (action: keep)
- Claim: On Fable 5, adaptive thinking is effectively always available and cannot be switched off: thinking unset = adaptive per the release notes, and an explicit thinking:{type:"disabled"} returns a 400 (unlike Opus 4.8 where disabled is accepted). budget_tokens and temperature/top_p/top_k also 400. Thinking text is omitted from responses by default (display defaults to 'omitted') but thinking tokens are still generated and billed as output at $50/M. For an always-on agent the per-turn spend lever is the effort parameter (low/medium/high/xhigh/max; xhigh is the Claude Code default, 'low' recommended for subagents/simple tasks).
- Evidence: /Users/ray/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md:23 'adaptive thinking is always on (thinking unset = adaptive; thinking:{type:"disabled"} is NOT supported — a migration difference). Raw thinking never returned (thinking.display defaults omitted)'. claude-api skill shared/error-codes.md: 'Fable 5 only: an explicit thinking: {type: "disabled"} returns 400 (it is accepted on Opus 4.8/4.7). Omit the thinking param entirely instead.' SKILL.md §Thinking & Effort: 'xhigh... the default in Claude Code' and 'use low for subagents or simple tasks'.
- Recommendation: none
6. [info] cost-model/single-cache-miss-turn (action: keep)
- Claim: Input-side cost of one fully-uncached (cache-miss) turn, base input rate, with the 1.25x 5-min cache-write figure in parentheses (Claude Code writes cache on every miss, so the parenthesized number is the realistic one). 50k ctx: Fable $0.50 ($0.625), Opus 4.8 $0.25 ($0.3125), Sonnet 4.6 $0.15 ($0.1875), Haiku 4.5 $0.05 ($0.0625). 150k ctx: Fable $1.50 ($1.875), Opus $0.75 ($0.9375), Sonnet $0.45 ($0.5625), Haiku $0.15 ($0.1875). 400k ctx: Fable $4.00 ($5.00), Opus $2.00 ($2.50), Sonnet $1.20 ($1.50), Haiku N/A — exceeds its 200K window. Output and thinking tokens are additional ($50/M on Fable).
- Evidence: Arithmetic from grounded prices (claude-api SKILL.md model table; shared/prompt-caching.md 1.25x write multiplier): 50k=0.05 Mtok: 0.05x$10=$0.50, x1.25=$0.625; 0.05x$5=$0.25; 0.05x$3=$0.15; 0.05x$1=$0.05. 150k=0.15 Mtok: 0.15x$10=$1.50, x1.25=$1.875; 0.15x$5=$0.75; 0.15x$3=$0.45; 0.15x$1=$0.15. 400k=0.4 Mtok: 0.4x$10=$4.00, x1.25=$5.00; 0.4x$5=$2.00; 0.4x$3=$1.20. Haiku 400k impossible per SKILL.md table 'claude-haiku-4-5 | 200K'.
- Recommendation: none
7. [warn] cost-model/cron-cache-miss-exposure (action: fix)
- Claim: A cron firing 48x/day where every fire is a cache miss at 150k context costs on Fable 5: $72.00/day base input ($90.00/day counting the 1.25x cache-write premium) = $2,160-$2,700/month (30d), output/thinking tokens extra. The same job at 4x/day: $6.00-$7.50/day = $180-$225/month. With a shell pre-check so the model fires only ~2x/day: $3.00-$3.75/day = $90-$112.50/month — a ~96% reduction vs 48x. For scale, the identical 48x job costs $1,080-$1,350/mo on Opus 4.8, $648-$810/mo on Sonnet 4.6, $216-$270/mo on Haiku 4.5. The harness has at least one live 15-min cron (open-threads-check, which at 15-min cadence exceeds the 5-min cache TTL and is all-miss by construction), so this exposure is real, not hypothetical — its per-fire context size determines actual burn.
- Evidence: Arithmetic: per-fire 150k miss on Fable = 0.15 Mtok x $10 = $1.50 (x1.25 write = $1.875). 48 x $1.50 = $72.00/day; x30 = $2,160/mo. 48 x $1.875 = $90.00/day; x30 = $2,700/mo. 4 x $1.50..$1.875 = $6.00..$7.50/day -> $180..$225/mo. 2 x $1.50..$1.875 = $3.00..$3.75/day -> $90..$112.50/mo. Comparators: 48 x (0.15x$5)=36..45/day -> $1,080..$1,350/mo; 48 x (0.15x$3)=$21.60..$27/day -> $648..$810/mo; 48 x (0.15x$1)=$7.20..$9/day -> $216..$270/mo. TTL basis: shared/prompt-caching.md '5-minute TTL (default)'. Live instance: available-skills list, 'open-threads-check: Cron-driven parking check... Fires every 15min'.
- Recommendation: Adopt the gate-then-fire pattern for all recurring crons on Fable 5: a zero-cost shell/script pre-check (e.g. 'any unanswered Ray-asks older than 60min in the channel DB?') decides whether the model is invoked at all; target ~2 model fires/day average for checks that are usually no-ops. Also audit each cron's per-fire context — cron seats should run minimal context (or dispatch to a Haiku subagent), never inherit full parent context. Secondary option to evaluate: 1-hr-TTL cache_control on a stable cron prefix (write $20/M vs all-miss rewrites), but verify TTL-refresh-on-read behavior against live docs before relying on it — not asserted here because the sources read this session don't specify it.
8. [warn] cost-model/subagent-model-tiering-policy (action: add)
- Claim: No codified model-tiering policy exists for subagent dispatch, and the price ratios make one mandatory now: Fable 5 : Sonnet 4.6 : Haiku 4.5 = 10 : 3 : 1 on input ($10/$3/$1) and 10 : 3 : 1 on output ($50/$15/$5). Every subagent that silently inherits the parent model costs 10x what a Haiku seat would. Proposed policy — Haiku 4.5 (10x cheaper, 200K ctx cap): mechanical extraction/summarization seats, i.e. exactly the CLAUDE.md rule-4 '>5KB artifact' subagent routes (newsletter/email body extraction, transcript summarization, log/output parsing, classification steps in the investing pipeline); Sonnet 4.6 (3.3x cheaper, 1M ctx): reasoning-but-bounded seats — fresh-eyes critics (design-critic, video-critic, verify-* gates), the 4 pipeline seats (spec/test/code/critic), research-brief synthesis, draft review; inherit Fable 5: only seats whose output goes directly into founder-facing judgment — investing thesis synthesis, strategic verification final pass, production-mode final review. Opus 4.8 is not needed as a subagent tier (Sonnet covers mid-reasoning at 60% of Opus price). Pair with effort: 'low' for Haiku/Sonnet utility seats.
- Evidence: Price ratios from claude-api SKILL.md model table ($10/$50 vs $3/$15 vs $1/$5): 10/1=10x, 10/3=3.33x input; 50/5=10x, 50/15=3.33x output. Precedent in the same skill, shared/agent-design.md §Caching for Agents: 'Spawn a subagent with the cheaper model for the sub-task; keep the main loop on one model. Claude Code's Explore subagents use Haiku this way.' Haiku context cap: SKILL.md table 'claude-haiku-4-5 | 200K'. The >5KB routing rule: /Users/ray/CLAUDE.md hard rule 4 'any single artifact >5KB should be processed by a subagent'. Vault already endorses selective tiering: /Users/ray/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md:30 '$10/$50 is steep for high-volume classification — keep Haiku/Sonnet there; reserve Fable 5 for the hardest thesis-synthesis steps only.'
- Recommendation: Add a 'Subagent model tiering' section to CLAUDE.md (or a dispatch SOP) mapping seat types to haiku/sonnet/inherit as above, and make model an explicit parameter in every Task/subagent dispatch rather than defaulting to inherit. Caveat for Haiku seats: 200K context cap and (per prompt-caching.md) a 4096-token minimum cacheable prefix.
9. [info] cost-model/batch-api-for-offline-pipelines (action: decide)
- Claim: The Batches API gives 50% off all token usage (Fable 5 batch $5/$25; Haiku batch $0.50/$2.50) with most batches completing within 1 hour. This is unusable for the interactive Claude Code session but applicable to standalone non-latency-sensitive pipeline scripts (investing classifiers, bulk vault re-processing, 13F/PTR diff classification).
- Evidence: python/claude-api/batches.md (claude-api skill): 'processes Messages API requests asynchronously at 50% of standard prices... Most batches complete within 1 hour; maximum 24 hours'. Fable batch prices: /Users/ray/rdco-vault/06-reference/2026-06-09-claude-fable-5-mythos-5-release.md:22 'Batch $5/$25'.
- Recommendation: Founder decision: when any standalone API-calling pipeline script is next built or revised (e.g. Markov phase-tracker classification steps), default it to Haiku/Sonnet via the Batches API rather than synchronous calls — compounds the tiering discount (Haiku batch is 20x cheaper than synchronous Fable per input token).
Verification
- finding 7 — "A cron firing 48x/day where every fire is a cache miss at 150k context costs on Fable 5: $72.00/day base input ($90.00/day counting the 1.25x cache-write premiu…": NOT refuted (verified), confidence high. Reproduced all cited evidence independently. (1) Pricing: claude-api skill Current Models table (cached 2026-05-26) confirms Fable 5 $10.00/MTok input, Opus 4.8 $5.00, Sonnet 4.6 $3.00, Haiku 4.5 $1.00. (2) shared/prompt-caching.md confirms verbatim '5-minute TTL (default)' and 'Cache writes cost 1.25× for 5-minute TTL, 2× for 1-hour TTL' (so 1-hr write = $20/M on Fable). (3) Arithmetic recomputed exactly: $1.50/$1.875 per 150k fire; 48x = $72.00/$90.00 per day = $2,160/$2,700 per 30d month; 4x = $180-$225/mo; 2x = $90-$112.50/mo; reduction 1-3/72 = 95.8% ≈ 96%; comparators $1,080-$1,350 (Opus), $648-$810 (Sonnet), $216-$270 (Haiku) all exact. (4) Live cron confirmed in four places: skills list description ('Fires every 15min'), /Users/ray/.claude/skills/open-threads-check/SKILL.md, /Users/ray/.claude/scripts/scheduled-jobs.txt line 71 ('*/15 9-20 * * * | /open-threads-check'), and an armed CronList entry — and */15 over hours 9-20 is exactly 48 fires/day, matching the claim's 48x figure. 15-min spacing exceeds the 5-min TTL, so all-miss-by-construction holds even if reads refresh TTL. Minor non-refuting nits: the 1.25x premium applies only to cache-written tokens (claim's full-150k treatment is the stated worst case, presented as a range); the doc actually implies TTL-refresh-on-read ('requests more often than every 5 minutes keep the cache warm on their own'), so the recommendation's caution there is conservative but not wrong; the 150k per-fire context for open-threads-check is hypothetical exposure, which the claim itself flags.
Run stats
23 agents, ~2.63M subagent tokens, 237 tool uses, ~15 min wall clock.