Shadow Mode
Observe real authorization decisions in production without blocking execution.
shadow mode is a non-blocking rollout mode for production hardening.
Veto still evaluates every tool call against all policies and computes the real decision, but wrapped execution is never blocked. This lets you measure impact safely before switching to strict.
Why use shadow mode
- Validate policy quality against live traffic before enforcement.
- See exactly what would have been denied or sent for approval.
- Keep guardrails observable with no availability risk from false positives.
Strict vs log vs shadow
| Mode | Wrapped execution | Validation decision returned for wrapped calls | guard() result |
|---|---|---|---|
strict | Blocks deny / require_approval | Real decision | Real decision |
log | Never blocks | Overridden to allow | Real decision |
shadow | Never blocks | Real decision preserved (deny / require_approval) | Real decision + shadow flags |
Enable shadow mode
import { Veto, protect } from 'veto-sdk';
const veto = await Veto.init({ mode: 'shadow' });
const safeTools = await protect(tools, { mode: 'shadow' });Or via environment variable:
export VETO_MODE=shadowfrom veto import Veto, VetoOptions, protect
veto = await Veto.init(VetoOptions(mode="shadow"))
safe_tools = await protect(tools, mode="shadow")Or via environment variable:
export VETO_MODE=shadowMode precedence is: explicit option > config file mode > VETO_MODE env var > strict.
Reading shadow output
When a call would be denied or require approval, Veto writes a formatted stderr line (unless log level is silent):
[shadow] 10:14:33 transfer_funds({"amount":50000,"to":"acct_123"}) - WOULD BE DENIED by transfer-limit
[shadow] 10:14:35 deploy({"env":"prod"}) - WOULD REQUIRE APPROVAL by prod-approvalInterpretation:
WOULD BE DENIEDmeans strict mode would block this call.WOULD REQUIRE APPROVALmeans strict mode would pause for approval workflow.by <rule-id>identifies the matched rule when available.
Telemetry and dashboard filtering
Shadow decisions are explicitly tagged for analytics and filtering:
- Webhook events include
shadow: true. - Decision-log context includes
shadow: trueandshadow_decision. - Guard results include
shadowandshadowDecision/shadow_decisionfor non-allow outcomes.
This allows dashboard views and downstream pipelines to separate observed shadow activity from enforced strict blocks.
Migration path
- Run
shadowmode in production for about one week. - Review shadow denials and approvals in logs/dashboard.
- Refine policies to reduce false positives.
- Switch to
strictwhen deny/approval volume is acceptable.