Shadow mode: watching without acting
Before a policy blocks anything in production, you want to see what it would do to real traffic. Shadow mode runs the whole gate and lets nothing through: an allowed call is recorded as a simulation rather than run.
The flag on the kernel
from agent_control_plane import AgentKernel, PolicyEngine
policy = PolicyEngine()
policy.add_constraint("support", ["lookup_order", "issue_refund"])
shadow = AgentKernel(policy_engine=policy, shadow_mode=True)
print(shadow.intercept_tool_execution("support", "lookup_order", {"order_id": "A17"}))In lesson 5 an allowed call returned None, meaning proceed. With shadow_mode=True the same allowed call comes back as a dictionary with status of simulated instead. The gate ran, the call was permitted, and nothing was handed back to execute.
A blocked call is still blocked
from agent_control_plane import AgentKernel, PolicyEngine
policy = PolicyEngine()
policy.add_constraint("support", ["lookup_order", "issue_refund"])
shadow = AgentKernel(policy_engine=policy, shadow_mode=True)
verdict = shadow.intercept_tool_execution("support", "delete_order", {})
print(verdict["status"], "|", verdict["mute"])Shadow mode changes only the allowed path. A policy violation is refused exactly as in enforcing mode, with the muting verdict from lesson 5. So shadow mode never lets through something a policy forbids; it withholds the calls a policy would have allowed.
Running an agent in the dark
from agent_control_plane import AgentKernel, PolicyEngine
from pretend_agent_governance import PretendAgent, TOOLS, REFUNDS
policy = PolicyEngine()
policy.add_constraint("support", ["lookup_order", "issue_refund"])
shadow = AgentKernel(policy_engine=policy, shadow_mode=True)
agent = PretendAgent()
for message in ["Where is order A17?", "refund order A17 for 40", "delete order A17"]:
tool, args = agent.decide(message)
verdict = shadow.intercept_tool_execution("support", tool, args)
print(f"{tool:13}", verdict["status"] if verdict else "allowed")
print("refunds actually made:", len(REFUNDS))Two calls were allowed and simulated, one was blocked, and no refund was made: the money-moving tool never ran, because a simulated verdict is not a green light to call it. That is what shadow mode is for. Point it at a copy of live traffic, read the log, and see what the policy would do before it does it for real.
This is the imperative counterpart of the audit action from lesson 14. The audit action, written in a policy document, lets a call through and marks it worth recording; shadow mode, set on the kernel, holds every allowed call back and records the simulation. Both watch without the real consequence; they differ in whether the call still runs.
- Turn
shadow_modeoff and run the same loop; note which tools now run for real. - Add a
FlightRecorderfrom lesson 20 and read what shadow mode logs for a simulated call. - Give the agent a message that routes to
send_emailand see whether shadow mode simulates or blocks it.
This is what real progress feels like.