Start with the part that works.
The gate is fail-closed, and that is not a small thing
When the policy engine composes an ASK, the runtime hands the result to an approval helper that drives one elicitation round-trip and returns true only when the verdict carries an action of exactly accept [4]. Decline, cancel, malformed JSON, a missing field, an unparseable body, a timeout — every one of them returns false and the caller maps it to a denial. The source calls this fail-closed and cites the section of its own policy specification that requires it.
Better than that: the labels and state updates an ASKing policy accumulated are applied only on approve [4]. A refused, cancelled, or timed-out approval applies none of the policy’s pending session-state writes. It still leaves operational records — the elicitation row is registered before the prompt is emitted, and every evaluation is recorded on a telemetry span [4][5]. The engine composes the same way — an ASK carries its writes forward unapplied, and the caller lands them after the verdict [5].
This is a well-built gate. It fails in the safe direction, it applies no pending policy-state effects on refusal, and it rides the Model Context Protocol elicitation primitive rather than a bespoke prompt. An assurance case can rely on that gate contract: anything short of an explicit accept is denied, and pending policy writes land only after approval.
Two questions remain, and neither is about the gate. What raises it, and who may walk through.
What raises the gate abstains
The control that decides whether a tool call warrants an approval at all is intent_based_authorization, and at v0.9.0 it is unchanged from the release the prior dispatch read [6]. It records the user’s first message as the session intent, truncated to one thousand characters, and shows the judge the first five hundred. It abstains when no model client is configured, when the response carries no text, when the call or parse raises, when the verdict is unrecognized, and when no intent has been captured yet. Two of those paths are annotated as fail-open in the source. The docstrings still say off-task calls are denied before they run; the implementation still returns ASK.
So the composition is precise, and worth stating plainly. The gate is fail-closed. The judge that decides whether to raise the gate is fail-open. Those are different layers with opposite failure postures, in the same product, and the assurance claim an enterprise infers from “intent-based authorization” depends on the one that abstains.
Who may walk through
Databricks states the human requirement directly: the agent is given tools to browse and to add policies but none to remove, edit, or disable one; even adding a policy needs a human, because a built-in rule requires explicit user approval before any new policy takes effect; and a new policy cannot overrule the old one, because when policies combine a single denial wins [7]. Three properties, offered as verifiable in the source code. So we read the source code.
The route that resolves an outstanding elicitation gates on LEVEL_EDIT [8]. The constants are unambiguous: read is 1, edit is 2, manage is 3, owner is 4 [9]. Nothing in the resolution path requires owner. The route that renders the approval page gates identically.
An administrator check returns true before the conversation is even looked up, so an approval is independently resolvable by an administrator through a path that does not depend on any session grant [10].
A public grant satisfies the required level, so a session shared broadly at edit level makes the approval reachable by whoever holds that share [10].
A sub-agent conversation delegates its check to its parent, so access to it is governed by the parent conversation’s grants [10].
Their own wording gives way twice here. The resolve route’s docstring calls its gate the session-owner LEVEL_EDIT gate — naming as owner a constant their own scale puts two levels below owner. And the registry the route leans on for a server-side ownership check maps an elicitation id to a conversation id, so what it verifies is that the elicitation belongs to that session [11]. It holds no caller identity. It cannot check ownership, and its docstring says it does.
None of this is stale behavior discovered after the fact. It is the approval model Omnigent deliberately restored in v0.9.0 and listed as a breaking change [1].
And there is a gap underneath the level. The session intent is set by one principal — the first user message. The approval that clears a departure from that intent is resolved by any editor, an administrator, or whoever holds a public share. Nothing binds the two. The route extracts the caller’s identity, spends it on the access check, and then drops it: the resolver receives the session id, the elicitation id, and the verdict body, and no approver identity travels into the resolver [8]. The route’s own docstring adds that resolution persists no conversation item. So the human in the loop need not be the human whose purpose is being enforced, and the action’s in-session provenance does not identify who cleared it. Records may exist elsewhere — access logs, tracing attributes, managed-platform audit trails — but they sit outside the authorization path and outside the session record.
The elicitation id is a sixteen-byte random token the docstring describes as the capability scoping the resolution. Read precisely: the token identifies which approval is being answered, and edit-level authorization determines who may answer it. The defect is not unauthenticated possession — the resolution is authenticated. It is authenticated resolution without originator binding. The token identifies the approval; nothing binds that approval to the principal who declared the intent.
The lever exists
The first tamper-resistance property is the one to test against the API rather than the agent.
Session policies are managed over HTTP. Creating one requires edit. Updating one requires edit, and the update accepts enabled, so a policy can be switched off, and accepts handler, so a policy can be repointed within the registry allowlist. Deleting one requires edit [12].
Read that against the claim. There is no lever in the agent’s toolbelt — that part is accurate, and it is a real design choice. But the lever exists in the product, and it is an edit-level operation. Delete, disable, repoint. An editor holds all three.
The second property resolves the same way. There is no approval step in the create route [12]. The rule requiring explicit user approval guards the agent’s policy-adding path; an editor posting to the endpoint directly is not gated by it. “Even adding a policy needs a human” is exact if the human meant is any editor, and the reversion in v0.9.0 moved session approvals back to any shared editor rather than the owner alone [1].
The third property survives intact. The engine short-circuits on DENY, accumulates ASK, and continues on ALLOW, so a permissive addition cannot lift an existing block [5]. Stated as written, verified as written.
And one counterweight belongs here, because it is the strongest thing in the design. Spec-declared policies return with a null id and cannot be patched or deleted through this API [12]. The design-time intent Databricks describes for autonomous agents genuinely is immutable at runtime. The exposure is specific to session policies — which is precisely how their own blog says an interactive agent receives its intent [7].
One approval, wider than it looks
Two scoping behaviors in the engine deserve a risk committee’s attention, both first-party.
A per-session cost-budget approval is routed to the root conversation rather than the conversation that raised it, so approving once covers the whole spawn tree; the source gives the reason, which is that a sub-agent runs as its own conversation and would otherwise re-prompt [5]. A per-user daily approval persists to that user’s day record so the checkpoint will not prompt them again that day, including from their other sessions [5].
Neither is a defect. Each is a deliberate reduction of approval fatigue, which is a real problem Databricks names in its own writing. But each converts one human act into a broader grant than the immediate approval event might suggest, and neither appears in the managed documentation’s account of what a permission level allows.
What managed says, and what it omits
On Databricks, sharing a session grants one of two levels: Read or Edit [2]. Edit is described as full control of the session — send messages, open shells, edit files in the host file system, rename the session. The warning is theirs: grant edit carefully, because an editor can run shell commands and modify files on the host through the agent, including any action available through the Omnigent MCP server, and an editor can also view your other session chats.
That enumeration is doing real work, and it stops one item short. It does not say that an editor can resolve an approval, or create, disable, repoint, or delete a session policy. In the open-source server those are the same edit level. An enterprise reading the managed table to decide who gets Edit is reading an incomplete account of what Edit confers.
I am scoping that claim deliberately. The route reads are from the open-source server; the managed product runs on Databricks-hosted infrastructure whose permission implementation I have not verified, and its custom-policy handler restriction already differs from open source [3]. What I am asserting is a documentation gap, not that the managed permission model is identical.
What a predicate can guarantee, and what it cannot
It is worth being unambiguous about the landscape, because the two halves of this problem admit different kinds of assurance.
Some properties are structurally decidable. A predicate settles them, and the answer is the same every time: which verdict wins when policies disagree; what happens when a policy component fails; whether a design-time policy can be altered at runtime; whether the principal who declared the purpose is the principal who may clear a departure from it; whether collaborating in a session is the same privilege as clearing a paused action or deleting the policy behind it.
Some are not decidable at all. Whether a tool call serves a declared purpose is a semantic judgment. So is whether a passage of retrieved content is an instruction from an adversary. No predicate settles these. Any control here is an assessment, and it cannot be promoted to a guarantee by better engineering. Databricks’ own title acknowledges the category distinction: permission is not purpose.
Denial dominance in composition, a fail-closed exception contract in the engine, runtime immutability of spec-declared policies, and a strict acceptance contract at the approval gate. Real work, with one qualification: the exception contract is available in the engine but declined by this policy, because the intent classifier catches its own failures before the engine can convert them into a denial [5][6].
Purpose-declaring identity is not bound to purpose-clearing identity. And session collaboration, approval resolution, and policy deletion are one privilege rather than three.
On the undecidable surface they place a judgment control, which is the only thing available. But the failure mode of that control was itself a decidable choice, and this is where the criticism lands — carefully, because the obvious version of it is wrong.
“No judge is available” is not a semantic question. It is a predicate, and it had three wirings.
Wrong. It couples the authorization plane’s availability to an inference endpoint: a model outage halts an autonomous fleet, and the governance layer becomes the most fragile component in the platform.
Wrong for a better reason. It converts an inference outage into an approval storm — every call in every session raising an elicitation, multiplied across a spawn tree, which is why Databricks already routes cost approvals to the root conversation [5]. A human facing hundreds of prompts they cannot evaluate approves them, and a rubber-stamped gate is worse than none, because it manufactures the appearance of review.
Preserves availability without handing every inference failure to a human. Validate the dependency when the policy is configured, and represent the abstention in the decision record when that dependency later goes away. Neither is free: validation raises lifecycle questions about when the model must exist and whether a transient outage invalidates a previously valid configuration, and the verdict schema would need to carry an abstention reason. But neither couples tool execution to model availability, and neither generates an approval storm.
The policy does log a warning when no model client is present [6]. That is evidence, and it sits in the operational surface rather than the authorization surface. It does not stop an operator from believing intent authorization is enforcing, and it does not appear in the trace an auditor reads.
So the objection is not that the control fails open. Failing open was defensible. The objection is that its abstention appears in an operational warning rather than in configuration validity or in the authorization decision itself. The problem is not literal silence — it is assurance silence. And the expense was not avoided, it was transferred. Fail-closed would have charged Databricks in support tickets and availability complaints, both loud and immediate. Assurance silence charges the customer’s assurance case instead, and that invoice arrives only when someone reads the source.
The approval gate in Omnigent is fail-closed, applies no pending policy writes on refusal, and is built to a specification. What decides whether to raise it abstains five ways. What clears it is an edit-level capability — independently resolvable by an administrator, satisfiable by a public share, governed for sub-agents by the parent conversation’s grants, and as of v0.9.0 returned to any shared editor rather than the owner. The same level deletes the policy, disables it, or repoints it.
So the tamper-resistance claim holds where it is scoped to the agent and gives way where it is read as a property of the product. The agent has no lever. The product has three, and the documentation that tells an enterprise who to trust with Edit does not mention them.
The criticism is not that Omnigent abstains from governing. It governs: three structural properties are delivered here, and a fourth — the engine’s fail-closed exception contract — is built but declined by this policy. The criticism is narrower and harder: at each point where a structural choice was available in the authority layer, the answer favored operational convenience over assurance separation. Identity was authorized and then discarded. Three privileges were collapsed into one level. And an unavailable judge abstains into a warning when it could have abstained into the decision.
The first two are authority choices: binding purpose declaration to approval, and separating collaboration from approval and policy administration, require a finer authorization model. The third is an evidence choice: an unavailable judge could remain fail-open while recording its abstention in the decision. A control’s strength is the weakest authority that can stand it down, and its assurance value is the evidence it leaves when it does nothing at all.
