v3.19.1¶
94 changes since v3.19.0. This is the release where the name caught up with the product.
Bernstein began as a scheduler for coding agents. Along the way it started keeping receipts: for every approval, every key, every model, every span an agent emits. What ships here is a governance framework for AI agents — the part that lets a security officer say "I know what the agents did, and I can prove it", and lets an auditor check the proof without trusting us. It is Apache-2.0, and every claim in it can be verified by someone who does not like us.
Seven questions, answered from the record¶
| The question you get asked | Before | Now |
|---|---|---|
| Did a person approve this? | An approval gate that timed out counted as approved. Nobody could tell that record from a real one. | It fails closed and the record says timed_out. Approving on timeout is a named opt-in, and the expiry is still written down as an expiry (#5051). We are not proud of the "before". |
| Where are the secrets? | Copied into Bernstein's store. | They stay in your store. Bernstein brokers a short-lived credential and records the grant, the issuer, the audience and the expiry — never the value (#4984). A token can be bound to the certificate that must present it; a replay from anywhere else is refused, and the refusal is chained (#5030). Secrets surfacing in tool output are redacted before storage (#4992). |
| Who is this agent, and who says so? | An identity per credential format, minted on request. | One principal type behind both credential formats, and authority decisions are checked against it (#2926). Principals are provisioned and deprovisioned through an append-only, HMAC-chained lifecycle (#4972), and a child identity cannot be minted with a wider scope than its parent (#5046). Your identity system reads the roster over SCIM 2.0 (#5040). |
| Which model was allowed, on that day? | Whatever today's config file says. | Replayed from chain events at that instant (#5038). Drift observations are signed (#5041), an MCP server's tool-set changes are logged (#4975), every spawn records which endpoint served it (#4908), and plugins and skills are pinned to exact content addresses — latest is refused (#5089), a catalog skill linted for hostile prompt patterns before install (#2899). |
| What did the agents we did not schedule do? | Nothing on record. | Point the OTLP collector you already run at Bernstein. Spans become receipted chain entries, and the receipt states its coverage limit instead of implying more (#4983, #4962, #5024). A guard that never fired is now distinguishable from a guard that was never reached (#3454). |
| Show me the audit. | A printout. | bernstein govern is the one CLI (#5010). The report is a chain-anchored artefact: two audits of an unchanged install are byte-identical, an edited report fails verification (#5077). One number scores posture from what the chain evidences (#4989), against checks with stable ids and a verdict that can say "not measurable" (#5072). Per control, compliance coverage says evidenced, partly, or cannot be (#4978), and separates what was observed from what an operator asserted (#5029). govern reconcile --propose asks whether the declared surface is still installed (#5085); governance plan diffs declared posture against what is deployed (#4980); cluster govern-inventory covers the workloads nobody remembered to wire (#4988), and govern inventory --render draws the result (#5133). A run reports what share of its actions a decision covers, and an uploaded receipt gets a verdict (#5067); every external policy verdict is recorded, including "the engine did not answer" (#4912); playbooks hash the same in any clause order (#4979); cost rolls up per principal and per grant (#4985), and crossing a budget cap is a chain event, not a log line (#2918). Evidence exports against the records-derivable subset of ISO/IEC 42001 Annex A (#3238), and the AI-BOM comes from the run's own lineage (#2916). |
| Can I check this without you? | Mostly. | Signing keys rotate and revoke through a signed succession chain: receipts an auditor already holds stay valid, a revoked key fails (#4211); an out-of-band key can be pinned when verifying an envelope (#5064). Session revocation is chained (#5031). Audit checkpoints can be timestamped by an outside RFC 3161 authority and co-signed by a witness, so a rewind no longer verifies clean (#5147, #3161). Evidence ships as a versioned signed envelope (#5063), receipts are checked against numbered format requirements with an executable corpus (#4987), and bernstein verify picks its verifier from the artefact itself (#5103). Lineage exports to W3C PROV-O (#5039); run evidence exports as a signed TRACE 0.2 record, offline (#4667). KMS adapters live in a custody module (#5033). |
The receipt that did not verify¶
Offline verification of a signed refusal receipt failed on every input, and a broad exception guard hid it: a valid receipt and a forged one looked the same (#2980). Fixed, with a test that verifies a real receipt from the on-disk record alone. The standalone verifier had a second version of the same problem — run as a script it exited without verifying anything (#5054). In the same spirit: volunteer bundles are re-run in a clean worktree before they are believed (#3871); diff comments bind to bytes, not line numbers (#3456); every adapter kill returns a reap receipt (#5015); scan results record the invocation that produced them (#5151); receipts on targets carry a freshness window (#5087); a run receipt binds the audit window it declares, not only its content hash (#5269); a checkpoint binds the bytes its suspended work was derived from, so a resume cannot continue on files that moved underneath it (#5206); findings are canonicalised strictly, so a payload that was silently accepted before is now rejected (#2953); and sensitivity propagates across a lineage closure, so a summary of a confidential document is confidential (#5042). And every number in a pull-request description now describes the same diff: the diff-stat is asked of the branch, like the commit list beside it, instead of a snapshot of a worktree that had since been cleaned.
For the engineers¶
Context: an opt-in pack folds co-change neighbours, the test-to-source map and the nearest AGENTS.md into one content-addressed prompt section (#4522); context manifest (#3366) and context segment-prompt (#3455) digest what an agent was given; structural compaction is reproducible, with correlation ids derived from the fold rather than a random uuid (#2915); memory show folds a memory chain to its live claims (#2914). Runs: deterministic repository-flow samples (#4940) feed a stagnation detector (#4941); runs report shows lifecycle state and step timings (#5127); a lease primitive claims a TTL'd resource (#5128); completions can name what they produced (#5002); the per-task token budget is actually wired into the tick (#3374); evolve run folds a recurring failure into one issue instead of many (#4504); GitHub push events respect the cooldown, dedup and filter rules in triggers.yaml (#4545); a volunteer hub can offer work with no git forge behind it (#3877). Adapters: Kimchi over ACP (#3100), Nmap (#3618), garak (#4839), Skyvern (#4876); adapters draft proposes a profile from an installed CLI (#3763); agents discover --harness-local reports harness paths, status and content digests (#3969); gptme honours max_tokens (#4955); feed-pinned Trivy scans verify the database they loaded (#4961); bernstein activity gained research, data and ops subgroups (#4925); Qwen, OpenCode, Codex and Gemini all deliver the completion protocol a spawned agent needs to finish (#5325); a codex run whose sandbox denied every command is reported as the failure it was, instead of exiting 0 (#5314); an operator whose host already isolates can declare that, instead of switching everything off (#5341); and the codex sandbox argv follows the adapter's declared dangerous-mode strategy rather than a hardcoded flag (#5323). Two paths that could reach the operator's own checkout — a warm-pool slot with an empty worktree path, and salvage — no longer can.
On upgrade¶
bernstein governanceforwards tobernstein governwith a warning; it goes away in v4.0.0.- If you relied on approval gates resolving on timeout, set
approve_on_timeout. The expiry is still recorded as an expiry. - A skill installed from a catalog is now linted before promotion; a skill that fails the lint is refused rather than installed.
Smaller fixes¶
2919, #4873, #4904, #4913, #4916, #4918, #4938, #4947, #5048, #4996.¶
Contributors¶
Thanks to @vaibhav8a, @Phoenix1504e, @PARZIVAL7498, @saketh-bandi, @albin-george-kurian, @chuanxu742-glitch, @GOLDMEMARY, @kudala-bharani, @prateeekbuilds, and @Rehan30g.