Validate paybond.policy.yaml before you bind an agent run or deploy policy-as-code to production. Paybond ships two layers:
| Layer | When to use | Credentials |
|---|---|---|
| Local | Offline CI, pre-commit, air-gapped dev | None |
| Remote | Catch Harbor registry drift (template heads, tenant bindings) | Sandbox or production API key |
CLI
Local-only (offline)
paybond policy validate-tools --file paybond.policy.yaml --local-only --format json
Checks schema version, completion preset IDs, registry/intent alignment, and optional strict allowed_tools rules (--strict or PAYBOND_POLICY_STRICT=1).
Server-authoritative (recommended when logged in)
paybond login paybond policy validate-tools --file paybond.policy.yaml --remote --format json
When PAYBOND_API_KEY is configured (env or .env.local), validate-tools defaults to remote unless you pass --local-only.
Remote validation calls Gateway POST /v1/policy/validate. The tenant scope is derived from your bearer credential — cross-tenant template rows are never returned.
Example report when local checks pass but the published template head drifted:
{ "valid": false, "local_valid": true, "remote_valid": false, "policy_name": "travel-agent-v1", "tenant_id": "tenant-sandbox-…", "errors": [ { "path": "intent.policy_binding.head_digest", "code": "template_head_mismatch", "message": "head digest does not match published tenant head" } ], "checks": [ { "name": "template_exists", "passed": true }, { "name": "head_digest_match", "passed": false } ] }
Legacy template catalog probe
--check-gateway remains available for template-id existence checks against /harbor/policy/v1/templates. Prefer --remote for full registry validation.
Kit API
TypeScript:
import { PaybondPolicy } from "@paybond/kit/policy"; const policy = await PaybondPolicy.load("./paybond.policy.yaml"); const local = await policy.validate({ strict: true }); const remote = await policy.validateRemote(paybond.harbor, { strict: true });
Python:
from paybond_kit.policy import PaybondPolicy policy = PaybondPolicy.load("./paybond.policy.yaml") local = policy.validate(strict=True) remote = await policy.validate_remote(paybond.harbor, options=PolicyRemoteValidateOptions(strict=True))
CI
Offline gate (no secrets):
paybond policy validate-tools --file paybond.policy.yaml --local-only --format json
Sandbox registry gate (catches template head drift):
paybond policy validate-tools --file paybond.policy.yaml --remote --format json
Set PAYBOND_API_KEY to a sandbox service-account key. The Paybond monorepo kit-release-gates job runs remote validation when PAYBOND_SANDBOX_API_KEY is configured in CI.
Gateway contract
See Gateway API — Policy validation and OpenAPI POST /v1/policy/validate.
Related
- Agent policy-as-code — policy file format and middleware wiring
- Agent middleware — run binding and interceptors
- CLI contract — JSON envelope and exit codes