Current harness — skills, rules, hooks, CLAUDE.md (audit Jun 30 2026)

Investigation, report-only (investigator skill). Generated 2026-06-30. Leads: memory_palace/summaries/2026-06-30-palace-measurement-and-dedup.md, tasks/TASK_BOARD.md, prior audit session af18b5f9.

Answer first

  • One file wires every live hook: Code/.claude/settings.json. Inspection/.claude has 8 hook files but no settings.json → all 8 are inert (present, bound to nothing). Docs/.claude has no hooks at all. A hook existing on disk does not mean it fires.
  • Not one duplicated skill or rule is byte-identical — every cross-tree copy has drifted. Same name, different behavior. Only two inert hooks (ast-grep-nudge, firecrawl-nudge) are still identical. Drifted duplication is worse than plain duplication: a subagent or an Inspection/Docs-rooted session silently loads a different skill than the one tested in Code.
  • The sim-runner debug hole is a path-frame mismatch. Every relative path in sim-runner (.claude/rules/MEASUREMENT.md, analysis/data_analyzer.py, analysis/dispatch.py, YAMLs_by_domain/metrics.yaml) is Inspection-relative, but the skill lives in Code/.claude/skills and the session launches from Code/. From the Code root they are all off by the missing Inspection/ prefix.
  • Compounding it: MEASUREMENT.md is path-scoped to validation/**/*.py + GNC/**/*.py. sim-runner’s measure/collect steps often touch neither (reading a log, editing a tmp_ YAML), so its “REQUIRED READING” never auto-loads — and through a subagent it never propagates (Inspection/CLAUDE.md documents this as a known open gap).
  • Code/.claude/rules/ is empty. The active project tree carries zero rules; all 9 rules live in the two path-scoped subtrees (Inspection 5, Docs 4), reachable only when you touch a matching path.
  • Non-finding (do not delete): koans.py. It is unwired in settings because it is a shared library (from koans import koan) imported by four hooks, not an event hook.

Scope and the load model

“Loaded” depends on where a .claude tree sits relative to the session. Four scopes:

