Playbooks
A playbook is the source of a decision pack: a YAML file that names the pack, lists its actions, declares how facts are extracted and states the rules. This page explains each section, using the built-in example pack (data protection, compliance.regulatory_pii_guard.v1) as the worked example.
About the example
This page uses the built-in data-protection pack so you can read a complete, working playbook without writing one first. The same sections describe any decision pack: eligibility, limits, routing and so on. See Core concepts.
Adaptive strategy integration is planned
This page describes compiled decision packs. The proposed adaptive strategy loop does not add supported fields to this schema or make embedded evaluation read outcome memory. Hosted playbooks use a separate interface.
The whole file at a glance#
pack_id: compliance.regulatory_pii_guard.v1
version: 1.0.0
name: Regulatory PII and Sensitive Data Guard
kind: compliance
description: "Fail-closed PII inspection for GLBA, PCI-DSS, HIPAA and GDPR/CCPA."
budget:
max_latency_ms: 1.0
max_tokens: 0
actions:
- permit_clean_payload
- block_glba_ssn_leakage
- block_pci_dss_pan_leakage
- block_hipaa_phi_leakage
- redact_and_permit_contact_pii
codons:
- code: PII_SSN_EXTRACT
kind: codon
codon_type: extract_pattern
trigger: on_input
params:
pattern: '\b(?!000|666|9\d{2})\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b'
binds_to: has_ssn
matches_field: ssn_matches
remedy_template: "[REDACTED_SSN]"
# ... card (with checksum: luhn), health ID, email, phone, IP
hard_rules:
- id: RULE-GLBA-SSN-BLOCK
condition: state.has_ssn == True
action: block_glba_ssn_leakage
description: "Statutory violation: Social Security Number (GLBA / FCRA) detected"
severity: fatal
# ... PCI-DSS, HIPAA (fatal), contact details (warning)
default_action: permit_clean_payload
Quote descriptions that contain a colon
A value such as Statutory violation: ... must be quoted, or YAML reads the second colon as a new key and the file fails to parse.
Identity#
| Key | Purpose |
|---|---|
pack_id | Required. Stable, dotted, ends in a major version: <domain>.<name>.v<N>. Licenses grant packs by this ID, so changing it is a breaking change. |
version | Semantic version of this revision. Bump it on every change you ship. |
name, kind, description | Human-facing metadata. |
Budget#
budget.max_latency_ms and budget.max_tokens record the pack's intended envelope: under a millisecond, zero model tokens. A compiled pack enforces them (changed in 0.3.0): max_latency_ms is checked on every decision, a slower decision raises DecisionBudgetExceededError with its result withheld, and any other budget key is rejected at compile time. The built-in example pack does not check its budget. Set max_latency_ms with room for your slowest host.
Actions and the default#
actions is the closed set of outcomes the pack may return. default_action names the outcome when no rule fires; a compiled pack always returns permit_clean_payload then. A compiled pack enforces both (changed in 0.3.0): actions, when present, must list every action the pack can return, including the five of the built-in checks, and default_action may only be permit_clean_payload. See Playbook schema. Name actions so callers can route on the prefix, as the example pack does:
permit_…the payload may proceed unchanged,redact_…the payload may proceed asremedy.clean_text,block_…the payload must stop.
Codons#
Each codon extracts one typed fact from the input into state. The keys that matter:
| Key | Meaning |
|---|---|
code | Unique codon ID, upper snake case. |
codon_type | extract_pattern for regular-expression extraction. Also defined: checksum_validator, range_filter, custom. |
trigger | on_input: run on every evaluation. |
params.pattern | The regular expression. params.flags takes MULTILINE, IGNORECASE, DOTALL, ASCII. |
checksum | luhn discards matches that fail the Luhn check. |
binds_to | The boolean state field set when anything matches. |
matches_field | The state field that holds the matches. |
remedy_template | Replacement text for each match in remedy.clean_text. |
Rules#
A rule pairs a condition over state with an action and a severity (fatal, warning or info). Rules are evaluated in file order; put the most severe first.
What runs in 0.3.1#
The playbook format is ahead of the pack compiler. Know which parts execute. The compiler rejects declarations a compiled pack would not execute, with UnsupportedPackDeclarationError, instead of sealing them silently:
| Section | Built-in example pack | Pack you compile |
|---|---|---|
| The example pack's built-in codons and rules | Run | Run |
rules entries with type: regex or type: luhn_checksum | n/a | Run on every payload, next to the built-in checks |
Your own codons | n/a | Rejected at compile time; executing them is Planned |
Your own hard_rules | n/a | Rejected at compile time; executing them is Planned |
budget enforcement | Not checked | max_latency_ms checked on every decision (changed in 0.3.0) |
To add your own detection today, declare regex rules:
pack_id: acme.project_codes.v1
version: 1.0.0
actions: [permit_clean_payload, block_project_code, block_glba_ssn_leakage,
block_pci_dss_pan_leakage, block_hipaa_phi_leakage, redact_and_permit_contact_pii]
rules:
- id: project_code
type: regex
pattern: '\bPROJ-[A-Z]+-\d[A-Z]\b'
action: block
default_action: permit_clean_payload
How regex rules behave in 0.3.1:
- Every rule and every built-in check runs on every payload, and every match is reported in
triggers. The first fatal match decides the action, with your rules checked before the built-in ones; with no fatal match, the first warning decides. - The returned action is
block_<id>(hereblock_project_code) with severityFATALforaction: block, andredact_<id>with severityWARNINGforaction: redact. Name the ruleidso that the result reads well, and list the same name underactionsfor reviewers. - A
redactrule replaces each match with[REDACTED_<ID>], the rule ID in upper case. Overlapping matches merge into one redaction. When anyblockrule fires,remedy.clean_textis[BLOCKED: Prohibited Content], even if another rule redacted something (changed in 0.3.0: in 0.2.1 the blocked value could stay inclean_text). Still, never forward the text of a blocked result. - The whole match is reported and redacted, whether or not the pattern has capturing groups (changed in 0.3.0: 0.2.1 used the first group's text).
Compile it with your license and run it; see Packs and the custom rules tutorial. The full key list is in the playbook schema reference.
Writing good playbooks#
- Anchor patterns with
\band test them against both true and near-miss inputs. - Prefer a checksum where the identifier has one; it removes most false positives.
- Avoid nested quantifiers such as
(a+)+. Patterns run on every payload with no timeout. - Keep a golden test set next to the playbook and run it in CI before compiling. See Testing policies.