v3.4.0¶
Released 2026-07-12.
A feature release built around one idea: the artefact an operator sees is itself the verifiable receipt. Typed activity records, detached runs, tournament selection, cost-aware dispatch, in-process gates, a spec-to-graph pipeline, workload identity, an MCP Tasks surface, a receipt-backed update path, and the run review board all land as signed, replayable records rather than logs beside the work. Windows parity coverage and the MCP registry OCI packaging fix round out the release.
A few extra-large items shipped a complete first phase with documented follow-ups; each section below says what landed and what is deferred.
Typed activity data and ops modalities (#2311)¶
The typed activity boundary gains explicit data and ops modalities, so an activity is recorded with its shape rather than as opaque text.
- Each activity result is projected into the HMAC audit chain as an
activity.resultreceipt carrying the modality, the content hash, and the prior chain digest. - A verifier can join a chain entry to the recorded activity and confirm the modality and payload hash without replaying the run.
bernstein activityrenders and checks the recorded modalities.
Detached run service (#2352)¶
A run is no longer tied to the process that started it. Operators submit a goal, disconnect, and reattach later.
bernstein run-servicesubmits a goal, detaches to a supervisor, and reattaches to an existing run.- A restart resumes from the durable run descriptor and ledger rather than starting over; the active chain is never rotated mid-run.
- Submit, detach, reattach, and completion are each
run.lifecyclereceipts in the audit chain, so the full life of a detached run is reconstructable. - Run directories are realpath-contained under the service root, so a run id can never redirect state outside the runtime tree.
Follow-ups: broader supervisor back-pressure controls are tracked separately.
Tournament runs (#2353)¶
A hard task can fan out into parallel attempts and keep only the winner, with the decision fully explained.
- A task declares
attempts: Nwith scripted evaluators (test pass rate, lint status, coverage delta, mutation score, or an arbitrary command). - The scheduler runs N sibling attempts in isolated worktrees with identical inputs; the winner is a pure function of the evaluator outputs with a stable attempt-hash tie-break, with no model call in the decision path.
- The result is a signed, spine-anchored
TournamentReceiptnaming every attempt hash, every evaluator output, the winner, and the lineage edges; the selection is mirrored as atournament.selectionaudit event. bernstein tournament showandbernstein tournament verifyrender and recompute a selection offline, so a tampered score or a hand-picked winner diverges from the replay and fails.- Fan-out is gated on the task's existing per-ticket budget ceiling and aborts before spawning when projected spend would breach the cap.
Cost-aware scheduling (#2354)¶
Dispatch decisions now respect USD budgets and route work to the cheapest surface that can honour it.
- Each cost-aware dispatch is a
cost.dispatch_receipt: a deterministic admit or halt under USD caps, pinned by a decision hash over the price table, spend ledger, and caps, so two operators replay the same verdict. - Non-interactive work routes to a provider batch surface where the adapter declares one; a prompt-cache window schedules a warm-up fan-out where the adapter documents one. Both capabilities are declared per adapter and default to the conservative option, so work is never routed to a surface an adapter does not offer.
- Pool preflight projects per-pool spend before dispatch and refuses work that would exhaust a pool.
Follow-ups: additional provider batch endpoints are added as adapters declare them.
In-process verification gate (#2360)¶
A gate-capable adapter can enforce the completion and path policy in-session, the moment a worker believes it is done.
bernstein hook-gatereads the worker's hook events, loads the task policy, refuses an out-of-scope write, and refuses to end a turn on a failed required check.- A gate decision is sealed as an evidence bundle, so a verifier cannot tell from the schema whether the gate fired in-process or scheduler-side.
- An adapter with no blocking hook surface injects no gate hooks and degrades to the authoritative scheduler-side gate with no policy weakening.
Spec-to-task-graph pipeline (#2361)¶
Teams that write specs first get a supported path from a requirements document to a gated task graph.
bernstein plan compileholds at most one model call: draft extracts acceptance lines into a content-addressed requirement set, approve binds the requirement-set hash into the audit chain as aspec.requirement_setreceipt, and compile turns the approved set into a task graph as a pure, model-free transformation.- Each task node is content-addressed over the requirement lines it implements, so the same approved set always compiles to a byte-identical graph and editing one requirement re-plans only the affected node.
- A verifier can prove offline that a graph was compiled from the exact requirement set the operator approved; any post-approval edit breaks the chain.
SPIFFE-compatible workload identity (#2363)¶
Fleets standardizing on SPIFFE workload identity can map a bernstein fleet onto deterministic SPIFFE IDs.
- The Ed25519 install identity and each agent card map onto a deterministic SPIFFE ID, so two operators derive the same id for the same install and agent and a verifier re-derives it later.
- With a SPIRE agent present (optional
bernstein[spiffe]extra), the issued X.509-SVID is bound to a card by aspiffe.svid_bindingreceipt that re-derives the id, refuses any SVID whose id disagrees, and appends the binding hash to the audit chain. bernstein spiffe idderives the id offline andbernstein spiffe verify-bindingre-derives it and proves the card-to-SVID binding against its chained receipt. Without the extra, the self-contained Ed25519 path stays the default and every existing flow is unchanged.
MCP Tasks extension (#2364)¶
Long-running runs are exposed through the MCP Tasks surface as verifiable run handles.
- A run handle is emitted as an
mcp.task_handlereceipt, so a caller can reconnect to a long-running run and verify the handle against the chain.
Receipt-backed skill and plugin update path (#2369)¶
Installing and updating bernstein as a skill or plugin now produces provenance rather than a silent overwrite.
- An update is a
plugin.update_receipt: the manifest hash and spine anchor are recorded, and an update whose manifest hash does not match the receipt is refused. - Aggregate install status reports the verified state across installs.
Run review board: diff viewer, evidence panel, attested actions (#2365)¶
The run review board gains a diff viewer and an evidence panel, and every board action is attested.
- A reviewer sees the run diff and the sealed evidence behind each step in one view.
- Approvals and rejections are
review_board.actionreceipts joined to the run journal, so a review can prove which action a principal took under which scope.
Windows process and worktree parity coverage (#2367)¶
Windows process and worktree branches gain mock coverage, and the lane promotion path is documented, closing gaps ahead of first-class Windows support.
MCP registry OCI packaging fix (#2424)¶
The MCP registry packaging path publishes a correct OCI artefact, fixing the registry publish flow.
Upgrading¶
No configuration migration is required. The SPIFFE integration is opt-in via the bernstein[spiffe] extra; every other capability is available by default and leaves existing flows unchanged.