Skip to content

Policies, rules & bundles

A policy is a versioned set of rules. Each rule is one statement like “block PII above threshold 0.6” or “only allow models from this list”. Assigned policies compile together into one bundle per agent; the kernel evaluates that bundle on every call.

Policy ──▶ PolicyVersion (draft → shadow → active → retired)
└── PolicyRule[] — kind + params + mode (enforce | shadow)
▼ compile
compiled rule ──▶ per-agent bundle ──▶ kernel
  • Params — the threshold, the model list, the domain allowlist. Same kind, many rules.
  • Modeenforce (decides) or shadow (evaluated and recorded in the decision’s evidence, never blocks). Shadow is how you prove a rule before you trust it.

Policies attach to the org tree at four levels:

Scope Applies to
org every agent in the organization
project agents in one project
team agents owned by one team
agent one agent

An agent’s governance is the union of all policies assigned up its tree. Scopes compose in precedence order (org first, agent last); on conflict the more specific scope wins. Assignments can be time-bounded (effective_from / effective_until) — e.g. a stricter policy for an incident window.

Composition produces one artifact per agent:

  • package tappass.policy — the merged rules from every assigned, active policy version, plus the merge resolver.
  • Sidecar data — per-rule payloads, origin, kind, order, and mode, so the decision evidence can name exactly which rule fired.
  • Content addressing — each bundle is content-addressed, and every audit record carries the hash that decided it, which is what makes decisions replayable.

Composition happens eagerly: publishing a policy version recompiles every reached agent inline and fails loudly if any agent’s bundle doesn’t compile. A broken policy can never reach the hot path.

All rules across all layers vote; the resolver applies:

  1. Rules ordered by composition order (scope precedence, then rule ordinal).
  2. First blocking rule wins — the decision names it, with all other violations in evidence.all_reasons.
  3. Shadow rules never vote; their would-have-fired results are recorded under evidence.shadow.
  4. Numeric caps (MaxTokensPerRequest, MaxTokensPerDay) merge as the minimum across layers — the strictest applicable limit wins.
  5. No blocking rule → allow (the org’s configured default_action).

Rules cannot call out; everything is supplied in the policy input, which keeps evaluation fast and replayable.

The kernel composes no hardcoded safety policy. A fresh org starts empty: nothing blocked, everything audited. Every block in every audit record traces to a rule someone in your org wrote and activated. Combined with fail-closed evaluation (missing bundle → block), you get both properties: nothing enforced you didn’t ask for, and nothing silent when enforcement breaks.