rdmsm4x-changelog-20260831-2058-project-state-routing-hooks-fleet
Window: 2026-08-31 20:50 – 20:58 EDT · Lead:
claude@rdmsm4x session dev-94 [785f8b]
One-line summary: deployed project-state routing hooks to all six Macs, so any session that starts in a project dir — or merely names a project in a prompt — automatically gets that project's last known state, its live owner, and its open tickets.
Scope
All six hosts: rdmsm4x, rdmbair15m5, rdmbair13m5, jdmbair13m5, rdmpw3265m, rdmpw3275m.
Decisions Rich made before the build
- Advisory, not blocking on ownership conflict — inject and continue.
- All six hosts now, overriding the standing "hooks are per-host, never force-synced" baseline note. Recorded here because that note still governs every other hook.
- Auto-heartbeat + prompted narrative — the machine keeps the lease alive, a human/agent writes what is verified vs assumed.
What changed, per host
~/dev/fleet/ops/project-state/project_state_hook.py— new, sha256 prefixacf87d56fe81, mode 755, byte-identical on all six.~/.claude/settings.json— three hook blocks appended (SessionStart,UserPromptSubmit,Stop). Existing per-host hooks preserved (block count 1→4 on each of the five spokes). Timestamped backup.bak-20260831-*-pre-project-statewritten beside each.- New runtime state:
~/.agent-coordination/project-owners/<slug>.json(TTL 30 min) andproject-index.json(hourly rebuild).
Verification (end state, all six)
| Host | script sha | hook runs | context produced | malformed input | defaultMode |
|---|---|---|---|---|---|
| rdmsm4x | acf87d56fe81 | rc=0 | yes (756 B) | rc=0 | bypassPermissions |
| rdmbair15m5 | acf87d56fe81 | rc=0 | yes (384 B) | rc=0 | bypassPermissions |
| rdmbair13m5 | acf87d56fe81 | rc=0 | yes (322 B) | rc=0 | bypassPermissions |
| jdmbair13m5 | acf87d56fe81 | rc=0 | yes (321 B) | rc=0 | bypassPermissions |
| rdmpw3265m | acf87d56fe81 | rc=0 | yes (321 B) | rc=0 | bypassPermissions |
| rdmpw3275m | acf87d56fe81 | rc=0 | yes (321 B) | rc=0 | bypassPermissions |
Verified by running the hook with a real payload on each
host, not by checking the file exists. Cross-thread routing proven
locally: a prompt saying "status of tyrell please" from a different
project injected ~/dev/apps/Tyrell with its 3 open tickets.
Timing 42 ms/run.
Outstanding owner actions
- Every session already running is unaffected until it
restarts, including the one that installed this. Settings are
read at session start. Restart a session (or open
/hooks) to pick the hooks up. - The 30-minute owner TTL and the ≥4-character name-match rule are first guesses. If ownership lines feel noisy or stale, those two constants are the dials — both at the top of the script.
How to undo
Remove the three project_state_hook blocks from
~/.claude/settings.json (backup beside it on every host),
or set disableAllHooks: true. Full detail:
~/dev/fleet/ops/project-state/README.md.
No secrets were read or written.
v1.1 + reboot save — 2026-08-31 21:15 EDT
v1.1 (sha f5321fc02c1e, all six hosts).
v1.0's Stop reminder fired twice on
~/dev/fleet in the session that built it, and nothing the
author was willing to do could clear it. Fixed:
- domain roots (
~/dev/fleet,~/dev/apps, …) are never nagged — they are shared containers with no single owner to act on the reminder; - the reminder now requires EVIDENCE of change
(
git status --porcelainnon-empty, or a file touched in the last 90 min) — v1.0 nagged read-only sessions; - an id-less session no longer claims ownership — it cannot be reached
by
SendMessage.
Owner registry cleaned on all six hosts. Probe
entries created during my own testing (probe,
probe11, verify-probe, unknown,
t) were purged — they would have appeared as phantom owners
for 30 minutes. Registry now shows only real sessions;
apps-tyrell legitimately has two concurrent owners, which
is exactly the case the advisory exists for.
Corrections to my own verification, both worth carrying forward:
- I probed
~/dev/fleeton the spokes, got no context on all five, and nearly filed it as a failure. On spokes that path is plain scratch with no project markers, so producing nothing is CORRECT. Probe a path that exists on the target, not one that exists on the host you are standing on. - A remote
&&-chained one-liner broke mid-chain and printed nothing — silent failure indistinguishable from silent success. The base64-script-over-ssh method is the reliable one. - I told Rich running sessions would not pick up the new hooks. Wrong: they fired in this session within minutes. The documented caveat is about the settings watcher's directory scope, not a guarantee that running sessions are excluded.
Reboot readiness — verified on all six by running the checks, not by inspecting files:
| Host | claude | update job | update script | hooks | hook sha | defaultMode |
|---|---|---|---|---|---|---|
| rdmsm4x | 2.1.252 | loaded exit=0 | 9a586985faf9 | 3/3 | f5321fc02c1e | bypassPermissions |
| rdmbair15m5 | 2.1.252 | loaded exit=0 | 9a586985faf9 | 3/3 | f5321fc02c1e | bypassPermissions |
| rdmbair13m5 | 2.1.252 | loaded exit=0 | 9a586985faf9 | 3/3 | f5321fc02c1e | bypassPermissions |
| jdmbair13m5 | 2.1.252 | loaded exit=0 | 9a586985faf9 | 3/3 | f5321fc02c1e | bypassPermissions |
| rdmpw3265m | 2.1.252 | loaded exit=0 | 9a586985faf9 | 3/3 | f5321fc02c1e | bypassPermissions |
| rdmpw3275m | 2.1.252 | loaded exit=0 | 9a586985faf9 | 3/3 | f5321fc02c1e | bypassPermissions |
Resume pin
~/dev/fleet/ops/resume/PINNED-SESSION-fleetcc → session
c8b04c2f-7c11-4c01-ad78-5287fbb0e92e, cwd
~/dev/fleet/ops/project-state. Dry-run resolved the 1.4 MB
transcript at 21:16 EDT. Login agent
com.eastcoastscience.claude-resume-fleetcc is installed and
lint-clean but deliberately NOT bootstrapped — RunAtLoad
would have opened a Terminal resuming this still-running session.
~/Library/LaunchAgents auto-loads at next GUI login, which
is the intended trigger.
Note on the reboot itself: jdmbair13m5's
syspolicyd wedge (ISSUE-20260831-19) clears naturally on
restart. If the hang returns after this reboot, that is new information
and the ticket says to capture spindump BEFORE restarting
the daemon.
Commits in ~/dev/fleet: de33318,
75d75d1, c7895e7, 8baf143,
6c6c08b — all staged by explicit path; other agents'
untracked resume pins in the same directory were left untouched.