Skip to content

operator runbooks

Intended Documentation

Author a Policy

Guide for authoring Intended authorization policies safely, including YAML structure, validation, local testing, and review workflow.

Author a Policy#

This runbook walks you through authoring a Intended authorization policy from scratch. You will define the policy YAML, validate it against the schema, test it locally, and submit it for peer review before deployment.

Prerequisites#

Before you begin, make sure you have:

  • The Intended CLI installed and authenticated (meritt auth status)
  • Access to the workspace where the policy will be applied
  • A local checkout of your organization's policy repository

Tip

Policies are version-controlled alongside your infrastructure. Always author policies in a feature branch and submit them through your standard review process.

Policy YAML Structure#

Every Intended policy is a YAML document that declares authorization constraints for AI execution. The top-level structure follows a strict schema.

Policy definition — policies/restrict-production.yaml
yaml
apiVersion: meritt.io/v1
kind: Policy
metadata:
  name: restrict-production-deploys
  description: Require dual approval for production AI deployments
  labels:
    environment: production
    team: platform
spec:
  scope:
    environments: ["production"]
    services: ["*"]
  rules:
    - action: deploy
      effect: deny
      conditions:
        - type: approval
          required: 2
          from: ["role:deployer-lead", "role:security-reviewer"]
        - type: time-window
          allow: "Mon-Fri 09:00-17:00 UTC"
  fallback: deny
  audit:
    level: full
    include-decision-token: true

Key Fields#

FieldRequiredDescription
apiVersionYesSchema version, currently meritt.io/v1
kindYesMust be Policy
metadata.nameYesUnique identifier, lowercase with hyphens
metadata.descriptionYesHuman-readable purpose
spec.scopeYesEnvironments and services this policy targets
spec.rulesYesOne or more authorization rules
spec.fallbackYesDefault effect when no rule matches: allow or deny
spec.auditNoAudit configuration for decision logging

Warning

Always set fallback: deny for production policies. An open fallback in production creates an unaudited authorization gap.

Step 1: Scaffold the Policy#

Generate a policy skeleton

Use the CLI to scaffold a new policy file with the correct schema:

$meritt policy init <name>

Scaffold a new policy YAML file in the current directory.

--environment(-e)string
Target environment for the policy
--output(-o)string
Output file path (default: policies/<name>.yaml)
bash
$ meritt policy init restrict-staging-writes \
    --environment staging \
    --output policies/restrict-staging-writes.yaml

Policy scaffold created: policies/restrict-staging-writes.yaml

Edit the policy file

Open the generated file and fill in the spec.rules section. Each rule requires an action, an effect, and optional conditions.

Actions map to Intended execution verbs: deploy, invoke, read, write, delete, escalate.

Effects are either allow or deny.

Add conditions

Conditions constrain when a rule applies. Common condition types:

  • approval — require N approvals from specific roles
  • time-window — restrict to a time range
  • identity — match against caller identity attributes
  • resource-tag — match resource labels
  • trust-level — require a minimum trust score

Step 2: Validate the Policy#

Run schema validation before committing. The validator checks structure, field types, and cross-references.

$meritt policy validate <file>

Validate a policy file against the Intended schema.

--strictboolean
Enable strict mode: treat warnings as errors
--schema-versionstring
Override schema version for validation
bash
$ meritt policy validate policies/restrict-staging-writes.yaml --strict

Validating policies/restrict-staging-writes.yaml...
  Schema:       OK (meritt.io/v1)
  Metadata:     OK
  Scope:        OK (staging / *)
  Rules:        OK (2 rules)
  Conditions:   OK
  Audit config: OK

Result: PASS (0 errors, 0 warnings)

Danger

Never bypass validation errors. A malformed policy can fail open in the runtime, granting unintended authorization to AI execution.

Step 3: Test Locally#

Test the policy against recorded decision logs to verify it behaves as expected before pushing to the remote.

bash
$ meritt policy test policies/restrict-staging-writes.yaml \
    --replay-log decisions/staging-last-24h.json \
    --format table

DECISION    EXPECTED    ACTUAL    MATCH
deny        deny        deny      YES
allow       allow       allow     YES
deny        deny        allow     NO   ← rule gap in time-window condition
deny        deny        deny      YES

Results: 3/4 matched (75%)

Warning

If match rate drops below 100%, investigate each mismatch before proceeding. Use --verbose to see which rule fired and why.

bash
$ meritt policy test policies/restrict-staging-writes.yaml \
    --replay-log decisions/staging-last-24h.json \
    --verbose \
    --filter mismatches

Step 4: Submit for Review#

Once validation and testing pass, commit and push your branch, then open a review request.

Commit the policy

bash
$ git add policies/restrict-staging-writes.yaml
$ git commit -m "policy: add restrict-staging-writes"
$ git push origin feature/restrict-staging-writes

Request policy review

Use the CLI to create a formal review request that notifies the required approvers:

bash
$ meritt policy review request \
    --file policies/restrict-staging-writes.yaml \
    --reviewers "team:security,team:platform-leads"

Review request created: rev_abc123
Required approvals: 2
Reviewers notified: 4 members

Check review status

bash
$ meritt policy review status rev_abc123

Review:     rev_abc123
Policy:     restrict-staging-writes
Status:     pending (1/2 approvals)
Approvals:  alice@example.com (approved)
Pending:    bob@example.com

Common Mistakes#

MistakeConsequenceFix
Missing fallback fieldPolicy engine uses system default (may be allow)Always set fallback: deny explicitly
Overlapping scopesConflicting rules cause unpredictable evaluationUse meritt policy simulate to detect conflicts
Broad wildcard scopesUnintended services affectedScope to explicit service names for production
Skipping local testRegression discovered in productionAlways replay recent decision logs locally

Next Steps#