Problem
ADK's plugin callback semantics allow short-circuiting: the first plugin returning a non-None value bypasses all subsequent plugins AND agent callbacks. This is by design for general-purpose plugins, but it creates a gap for governance and audit use cases — these hooks must always execute, regardless of what other plugins do.
This gap was identified during the multi-party governance discussion in #4764 and affects all governance implementations currently being built for ADK.
Evidence from existing issues
This isn't theoretical — the short-circuit behavior is already causing problems:
Who needs this
Three governance implementations are being built for ADK, all affected:
All three use before_tool_callback and before_agent_callback as enforcement points. All three can be silently bypassed by an earlier plugin returning non-None.
Proposal
Add a two-phase callback execution model:
Phase 1: Standard plugins (current behavior — first non-None return short-circuits)
Phase 2: Mandatory plugins (always execute — governance, audit, telemetry)
If a Phase 2 plugin denies an action, its denial overrides Phase 1's result. This ensures governance has the final say.
Suggested API
class BasePlugin:
# Existing behavior
mandatory: bool = False
# When True:
# - Callbacks always execute, even if a prior plugin returned non-None
# - Denial from a mandatory plugin overrides earlier allow decisions
# - Audit/telemetry callbacks are guaranteed to fire
Why two phases instead of priority ordering
Priority ordering (e.g., priority=100) is fragile — plugin authors compete over priority values, and there's no guarantee governance wins. The two-phase model is simpler: standard plugins handle normal logic, mandatory plugins handle governance. No priority conflicts.
Impact
| Without mandatory tier |
With mandatory tier |
| Governance hooks can be bypassed |
Governance always executes |
| Audit trail has gaps |
Audit trail is complete |
| Policy enforcement is advisory |
Policy enforcement is real |
| Cannot satisfy regulatory requirements |
Auditors can rely on the layer |
Compatibility
Fully additive. Existing plugins with mandatory = False (the default) behave exactly as today. Only plugins explicitly opting into mandatory execution get the new guarantee. No breaking changes.
Related
cc @aeoess @imran-siddique @razashariff @evekhm @gautamvarmadatla
Problem
ADK's plugin callback semantics allow short-circuiting: the first plugin returning a non-None value bypasses all subsequent plugins AND agent callbacks. This is by design for general-purpose plugins, but it creates a gap for governance and audit use cases — these hooks must always execute, regardless of what other plugins do.
This gap was identified during the multi-party governance discussion in #4764 and affects all governance implementations currently being built for ADK.
Evidence from existing issues
This isn't theoretical — the short-circuit behavior is already causing problems:
output_keyis not written to session state whenbefore_agent_callbackshort-circuits execution #4837 —before_agent_callbackshort-circuit doesn't updateoutput_keyin session state, causing silent backend staleness. A mandatory tier would ensure state-management callbacks always run.Who needs this
Three governance implementations are being built for ADK, all affected:
PolicyEvaluatorprotocol with tool filtering, delegation scope, audit trails (@sunilp)evaluateIntent()enforcement (@aeoess)All three use
before_tool_callbackandbefore_agent_callbackas enforcement points. All three can be silently bypassed by an earlier plugin returning non-None.Proposal
Add a two-phase callback execution model:
If a Phase 2 plugin denies an action, its denial overrides Phase 1's result. This ensures governance has the final say.
Suggested API
Why two phases instead of priority ordering
Priority ordering (e.g.,
priority=100) is fragile — plugin authors compete over priority values, and there's no guarantee governance wins. The two-phase model is simpler: standard plugins handle normal logic, mandatory plugins handle governance. No priority conflicts.Impact
Compatibility
Fully additive. Existing plugins with
mandatory = False(the default) behave exactly as today. Only plugins explicitly opting into mandatory execution get the new guarantee. No breaking changes.Related
output_keyis not written to session state whenbefore_agent_callbackshort-circuits execution #4837 — Short-circuit doesn't update session state (symptom of the same design gap)cc @aeoess @imran-siddique @razashariff @evekhm @gautamvarmadatla