Skip to content

feat: Add GovernanceDecision and GovernanceOutcome contract types#6030

Open
nagasatish007 wants to merge 9 commits into
crewAIInc:mainfrom
nagasatish007:feat/governance-decision-contract
Open

feat: Add GovernanceDecision and GovernanceOutcome contract types#6030
nagasatish007 wants to merge 9 commits into
crewAIInc:mainfrom
nagasatish007:feat/governance-decision-contract

Conversation

@nagasatish007
Copy link
Copy Markdown

@nagasatish007 nagasatish007 commented Jun 3, 2026

Summary

Adds a vendor-neutral GovernanceDecision TypedDict contract that crew-level governance hooks (before_tool_call / after_tool_call from #5890) can optionally return. Also adds GovernanceOutcome as the linked post-execution record.

This gives the hook one return shape that works for blocking, approval, resume, and audit — without coupling CrewAI to any vendor's evidence format.

Closes #5888 (governance decision contract portion)

Design Principles

  • CrewAI owns the envelope — the type lives in CrewAI core, no vendor imports
  • Vendor-neutral — TealTiger, Neura Relay, Vaara, or any engine can implement this contract
  • Extensions are pass-throughextensions: dict[str, Any] is never validated by CrewAI. Vendors attach their evidence (signed receipts, Merkle proofs, etc.) under their own namespace key
  • Two-record boundaryGovernanceDecision is pre-execution, GovernanceOutcome is post-execution, linked via decision_id
  • Serialized contract first — the TypedDict defines the JSON wire format; implementations can wrap it in a dataclass if preferred

Files

File Purpose
lib/crewai/src/crewai/governance/governance_decision.py GovernanceDecision + GovernanceOutcome TypedDicts
lib/crewai/tests/governance/test_governance_decision_contract.py Contract-test fixtures for all 4 decision routes + extension round-trip

Contract Fields (GovernanceDecision)

class GovernanceDecision(TypedDict, total=False):
    decision_id: str
    agent_id: str
    agent_role: str
    tool: str
    request_id: str
    params_hash: str        # SHA-256 of JCS-canonicalized params
    target: str
    policy_refs: list[str]
    decision: Literal["allow", "deny", "require_approval", "revise"]
    reason: str
    issued_at: str          # ISO 8601
    expires_at: str | None
    supersedes: str | None
    revalidate_if: list[str]
    evidence_refs: list[str]
    extensions: dict[str, Any]  # vendor pass-through

Test Fixtures

Fixture Decision Tests
ALLOW allow Minimum valid decision
DENY deny Policy ref present
REQUIRE_APPROVAL require_approval Has expires_at
REVISE revise Has revalidate_if
ALLOW + extension allow TEEC evidence under extensions["teec"]
Unknown extension allow Arbitrary vendor payload round-trips unchanged
Outcome executed Links back via decision_id

Extension Round-Trip Test

The key test: an unknown vendor extension (extensions["custom_vendor"]) with nested dicts, arrays, and unicode passes through JSON serialize → deserialize without any data loss or validation failure. This proves CrewAI doesn't filter, validate, or modify vendor evidence.

Backward Compatibility

Co-authored with

Co-authored-by: rpelevin rpelevin@users.noreply.github.com

References

Summary by CodeRabbit

  • New Features

    • Added governance decision and outcome contract types for authorization metadata, including verdicts, expiry/revalidation hints, evidence references, and vendor-specific extensions
    • Exposed these governance types at the governance package level for easier import
  • Tests

    • Added tests validating JSON round-trip serialization, extension payload passthrough, required fields, expiry/revalidate semantics, error outcomes, and decision→outcome linkage

This module defines the GovernanceDecision and GovernanceOutcome TypedDicts for vendor-neutral governance hooks in CrewAI. It specifies the structure and fields for pre-execution and post-execution records used in governance processes.
This file contains contract tests for GovernanceDecision and GovernanceOutcome, validating decision routes, JSON serialization, and outcome references.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a68f6ee-6fe8-4040-9a11-4227520fb0ca

📥 Commits

Reviewing files that changed from the base of the PR and between 2ee3042 and bd039bf.

📒 Files selected for processing (1)
  • lib/crewai/tests/test_governance_decision_contract.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/crewai/tests/test_governance_decision_contract.py

📝 Walkthrough

Walkthrough

Adds vendor-neutral governance TypedDict contracts: pre-execution GovernanceDecision and post-execution GovernanceOutcome, exposes them from the package, and adds comprehensive pytest fixtures/tests that validate fields and JSON round-trip preservation of extensions.

Changes

Governance Decision and Outcome Contracts

Layer / File(s) Summary
Governance contract types
lib/crewai/src/crewai/governance/governance_decision.py, lib/crewai/src/crewai/governance/__init__.py
Module docs plus GovernanceDecision and GovernanceOutcome TypedDicts define pre-execution authorization metadata and post-execution results. __init__.py exports GovernanceDecision and GovernanceOutcome.
Contract validation tests
lib/crewai/tests/test_governance_decision_contract.py
Adds typed fixtures for allow/deny/require_approval/revise decisions, structured (extensions.teec) and unknown vendor extension fixtures, success/error outcome fixtures, and pytest functions verifying required fields, lifecycle hints (expires_at, revalidate_if), outcome→decision linkage, and JSON round-trip equality for all fixtures.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 I thump a note for decisions made,

Typed and tidy, each outcome laid,
Extensions carried through the night,
Round-tripped JSON keeps them right,
A rabbit nods — governance in sight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add GovernanceDecision and GovernanceOutcome contract types' accurately describes the main change: introducing two new TypedDict contracts for governance decision and outcome handling.
Linked Issues check ✅ Passed The pull request adds GovernanceDecision and GovernanceOutcome contract types that provide the structured decision-making capability required by issue #5888 for governance middleware hook authorization.
Out of Scope Changes check ✅ Passed All changes are scoped to governance decision contracts: adding TypedDict definitions, module exports, and comprehensive contract tests. No unrelated refactoring or unscoped modifications present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
lib/crewai/src/crewai/governance/__init__.py (1)

1-2: ⚡ Quick win

Export types from __init__.py for better ergonomics.

The governance module's __init__.py is empty, requiring users to import from the full submodule path. Exporting the public types would make imports more convenient and discoverable.

📦 Proposed export pattern
+"""
+CrewAI governance contracts.
+"""
+
+from crewai.governance.governance_decision import (
+    GovernanceDecision,
+    GovernanceOutcome,
+)
+
+__all__ = ["GovernanceDecision", "GovernanceOutcome"]

This allows cleaner imports:

from crewai.governance import GovernanceDecision, GovernanceOutcome

instead of:

from crewai.governance.governance_decision import GovernanceDecision, GovernanceOutcome
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai/src/crewai/governance/__init__.py` around lines 1 - 2, Add public
exports to the governance package by importing and re-exporting the key types in
the package __init__.py: import GovernanceDecision and GovernanceOutcome (and
any other public classes) from their defining module (e.g., governance_decision)
and add them to the package's __all__ so users can do "from crewai.governance
import GovernanceDecision, GovernanceOutcome"; ensure you reference the exact
class names GovernanceDecision and GovernanceOutcome and any other public
symbols you want exposed.
test_governance_decision_contract.py (1)

98-103: ⚡ Quick win

Consider adding error outcome fixture for completeness.

The current outcome fixture only tests outcome="executed". Since GovernanceOutcome defines error_type and error_message fields and includes "error" as a valid outcome, adding a fixture that demonstrates the error case would strengthen contract coverage.

🧪 Proposed error outcome fixture
FIXTURE_OUTCOME_ERROR: GovernanceOutcome = {
    "decision_id": "d-002",  # Link to FIXTURE_DENY or any decision
    "outcome": "error",
    "error_type": "PermissionError",
    "error_message": "Insufficient permissions to execute tool",
    "completed_at": "2026-06-03T14:01:05Z",
}

Then add to test_all_fixtures_json_serializable:

     fixtures: list[dict[str, Any]] = [
         FIXTURE_ALLOW,
         FIXTURE_DENY,
         FIXTURE_REQUIRE_APPROVAL,
         FIXTURE_ALLOW_WITH_EXTENSION,
         FIXTURE_REVISE,
         FIXTURE_OUTCOME,
+        FIXTURE_OUTCOME_ERROR,
         FIXTURE_UNKNOWN_EXTENSION,
     ]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test_governance_decision_contract.py` around lines 98 - 103, Add an
error-case fixture for GovernanceOutcome named FIXTURE_OUTCOME_ERROR that sets
"outcome" to "error" and includes "error_type" and "error_message" plus
"decision_id" and "completed_at" to mirror FIXTURE_OUTCOME structure; then
include FIXTURE_OUTCOME_ERROR in the test_all_fixtures_json_serializable
assertions so the error-path (outcome="error") is covered by serialization tests
(reference symbols: FIXTURE_OUTCOME, FIXTURE_OUTCOME_ERROR, GovernanceOutcome,
test_all_fixtures_json_serializable).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@lib/crewai/src/crewai/governance/__init__.py`:
- Around line 1-2: Add public exports to the governance package by importing and
re-exporting the key types in the package __init__.py: import GovernanceDecision
and GovernanceOutcome (and any other public classes) from their defining module
(e.g., governance_decision) and add them to the package's __all__ so users can
do "from crewai.governance import GovernanceDecision, GovernanceOutcome"; ensure
you reference the exact class names GovernanceDecision and GovernanceOutcome and
any other public symbols you want exposed.

In `@test_governance_decision_contract.py`:
- Around line 98-103: Add an error-case fixture for GovernanceOutcome named
FIXTURE_OUTCOME_ERROR that sets "outcome" to "error" and includes "error_type"
and "error_message" plus "decision_id" and "completed_at" to mirror
FIXTURE_OUTCOME structure; then include FIXTURE_OUTCOME_ERROR in the
test_all_fixtures_json_serializable assertions so the error-path
(outcome="error") is covered by serialization tests (reference symbols:
FIXTURE_OUTCOME, FIXTURE_OUTCOME_ERROR, GovernanceOutcome,
test_all_fixtures_json_serializable).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 00f632c3-6eb2-4dd0-89e0-6bb603ca4224

📥 Commits

Reviewing files that changed from the base of the PR and between 68cdd44 and 6ff28b2.

📒 Files selected for processing (3)
  • governance_decision.py
  • lib/crewai/src/crewai/governance/__init__.py
  • test_governance_decision_contract.py

@rpelevin
Copy link
Copy Markdown

rpelevin commented Jun 3, 2026

Thanks, Naga. Directionally this is the right contract shape.

One mechanical thing I would fix before merge: governance_decision.py appears to be added at repo root, while the test imports crewai.governance.governance_decision. I think the contract should live at lib/crewai/src/crewai/governance/governance_decision.py, with GovernanceDecision and GovernanceOutcome exported from lib/crewai/src/crewai/governance/__init__.py.

I would also move the contract test into CrewAI's test tree, e.g. lib/crewai/tests/governance/test_governance_decision_contract.py, so it runs with the package layout.

Field names and boundary look right to me: decision_id, params_hash, policy_refs, revalidate_if, evidence_refs, extensions, and separate GovernanceOutcome linked by decision_id. The unknown-extension round-trip test is exactly the right vendor-neutral proof.

Optional but useful: add one outcome="error" fixture so error_type / error_message are covered too.

This file contains contract tests for GovernanceDecision and GovernanceOutcome, validating decision routes, JSON serialization, and outcome references.
This module defines the GovernanceDecision and GovernanceOutcome types for vendor-neutral governance hooks in CrewAI, including their fields and documentation.
Added test for error outcomes to validate error_type and error_message fields.
@nagasatish007
Copy link
Copy Markdown
Author

@rpelevin the changes have been done.

@rpelevin
Copy link
Copy Markdown

rpelevin commented Jun 4, 2026

Thanks, Naga. I went through the latest commits. This addresses the core things I called out: the contract now lives under crewai.governance, the types are exported from the package, GovernanceDecision and GovernanceOutcome stay separate with decision_id linking them, and the extension round-trip plus error-outcome coverage are now in the tests.

From my side the field names and vendor-neutral boundary look right. I would avoid adding more scope here and let the CrewAI maintainers decide the final test layout and merge mechanics. Great work getting this tightened up.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]:Governance middleware hook for tool call authorization

2 participants