1919RuntimeMode = Literal ["auto" , "ebpf" , "proxy" , "sdk-only" ]
2020NetworkMode = Literal ["ebpf" , "proxy" , "sdk-only" ]
2121
22+ EnforcementMode = Literal ["enforce" , "observe" , "disabled" ]
23+ """Posture the governance gateway should apply to this agent's actions.
24+
25+ * ``"enforce"`` — default; deny blocks the action, redact strips secrets.
26+ * ``"observe"`` — dry-run; the gateway records what *would* have happened
27+ but lets every action through. Surfaced by ``aa audit list --dry-run-only``.
28+ * ``"disabled"`` — policy evaluation skipped entirely. Hermetic test only.
29+
30+ Mirrors ``aa_core::EnforcementMode`` on the wire; uses the same snake_case
31+ tokens the gateway expects in the registration body."""
32+
2233_DEFAULT_AGENT_ID = "agent-assembly-default"
2334_VALID_RUNTIME_MODES = {"auto" , "ebpf" , "proxy" , "sdk-only" }
35+ _VALID_ENFORCEMENT_MODES : frozenset [EnforcementMode ] = frozenset ({"enforce" , "observe" , "disabled" })
2436_INIT_LOCK = Lock ()
2537_ACTIVE_CONTEXT : AssemblyContext | None = None
2638
@@ -115,6 +127,7 @@ def init_assembly(
115127 delegation_reason : str | None = None ,
116128 spawned_by_tool : str | None = None ,
117129 depth : int | None = None ,
130+ enforcement_mode : EnforcementMode | None = None ,
118131) -> AssemblyContext :
119132 """Initialize the Agent Assembly SDK runtime for this process.
120133
@@ -125,10 +138,18 @@ def init_assembly(
125138 through the resolver chain (env → config file → local default with
126139 optional auto-start) per Epic 17 S-G — see
127140 ``agent_assembly.core.gateway_resolver``.
141+
142+ :param enforcement_mode: Per-agent governance posture sent to the gateway
143+ at registration (see :data:`EnforcementMode`). Defaults to ``None``,
144+ which omits the field from the registration body — the gateway then
145+ applies its server-side default (live ``enforce``). Pass ``"observe"``
146+ to register the agent in dry-run / sandbox mode: every action
147+ proceeds and the gateway records would-be violations as shadow audit
148+ events.
128149 """
129150 gateway_url = resolve_gateway_url (gateway_url )
130151 api_key = resolve_api_key (api_key )
131- _validate_inputs (gateway_url = gateway_url , mode = mode )
152+ _validate_inputs (gateway_url = gateway_url , mode = mode , enforcement_mode = enforcement_mode )
132153 if delegation_reason is not None and len (delegation_reason ) > 256 :
133154 raise ValueError ("delegation_reason must be <= 256 characters" )
134155
@@ -164,6 +185,7 @@ def init_assembly(
164185 delegation_reason = delegation_reason ,
165186 spawned_by_tool = spawned_by_tool ,
166187 depth = depth ,
188+ enforcement_mode = enforcement_mode ,
167189 )
168190
169191 registered_adapters : list [FrameworkAdapter ] = []
@@ -190,11 +212,17 @@ def init_assembly(
190212 return context
191213
192214
193- def _validate_inputs (* , gateway_url : str , mode : RuntimeMode ) -> None :
215+ def _validate_inputs (
216+ * , gateway_url : str , mode : RuntimeMode , enforcement_mode : EnforcementMode | None = None
217+ ) -> None :
194218 if not gateway_url :
195219 raise ConfigurationError ("gateway_url is required" )
196220 if mode not in _VALID_RUNTIME_MODES :
197221 raise ConfigurationError ("mode must be one of: auto, ebpf, proxy, sdk-only" )
222+ if enforcement_mode is not None and enforcement_mode not in _VALID_ENFORCEMENT_MODES :
223+ raise ConfigurationError (
224+ f"enforcement_mode must be one of: enforce, observe, disabled (got: { enforcement_mode !r} )"
225+ )
198226
199227
200228def _register_adapters (
0 commit comments