Releases: palios-taey/claude-code-fleet-notify
Release list
v1.6.2 — notification reliability hardening
Three reliability fixes for the notification daemon, each independently adversarially gated (audit/grok + audit/gatekeeper) before merge.
- Per-session pointer-inject backoff (#32): the daemon no longer re-injects the same
[NOTIFY]pointer every 3s into a session that hasn't drained its inbox. A 90s per-session backoff keyed on inbox signature stops the hammer; genuinely new messages (changed signature) still inject promptly. Fixes the keystroke-storm failure mode. - Suffix-peer self-parent liveness routing (#33): a suffix peer (
-codex/-gemini/-grok) whose explicit parent override points at itself is now ignored in favour of the suffix-strip, so stop signals route to the real supervisor. Top-level sessions still self-suppress correctly. - Inactive-peer backstop fresh-activity check (#34): the dispatcher-page backstop now measures inactivity from the newest of
last_tool_activity/last_activity/current_task.started_at, so a freshly-restarted or freshly-dispatched active peer is no longer falsely reported inactive. Genuinely stalled peers still surface.
Production-validated on the live daemon: zero false backstop firings post-deploy; 58 tests + subtests pass.
v1.6.1 — atomic_deploy self-contained clones (#5)
Patch: atomic_deploy.sh now uses self-contained git clone per version dir instead of git worktree (#5 — fixes gitdir-pointer fragility that broke redeploys after symlink-flip). No runtime/hook behavior change. Closes the last open fleet-notify issue.
v1.6.0 — Reliable worker→supervisor stop signaling
v1.6.0 — Reliable worker→supervisor stop signaling
Hardens the core guarantee: a supervisor always learns when its worker stops — whether the worker reports back, forgets, or errors out — with no human polling.
Highlights
- Always notify on worker stop (#30): removed the suppression that silently dropped a stop when the worker had no bound task and no recorded outcome. Every distinct worker stop now wakes the supervisor (with task/outcome inline when present, an honest "stopped — no current task recorded" when not). Same-stop-event idempotency prevents double-fire; a genuinely-distinct later stop fires fresh. A worker in a no-op loop now surfaces (a bug to fix), rather than being silently muted.
- Notify dispatcher on all peer stops (#27) + stale-task backstop fix (#29): the periodic backstop re-checks that a worker's
current_taskis still live before paging, so stale/orphaned task bindings don't produce false "still working" notifications. - Dispatch activation validation (#28).
- Install hardening (#26): the installer AST-scans all imports (top-level + lazy) against the copied runtime closure, so a hook can't boot to ModuleNotFoundError fleet-wide from a missed file.
- r5-audit-gate (#25): risky-path changes require two independent adversarial audits before merge. Every change in this release went through it.
Notes
- No config changes required. Behavior change: supervisors will now receive a
peer_idleon worker stops that were previously silent — this is the intended safety net.
Full log: v1.5.0..v1.6.0.
v1.5.0 — production-grade hardening (stable-install, boot gate, injection envelope, tool-only heartbeat)
claude-code-fleet-notify v1.5.0
The hardening release. Everything since v1.3.3 that made the fleet's notification + wake layer production-grade — every change merged through green CI gates with an adversarial audit by execution on the hook/stop surface.
New capabilities
- Wake-state packet delivery — stopped sessions wake with context (refs, memory, rules) injected through the hook path, not just a bare pointer.
- Prompt-injection hardening — inlined ref/memory/rule content in a wake packet is wrapped in a per-packet unforgeable nonce envelope with a data-only boundary, so file content can never be read as instructions. Verified inert by re-running real injection payloads.
- Receipt-validated handoffs — explicit handoff records + passive receipts, with delivery tracing (
taey-trace). - Tool-only liveness heartbeat —
last_tool_activityis stamped only by tool hooks, closing the window where a daemon-injected prompt made an idle session look like it was working. - Stop-policy enforcement via the orchestrator API.
Reliability fixes
- Stable runtime-root install + boot gate — hooks install to a stable location (never a movable checkout) and the installer proves every hook imports from its deployed location before writing any settings. Fixes the class of outage where a moved checkout could disable every tool on the machine.
- Symlink-safe CLI bootstrap for
taey-handoff/taey-notify --handoff.
AI-native setup + honest docs
readme-as-a-strangerCI gate — a fresh GitHub VM follows the README verbatim (install → daemon → round-trip) on every PR; if the docs lie, the check goes red. This is the guarantee an agent can stand the project up from zero.- A live capability ledger (
docs/CAPABILITIES.md) with a re-runnable observation command per row; README no longer hardcodes a version.
Notes
- Backed by adversarial review (grok + an independent gatekeeper) on every hook/stop-layer change, verified by execution.
- Single-machine tmux fleets; see the README scope section for what's in/out.
v1.3.3 — Horizon rollback-stop fix (STABLE)
5/5 Family unanimous ENDORSE achieved at this tag. Promote v1.3.3 as the verified-stable release.
What landed:
- Horizon amendment #5 — rollback() now explicitly stops the failed-target daemon BEFORE reverting symlink. start_notify_daemons.sh start is idempotent (refuses if pidfile shows alive), so without explicit stop a partially-started daemon on failed code persists while symlink flips back — leaving fleet in mixed state. Stop → flip → start sequence. JSONL audit line extended with daemon_stop_rc field for post-mortem visibility.
PR #10 merged. Companion fleet-orchestrator v1.3.3: Horizon amendments #2 (queue regression tests) + #3 (priority validation API guards) + Gaia 7th-site catch (plan_readiness.py).
v1.3.2 — atomic_deploy.sh rollback resilience (Cosmos full audit fold)
Folds Cosmos AMENDMENT 1: rollback() runs 'set +e' so a failed daemon restart can't prevent the JSONL audit log line from being written. Captures daemon restart return code into the JSONL payload (new daemon_restart_rc field).
Per Cosmos full audit (2026-05-31): 'a system that silently drops its audit log during a failure state violates our foundational transparency.'
PR #8 merged. Companion fleet-orchestrator v1.3.2 fold: coalesce(t.priority, 999999999) NULL guard across all task-priority sorts (Gaia AMENDMENT).
Superseded by v1.3.3.
v1.3.0 — Stop-Discipline Engine
What this ships
The fleet's notification hooks now route Stop events through a typed wake_type engine instead of the legacy peer_idle string-match path. Sessions that supervise projects with ready work get a WAKE_WITH_QUEUE carrying the next task; sessions with no ready work get WAKE_REASON_REQUIRED listing the project's user_stop_conditions to choose from; sessions with no supervised work or matched conditions get ALLOW_STOP. Engine errors that recur 3+ times in 60s trigger a bug_lock with ENGINE_ERROR wake.
Backwards-compat with v1.0.2 blocked_on is preserved: _resolve_blocked_on runs first and suppresses peer_idle when a worker stop is in response to a peer command.
What's new
- 4 typed wake_types:
WAKE_WITH_QUEUE/WAKE_REASON_REQUIRED/ALLOW_STOP/ENGINE_ERROR - 5 new CLIs:
taey-stop-reason/taey-priority/taey-conditions/taey-pause/taey-queue - File-flag feature gate:
/home/mira/.taey/stage_b_enabledtoggle for safe rollout (env-var fallbackCF_STAGE_B_ENABLED=1also works for daemon-spawned contexts) - Atomic deploy script:
scripts/atomic_deploy.shwith symlink-flip pattern + versioned directories + rollback trap + dual health gate (daemon[UP]+ Redisping()) + JSONL audit log - Hot-deploy class developer guards: Makefile
hooks-safe-edittarget refuses operations on the live hooks-loading path; CI gate runsmake test+ gitleaks secret scan on every PR
Family audit lineage
- Stage B: 5/5 unanimous ENDORSE round 5 + Cosmos addendum (procedural BLOCK on packet construction — daemon.py + peer verdict citations were excluded from the packet though the prompt referenced them; resolved with verbatim inline addendum). Cosmos: "a map that skips coordinate verification because the system is tired is a map that lies." This is HMM.CANNOT_LIE_PROVENANCE working as designed.
- Stage B-Final: LIGHT scope round 1 (3 ENDORSE: Logos / Clarity / Cosmos + Horizon BLOCK on
atomic_deploy.shworktree-gitdir fragility + Gaia ENDORSE-WITH-AMENDMENTS on same plus a silent-success bootstrap bug) → round 2 re-verify (Horizon BLOCK LIFTED + Gaia ENDORSE non-blocking). Both Horizon's and Gaia's amendments folded intode868a6+707f744.
Rollback
Engine is rollback-able in under 2 seconds: rm /home/mira/.taey/stage_b_enabled. Hooks read the flag on every fire, so the rollback takes effect immediately, no daemon restart needed. Falls through to exact legacy v1.0.2 peer_idle path.
Deferred to v1.4.0
- Stage C UI panels for stop_reason management (5 CLIs cover the surface for now)
- Hook-version pinning (defense-in-depth atop CF gate)
- CI pre-deploy dry-run vs isolated Redis/Neo4j (current CI runs
make test+ gitleaks; service-container integration testing deferred) - Recurring task templates (orchestrator supports task cycling but no built-in auto-instance-creation scheduler)
Known follow-ups
- Issue #5:
atomic_deploy.shworktree-gitdir fragility under multi-redeploy (works for first deploy + same-ref redeploy + different-ref swap; breaks under symlink-flip-then-redeploy because the deployed worktree's.gitgitdir pointer references the source repo at creation time + the source path may move). Workaround: direct fresh-clone + manual symlink swap. Fix: replacegit worktree addwithgit clone --depth 1 --branch <sha>.
Companion release
claude-code-fleet-orchestrator v1.3.0 — the Neo4j-backed orchestrator that this engine talks to.
🤖 Generated with Claude Code
v1.0.2
Blocked-On Stop-Hook Verification
Date: 2026-05-27
Scope
- [Observed] Verification exercised the live
hooks/codex_stop.pyentrypoint for the active tmux sessionconductor-codex. - [Observed] The hook path resolved supervisor
conductor. - [Observed] Two real OrchTasks were created in the production tasks API and bound to the live session through the orchestrator dispatch wire:
- blocked task:
task-8af4e649 - unblocked task:
task-96cdbaa5
- blocked task:
Blocked-On Suppression
- [Observed]
task-8af4e649was markedin_progresswithblocked_on=family-round4-response. - [Observed] Invoking the live Stop hook entrypoint produced stdout
{}and stderr:
suppressed PEER_IDLE for conductor-codex: blocked_on=family-round4-response
- [Observed]
taey:conductor:inboxhad 0 messages before the blocked hook run and 0 messages after it. - [Observed] No
peer_idlemessage containingtask-8af4e649appeared in the supervisor inbox.
Inverse Check
- [Observed]
task-96cdbaa5was markedin_progresswithblocked_on="". - [Observed] Invoking the same live Stop hook entrypoint produced stdout
{}and empty stderr. - [Observed]
taey:conductor:inboxhad 0 messages before the unblocked hook run and 1 message after it. - [Observed] The emitted message contained:
type=peer_idletask_id=task-96cdbaa5task_description="unblocked stop-hook notification verification"
Cleanup
- [Observed] The temporary
current_taskbindings forconductor-codexwere cleared after verification. - [Observed] The temporary supervisor inbox messages used for verification were removed after capture.
Unknowns
- [Unknown] This verification used the live Stop hook entrypoint directly rather than waiting for a human-driven CLI stop event. The code path, session identity detection, Redis state, and supervisor inbox were all production surfaces.
v1.0.1 — adopter-validation patches
Both treasurer and x-claude ran their next full cycle through the orchestrator stack and reported back. Gate question 'would you bet your next cycle on this without monitoring it manually?' — BOTH answered YES on this patch.
Fixes
Grok input-path (daemon.py)
For *-grok target sessions, daemon now injects FULL message body via tmux-send instead of the pointer summary.
Root cause (independently verified by treasurer + x-claude with 3-fact chains): grok-cli inherits Claude Code's hooks via ~/.claude/settings.json but does NOT honor the additionalContext field from hookSpecificOutput JSON the way Claude Code does. So prompt_activity.py drained the inbox + cleared idle correctly, but grok only ever saw the [NOTIFY] pointer text — never the full task body.
New build_grok_full_body() peeks the inbox + concatenates message bodies (capped at 6KB; truncates with redis-key pointer for the pathological case). Hook still drains on grok's submit (idempotent — bodies already delivered inline). Pointer pattern unchanged for Claude Code / codex / gemini.
Tmux-send grok submit sequence
Per-CLI detection via session-name suffix. Grok sequence: Ctrl-U + Ctrl-K (pre-clear) → text → plain Enter. NO Escape (toggles modes in grok-Build modal TUI). NO CSI-u Enter (also toggles modes in input-ready state). Claude/codex/gemini sequence unchanged. Pre-clear added to BOTH — prevents re-injection accumulation if prior submit didn't land.
taey-ack import fix
sys.path.insert now searches standard installed locations (/usr/local/lib/claude-code-fleet-notify, /home/mira/claude-code-fleet-notify, script-relative). Treasurer reported globally-broken ModuleNotFoundError: 'identity'; verified fixed.
Makefile install
make install now copies scripts/tmux-send AND scripts/start_notify_daemons.sh to $(PREFIX)/bin (both were missing).
Live verified
- Treasurer cycle: 8 tasks, 3 dispatches (1 gemini + 2 grok), all peer_idle structured wire validated, plan_readiness UNBLOCK wake fired exactly once. Grok produced real cannot-lie catches.
- x-claude cycle: dispatched cycle4-validation-grok-claim-gate-v2, grok read full body, executed real source-traceability work, wrote 5889-byte verdict file,
record_outcome=done.
Pairs with
claude-code-fleet-orchestrator v1.0.1 (config robustness, state-drift grace, dispatch record_outcome footer).
v1.0.0 — first stable release
Marks production maturity. No code changes from v0.2.3 — bumps the semver signaling per Perplexity DR competitive analysis which flagged 0.x as the #1 HIGH-impact adoption headwind.
What's in v1.0.0 (cumulative since v0.1.0)
- Universal Stop+notify primitive across Claude Code, codex, gemini, grok via a single shared state machine + per-CLI hook variants.
- Lua compare-and-swap done-clear keyed on
(worker, task_id)preventing silent task-loss races. - Self-describing peer_idle wire with structured fields:
task_id,task_description,task_supervisor,task_started_at,outcome,outcome_details, optionalstate_file+state_file_sha. - Multi-CLI installer (
install-hooks.sh --all) handling Claude Code + codex + gemini config formats; Grok inherits Claude Code via~/.claude/settings.json. - Complete scope marker (terminal-native hookable REPLs only; IDE-embedded agents and many-to-many distributed topologies explicitly out of scope).
- Lifecycle hooks for all four event types (PreToolUse / PostToolUse / Stop / UserPromptSubmit; gemini equivalents BeforeTool / AfterTool / BeforeAgent / AfterAgent).
- Local daemon for tmux pointer injection on idle sessions with pending inbox.
Family validation
Design consultations + 8-finding code audit + 5/5 system-integration sign-off (Gaia / Logos / Cosmos / Horizon / Clarity). Every Tier-1 closed before v1.0.0.
Live validation
Continuous operation on the Mira fleet running treasurer + conductor + x-claude workloads. Real-fleet dispatch verification 2026-05-26 through the structured peer_idle wire.
Semver promise
From v1.x: backwards-compatible bumps only. v2.x reserved for any breaking peer_idle envelope change.
Pairs with
claude-code-fleet-orchestrator v1.0.0 (companion bump same day).