ScopeTreeWhen it loads
🌐 Global~/.claudeEvery session, always. CLAUDE.md + settings (permissions/plugins/sandbox). No rules, no hooks.
🟢 Active projectCode/.claudeThis session (cwd = Code/). The only tree whose hooks are wired.
🟡 Path-scopedInspection/.claude, Docs/.claudeRules + nested CLAUDE.md attach only when a tool touches a file matching the rule’s paths: glob. Subagents do not propagate them back up.
💀 InertInspection/.claude/hooks/*On disk but bound to nothing (no settings.json wires them).

Legend below: 🟢 active · 🌐 global · 🟡 path-scoped · 💀 inert · ⚠️ duplicated and drifted · 🎯 sim-runner focal.

The mind map

mindmap
  root((Harness<br/>4 .claude trees))
    🌐 HOME ~/.claude
      Global CLAUDE.md
      settings.json perms+plugins+sandbox
      no rules · no hooks
      Skills 7
        caveman
        theme-factory
        firecrawl-research-papers
        obsidian-clipper-template-creator
        plannotator-annotate
        plannotator-last
        plannotator-review
    🟢 CODE active project
      Project CLAUDE.md
      settings.json wires 9 hooks
      settings.local.json firecrawl-redirect
      rules EMPTY
      Hooks 9 live
        allow-read-only
        preflight_guard
        plotting-guard
        ast-grep-nudge
        firecrawl-nudge
        wiki_yq_nudge
        board_hygiene_stop
        reflow_md
        comms_nudge
        koans lib not a hook
      Skills 23
        sim-runner 🎯
        root-cause-analysis
        investigator ⚠️
        loading-yamls ⚠️
        validation-purge ⚠️
        long-form-math ⚠️
        grill-me
        handoff
        mempalace-capture
        checkin
        planning-with-files
        writing-great-skills
        mermaid
        ast-grep
        drawio
        firecrawl
        marp-magic
        matplotlib
        plotly
        pandas-to-latex
        obsidian-bases
        obsidian-markdown
        sympy
    🟡 INSPECTION path-scoped
      CLAUDE.md orchestrator-invariants
      NO settings → hooks INERT 💀
        allow-read-only 💀
        preflight_guard 💀
        plotting-guard 💀
        ast-grep-nudge 💀
        firecrawl-nudge 💀
        check_board 💀
        check_ongoing 💀
        palace_capture 💀
      Rules 5
        MEASUREMENT 🎯
        GNC
        ANALYSIS
        VALIDATION
        PYTHON ⚠️
      Skills 9
        log-driver
        note-taking
        searching-research-wiki
        investigator ⚠️
        loading-yamls ⚠️
        validation-purge ⚠️
        wiki-docs ⚠️
        wiki-ingest ⚠️
        wiki-lint ⚠️
    🟡 DOCS path-scoped
      Project CLAUDE.md
      NO settings · NO hooks
      env-contract + hookify rules
      Rules 4
        WIKI
        BULLETIN
        LATEX
        PYTHON ⚠️
      Skills 10
        arxiv-lookup
        research-assistant
        insight-guru
        tex-report-writing
        tikz-artist
        long-form-math ⚠️
        wiki-docs ⚠️
        wiki-ingest ⚠️
        wiki-lint ⚠️
        wiki-tidy

Full inventory

Skills (49 files across 4 trees)

Skill🌐 ~🟢 Code🟡 Inspection🟡 DocsStatus
investigator⚠️ drifted — Inspection adds disable-model-invocation:true + local MERMAID.md; Code says “use the mermaid skill”
loading-yamls⚠️ drifted
validation-purge⚠️ drifted
long-form-math⚠️ drifted
wiki-docs⚠️ drifted
wiki-ingest⚠️ drifted
wiki-lint⚠️ drifted
sim-runner🎯 Code-only; Inspection-relative paths (see Findings)
checkintwin of log-driver (board item)
log-drivertwin of checkin (board item)
wiki-tidyDocs-only; vault-relocation suspect
root-cause-analysis, grill-me, handoff, mempalace-capture, planning-with-files, writing-great-skills, mermaid, ast-grep, drawio, firecrawl, marp-magic, matplotlib, plotly, pandas-to-latex, obsidian-bases, obsidian-markdown, sympyunique to Code
note-taking, searching-research-wikiunique to Inspection
arxiv-lookup, research-assistant, insight-guru, tex-report-writing, tikz-artistunique to Docs
caveman, theme-factory, firecrawl-research-papers, obsidian-clipper-template-creator, plannotator-annotate/last/reviewglobal

Rules (9 files — Code/.claude/rules is empty)

RuleTreepaths: scopeNote
MEASUREMENT.mdInspectionvalidation/**, GNC/**🎯 measurement contract; sim-runner’s required reading
GNC.mdInspectionGNC/**/*.pyguidance/control orientation
ANALYSIS.mdInspectionanalysis/*.py
VALIDATION.mdInspectionvalidation/*.py
PYTHON.mdInspectionevery *.py⚠️ drifted vs Docs PYTHON.md
WIKI.mdDocswiki pathsvault-relocation suspect (board)
BULLETIN.mdDocsboard lifecycle
LATEX.mdDocsLaTeX
PYTHON.mdDocs*.py⚠️ drifted vs Inspection PYTHON.md (likely different env — verify before merging)

Hooks (wiring = Code/.claude/settings.json only)

Hook🟢 Code (wired)🟡 Inspection (inert)Cross-tree state
allow-read-only.pyPreToolUse Bash💀drifted
preflight_guard.pyPreToolUse Write/Edit💀drifted
plotting-guard.pyPreToolUse Write/Edit💀drifted
ast-grep-nudge.pyPreToolUse Bash/Grep💀identical
firecrawl-nudge.pyPreToolUse WebFetch/Search💀identical
wiki_yq_nudge.pyPreToolUse BashCode-only
board_hygiene_stop.pyStopCode-only
reflow_md.pyPostToolUse Write/EditCode-only
comms_nudge.pyUserPromptSubmitCode-only
koans.pylibrary (imported by 4 hooks)not an event hook — keep
check_board.py💀Inspection-only, now dead
check_ongoing.py💀Inspection-only, now dead
palace_capture.sh💀Inspection-only, now dead

settings.local.json (Code) adds the WebFetch→deny firecrawl-redirect hook and the Edit/Write(**) allow. ~/.claude/settings.json carries no hooks block.

CLAUDE.md (8 files)

~/.claude (global advisor) · Code (project) · Inspection (orchestrator-invariants + path-scope map) · Docs (project) · Inspection/notes, Code/notes, vault, vault/research (scoped flavor notes) · Inspection/junk_drawer_june (stale, in a junk dir).

Findings

F1 — sim-runner paths are Inspection-relative but the skill lives in Code and launches from Code. Evidence: Code/.claude/skills/sim-runner/SKILL.md:8,10,12,78 reference .claude/rules/MEASUREMENT.md; :10,39 reference analysis/data_analyzer.py; :49,63,80 reference analysis/cluster.yaml/dispatch.py/YAMLs_by_domain/metrics.yaml. Code/.claude/rules/ is empty; the real files are under Inspection/. Impact: a fresh agent following sim-runner literally from the Code root hits dead paths — the “very easy to do” required-reading step fails. Decision (Jun 30): keep sim-runner in Code (stays globally invocable); add a one-line “paths relative to Inspection/” header and an explicit “read Inspection/.claude/rules/MEASUREMENT.md first” step (resolves F1+F2 together). Logged on TASK_BOARD.md Parked.

F2 — MEASUREMENT.md is path-scoped and won’t auto-load for most sim-runner work. Evidence: Inspection/.claude/rules/MEASUREMENT.md:2-6paths: validation/**/*.py, GNC/**/*.py. Inspection/CLAUDE.md “Orchestrator invariants”: scoped rules load only on direct touch of a matching file and “subagents do not propagate rules back up.” Impact: collecting/measuring a run (touching logs or a tmp_ YAML) never triggers the contract; sim-runner asserts it is loaded when it is not. Next step: sim-runner should instruct the agent to read Inspection/.claude/rules/MEASUREMENT.md explicitly at the start of any measure/collect step (the Inspection/CLAUDE.md preload pattern), not rely on path-scoped auto-load.

