Releases: husker/a2acast
Release list
0.21.0 — actor attestation end-to-end (default off), real exec on owner-signed grant
Actor attestation lands end-to-end (parse → emit → surface → authorize), the
owner-signed grant gains a real exec path, and the receive path stops
persisting task state from frames it has not authenticated. Every new wire
behaviour is off unless the operator turns it on: actor_receive,
actor_emit, and require_actor_for_exec are each read with is True, so an
absent key is off and older peers are unaffected.
- #188 Phases 1–3 — actor attestation. A frame can now carry which actor
(harness session) acted, not just which node. Phase 1 parses and verifies the
actor field on receive (actor_receive, default off); Phase 2 emits it
sender-side behind an explicit fleet-capability assertion (actor_emit,
default off); Phase 2b surfaces the verified actor fingerprint in deliveries;
Phase 3 authorizes auto-exec on the(node, actor)pair against a curated
actor_allowmap whenrequire_actor_for_execis on (default off). This
addresses the #136 boundary that co-located agents share one node key — but
only once an operator enables it; shipping the code changes no live posture. - #186/#187 — authenticate frames before task persistence. The receive path
wrote task records before the frame's verdict was established. Task state is
now written only after authentication. - #157/#62/#180 — B2b-2b: real exec on an owner-signed grant. A verified
owner-signed grant can execute a curated pipx/pip/uv-tool-pypi upgrade,
making the operational half of #62 usable rather than dry-run only. Gated on
the existing curatedexec_allow; the roster is not an authorization source. - #158/#178 —
mesh fleetWAKE column. The wake-stall verdict is now
reader-assertible fleet-wide instead of local-only. - #177/#179 — presence liveness requires proven delivery. A live pid is no
longer accepted as proof a node will deliver; a wedged hook holding the
relay subscription reads as stalled rather thanlistening. - #76 F3/#185 — separate auto-discovery roster budget. Auto-discovery no
longer consumes the operator-seeded roster budget. - #182/#192 — aged fleet-health reports render as
stale(<age>), not
unknown, so a report that arrived and aged is distinguishable from one that
never arrived. - #136/#189, #183/#184 — docs. The node-identity boundary (one node key per
machine, shared by co-located agents) and what the mesh health signals do and
do not prove. - #190 and iam-rename test hermeticity. Two tests depended on wall-clock
polling and ambient node identity; both are now deterministic.
0.20.0 — fleet-wide liveness: supervised + wake-path watchdogs, remote receiver/agent health, mesh fleet
Fleet-wide liveness truth: every stall mode of a receiver is now detectable, most are auto-recovered, and each node's health is visible from every other node — plus two receive-path crash-class fixes. All new presence fields (recv/agent/wake) are additive, advisory, and display-only; older peers ignore them and read as "unknown" (mixed-version-safe).
- #158/#164 —
watch --supervisedstall-watchdog: a supervised receiver with a stale heartbeat recovers itself (close-response, then os._exit under a KeepAlive restarter). - #166/#167 — presence carries receiver-health: pong/ack frames stamp the sender's own
recv: healthy|stalled. - #169 —
mesh fleet: read-only fleet health table (last-seen, posture/status, RECEIVER/AGENT columns). - #170/#171 — agent-liveness heartbeat: distinguishes a live agent from a bare watcher; propagated as a raw
agent: active|idlecolumn. - #173/#175 — receive-path type-gating: crafted authenticated frames carrying non-strings where state strings are expected can no longer crash the receive loop.
- #158/#176 — wake-path watchdog: detects deliveries buffered while no agent drains them; SIGTERMs a positively-identified wedged defer-mode hook (relay/unknown-mode holders never touched, pid-reuse guarded) so the wake path re-arms; surfaces the unarmed case via classification logs,
mesh status, and awake: ok|stalledpresence key. - #168 — no session URLs in the public record (repo attribution kill-switch + CLAUDE.md hard constraint).
See CHANGELOG.md for detail. Upgrade nodes with pipx install --force a2acast (or your install method) and restart long-lived mesh processes to cycle onto the new code.
v0.19.0
Receiver-stall visibility (#158/#161), a Windows signing fix (#159), and the first real-exec slice of supervised adoption (#162 B2b-2a, dormant/default-off).
- #158/#161 — per-node receiver heartbeat +
mesh statusok/STALLED/no-heartbeat indicator; a silently stalled watcher is now visible instead of dark. - #159 —
A2ACAST_SSH_KEYGENoverride fixes the Windows OpenSSH 9.5p2-Y sign~60s timeout race that degraded frames to unsigned. - #162 —
adopt-supervise --execapplies owner-signed git-working-tree upgrades (fetch-verify the signed SHA -> checkout -> import smoke-test -> local rollback on won't-start). Dormant: default dry-run; a received frame never auto-execs.
Independently seated (lighthouse) + CI green including all Windows lanes.
v0.18.0 — owner-signed approvals over the mesh (observe-only / dry-run, default-off)
Fleet-adoption release for the #62 owner-signed-approval pipeline. Every step below is off by default, log-only or dry-run, and inert on 0.17.0 nodes — the fleet adopts the wire format before any node acts on an approval.
- Phase A (#152) —
mesh approve … --broadcastdistributes an owner-signed grant; a receiver verifies it against the pinned owner pubkey and logsMESH_APPROVAL_OK/BAD. No action, no nonce consumed. - B1 (#153) —
act_on_approvalsopt-in (default off, operator-only, never frame-settable); when on, logsMESH_APPROVAL_WOULD_ACT, still no action. - B2a (#154) — a verified
adopt-releasegrant writes an authenticated pending-adoption record + logsMESH_ADOPT_PENDING. Receive path runs no code. - B2b-1 (#155) —
mesh adopt-supervise(operator-run, opt-in) reads a pending record, re-verifies the owner signature, detects install type, maps the pinned artifact to the op it would run, logsMESH_ADOPT_WOULDEXEC/REFUSED. Installs nothing, cycles nothing.
The real package-manager exec (B2b-2) is a separate, operator-gated slice — not in this release.
a2acast 0.17.0 — signed-approvals flagship groundwork
0.16.1 — no more silent delivery loss; per-node signing
0.16.1
- Fixed the two delivery-loss mechanisms behind #86, validated live on all
three platforms:- Every delivery path now writes the per-node activity file (shared
_activity_lineformat), so a lifecycle hook deferring behind a plain
mesh watchpresence holder wakes on delivery instead of starving and
dying silently when the watch exits. - Transport checkpoints (cursor + replay fingerprint) run only after the
delivery handoff — inline after a successful emit for standalone
watches, deferred until after the hook's own output in hook relay mode.
A death before handoff leaves the frame re-deliverable: at-least-once
instead of silent loss. Undeliverable frames are consumed exactly once
and leave a visible activity trace. - Activity previews decode message envelopes (not just tasks), keeping
the watch and MCP writers in agreement.
- Every delivery path now writes the per-node activity file (shared
- The agent-session watch warning now names the one-shot
mesh watch --timeoutre-arm fallback for harnesses where the hook
cannot wake yet; the defer-mode wake summary mentions the CLI drain
commands for sessions without MCP tools. - Known limb, tracked in #90: on Windows the harness-spawned async
claude-hook process exits instantly and never receives — with this
release that degrades to delayed redelivery, never loss; the one-shot
re-arm loop remains the Windows posture.
This release also ships everything from 0.16.0, which was never published (PyPI latest was 0.15.1):
0.16.0
- Per-node message signing (#62 phase 2): every node holds its own ed25519
key, signs its outbound frames over the wire AAD + payload, and classifies
inbound frames against a locally-pinned identity (verified / unverified /
unsigned / mismatch). Trust is trust-on-first-use; the receive path is
NON-ENFORCING — it surfaces a verdict and pins peers but drops no frame.
Enforcement + the downgrade ratchet are still pending (#74). A node
generates its key on first send, so upgrading an existing node is enough. - Owner keys are passphrase-protected by default (#64): minting an approval then needs the passphrase on the terminal, which a harnessed agent cannot answer — so an owner signature proves a human acted, not just that a process read the key.
owner-init --no-passphrasekeeps the old unprotected key (loudly warned);owner-trust --replacerotates the trusted owner key. - Owner-trust now prints a SHA256 fingerprint and requires a terminal
confirmation before pinning; the owner private key's permissions are
asserted (POSIX mode + Windows ACL). - Bound the replay ledger with time-based eviction (#77); mesh status shows
the held count. - mesh peek no longer mislabels expired large-message attachments as
[UNVERIFIED] (#65). mesh watch --followwarns when it would be a write-only pipe in an agent
session; join steers to the lifecycle hook (#57).mesh mcp-serve --harnessresolves identity from the pin at each startup,
somesh iamrenames take effect (#59, #60).- The generated .gitignore now uses a
.meshwire.*glob, closing a gap that
left the owner private key stageable.
0.15.1 — pinned join bootstrap + CI
- Security: invite bootstrap blocks now download
mesh.pypinned to the inviting node's release tag (v<VERSION>) instead of the tip ofmain, so a bad or malicious push to main cannot break or compromise future joins. - GitHub Actions CI: the unittest suite runs on Linux and macOS across Python 3.8–3.13 (Windows observational — #48), a consistency job keeps
mesh.py/pyproject.toml/plugin manifest versions in lock-step, and a gitleaks job scans full history for leaked secrets on every push. - PyPI publish workflow (trusted publishing, runs on GitHub release).
- Docs: list
mesh_delegatein the MCP tools roster.
0.15.0 — machine-wide worker pool
- Opt-in machine-wide worker pool with distinct Codex, Copilot, and Goose/Ollama identities.
- Versioned isolated-worktree jobs, structured branch/commit results, and recipient-scoped task records so parallel supervisors cannot race.
- Journaled execution, reply-only retries, health/cooldown routing, MCP delegation, conservative worktree cleanup, and macOS LaunchAgent lifecycle.
- Preserves the existing default-off, default-empty-allowlist Codex supervisor and documents that worktrees are not security sandboxes.