diff --git a/app/src/routes/_authed/admin/boundaries.tsx b/app/src/routes/_authed/admin/boundaries.tsx
index 8efa69457..e96fe7d91 100644
--- a/app/src/routes/_authed/admin/boundaries.tsx
+++ b/app/src/routes/_authed/admin/boundaries.tsx
@@ -178,9 +178,13 @@ function BoundariesPage() {
key being pressed, the file being touched, the{" "}
command being run, and mcp.server,{" "}
mcp.tool and mcp.effect for a call to
- somebody else’s tools. A rule that cannot be evaluated counts
- as a match, so a mistyped deny refuses rather than quietly
- permitting what it was meant to forbid.
+ somebody else’s tools. initiator.kind says what
+ started the run — person, routine or{" "}
+ handoff — which actor.id cannot,
+ because a scheduled run carries its owner’s authority while
+ nobody is watching. A rule that cannot be evaluated counts as a
+ match, so a mistyped deny refuses rather than quietly permitting
+ what it was meant to forbid.
>
}
title="It may never"
diff --git a/docs/architecture.md b/docs/architecture.md
index e5c78bdf5..1879e3805 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -58,6 +58,11 @@ Policy rules can inspect:
- `command`
- `file.path`, `file.name`, `file.extension`
- `mcp.server`, `mcp.tool`, `mcp.effect`
+- `initiator.kind`, `initiator.id` — what started the run, as distinct from whose
+ authority it carries. `person`, `deployment`, `routine` or `handoff`, with the
+ routine or Bot id where there is one. `actor.id` is the routine's owner on a
+ scheduled run, so this is the only field that can tell an unattended run from
+ somebody typing.
Rules use CEL expressions plus case-insensitive `contains()` and `matches()`.
Deny rules are evaluated before allow rules. The policy engine fails closed: a