✅ 2 fixes shipped live · 4 decisions staged for you
Triggered by your Hermes-video learning: hard character caps on the files that load every session, as a forcing function for clean markdown. I benchmarked every agent against Hermes, found the real gap, fixed the two safe high-value items, and staged the structural calls below.
The one-line finding: your identity/doctrine layer is actually leaner than Hermes. The bloat — and the missing enforcement — was concentrated in Aria’s memory-index layer, the one agent that had only a weekly (ignorable) audit.
🚀 Shipped this session
Consolidated memory/MEMORY.md under cap
fd42743 29,652 → 18,108 chars (39% smaller). Enforced the file’s own one-line/~150-char rule, dropped resolved + stale entries, fixed "Linq owns day-to-day" framing (Linq absorbed 2026-05-15), added 4 missing pointers. Clears the 6-day-carried "prune MEMORY.md" item.
aria-secondbrain
Extended pre-flight check.mjs to cover Aria
982e3a50 The session-start hygiene check audited the 5 Aspire specialists but NEVER Aria — her files live in a different repo. Added checkAriaMemoryHygiene() so every session now caps-checks CLAUDE.md, IDENTITY/SOUL/LANES, NEXT.md, MEMORY.md. Additive, non-blocking, tested (40→41 checks, exit 0).
aspire-clients
🧭 Three enforcement models, one platform
Hermes (M3)
StrongestHard caps in runtime code. memory_tool.py: USER.md ≤1375 chars, MEMORY.md ≤2200. Hitting the cap forces consolidation before you can add. Cannot be ignored.
Aspire specialists
MiddleRole caps + session-start warning. agents/_shared/memory-hygiene.md defines role-based caps; check.mjs warns at every session start. Advisory (non-blocking) but consistently surfaced.
Aria (personal)
Weakest → now patchedSoft prose caps + WEEKLY audit. Caps lived only as prose in CLAUDE.md; the shell audit runs Sundays and only flags. A weekly flag is trivially ignorable — MEMORY.md sat over cap for 6 days. (Fixed today: now covered at session-start too.)
A flag can be ignored forever; a hard cap cannot. That’s the entire lesson from the Hermes video — and why Aria’s weekly flag let MEMORY.md sit over cap for six days.
📊 Every-session file heatmap
| Agent | File | Chars | Cap | Status | Note |
|---|---|---|---|---|---|
| Aria | CLAUDE.md | 18,519 | 24 KB | ok | doctrine + Greeter — leaner than Hermes AGENTS.md |
| Aria | IDENTITY+SOUL+LANES | 8,331 | — | ok | identity layer, fine |
| Aria | memory/NEXT.md | 15,790 | 20 KB | watch | under cap, but "Last run" block is a 3.5 KB wall (rule = one line) |
| Aria | memory/MEMORY.md | 18,108 | 25 KB | fixed | was 29,652 (over cap) — consolidated today |
| Hermes | USER.md | ≤1,375 | HARD | enforced | enforced in runtime code (memory_tool.py) |
| Hermes | MEMORY.md | ≤2,200 | HARD | enforced | enforced in runtime code — cannot be ignored |
| Hermes | SOUL.md | 1,533 | — | ok | tiny identity + constraints |
| Circa | MEMORY.md | 19,464 | 20 KB (override) | ok | state-heavy override — GHL token/sub-account tables |
| Paris | AGENTS.md | 22,099 | 24 KB (override) | ok | workflow-manual override — inline per-prospect commands |
| Vegas | mistakes.md | 11,375 | — | watch | mistakes that are now mechanically prevented should be pruned |
🗺 Where enforcement runs (and didn’t)
SESSION START (every Claude Code session)
│
▼
~/.claude/settings.json SessionStart hook
│ runs: aspire-clients/skills/pre-flight/check.mjs --all --session-start
▼
checkMemoryHygiene() ──── walks aspire-digital/agents/<persona>
│ vegas · sahara · circa · strat · paris ✅ covered
│ linq (retired) ⚠ stale
│ aria ❌ WAS MISSING
│
└── checkAriaMemoryHygiene() ◀── ADDED TODAY
walks aria-secondbrain: CLAUDE.md, IDENTITY/SOUL/
LANES, NEXT.md, MEMORY.md ✅ now covered
WEEKLY (Sundays only)
│
▼
ops/aria-weekly-self-audit.sh ── flags Aria caps + drift + journal gaps
(flag-only; was Aria’s ONLY coverage — easy to ignore)
🧹 Data-integrity findings
memory/MEMORY.md over its own 25 KB cap · FIXED today
Flagged weekly, carried 6 days. Root cause: flag without forcing function.
Aria’s files invisible to the session-start check · FIXED today
check.mjs walked only aspire-digital/agents/<persona>; Aria is a separate repo.
check.mjs persona list still includes retired "linq", omits "aria" · STAGED
Audits a dead persona; daily-report writes to a linq/ path. Surgical rename needed.
aspire-digital doctrine points at "skills/pre-flight/check.mjs" — wrong repo · STAGED
Script actually lives in aspire-clients. Relative path misleads any reader.
~/projects/shared-skills/ is empty but CLAUDE.md advertises it · STAGED
CLAUDE.md claims it holds "web crawling, document generation, screenshots." Points at nothing.
NEXT.md "Last run" block is a 3.5 KB narrative wall · STAGED
Discipline says one-line Last-run; detail belongs in memory/daily/. Trim queued for end of session.
🎙 Wispr Flow — what it changes
Cleaner input at the source
Wispr improves dictation quality → cleaner capture → fewer garbled action items → less downstream cleanup. Compounds with tighter back-end caps.
Proper nouns still drift
In this very session Wispr rendered "Vegas"→"Begus" and "Jaime"→"Jamie". The voice-artifact parsing rule stays load-bearing.
Highest-value action: custom dictionary
Add Aspire jargon to Wispr’s vocabulary: Vegas, Sahara, Circa, Strat, Paris, Aria, Hermes, Jaime, Aspire, Otten, Willowbrook, Synchrony, Tirzepatide.
Per-person asymmetry
Topher on Wispr, Jaime on Apple dictation. Capture-quality assumptions should not bake in one engine until both are aligned.
⚙️ M4 operating model — web → terminal
Web → M4 launch
Claude Code on the web picks the com.aria.remote.plist daemon on M4. Anthropic clamps these sessions to "Ask permissions" — bypass is impossible upstream.
The allow-list workaround
Pre-approving every tool in ~/.claude/settings.json makes "Ask" never actually ask. But it’s maintained reactively ("if Topher gets prompted, add it") against a huge MCP surface — it lags.
Known fragility
env-id rotates on every daemon restart (triggers must be repointed); cron-leaked sessions need a 10-min reaper; logs need daily truncation; Opus prompts where Sonnet does not.
Idea: drift-check the allow-list
A pre-flight check that compares installed MCP servers against the settings.json allow-list would catch coverage gaps before they prompt. The /fewer-permission-prompts skill already does a version of this.
⚡ Round 2 — forcing-functions shipped
The thesis in action: convert prose rules into enforced checks so integrity survives any session forgetting.
Link-integrity check (weekly audit)
Converts the "every /info page must be linked" rule into an enforced check. Caught 1 true orphan (the redesign tracker) — now linked. Hardened to true reachability after it false-flagged 14 reachable sub-pages.
MCP allow-list drift check
ops/allowlist-drift-check.mjs — found 11 configured MCP servers (10 GHL + Linear) NOT in the allow-list, so each prompts mid-session. Detect-only by design: blanket-allowing send-capable GHL servers would disarm the confirmation prompt on client-facing writes.
Auto-journal backfill (OPS-91)
ops/journal-gap-detect.mjs + morning-cron STEP 6b. The cron now writes a journal for any committed human-session day that lacks one — the auto-generation CLAUDE.md named as the goal.
🧱 Round 3 — Tier 2 & 3 (autonomous)
Model-routing doctrine
memory/tools/model-routing.md — Haiku=cron triage, Sonnet=build/Astro, Opus 4.8+effort=deep reasoning/autonomous. Codifies your per-job switching.
⚠ MCP-context bug found (OPS-92)
While building cost instrumentation: the 10 GHL MCP servers are registered GLOBALLY (~400 tool defs) and overflow Haiku's 200K context — Haiku+MCP = "Prompt is too long," the same root cause as the subagent failures. This corrected my own Haiku-for-crons advice. Fix: scope GHL MCP per-project. Staged.
Usage meter + reader (Tier 2b)
ops/usage-meter.sh + usage-report.mjs — opt-in token/duration metering (cost is ~$0 on subscription). Built + tested; NOT wired into crons (production change left for you).
Productization (Tier 3)
Forcing-function lesson added to the personal-ai-starter build-doc (committed, public deploy held); new "Context Governance" sellable module in the Aspire RAG methodology with this audit as the dogfood case study.
🫵 Decisions staged for you
1. Adopt the session-start cap-check as the forcing function (DONE — confirm you want it kept)
I already wired Aria into check.mjs so it warns every session. Keep it. If you want it to be a true hard gate (block until acknowledged), that’s a one-line settings.json change I left for you.
5. MCP allow-list policy — reads vs writes
11 servers prompt mid-session. I did NOT auto-fix: blanket-allowing GHL would auto-approve sending messages to client customers. Decide: allow read-only GHL/Linear tools, keep write/send gated. Then I add the safe ones to settings.json.
2. Unify enforcement — the "third agent" trigger has fired
memory-hygiene.md §6 says: when a 3rd agent independently hits the same hygiene problem, build one shared layer. You now have 7 agents across 3 enforcement models. Recommend one canonical hygiene-check serving Aria + specialists + Hermes.
3. Fix the doctrine drift
Rename check.mjs persona linq→aria; correct the aspire-digital doctrine’s path to the real aspire-clients location; either populate shared-skills/ or remove the claim from CLAUDE.md.
4. Wispr custom dictionary
You add the wordlist in the Wispr app (I can’t reach it). 5-minute task, kills the proper-noun artifact class.
Tracked in Linear OPS. Reply with a yes/no on each and I’ll execute the approved ones.