F3 — Every cross-tree duplicate skill/rule has drifted. Evidence: diff Jun 30 — investigator (3 hunks incl. disable-model-invocation), loading-yamls, validation-purge, long-form-math, wiki-docs, wiki-ingest, wiki-lint, PYTHON.md all report “differ”; only hooks ast-grep-nudge/firecrawl-nudge identical. Impact: behavior depends on which tree the agent is rooted in — the staleness engine. Next step: this is the board’s “skill/rule cross-tree dedup” item; pick a canonical tree per skill, collapse, never one-side-patch. (PYTHON.md may be legitimately env-specific — verify before merging.)

F4 — All 8 Inspection hooks are inert (no settings.json). Evidence: ls Inspection/.claude/ shows no settings file; find for settings*.json returns only ~ and Code. Impact: 5 are dead duplicates of live Code hooks; 3 (check_board, check_ongoing, palace_capture.sh) are Inspection-only logic now superseded by Code’s board_hygiene_stop.py/palace. They mislead anyone who reads the tree expecting them to fire. Next step: delete the 5 duplicates; decide whether check_board/check_ongoing/palace_capture carry unique logic worth porting to a wired Code hook, else delete.

F5 — koans.py is a shared library, not an orphan hook. Keep it. Evidence: grep koanspreflight_guard.py:23, allow-read-only.py:33, comms_nudge.py:10, plotting-guard.py:24 all from koans import …. Impact: none — recorded so a future dedup pass does not flag it for deletion on “unwired” grounds.

F6 — Docs wiki tooling vs the vault relocation (already on board). Docs/.claude still carries WIKI.md/BULLETIN.md + wiki-docs/wiki-ingest/wiki-lint/wiki-tidy, but the research wiki was retired/relocated to vault. Verify these don’t operate on a moved target.

Proposed next tasks

New (not yet on the board):

  • Re-root sim-runner (F1+F2). Decide host tree + path convention, and add the explicit MEASUREMENT.md preload step. This is the headline “debug sim-runner” fix.
  • Delete the 5 inert duplicate Inspection hooks (F4); triage check_board/check_ongoing/palace_capture for unique logic first.
  • Drop Inspection/junk_drawer_june/CLAUDE.md (stale CLAUDE.md in a junk dir).

Already parked on tasks/TASK_BOARD.md — this audit adds the drift evidence (F3), don’t re-log:

  • Skill/rule cross-tree dedup (canonical-tree pick, collapse the 8 drifted pairs).
  • checkinlog-driver twin merge.
  • Docs wiki tooling vs vault relocation (F6).