Skip to content

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 governance forwards to bernstein govern with 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.