workspace: version the root CLAUDE.md + InstructionsLoaded hook, and report which rules fire (R-229)
gates / gates (push) Successful in 8s
gates / gates (push) Successful in 8s
install_workspace.py lays down the two things that shaped every session while existing on one host only. Unlike install_skills.py the targets are LIVE CONFIG, so: timestamped backup before every write, settings.json MERGED (this script owns exactly one key), a diverged CLAUDE.md reported rather than silently resolved, and an unparseable settings.json refused outright. Proven: all 7 top-level settings keys survived byte-identically, and run 2 wrote nothing. rules_report.py surfaces the column that matters -- rules that have NEVER fired, which are mis-globbed or dead. 6 of 9 on first run. The hook now self-rotates at 5 MB. The memory store is BACKED UP, NOT COMMITTED (auto-written, may name hosts/paths): added to dooplex-backup.service's User Data component. /opt/backup/scripts/ is itself unversioned host state -- filed, not fixed here.
This commit is contained in:
@@ -1,3 +1,35 @@
|
||||
## install_workspace.py + rules_report.py — the workspace survives the machine (2026-08-06, R-229)
|
||||
|
||||
The workspace-root `CLAUDE.md` and the `InstructionsLoaded` hook shape every session and existed on
|
||||
**one host** — the one that cannot be rebuilt from anything else. `install_workspace.py` lays both
|
||||
down from versioned copies.
|
||||
|
||||
**Canonical-path decision:** `documentation/runbooks/workspace-CLAUDE.md` stays the source.
|
||||
`workspace/` carries only the hook fragment. A `workspace/CLAUDE.md` would be a *third* copy of a
|
||||
file whose entire problem is that copies drift, and check 5 already enforces byte-identity against
|
||||
the runbooks path.
|
||||
|
||||
**Where this deliberately differs from `install_skills.py`:** that script's targets are disposable —
|
||||
a skill dir can be deleted and re-linked losing nothing. These are **live configuration**.
|
||||
`~/.claude/settings.json` holds permissions, plugins and effort level this repo knows nothing about.
|
||||
So every write is preceded by a timestamped backup; `settings.json` is **merged**, this script owning
|
||||
exactly one key (`hooks.InstructionsLoaded`); a diverged `CLAUDE.md` is backed up and *reported*, not
|
||||
silently resolved; and an unparseable `settings.json` is **refused**, never overwritten — a malformed
|
||||
settings file disables every setting in it, and overwriting would destroy whatever was mid-fix.
|
||||
|
||||
Proven: merge preserved all 7 top-level keys byte-identically (`sha256` of the file minus `.hooks`
|
||||
unchanged across the write), and a second run wrote nothing — *idempotent* means "changed nothing the
|
||||
second time", not "ran twice without erroring".
|
||||
|
||||
**`rules_report.py`** answers what the hook log exists for: which rules fired, how often, and **which
|
||||
never have**. The empty column is the point — a never-fired rule is mis-globbed or dead, which is the
|
||||
built-but-never-wired class applied to instructions. It prints each silent rule's `paths:` beside it
|
||||
so "wrong glob" is distinguishable from "quiet month", and it judges neither. First run: 6 of 9 rule
|
||||
files had never fired. **Caveat: the log only covers since the hook was armed** — `gates.md` shows
|
||||
silent despite having fired earlier the same day, before installation.
|
||||
|
||||
The hook now **self-rotates at 5 MB**, one generation, since the log is otherwise unbounded.
|
||||
|
||||
## instructions_gate.py — check 6: the auto-memory index (2026-08-06, R-229)
|
||||
|
||||
**The bigger half of what loads was watched by nothing.** Measured at the workspace root, the
|
||||
|
||||
Reference in New Issue
Block a user