Summary
AGT evaluates actions one at a time today. The catch is that a multi-agent workflow can pass every individual policy check and still end up somewhere it shouldn't, because sensitivity builds up as context accumulates across steps. A delegated agent can also quietly lose the constraints its parent was working under. I'd like to propose tracking the accumulated context of a workflow and checking actions and delegations against that running state, instead of only looking at the request in front of us.
The problem
AGT already governs actions, tools, identity, policy decisions, and audit events, but it mostly treats them as separate events. There's a gap when:
- A series of individually fine actions adds up to sensitive context.
- A derived result (an inference) ends up more sensitive than any of the inputs it came from.
- A delegated agent inherits workflow state that the current authorization decision doesn't actually see.
Concrete example: a customer's name, their renewal status, some usage analytics, and a couple of financial indicators are each low to moderate sensitivity on their own. Put them together and you can derive a fairly sensitive customer risk profile (churn likelihood, financial distress, account vulnerability). The policy engine approves each step while the combined picture quietly crosses a line.
The question I'd like governance to be able to ask before allowing an action or a delegation is basically: what will this agent be able to know or do once this action succeeds?
Why it fits the toolkit
This doesn't need a parallel stack. It composes with things AGT already has:
- DataClassification, DataLabel, and ABACPolicy in
agent_os/policies/data_classification.py already give us a sensitivity ladder and a label vocabulary to reuse.
- The Rust policy engine already attaches
result_labels to a verdict and carries them from one call to the next (policy-engine/core/src/verdict.rs). The accumulated envelope is really just the durable, workflow-scoped version of that.
- DelegationChain in the structural-authz integration already attenuates scopes on delegation. I'd extend it with restriction inheritance rather than replace it.
What I'm proposing (first cut, in-process)
A ContextEnvelope: an immutable, versioned value holding the labels accumulated so far, an aggregate sensitivity (the max over DataClassification), and a grow-only set of restrictions. On top of that:
- Aggregation rules over label combinations, with a backstop so combinations nobody wrote a rule for escalate for review instead of slipping through. Growing the label set by itself shouldn't elevate anything; only declared combinations should.
- Accumulate after execution, not before. Fold in an action's actual
result_labels once it has run, then check the next action against the updated state. I looked at projecting the envelope before running the action and decided against it, since you can't really gate on the labels of an output you haven't produced yet.
- A constrain outcome that means "allow, but carry these obligations forward." On the declarative policy path, which has no way to carry obligations, it fails closed to deny rather than quietly allowing.
- Restriction inheritance on delegation: a child's restrictions are the parent's plus whatever the child adds. A delegatee can add restrictions but never drop one. This sits alongside the existing scope attenuation and doesn't touch
validate().
- CONTEXT_* audit events for the transitions, each classified at least as high as the envelope it describes.
How I'd know it works
- Folding is order independent and idempotent; sensitivity only ever goes up; restrictions never get dropped.
- A rule over [pii, financial] elevates to restricted; an unenumerated multi-category combination escalates; adding an unrelated label doesn't change the classification.
- A restriction that's present gates its action regardless of sensitivity, so there's no quietly allowing it below some threshold; a constrain with nowhere to carry obligations becomes a deny.
- A delegated child can't end up with fewer restrictions than its parent.
- The existing DelegationChain tests stay green and
validate() behaves exactly as before.
- No new dependencies.
What I'm leaving out for now
These are real and probably deserve their own issues, but they're not in this first cut, and anyone deploying should know they're open:
- Splitting work across sibling agents, sessions, or separate workflows so no single envelope ever sees all the labels. Catching that needs a per-principal accumulation register.
- Signing and versioning envelopes that cross a trust boundary between agents. Until that exists, anything riding on an envelope across the mesh is advisory, since a peer could present a weaker one.
- Laundering through an unlabeled store (write it out, read it back clean) or by paraphrasing restricted content into new text. That needs labeling on ingest and taint-style propagation.
- Detecting an undeclared sensitive inference. That's undecidable in general, so for now an artifact produced while the envelope is already sensitive just inherits that classification.
Standards it lines up with
It's mostly a data-governance and access-control control, and worth noting, it stores labels and classification levels rather than the underlying data, which keeps its own footprint small. It lines up with EU AI Act Article 12 (record-keeping) and Article 14 (human oversight), NIST 800-53 around information flow and security attributes (AC-4, AC-16, AC-21), the NIST AI RMF functions, SOC 2 CC6 and CC7, GDPR Article 25, and HIPAA's access and audit controls. There's an existing EU AI Act checklist under docs/compliance that this connects to.
Open questions
- Where should the envelope schema live, and which component owns propagation across the mesh?
- Immutable and versioned, or mutable with audit transitions? I lean immutable.
- Who's allowed to authorize a declassification?
- Should envelope IDs show up in the agt-evidence receipts?
I've written up the full threat model, the invariants, and the diagrams in an ADR and can attach it or open it as a follow-up.
Summary
AGT evaluates actions one at a time today. The catch is that a multi-agent workflow can pass every individual policy check and still end up somewhere it shouldn't, because sensitivity builds up as context accumulates across steps. A delegated agent can also quietly lose the constraints its parent was working under. I'd like to propose tracking the accumulated context of a workflow and checking actions and delegations against that running state, instead of only looking at the request in front of us.
The problem
AGT already governs actions, tools, identity, policy decisions, and audit events, but it mostly treats them as separate events. There's a gap when:
Concrete example: a customer's name, their renewal status, some usage analytics, and a couple of financial indicators are each low to moderate sensitivity on their own. Put them together and you can derive a fairly sensitive customer risk profile (churn likelihood, financial distress, account vulnerability). The policy engine approves each step while the combined picture quietly crosses a line.
The question I'd like governance to be able to ask before allowing an action or a delegation is basically: what will this agent be able to know or do once this action succeeds?
Why it fits the toolkit
This doesn't need a parallel stack. It composes with things AGT already has:
agent_os/policies/data_classification.pyalready give us a sensitivity ladder and a label vocabulary to reuse.result_labelsto a verdict and carries them from one call to the next (policy-engine/core/src/verdict.rs). The accumulated envelope is really just the durable, workflow-scoped version of that.What I'm proposing (first cut, in-process)
A ContextEnvelope: an immutable, versioned value holding the labels accumulated so far, an aggregate sensitivity (the max over DataClassification), and a grow-only set of restrictions. On top of that:
result_labelsonce it has run, then check the next action against the updated state. I looked at projecting the envelope before running the action and decided against it, since you can't really gate on the labels of an output you haven't produced yet.validate().How I'd know it works
validate()behaves exactly as before.What I'm leaving out for now
These are real and probably deserve their own issues, but they're not in this first cut, and anyone deploying should know they're open:
Standards it lines up with
It's mostly a data-governance and access-control control, and worth noting, it stores labels and classification levels rather than the underlying data, which keeps its own footprint small. It lines up with EU AI Act Article 12 (record-keeping) and Article 14 (human oversight), NIST 800-53 around information flow and security attributes (AC-4, AC-16, AC-21), the NIST AI RMF functions, SOC 2 CC6 and CC7, GDPR Article 25, and HIPAA's access and audit controls. There's an existing EU AI Act checklist under
docs/compliancethat this connects to.Open questions
I've written up the full threat model, the invariants, and the diagrams in an ADR and can attach it or open it as a follow-up.