HexgateContext— the per-request scope. Marks “this invocation acts on behalf of alice, with roles X, and these attributes.” Async context manager; pushes a fact-bearing Biscuit through the agent runtime.- Role policies — one
policy.yamlper role, optionally inheriting from a base mixin. The runtime picks the right one at call time based on the active context’s primary role.
Minimal example
attenuate_for_user, extract_facts, or ToolUseContext plumbing at
the call site. The runtime mints the per-request token, picks the billing
role’s policy file, and evaluates its constraints against each tool call.
Filtering on attributes (ctx.*)
Beyond the role, a context can carry an open attributes bag that policy
constraints read through the ctx.* namespace — turning role-based access into
attribute-based (ABAC) filtering:
ctx.<key> fails closed (deny), like any absent reference.
FastAPI pattern
The scope must enclose the streaming iteration itself, because the role is resolved lazily — read on each tool call as the agent runs (see Notes). The robust shape is to open the scope inside the generator that produces the response:async with HexgateContext(...): return await invoke_agent(...) is fine — the agent runs to completion inside the scope.
HexgateContext fields
Only the first role in
user_roles reaches policy selection today (read via
primary_role); the rest are carried but inert until multi-role selection lands.
Role policies — one file per role
Agents that need per-role behaviour ship apolicies/ directory instead of a
single policy.yaml:
AgentPolicy. Inheritance is left-to-right, child
wins on conflicts:
ctx.*) and a role-scoped end-to-end walkthrough.
Notes
- Single-file policies still work. A legacy
policy.yamlis treated as thedefaultrole — no migration needed. - Lazy attenuation.
HexgateContext.__aenter__only pushes a contextvar — the cryptographic work happens insidestream_agent/invoke_agentthe first time the agent runs. Errors surface at first agent call, not at scope entry. - Local agents skip attenuation. A context scope around a
load_local_agentagent logs a warning and runs with no facts. Thedefaultpolicy still applies — useload_hexgate_agentfor the full signed chain. - Explicit override. Passing
tool_use_context=explicitly tostream_agent/invoke_agentwins over an active context scope. Useful for tests or one-off bypass. - Sync callers.
HexgateContextexposes bothasync with ctx:andctx.sync_scope(). The async form is the primary API; the sync mirror exists for CLI loops andRunner.run_sync-style callers.