Skip to content

Proposal: Tool Usage Policies for Agent Spec#174

Open
imran-siddique wants to merge 4 commits into
oracle:mainfrom
imran-siddique:125-governance-controls
Open

Proposal: Tool Usage Policies for Agent Spec#174
imran-siddique wants to merge 4 commits into
oracle:mainfrom
imran-siddique:125-governance-controls

Conversation

@imran-siddique
Copy link
Copy Markdown

@imran-siddique imran-siddique commented May 4, 2026

Summary

This PR proposes a tool_policy property for Tool and ToolBox components, enabling declarative constraints on tool invocation. This is the first step toward governance controls in Agent Spec, scoped to tool usage policies as discussed in #125.

What's included

  • ToolPolicy schema: rate limits, caller restrictions ($-based), data classification, conditional approval, and justification requirements.
  • ExecutionGuard abstraction: unified {type, condition, on_violation} shape for rate limits, approvals, and classification checks.
  • Compatibility: fully backward-compatible, version-gated, optional fields only.
  • Examples: rate-limited tools, caller-restricted tools, conditional approval workflows.
  • AGT mapping table: shows how each schema field maps to Agent Governance Toolkit enforcement.

What's intentionally deferred

  • Agent-level and flow-level governance (trust levels, audit, escalation) are out of scope for this PR and would follow as separate proposals.
  • No code changes: this is a specification proposal document only.

Design choices

  • Uses $ for caller restrictions (consistent with existing Agent Spec referencing).
  • data_classification is a free-form string rather than a fixed enum, for cross-org portability.
  • Guards use simple condition operators (input_equals, input_contains) rather than regex.
  • Does not duplicate requires_confirmation: the existing field stays, tool_policy extends it with conditional semantics.
  • allowed_callers/denied_callers marked as MAY for v1, since attachment already controls access in single-agent setups.

Open questions for discussion

  1. Should policies be inlined or standalone components referenced via $?
  2. Should data_classification be constrained or free-form?
  3. How should tool_policy on a ToolBox interact with policies on individual tools?
  4. Should there be a PolicyViolation event type for tracing?

Closes #125
cc @dhilloulinoracle @RhicheekPatra @cesarebernardis

Add proposals/governance-controls.md defining a ToolPolicy schema that
enables declarative constraints on tool invocation: rate limits, caller
restrictions, data classification, conditional approval, and justification
requirements.

Scoped to Tool and ToolBox components only. Agent-level and flow-level
governance is deferred to follow-up proposals.

Closes oracle#125

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Imran Siddique <imran.siddique@microsoft.com>
@imran-siddique imran-siddique requested a review from a team May 4, 2026 23:24
@oracle-contributor-agreement
Copy link
Copy Markdown

Thank you for your pull request and welcome to our community! To contribute, please sign the Oracle Contributor Agreement (OCA).
The following contributors of this PR have not signed the OCA:

To sign the OCA, please create an Oracle account and sign the OCA in Oracle's Contributor Agreement Application.

When signing the OCA, please provide your GitHub username. After signing the OCA and getting an OCA approval from Oracle, this PR will be automatically updated.

If you are an Oracle employee, please make sure that you are a member of the main Oracle GitHub organization, and your membership in this organization is public.

@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Required At least one contributor does not have an approved Oracle Contributor Agreement. label May 4, 2026
@dhilloulinoracle
Copy link
Copy Markdown
Contributor

Thanks a lot @imran-siddique for putting up the proposal :) .

I will try to answer first the questions you have in there, and then maybe ask a few of my own

@dhilloulinoracle
Copy link
Copy Markdown
Contributor

