v3.4.0
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_set
receipt, 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
pipx upgrade bernstein # or: uv tool upgrade bernsteinNo 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.