§ DOCUMENTATION
Policy-as-Code
Author policies as JSON or YAML in your repo, validate them before CI with execlave policies lint, reconcile them server-side with execlave policies sync, and audit every change through a tamper-evident version history.
Why policy-as-code
When policies live only in the dashboard, changes bypass the same review process you apply to application code. A single misconfigured rule — for example, flipping enforcementMode from block to log_only — can silently widen your agent's blast radius with no diff, no reviewer, and no automated test to catch it.
Execlave's policy-as-code workflow treats policy bundles as first-class source artefacts: code review, CI validation, and reproducible deployments for every policy change. The same schema the API enforces is available locally, so errors are caught at lint time rather than at runtime.
Authoring policy bundles
A policy bundle is a JSON or YAML file that declares one policy. The structure mirrors the POST /api/v1/policies request body: required fields are name, policyType, enforcementMode, and ruleDefinition. Optional metadata keys (owner, ticket, team) are stored verbatim and surfaced in the dashboard.
Store bundles anywhere in your repository — a conventional layout is a top-level policies/ directory. The CLI commands accept a directory path and process every .json and .yaml file within it recursively.
| Field | Required | Notes |
|---|---|---|
| name | yes | Human-readable label, must be unique within org |
| policyType | yes | tool_call, prompt_injection, pii_detection, … |
| enforcementMode | yes | block, log_only, require_approval |
| ruleDefinition | yes | Object — schema varies by policyType |
| metadata | no | Arbitrary key/value pairs stored as JSONB |
execlave policies lint
execlave policies lint <path> validates every bundle file against the policy JSON Schema before you commit or open a pull request. It exits non-zero on any error, making it drop-in for CI.| What lint catches | Example |
|---|---|
| Missing required fields | ruleDefinition omitted entirely |
| Unknown policy type | policyType: "custom_type" not in enum |
| Wrong field type | ruleDefinition.tools: string instead of array |
| Invalid enforcementMode | "allow" instead of "block" / "log_only" / "require_approval" |
| Extra top-level keys | Fields not in the schema trigger additionalProperties error |
# Validate all policy bundles before committingexeclave policies lint ./policies/ # Output on success✓ production-guardrails.json — valid✓ data-access.yaml — valid2 bundles validated, 0 errors # Output on failure (exits non-zero — CI-friendly)✗ production-guardrails.json — invalid ruleDefinition.tools: must be array1 error foundexeclave policies sync — dry-run & apply
execlave policies sync <path> diffs declared bundles against live policies in your org and prints the plan. No changes are applied until you pass --apply. Synced policies record source: "cli-sync" in their metadata field for provenance tracking.# Dry-run (default) — prints plan, no changes appliedexeclave policies sync ./policies/ Plan: + create "Require approval for file writes" (production-guardrails.json) ~ update "Block PII exfiltration" (data-access.yaml) enforcementMode: "log_only" → "block" = no-op "Rate limit external calls" (already in sync) 2 changes pending. Re-run with --apply to apply.# Apply the planexeclave policies sync ./policies/ --apply Applied: ✓ created pol_01j... "Require approval for file writes" ✓ updated pol_02j... "Block PII exfiltration"Policy history & metadata
Every policy write event is recorded in the tamper-evident audit log. Retrieve the full change history for a policy via GET /api/v1/policies/:id/history. The response is ordered oldest-first and includes the actor, timestamp, and a field-level diff for each change.
Because the audit log uses ENABLE ALWAYS triggers that prevent UPDATE and DELETE, the history cannot be altered after the fact — every entry is immutable by construction.
curl https://api.execlave.com/api/v1/policies/pol_01j.../history \ -H "Authorization: Bearer $EXECLAVE_API_KEY" # Response{ "data": [ { "eventType": "policy.updated", "actorId": "user_123", "changedAt": "2026-06-02T09:30:00Z", "diff": { "enforcementMode": { "from": "log_only", "to": "block" } } }, { "eventType": "policy.created", "actorId": "cli-sync", "changedAt": "2026-05-15T14:00:00Z", "diff": null } ]}