(At the time I am writing this, it doesn't seem possible to put comments directly on the files).
Regarding your questions:

Open Questions

  1. Should tool_policy be inlined on each tool, or should policies be defined as standalone components and referenced via >$component_ref? Standalone policies would enable reuse across tools.
  2. Should data_classification be a free-form string or a constrained enum? Free-form is more flexible across organizations; >an enum is more portable.
  3. Should there be a dedicated event type (e.g., PolicyViolation) in the tracing/events system for governance-related >events?
  4. How should tool_policy on a ToolBox interact with policies on individual tools within that box?
  1. I think it makes sense to have it as a component, it will be then re-usable. If used only once in an agent config, it can be inlined. (The canonical export should be inlining and avoiding the $component_ref when there is a single reference)

  2. if there is an idea of the values would be, I am in favor of an enum

  3. I think it is a good idea

  4. I imagine that a tool in the toolbox should have as policies the union of policies defined at the toolbox and tool level?

…omposition

- Make ToolPolicy a standalone component (referenceable via $component_ref)
- Change data_classification from free-form string to enum (public/internal/confidential/restricted)
- Add PolicyViolation event type for tracing/observability
- Define toolbox + tool policy composition as union semantics
- Replace Open Questions with Resolved Design Decisions section
- Add reusable policy example showing  pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@imran-siddique
Copy link
Copy Markdown
Author

Thanks @dhilloulinoracle for the thorough answers! I've updated the proposal to address all four points:

  1. Standalone component: ToolPolicy is now a first-class component with component_type, id, and name. Referenceable via \ across tools, or inlined when single-use.

  2. Enum for data_classification: Changed to a four-level enum: public, internal, confidential, restricted. This gives us well-defined composition semantics (higher sensitivity wins) while keeping it simple. Orgs needing custom labels can extend via metadata.

  3. PolicyViolation event: Added with violation_type enum (rate_limit_exceeded, caller_denied, justification_missing, approval_required, classification_breach) and action_taken (blocked/flagged/logged).

  4. Toolbox + Tool composition: Defined as union with per-field semantics: more restrictive rate limits, higher classification wins, intersection for allowed_callers, union for denied_callers and approval conditions.

Also replaced the "Open Questions" section with "Resolved Design Decisions" to document the rationale.

Ready for another round of review when you get a chance.

@dhilloulinoracle
Copy link
Copy Markdown
Contributor

Thank you @imran-siddique for the update.
I also asked @cesarebernardis to have a look, and he a few comments/questions as well.

On my side, I have another general question: you have already a way to define policies with https://github.com/microsoft/agent-governance-toolkit/blob/main/agent-governance-python/agent-os/src/agent_os/policies/schema.py . It seems to me a bit different what you have proposed here, but maybe close enough so that we could have compatibility?

I think it would be beneficial to the community if policies defined in one place can be loaded in another, but please let me know what you think.

@cesarebernardis
Copy link
Copy Markdown
Member

@imran-siddique Thanks for putting this together. I really like the overall direction, and I had a few questions that might help clarify the v1 shape while also keeping the model extensible over time.

  1. On caller restrictions: how important do we think allowed_callers / denied_callers are for v1, given that tool availability is already largely determined by where a tool is attached today? Is the primary use case shared toolboxes or shared policies across different agents, and if so, would it make sense to keep this part minimal or optional at first?
  2. On approvals: would it simplify the model to think of requires_confirmation and approval_required_for as two forms of the same underlying execution constraint, rather than as separate mechanisms? For example, could unconditional approval be one case and input-conditional approval another possibly under a more general "guard-like" abstraction that we could reuse later?
  3. On rate limits and other execution-time constraints: would it help to look at approvals, rate limits, and similar controls through the same lens, as different kinds of guard-like rules on tool execution? If so, is there value in giving them a more uniform shape, including a clearer definition of what happens when the constraint is not satisfied, so that runtime behavior and policy-violation reporting are easier to reason about?
  4. On toolbox-level policies: we probably need to make the inheritance/composition behavior a bit more explicit. For example, is the intent that a ToolBox.tool_policy acts as a base policy for all exposed tools, and that a tool-specific policy is then combined with it rather than replacing it? It feels like spelling that out would help avoid different runtime interpretations.

@imran-siddique
Copy link
Copy Markdown
Author

imran-siddique commented May 7, 2026

Responding to @dhilloulinoracle's question on policy compatibility:

Good catch. AGT's policy schema covers more (agent-level, flow-level), but the tool-level subset maps to what's proposed here.

Main difference: AGT uses condition expressions (tool_name == 'x') while this proposal uses structured fields (allowed_callers). Same semantics, different serialization. I'll add a mapping table in the next revision so the two formats can round-trip.

@imran-siddique
Copy link
Copy Markdown
Author

imran-siddique commented May 7, 2026

Responding to @cesarebernardis Q4 (toolbox composition):

Right, ToolBox.tool_policy is a base that combines with tool-level policies, not replaces. Current revision has per-field rules: stricter rate limits win, higher classification wins, allowed_callers intersect, denied_callers union.

I'll add a dedicated "Policy Composition" section with concrete before/after examples to make this unambiguous.

@imran-siddique
Copy link
Copy Markdown
Author

imran-siddique commented May 7, 2026

Responding to @cesarebernardis Q2 (approval unification):

This is a better model. One execution_guard with a condition field: unconditional (always), input-conditional (when: {input_contains: "PII"}), threshold-based, etc. requires_confirmation becomes sugar for execution_guard: {condition: always, action: require_approval}.

Cleaner extension point too, no new top-level fields every time we add a guard type. I'll sketch this in the next revision.

Address review feedback from @dhilloulinoracle and @cesarebernardis:

- Refactor to ExecutionGuard abstraction: rate limits, approvals,
  and future constraints share a common {type, condition, on_violation}
  shape instead of separate top-level fields
- Mark allowed_callers/denied_callers as MAY for v1 runtimes
- Add AGT policy compatibility mapping table
- Expand Policy Composition section with before/after examples
  making ToolBox base + combine semantics explicit
- Add escalate to on_violation and PolicyViolation action_taken
- Update all examples to use guards syntax

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@imran-siddique
Copy link
Copy Markdown
Author

Updated the proposal to address all feedback. Key changes in the latest push:

  1. ExecutionGuard abstraction (per @cesarebernardis Q2/Q3): Rate limits, approvals, and future constraints now share a common {type, condition, on_violation} shape via a guards array. Replaces the earlier separate top-level fields.

  2. Caller restrictions as MAY (per @cesarebernardis Q1): allowed_callers/denied_callers are explicitly marked as optional for v1 runtimes.

  3. AGT compatibility mapping (per @dhilloulinoracle): Added a table showing how Agent Spec ToolPolicy fields map to AGT's condition-expression policy format.

  4. Explicit composition semantics (per @cesarebernardis Q4): ToolBox policy is a base that combines with tool-level policies. Added before/after YAML examples showing exactly how composition works per field.

  5. on_violation and escalate: Every guard defines what happens when the constraint isn't met (block, flag, log, escalate). Maps directly to PolicyViolation event's action_taken.

Ready for another look when you get a chance.

@imran-siddique
Copy link
Copy Markdown
Author

What is explicitly not included in this proposal

To keep the scope focused on tool usage policies, the following are intentionally deferred to future proposals:

  • Agent-level governance: trust levels, audit requirements, escalation policies, max tool calls per turn
  • Flow-level governance: workflow-scoped constraints, cross-node policy propagation
  • Cross-level policy composition: rules for how tool, agent, and flow policies interact or override each other
  • Runtime-specific controls: sandbox execution, session management, turn-based limits
  • Identity and authentication: DID-based identity, inter-agent trust protocols, credential management
  • Policy language integration: Cedar or OPA policy references, external policy engine bindings
  • Tracing/events integration: PolicyViolation event types, governance-specific spans (listed as an open question only)
  • Code changes: no Pydantic models, no serialization, no runtime enforcement. This PR is a specification proposal only.

These are all valid directions for follow-up work once the core tool_policy schema is agreed upon.

@imran-siddique
Copy link
Copy Markdown
Author

Responding to @cesarebernardis Q1 (caller restrictions):

For single-agent setups, yeah, attachment already controls who can call what. The real use case is shared toolboxes in multi-agent systems where the same tool is exposed to agents with different trust levels. That said, totally fine making allowed_callers/denied_callers a MAY for v1. They're already optional in the schema, so runtimes can skip them without breaking anything.

@imran-siddique
Copy link
Copy Markdown
Author

Responding to @cesarebernardis Q3 (uniform guard shape):

+1. Rate limits, approvals, classification checks as guard types with a common shape: {type, condition, on_violation}. The on_violation defines what happens: block, flag, log, escalate. Maps directly to the PolicyViolation event type we already added, so every guard violation is traceable without extra wiring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Required At least one contributor does not have an approved Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Collaboration: Governance controls mapping for Agent Spec

3 participants