AIOS · M2 · host TopBook-Pro · uid 502
Eleven diagnostic tools, three staged production defects, and every published number re-measured from scratch. Three rounds of inflated figures are corrected below. The corrections section is the part worth your time.
If ~/.claude/settings.json were broken, nothing else on this page would
matter. It is not broken.
Valid JSON. 4,308 bytes on disk, 2,951 minified. Four PreToolUse:Bash hooks in order:
pre-bash-guard, path-guard, syntax guard-bash, block-cue-hook. All sixteen files referenced
across the whole hook chain are present on disk. Eight timestamped backups sit beside it,
oldest 2026-05-04. ~/CLAUDE.md is intact at 9,523 bytes and still carries the
agent-live block at line 101 and the aios-doctor block at line 112.
python3 -c "import json;d=json.load(open('$HOME/.claude/settings.json'));print(len(json.dumps(d)))"
Reachability counted against four places a tool can actually be invoked from: CLAUDE.md, settings.json, a LaunchAgent, or aios-doctor.sh.
| Tool | CLAUDE.md | settings.json | LaunchAgent | aios-doctor | Verdict |
|---|---|---|---|---|---|
| aios-doctor.sh | yes | no | no | yes | reachable |
| agent-live.sh | yes | no | no | yes | reachable |
| block-cue-hook.py | no | yes | no | no | automatic |
| block-cue-staleness.py | no | yes | no | yes | automatic |
| block-cue-index.py | no | yes | no | yes | reachable |
| agent-ledger.sh | no | no | no | yes | manual |
| agent-run-ledger.py | no | no | no | yes | manual |
| skill-doctor.py | no | no | no | yes | manual |
| comms-map.py | no | no | no | yes | manual |
| memory-doctor.py | no | no | no | yes | manual |
| block-cue-bench.py | no | no | no | no | orphan |
Replaces an ssh to the box you are already sitting on (agent-check.sh at 71.6s
for 1,615 undated rows), ls comms/outputs (103,603 bytes of bare filenames into
context), and reading LaunchAgent plists by hand. It writes nothing except memory-doctor
refreshing its own proposed-index file, and it refuses to forward any writing flag.
bash ~/AI_OS/ops/scripts/aios-doctor.sh # quick, 2.9-5.0s
bash ~/AI_OS/ops/scripts/aios-doctor.sh full # every check, ~5.4s
bash ~/AI_OS/ops/scripts/aios-doctor.sh list # the tool table
Two of eleven. These fire on their own and were observed firing during this audit.
Matches every Bash command against the compiled ICM wall library and injects at most two already-climbed blocks as advice. Never denies, never writes, never shells out, fails open on any exception.
python3 ops/scripts/block-cue-hook.py --explain "some command text"
Verified by observation, not by claim: it injected B15 and B104 advisories into two of this session's own Bash calls unprompted. One of those two was relevant, one was noise. Measured noise floor is 8.6% of real commands at a 1,200-command sample.
Compares the index's stored source hash against icm/blocks.json by reading the index head, not by parsing 115KB. Chains into a rebuild on mismatch.
python3 ops/scripts/block-cue-staleness.py
0.02s measured. Currently FRESH: index and blocks.json both at sha 7e4f14f9657c, both at 128 blocks. The chain has fired for real once, taking the index from 124 to 128 blocks with nobody typing anything. This is the only self-healing loop the three rounds produced.
Six tools, all reachable through the doctor, none of them self-starting.
Which subagents actually moved, dated and sorted. The old agent-check.sh was slow because the observer LaunchAgent re-registers long-dead subagents every minute, so a May corpse rendered identically to a live agent.
~/AI_OS/ops/scripts/agent-live.sh --since 24h
3.08s and 4.97s over 2,081 sidecars tonight, against a 71.6s baseline that is itself getting slower. Quote it as 3-5s warm and 6-7s on the first run of the day, never as "under 5 seconds" — the first run has never met that.
One row per installed plist, with verdict, exit code, schedule and log age, plus an overlay coverage audit and a stop-criteria section.
bash ops/scripts/agent-ledger.sh
RED 11 | AMBER 11 | GREEN 11 across all 33 plists. It found RED C on its own before any human did: "mailer-guard.sh — SILENT DEATH (0 tg/notify refs): it can take a live system down and tell nobody." But its wake-count column prints ~1,033,815 no-op wakes for screen-audit-capture, computed as plist age over the declared 5s interval. The live counter says 54,588. That column overstates by 18.9x and is the source of every inflated wake figure in this project.
Separates the three skill tiers so the token bill is the injected tier only, and scores each skill against real usage evidence from transcripts.
python3 ops/scripts/skill-doctor.py cost
8,344 tokens injected per session across 144 loadable skills; 5,420 of those (65%) belong to 124 skills with zero usage evidence. The read-only tier adds 4,849 tokens of findability cost that never reaches a system prompt. Never blend the tiers — the blend reads 13,193 tokens and overstates the real bill by 58%.
Lints the memory store that seeds every session: orphans, dead homes, broken wiki-links, and a proposed MEMORY.md index block.
python3 ops/scripts/memory-doctor.py all
335 fact files, 140 true orphans at 384,721 bytes and 41% of the store, 53 of them hard-isolated. The orphan histogram is live drift, not a legacy backlog: 51 in July, 46 in August, 12 in September. It has now reported 140 orphans three times and nothing has been actioned once. Output is a paste-by-hand block.
A bounded view of a tree that costs 26k tokens to list. Reads from a manifest, never from the directory.
python3 ops/scripts/comms-map.py digest
python3 ops/scripts/comms-map.py links
2,861 citations, 444 dead (15.5%), splitting 48 repairable / 122 ambiguous / 274 with no candidate. Seven hours ago the same tool against the same unrebuilt manifest read 517 dead. This round's own file creation healed 73 citations. Treat the dead count as a moving number, not a score.
Subagent run accounting against a stable key rather than exact call ids.
python3 ops/scripts/agent-run-ledger.py --stalls --older-than 15m
19 unmatched starts in the window, every one labelled SYNTHETIC harness row and most tagged as the known hash-break artifact, plus 23 older than 7d from pre-repair log damage. The stable key leaves 42 dangling where exact-call_id would have called 82.
The one writer in the block-cue family. It was stuck at 120 blocks because the collision rule was inverted: every rebuild diverted to a sidecar the hook never loaded, so the index silently stopped tracking icm/blocks.json.
python3 ops/scripts/block-cue-index.py
The index now matches icm/blocks.json exactly, 128 blocks and sha 7e4f14f9657c on both sides. But measured on the tool's own eval set, the stale 120-block index scored 7/8 on the must-fire controls and the live 128-block index also scores 7/8. Noise floor identical to the command at both 500 and 1,200 samples. The eight added blocks fired on zero of 1,200 real historical commands, because they are walls recorded this week that have not recurred. Currency was bought. Accuracy was not. The permanent miss is launchctl bootout — no launchctl, bootout or plist cue exists anywhere in the index.
Measures the hook's noise floor against real harvested commands. Referenced nowhere except one reference doc.
grep -rn '\.round2' --include='*.py' --include='*.sh' ops/ skills/
It is the last script still implementing the
retired collision rule, in live executable code at line 300 and line 305. A second
--md run writes a .round2 twin instead of refreshing. Three rounds passed and no
unit ever owned this file. Fix it to the P.1-P.9 rule or delete it.
The umbrella that makes the other tools get run instead of remembered. Named in CLAUDE.md, which is the only thing that will make anyone type it.
bash ops/scripts/aios-doctor.sh full
Nothing schedules it. The umbrella is the whole durability argument for round 2 and it depends entirely on a human remembering. That is the open question about whether any of this survives the month.
Files live in ops/reference/staged/. No launchd state was touched by
any round.
The sentinel ops/screen-audit/PAUSED is 0 bytes with an mtime of 2026-07-26 16:00
— 48.6 days. The job is still loaded and still waking; last exit code = 0 is
truthful because thirteen lines of bash decide to exit each time. The plist declares a 5 second
interval but launchd also reports minimum runtime = 10, and the floor wins.
launchctl bootout gui/$(id -u)/com.aios.screen-audit-capture
launchctl disable gui/$(id -u)/com.aios.screen-audit-capture # persist across login
Tradeoff, written up in RED-A-screen-audit-capture.md: after
disable, deleting the PAUSED sentinel no longer re-arms capture. Sentinel and job
state become two switches that can disagree.
The live plist fails plutil -lint on a bare ampersand at line 13, so it will not
survive a reboot, and PID 1002 is running against it right now. It also carries
SHELL_BASIC_AUTH_PASSWORD in cleartext under EnvironmentVariables, world-readable
since 2026-07-19.
install -m 755 ops/reference/staged/RED-B-with-secret.sh ops/scripts/with-secret.sh
plutil -lint ~/Library/LaunchAgents/com.aios.deliverables-cesar.plist # must say OK first
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3120/ # expect 401
Full seven-step install in RED-B-NOTES.md. Read the secret out of the
live plist yourself; never ask an agent to echo it. Step 7 is the one people skip: shred the
.bak- copy and rotate the password. The backup is a live secret.
Twelve consecutive failures at 300s is one hour. The block at lines 27-36 of
mailer-guard.sh reaches exactly four side effects: a cat > into a
markdown file, an echo >> into a log, an rm -f, and a
launchctl bootout. There is no notification path. Runs on Nano, so apply there.
cp skills/booking-mailer/mailer-guard.sh skills/booking-mailer/mailer-guard.sh.bak-$(date -u +%Y%m%dT%H%M%SZ)
patch -p1 -i ops/reference/staged/RED-C-mailer-guard-notify.patch skills/booking-mailer/mailer-guard.sh
bash -n skills/booking-mailer/mailer-guard.sh
After patching, force a real twelve-strike run and confirm your phone buzzes. An untested alarm is not an alarm.
This is the centrepiece. Three rounds produced three generations of figures; these are the ones that moved and the reason each one was wrong.
No earlier round measured this, and it is the correction that matters most. Replaying the tool's own must-fire control set against the stale 120-block index and the live 128-block index gives an identical 7 of 8, and an identical noise floor, at both a 500-command and a 1,200-command sample. The eight blocks the fix added fired on zero of 1,200 real historical commands. The staleness repair is genuine — the index hash now matches blocks.json, so future walls will reach the hook — but it bought currency, not accuracy.
The original figure is fully reproducible and fully wrong. It is agent-ledger.sh's own arithmetic, plist age divided by the declared 5 second interval, and the tool still prints ~1,033,815 today. It is 18.9x the live counter because launchd throttles to a 10 second floor and the machine sleeps roughly 41% of wall time. The intermediate 829,000 used 17,280 wakes per day and is 2.7x too high. Use 54,588 observed and stop quoting the ledger column.
The plist says 5, launchd reports minimum runtime 10, and direct measurement lands at 9.69 rather than a clean 10.0. The conclusion is unchanged; the precision was overstated.
Every command in the first draft targeted a launchd domain that does not exist on this box. gui/501 returns error 125.
All eleven are the substring "mail" inside "booking-mailer". The finding was right and the transcript was wrong: a command-position grep still returns zero notification calls, so the defect stands undowngraded.
The old figure blended three loadability tiers including 83 skills the Skill tool cannot load, overstating the real per-session bill by 58%. It drifted again tonight: the read-only tier moved from 82 skills at 4,679 tokens to 86 (83 deduped) at 4,849, and the blend now reads 13,193 / 45%.
Certified "CONFIRMED correct against a live re-run" seven hours ago. Tonight it reads 444 against the identical, unrebuilt manifest, because this round's own file creation resolved 73 previously-dead paths. The tool is stable; the filesystem is not. The "126 fixable now" that preceded both was first-match guessing and stays retired.
Measured a day apart. The tool is getting slower as the observer accumulates dead subagents, so the speedup claim for agent-live.sh is stated against the newer, slower baseline.
com.aios.overnight-council went RED on LastExitStatus 1 between rounds. Separately, AGENT-LEDGER.md moved from 124 to 135 lines: the shipped render used --quiet-green and silently dropped 11 of 33 agents.
Live drift from concurrent sessions writing memory. The orphan count held at exactly 140 through all three measurements.
33 backup and sidecar files totalling 3,935,955 bytes now sit on disk, plus a 112 KB quarantine entry. The emitted delete command also reclaims zero bytes on the day it runs, because gc-safe-delete moves files into a quarantine inside the same tree.