Modes and sanitized logs
The same policy can run in three modes. Logging is optional, and log records deliberately exclude commands, arguments, prompts, context, secrets, session IDs, call IDs, and persistent identifiers.
| Mode | Behavior |
|---|---|
enforce |
Denied actions block; an active Pi session may call the judge for eligible input. |
shadow |
Deterministic policy and logs run, but actions do not block and the judge is not called. |
off |
The adapter remains loaded, does not block, and does not call the judge. |
shadow is an observation mode, not a security control. A project can tighten shadow to enforce, but it cannot relax a global enforce setting or activate a globally disabled gate.
Log records
Section titled “Log records”When the global file contains an absolute logPath, each JSONL record contains only:
- host, tool, and shell enums;
- policy verdict, final effect, and stable decision code;
- deterministic or judge source, mode, and blocked state;
- an in-memory repeated-rejection count.
The rejection tracker keeps at most 1,024 counts in memory. Its hash is not returned or written to the log. Judge requests, responses, model references, the static instruction, timing, and provider errors are also excluded.
Log failures
Section titled “Log failures”If an enforce decision cannot be written to the configured log file, the tool call blocks with AMG_DENY_INTERNAL_ERROR. Logging is disabled when logPath is absent.
The adapter does not turn a log failure into silent success. This is part of the fail-closed behavior at the logging boundary.
Legacy migration copies logPath with the rest of the validated file and does not rewrite it. If OpenCode and Pi migrate the same legacy global policy, both destinations retain that explicitly shared log path until you change one host’s file.