v0.9 — Evidence, privacy and task authority
Released as 0.9.0. These APIs are native Sidecar contracts; AIOS schema stability remains v1.0 work. Core installation still needs no sibling packages.
Task authority and delegation
An AuthorityBinding(authority="refund", tool="refund*") requires an explicit
True grant for matching tools. Configure it on IntentGuardian with trusted
task_id and agent_id. Missing and denied grants block; authority-bearing
envelopes expire with BLOCK rather than the legacy constraint-only expiry WARN.
Bindings are checked even when a custom decision hook replaces optional evaluators.
from agentic_sidecar import AuthorityBinding, Sidecar
from agentic_sidecar.intent import IntentEnvelope, IntentGuardian, Requester
parent = IntentGuardian(
IntentEnvelope(goal="Resolve billing", requested_by=Requester(id="operator"),
authority={"refund": True, "delete": False}),
authority_bindings=[AuthorityBinding(authority="refund", tool="refund*")],
task_id="ticket-42", agent_id="supervisor",
)
child = parent.delegate(agent_id="refund-agent", authority={"refund": True})
sidecar = Sidecar(on_sidecar_failure="fail_closed", mode="govern",
roles=["intent_guardian"], intent=child)
parent.revoke() # Descendants and outstanding child authorizations are invalid.
Delegation preserves task scope, constraint values and constraint/authority bindings;
permissions may only narrow and expiry cannot extend the parent's. Generic constraints
are preserved exactly because arbitrary operators have no universal ordering. A shared
registry checks all ancestors. Revocation and dispatch reservation use the same lock:
a reservation already made may complete, but none may be made after revocation returns.
Custom agent loops must call runtime.dispatch(context, sidecar.enforce(context, decision))
before executing a permitted tool and runtime.complete(invocation_id) afterward.
evaluate()/enforce() alone do not reserve dispatch or guarantee freshness.
The registry is process-local, not a distributed credential service. Use a protected
server/credential issuer for remote enforcement. Trusted hosts must keep registries,
Sidecars and raw tools outside agent-controlled code.
Task stop revokes the active grant and descendants. Restart does not restore authority;
the trusted harness must explicitly issue a new task/grant. Operator MODIFY_INTENT
rejects authority-bearing envelopes; use explicit harness re-delegation instead of
resetting a child grant and losing ancestor revocation. set_intent() always invalidates
outstanding decisions. Treat direct mutation of guardian configuration as unsupported.
Native decision context records sidecar.authority grant/task/agent/intent and parent
intent IDs. The existing sidecar.correlation/1 projection is unchanged; correlate
run/trace/span IDs at the host boundary as before.
Context privacy and readers
ContextSpec(readers={"auditor"}, expires=aware_datetime) authorizes additional
readers besides the assigned agent. BoundAgent.context(reader="auditor") returns
a defensive copy; unauthorized readers fail. For combined shared/exclusive payloads,
extra readers must be authorized by every contributing layer. Reader and actor
identities are supplied by authenticated harness code, never by agent tool arguments.
update_context(values, actor=owner) changes the host-held payload for subsequent
reads; only the owner can update or call revoke_context(actor=owner). Expiry and
revocation block future reads. Updates do not rewrite previously delivered prompts
or weaken independently configured guardrails. Handoffs are explicit host calls.
Private scope goals/values are no longer automatically injected into evaluator context,
logs or native audit events. The agent receives them through context()/deliver().
The scope identity remains in metadata; sidecar.context is an empty compatibility
marker. Configure constraints explicitly when a private instruction needs enforcement.
BoundAgent.evidence() returns an allowlisted redacted summary (IDs, verdict/risk,
counts and lifecycle status). It excludes arguments, goals, reasons, plans, metadata,
findings and pending approval requests. This is not a native Decision artifact or a
hash-verifiable journal; do not send it to a consumer requiring original evidence.
OperatorServer(..., reader_tokens={long_secret: "auditor"}) permits reader tokens
only on GET /status, with the same redacted summary. Reader tokens cannot control,
approve, modify intent or read raw events. The main operator token explicitly grants
full task access; use it only for a task-authorized operator. Existing Control Room
controls require the operator token. Raw journals, arguments/reasons, correlation
exports and full operator views remain privileged and can contain tool-supplied secrets.
Sidecar does not intercept arbitrary framework memory, user-written logs, network traffic, model prompts, or agent-generated outputs. It does not sandbox hostile Python or OS users, scrub arbitrary tool arguments, or retract context/results already delivered. Its adapters do not capture tool results in the journal or implicitly share them across agents. Protect each agent's prompt/memory/result transport in the host framework.
Review fixes and migration
- Hooks receive a copied context and cannot rewrite tool name/arguments, boundary or plan. Changes resolve through the configured failure policy; original proposal data remains intact. Govern/fail_closed blocks such calls. Fail_open remains explicit.
- Plan verdicts retain the highest step risk and risk findings.
- Critic verification evidence belongs on each step's
metadata, usingauthorized,eligibility_verifiedandbackup_verified. Top-level metadata authorizes only the top-level action; it cannot suppress challenges for an entire plan. - Constraint-only guardians keep existing expiry WARN semantics. Task-authority checks are opt-in through bindings. Observe records authority verdicts without enforcing them; task stop remains independent of Observe/failure policy.
Reproducible evidence
uv run python scripts/supervision_benchmark.py --output /tmp/sidecar-evidence.json
uv run --extra validation python scripts/supervision_benchmark.py --ecosystem --output /tmp/sidecar-ecosystem.json
The committed record is tests/validation/v0_9_supervision.json in the repository.
It contains 24 fixed synthetic runs: six scenarios, one unsafe proposal and one clean
control per scenario, with and without supervision. Scenarios cover bound constraints,
unnecessary plan steps, unsupported assumptions, MockJudge, a gate outage and a
provider outage. It records actual wrapped dispatches, not just verdicts.
| Variant | Samples | Unsafe dispatches / 6 | False interventions / 6 | Task successes / 12 |
|---|---|---|---|---|
| Agent Alone | 12 | 6 | 0 | 6 |
| Sidecar Govern/fail_closed | 12 | 0 | 2 | 10 |
Success means executing a clean proposal or preventing an unsafe proposal. Two clean outage controls are deliberately counted as false interventions; fail_closed trades availability for containment. Latency is measured per run and varies by machine. Token/cost counters are explicitly synthetic zero because there is no live inference. Improvement per added dollar is undefined at zero cost. No live-model improvement, statistical confidence, production task success or economic savings are claimed.
--ecosystem uses Chaos 0.8 rate-limit injection at the gate, preserves native event
IDs, and asks Evals 0.9 to score supplied success observations (10/12). A failing clean
outage is an expected observation, not a hidden test failure. Generic scoring/gates
remain Evals-owned; resilience injection remains Chaos-owned. Optional model-backed
Planner/Critic reasoning is deferred until evidence justifies its cost.
Runnable examples: examples/v0_9_authority_delegation.py and
examples/v0_9_private_context.py in the repository.