attenu

Blog · · by , Attenu

Omnigent's budget is a count. Authority needs a ceiling.

What Omnigent built well. Omnigent is a meta-harness: it drives Claude Code, Codex, Cursor, OpenCode, Pi and custom agents behind one orchestrator, and you can swap the harness without rewriting the agent. What is unusual is that it put a decision point on every action from the start. A policy is a Python callable registered from YAML; it returns ALLOW, ASK, DENY, or None to abstain. Composition is stated in one sentence in docs/POLICIES.md: "The engine evaluates them in declaration order. A DENY from any policy short-circuits the rest." The tool-call and request phases fail closed, and an exception inside a policy becomes a DENY rather than a pass. Sub-agent dispatch has a named interception point — sys_session_send — and two builtins already gate it: spawn_bounds caps dispatches per orchestrator turn, headless_subagent_purpose_guard makes every dispatch declare what kind of work it is. Most frameworks we integrate have nothing this deliberate.

The two things left open, in their words. Both issues are open today. #5169, filed 2026-08-21: "Nothing bounds how deep a sub-agent tree can go… It counts dispatches within a single orchestrator turn and denies past the cap, with a per-turn counter reset by the runner's reset_turn hook… That bounds one node's branching factor. It does not bound the tree, because each child gets its own turn and therefore its own fresh counter." The author does the arithmetic: five dispatches per level is 5ⁿ sessions at depth n, and every level is individually inside its cap. And #2390, filed 2026-07-10: "sys_session_send is the interception point for sub-agent dispatch (existing builtins like spawn_bounds and headless_subagent_purpose_guard already gate it), but there's no built-in policy for the specific, common case of per-user sub-agent access control."

Both are asking the same underlying question from different ends. A counter can say how many. It cannot say how much.

The code. One factory, registered exactly like spawn_bounds is: type: function, a dotted path, and arguments. What it takes is the roster an Omnigent agent spec already carries — each agent's tools and its subagents — plus a map from tool name to scope, a max_depth and a max_fanout. From that it derives an authority per sub-agent and puts it on a delegation chain shared by every policy instance in the process. On a sys_session_send it attenuates the named child onto the chain; on any other tool call it asks the acting agent's authority. Thirty lines of decision logic; the rest is the roster.

The denials. Four in one scripted run, none of which needs a model to behave. The researcher's repo_write is denied: repo.write belongs to the coder's branch, and a branch never receives another branch's scopes. The deployer's second release is denied by a ceiling that says one, counted per node for the life of the chain rather than per turn. Its shell call is denied because shell appears in no agent's declared tools, so it is held by nobody — denied by default rather than allowed by omission. And its dispatch to a fourth level is denied at max_depth, in a turn that has dispatched nothing else: that is the difference between a chain ceiling and a counter. In every case the tool body does not run, and the run with no policy attached executes all ten bodies — so the oracle is known to see what it later reports absent.

The verify. AuditLog.verify on the ledger, then verify_bundle on a signed export: integrity, child subset of parent, and containment of every permitted action — checked from the bundle alone, with our software absent. Rewrite one deny into an allow and integrity fails.

What remains Omnigent's. The decision points, the phases and their fail-closed set, composition, the ASK path, the sandbox, the harness abstraction — and whether a depth bound belongs upstream at all. #5169 and #2390 are theirs to answer; this is one working answer offered on those threads. And read the trust boundary first: the handler sees what Omnigent hands its policies, not a direct Python call around it, and the chain binds the sessions that share one process.

Verified against omnigent 0.10.0 on 2026-08-25. Recipe: https://github.com/attenu-io/attenu-guard/tree/main/examples/integrations/omnigent/policy_handler · https://attenu.io

Rafael Asor is the founder of Attenu and the maintainer of attenu-guard and attenu-derive, open-source Python libraries for AI agent permissions across sub-agent handoffs. He is the author of the IETF Internet-Draft draft-asor-wimse-agent-delegation-chain and is based in Tel Aviv.