Production profiles
Everything on this page composes features documented elsewhere; nothing here is a new switch. The value of a named profile is that its parts fail closed TOGETHER: each posture below lists what to turn on, what the posture guarantees, and, just as deliberately, what it does not.
Read-only diagnosis
The posture for investigation workloads: incident triage, repository research, audit sweeps. The run may read anything it is pointed at and must change nothing.
- Give agents read-only toolsets: the repository research toolset is built for exactly this shape, and its
record_evidenceentries feed the claim-consistency pool so conclusions stay tied to what was actually read. - Pin each profile's toolset with a toolset attestation, so a drifted or poisoned tool description refuses typed at spawn time instead of silently re-keying into the run.
- Compile permissions with a deny-by-default preset and
strictApprovals: true, so a blanket allow from a hook can never silently clear a tool that declaredneedsApproval. - Declare evidence contracts on the reading agents and hold acceptance to them with
requireEvidenceFloor, so a child that read too little cannot be promoted into the roster that steers synthesis. - Bound the money before the first call: a run budget ceiling, the in-flight exposure cap, and the strict pricing gate together refuse surprise spend instead of reporting it afterward.
- Importing tools from an MCP server? Declare
requireBounds: trueon the source (RV1808), so the four discovery bounds (maxTools,maxPages,maxSchemaBytes,timeouts.discoveryMs) must all be stated and an unbounded sweep against a remote registry cannot happen by omission; the cycle guards need no configuration. See MCP. - Gate downstream automation on the (
status,completion) pair and the envelope facts, per the terminal contract for consumers.
What this posture guarantees: no tool with side effects is reachable, no approval is silently waived, and an accepted result names the evidence it stands on. What it does not guarantee: that the model read everything relevant; the evidence floor bounds under-reading, not judgment.
Since RV1606 the profile half of this list ships assembled: pilotAgentProfile(options) (async, because the attestation pins the RESOLVED toolset) wraps researchAgentProfile and returns { profile, evidence, attestation } with the toolset attestation recorded, permissions hard-denying every risk class outside declared reads (write, network, execute, destructive, and undeclared in one deny rule) with strictApprovals armed and inheritPermissions off, and isolation pinned to 'none'. A write-risk tool smuggled in through extraTools is still attested (the pin covers what the factory resolved) and still refused at dispatch by the risk rule, pre-effect; a registration that drifts from the pin refuses typed at spawn. The engine-level halves of the posture (budget ceiling, exposure cap, strict pricing, acceptance floors) stay explicit engine and run options: a profile cannot set them, and the factory does not pretend to.
Isolated patch
The posture for workloads that produce changes without applying them: fix generation, migration drafts, review remediation.
- Run tool work out of process through the isolated executor (subprocess or container adapter), so a hostile or model-generated script cannot reach host capabilities.
- Give write access only inside worktree isolation: the child works on an isolated copy, and its changes come back as patch artifacts the host applies or discards.
- Keep the effect ledger's boundaries in mind: it records what the executor observed, and what the ledger is NOT (not an outbox, not authorization, not exactly-once) is the reason the APPLY step below stays with the host.
- Put every apply behind an approval with an explicit
defaultDecisionon unattended flows, so an expired approval resolves the way the host declared, never a library-invented accept.
What this posture guarantees: the blast radius of a bad patch is the worktree it was drafted in, and applying it is a host decision recorded on the host's side. What it does not guarantee: patch quality; validators and review own that.
The regulated floor: one call, refusals typed
Every assurance posture in this library is an opt-in knob, which is correct for a library and hazardous for an unreviewed config: a deployment that hand-assembles twelve options can silently omit the one that mattered. compileRegulatedProfile(input) (RV4009) is the one-call composition for workloads that must not run loose. It takes ordinary { engine, run, orchestrate? } options and returns the same shapes with the regulated floor applied:
permissions.strictApprovals: trueon the engine defaults (the monotonic mode; a profile cannot un-arm it).billingReceipts: 'intent', so every provider wire journals its intent before it can bill.determinism: { mode: 'error' }: bare nondeterminism in workflow bodies refuses instead of warning.strictPricingarmed and a positive finitebudgetUsdrequired (RV4107: NaN and Infinity are not ceilings), underbudgetPolicy: 'immutable-lifetime', so the recorded ceiling binds every later segment.scoperequired (RV4007): a regulated run has an owner, recorded at genesis. The compile normalizes it (RV4107) and enforcesscopePolicy: { unknown: 'reject' }(RV4205): an unknown dimension refuses typed by name at compile time (a silently dropped dimension is a dimension nothing downstream recorded or bound), an empty or malformed scope refuses the same way, and the named dimensions (tenant,account,project,legalDomain,region,providerAccount, and since RV4408sponsor, the principal on whose behalf and at whose expense the work runs, distinct from the owning tenant and the billing account) enter the hashed posture.- When
orchestrateoptions are present:budget.acceptanceReserve: 'require',citationAuditmust be declared, andclaimConsistencymust be declared with stage'final'or'both', running atcoveragePolicy: 'strict-final'on the shipped document, not the draft (RV4103). Absence is the loosest claim posture there is: an orchestration with no claim machinery runs no pass, grades no coverage, and arms no gate, so the floor refuses the omission exactly like an explicit loosening; it does not autofill a judge it would have to invent billable defaults for. - The findings postures fail closed too (RV4201, the sixth comparison experiment):
claimConsistency.onFoundandcitationAudit.onFoundrefuse'report'and'carry'(the observing postures let a run settle accepted over what its own judge found; the sixth run shipped a judged contradiction and five unsupported citations through exactly them), fill'fail'when absent, and license an armed'repair', fillingcoverageRepair: truebeside it so the one bounded round serves every defect class. AcoverageTargetbelow 1 refuses (the regulated acceptance requires the'full'grade, unreachable under a pass sized to cover less), and a STANDINGclaimConsistency.waiverrefuses outright: regulated acceptance admits either no exception or the pinned-hash form. The compile then writes thesemanticAcceptancedeclaration from the postures it enforced (or judges a declared one for mismatches, the RV4107 rule: the floor judges its own intake), so a regulated run physically cannot settle accepted over a non-'full'grade, a surviving contradiction, or a surviving unsupported citation, and the only waiver it can honor is a signature under one reviewed document'sjudgedHash. - The deliverable contract is the floor too (RV4303, v4): with
orchestrateoptions present,finishValidationmust be declared with the host's own validators, because without the contract there is no deliverable verdict and no candidate chain, and the floor does not invent acceptance criteria (the RV4103 rule, symmetric withclaimConsistency). Inside it the compile fillscandidatePersistence: 'hash-only'(the auditability minimum: every verdict carries the candidate identity, and an absent blob reads as declared policy, never as loss;'transcript'is the legal richer declaration), and the legacyretainRejectedCandidatesboolean refuses at BOTH values, the fail-closed migration: a silent canonical rewrite would compile a lineage posture the host never wrote. The citation audit's resolver generation is pinned the same way:citationAudit.resolverfills2(the bounded logical-unit resolver, RV4208) and an explicit1refuses, because the fixed four-line window is the diagnostic resolver whose truncation manufactured the sixth comparison run's false negatives. - The audit's SCOPE stays the host's call, with one recommendation (RV4407, not floor): for critical document classes, declare
citationAudit.auditScope: 'all', the census mode that judges EVERY anchor row of the document instead of the default deterministic sample. The seventh comparison experiment's terminal counted 10 unsupported of 24 SAMPLED rows over a 105-citing-sentence document, and the sample-versus-census gap was the loudest open question of its post-mortem. The cost arithmetic is prompt-shaped, not pass-shaped: the census is still ONE judge invocation (two under an armed round, exactly the sample's worst case), its rows ride the prompt, so at the seventh run's shape the census prompt is roughly four times the 24-row sample's andjudge.estCostshould be sized accordingly (the declared estimate enters the acceptance tail unchanged, one term per pass). The floor question has since been settled by evidence, in both directions at once: census rejudges of two refused candidates showed the SAMPLE is honest, the judge making zero errors over honest resolver 2 windows and the RV4401 fix collapsing the sampled unsupported count to exactly the candidate's real defects, so a mandate would buy no correctness; and the CENSUS is completeness, surfacing roughly three times the real defects the sample could reach for under five times the judge's price, and holding at scale (215 rows, one invocation, a full verdict bijection back). So the floor still does not require the census, now on evidence rather than expectation: sample buys honesty, census buys completeness, and the document class chooses. Declaring it, sizejudge.limits.maxOutputTokensPerTurnfor the bijection: the RV4706 guard refuses a declared cap below 70 tokens per judged row plus 500 BEFORE any provider call, the arithmetic both census rejudges had to do by hand. - Any profile that declares
toolsmust carry a toolset attestation, and since RV4204 the pin must be a FULL one: a legacy contract-only pin (noauthorityHash) refuses outright, because authority drift (risk, needsApproval, executor, executorSpec) passes it silently by its own documented posture. Re-record withattestToolset(). - The attestation floor is armed engine-wide (RV4204):
defaults.requireToolsetAttestationfillstrue, so a spawn that resolves a NON-EMPTY toolset under a profile with no pin (the per-call-tools hole the profile pins could not see) refuses typed at spawn time, before any provider call. - Constructions the options reach must hold their posture (RV4101): an
mcp()source must rundrift: 'refuse'with every discovery bound declared, and abridgeAiSdk()adapter must keepproviderExecutedTools: 'deny'. Since RV4204 the first-party constructions attest too:anthropic()andopenai()report their egress (official, acustom-base-urlwhose origin the hash pins, or apreconstructed-clientnamed honestly) and the caps pagination bound,subprocessExecutor()andcontainerExecutor()report their ledger, env allowlist, ceilings and isolation seam, and the walk coversengine.executorsand the sandbox runner beside adapters and toolsets. A regulated executor without aToolEffectLedgerrefuses by field name: an effect no ledger records is an effect nobody can reconcile. A construction exposing nodescribeRegulatedPosture()is counted into the hash asunrecognizedrather than implied verified, and the opt-inconstruction: 'require-recognized'turns that count into a typed refusal naming the blind constructions, satisfiable now that the first-party surface attests.
The compile REFUSES what it cannot keep: a field that loosens the floor (billingReceipts: 'async', determinism: { mode: 'warn' }, a missing budget or scope) throws a typed ConfigError naming the field, never a silent overwrite. A config that compiles is a config whose author either stated the floor or left it to be filled; a config that fights the floor fails loud at construction, before any wire.
The returned profileHash is a sha256 over the enforced posture map, and the compile writes it into run.configFingerprint as regulated:4:<hash> (the 4 is the posture-map version: RV4101 added the construction key, RV4203 added the semantic postures, because the sixth comparison experiment's headline finding was exactly that the v2 map hashed none of them: a run configured report beside a standing waiver and a run configured fail closed carried the identical fingerprint, so the attestation could not tell a diagnostic posture from a production one; and RV4303 added the deliverable contract, because candidatePersistence lives inside a finishValidation the v3 floor never required, so a regulated orchestration could run with no deliverable verdict at all). The v4 map hashes the findings postures of all three passes, the waiver mode and its declared terms, the citation audit's sampling, judge parameters and resolver generation, the semanticAcceptance declaration in full, the required-contract fact with its candidate persistence mode, and the declared toolset attestation pins (contract and authority hashes, so an upgraded pin moves the fingerprint). The existing fingerprint machinery does the rest: genesis records it, and a resume asserting a different fingerprint refuses before ownership. No new meta surface, no engine branch: the compiled options are DATA, applied like any others.
Since RV4101 the hash covers the constructions too. A risk-bearing construction exposes describeRegulatedPosture(), a pure snapshot of what it chose at build time: an mcp() source reports its drift and discovery bounds, bridgeAiSdk() reports its provider-executed-tools seam. The compile walks every construction the options reach (adapters, named toolsets, profile toolsets), refuses a loosened posture by field name (construction['mcp:http:...'].drift must be 'refuse'), and folds the sorted descriptors into the hashed posture map beside an unrecognized count of the constructions that exposed nothing, so the hash names its own blind spot instead of implying totality. The RV4009 rule stands, sharpened: a hash must not imply what it cannot verify, and what it CAN verify it now does. The window between compile time and use is held too (RV4102, the RV1608 template): the compiled options carry each attested construction wrapped, so every use of its risk seam (tools() on a source, stream() on an adapter) re-reads and re-judges the descriptor first; a posture loosened after compile refuses with the same field-named error, any other movement refuses naming the drift, and everything else (close(), caps(), identity fields) passes through untouched. The cross-process half of the window never needed a wrapper: a mutated construction compiles to a different profile hash, and the RV3210 resume assertion refuses it.
Merge and deploy authority: not claimed
There is no rulvar profile for merging to a protected branch, deploying, or mutating production data, and that absence is a design position, not a missing feature. The library gives a host strict hooks and fail-closed gates; it does not own fleet budgets, IAM, transactional outboxes, or multi-region consensus, and a workflow result is facts, never permission. A deployment that wants agent-produced changes takes them as artifacts from the isolated-patch posture and pushes them through the same review and release machinery humans use, on infrastructure that owns authorization. Anything that promises otherwise is claiming authority this library deliberately refuses to hold.