Organizations can publish org base policies that tenant overlays extend. Each business unit keeps a local paybond.policy.yaml overlay while inheriting shared side-effecting tool definitions, evidence presets, and spend caps from the platform operator.
Tenant isolation remains absolute: overlays never merge policies from another org, and tenants cannot widen org allowed_tools or raise org spend caps.
Inheritance model
Org base policy (platform-published) + Tenant overlay (paybond.policy.yaml) ↓ Effective policy (per tenant, Gateway-resolved)
Gateway resolves the merged effective policy so tenants cannot bypass org constraints by editing local files alone. Kit middleware consumes the effective policy the same way as a flat v1 policy file.
Schema v2
Org base policies use version: 2 without an extends block:
version: 2 name: acme-agent-spend-v1 default_deny: true tools: travel.book_hotel: side_effecting: true max_spend_cents: 20000 evidence_preset: cost_and_completion intent: policy_binding: template_id: completion_budget_v1 allowed_tools: - travel.book_hotel
Tenant overlays declare what they extend and what they override:
version: 2 name: acme-travel-tenant-east extends: org_policy_id: acme-agent-spend-v1 org_id: org_acme_corp default_deny: true overrides: tools: travel.book_hotel: max_spend_cents: 15000 # stricter than org default intent: budget: max_spend_usd: 150 tools: acme.internal.approve_po: side_effecting: true evidence_preset: cost_and_completion
Merge rules (deterministic):
| Field | Rule |
|---|---|
tools | Union; tenant wins on spend/evidence conflicts; cannot remove org-required side-effecting tools |
default_deny | Tenant may only make stricter (true wins) |
intent.allowed_tools | Intersection when org defines an allowlist; tenant may narrow, not widen |
evidence_preset | Tenant may swap only within org-approved catalog subset |
For offline CI, add extends.base_policy pointing at a checked-in org base file. Production should use Gateway effective resolution.
Multi-team topology
A typical multi-team layout publishes one org base and attaches per-business-unit overlays. Each team keeps its own paybond.policy.yaml; Gateway resolves a distinct effective policy per tenant credential.
org_acme_corp ├── org base: acme-agent-spend-v1 (platform operator) ├── tenant travel-east (stricter hotel cap and east approval tool) ├── tenant travel-west (lower regional budget and concierge tool) └── tenant procurement (procurement spend focus and vendor gate)
| Team | Overlay focus | Effective change vs org base |
|---|---|---|
| Travel East | Regional travel agents | travel.book_hotel cap 15000¢ (org 20000¢); allowed_tools narrowed to hotel and search and east approval |
| Travel West | Smaller regional budget | travel.book_hotel cap 10000¢; budget $75 (org $200); allowed_tools narrowed to hotel and search and west concierge |
| Procurement | RFQ workflows | procurement.submit_rfq cap 75000¢ (org 100000¢); budget $175; allowed_tools narrowed to RFQ and search and vendor gate |
The org base publishes a superset intent.allowed_tools list (all team-specific tools pre-approved by the platform operator). Each team overlay narrows that list to the tools its agents may execute — tenants cannot add tools outside the org allowlist.
Runnable reference: examples/enterprise-multi-team-policy/ (org base YAML and three team overlays and validate.sh).
Travel East overlay (excerpt)
version: 2 name: acme-travel-east extends: org_policy_id: acme-agent-spend-v1 org_id: org_acme_corp base_policy: ../../org-agent-spend-v1.yaml default_deny: true overrides: tools: travel.book_hotel: max_spend_cents: 15000 intent: budget: currency: usd max_spend_usd: 150 allowed_tools: - travel.book_hotel - search.web - acme.east.approve_travel tools: acme.east.approve_travel: side_effecting: true evidence_preset: cost_and_completion
Procurement and Travel West follow the same extends shape with different overrides and tenant-only tools blocks.
Gateway resolution behavior
Gateway is authoritative for effective policy in production. Tenant overlays submitted at bind time or via POST /v1/org-policies/{policy_id}/effective are merged server-side against the latest org base head — local file edits alone cannot bypass org constraints.
Tenant cannot widen org allowlist. If the org base defines intent.allowed_tools, a tenant overlay may only narrow the list (intersection). Adding a tool outside the org allowlist fails merge:
# ❌ Rejected at merge — widens org allowlist overrides: intent: allowed_tools: - travel.book_hotel - payments.wire # not in org base
Gateway and Kit offline merge return policy.cannot_widen_allowed_tools for this case.
Tenant cannot raise org spend caps. Overrides that increase max_spend_cents or intent.budget.max_spend_usd above the org base are rejected with policy.cannot_raise_spend_cap / policy.cannot_raise_budget_cap.
Tenant cannot disable org-required side-effecting tools. Setting side_effecting: false on an org-mandated tool fails with policy.cannot_disable_org_side_effecting_tool.
Org tools remain in the effective registry. Merge unions org and tenant tools; narrowing allowed_tools restricts which registered tools may execute under default_deny, but org-defined tool entries stay in the merged document.
Poll-friendly digest checks: pass ?digest=<sha256:...> to POST /v1/org-policies/{policy_id}/effective to receive { unchanged: true, ... } when the merged effective policy has not changed since the last bind.
CLI workflow
Platform operator: scaffold org base
paybond policy init-org \ --policy-id acme-agent-spend-v1 \ --out org-agent-spend-v1.yaml \ --operation travel.book_hotel \ --evidence-preset cost_and_completion \ --max-spend-cents 20000
Review the file, then publish via Gateway (requires platform operator credentials or PAYBOND_ORG_POLICY_PUBLISH_SECRET):
curl -X PUT \ "https://api.paybond.ai/v1/admin/org-policies/acme-agent-spend-v1?org_id=org_acme_corp" \ -H "Authorization: Bearer $PAYBOND_ORG_POLICY_PUBLISH_SECRET" \ -H "Content-Type: application/json" \ --data-binary @org-agent-spend-v1.json
See Gateway API — org policy inheritance.
Tenant: scaffold overlay
paybond policy extend \ --extends org_acme_corp/acme-agent-spend-v1 \ --out paybond.policy.yaml
Optional tenant-only tool:
paybond policy extend \ --extends org_acme_corp/acme-agent-spend-v1 \ --operation acme.internal.approve_po \ --evidence-preset cost_and_completion \ --out paybond.policy.yaml
For local merge in CI, pin the org base file:
paybond policy extend \ --extends org_acme_corp/acme-agent-spend-v1 \ --base-policy ./org-agent-spend-v1.yaml \ --out paybond.policy.yaml
Validate merged policy (server)
paybond login paybond policy validate-tools \ --file paybond.policy.yaml \ --remote \ --resolve-inheritance \ --format json
The response includes effective_policy_digest and merge_report when inheritance resolves successfully.
CI validation
Validate effective merged policies before deploy — not just overlay syntax.
Offline gate (no secrets)
Pin extends.base_policy in each overlay to a checked-in org base file. paybond policy validate-tools --local-only loads the overlay, merges via base_policy, and validates the resulting v1 effective document:
cd examples/enterprise-multi-team-policy paybond policy validate-tools \ --file teams/travel-east/paybond.policy.yaml \ --local-only --format json paybond policy validate-tools \ --file teams/procurement/paybond.policy.yaml \ --local-only --format json # Or all teams: ./validate.sh
Use --strict (or PAYBOND_POLICY_STRICT=1) when the effective policy should declare every side-effecting tool in intent.allowed_tools — typical for flat v1 policies or overlays that inherit the full org allowlist without narrowing. When a team narrows allowed_tools, org side-effecting tools remain in the merged tools registry (see Gateway resolution behavior); use non-strict local validation in that case and rely on middleware default_deny and narrowed allowed_tools at runtime.
GitHub Actions pattern (monorepo kit job):
- name: Validate multi-team overlays run: | cd examples/enterprise-multi-team-policy chmod +x validate.sh ./validate.sh
The kit test suite also locks merge behavior: kit/ts/tests/policy/enterprise-multi-team.test.ts.
Sandbox registry gate (with credentials)
When the org base is published to Gateway, validate each team overlay against the live org head:
export PAYBOND_API_KEY=pb_test_sandbox_... paybond policy validate-tools \ --file teams/travel-east/paybond.policy.yaml \ --remote --resolve-inheritance --format json
--resolve-inheritance requires remote mode. The response includes effective_policy_digest, merge_report, and Harbor registry checks (template_head_mismatch, etc.).
Pre-commit
paybond policy validate-tools --file paybond.policy.yaml --local-only
For tenant overlays in a multi-team repo, run validation per overlay path in CI — see examples/enterprise-multi-team-policy/validate.sh.
Kit API
TypeScript:
import { PaybondPolicy } from "@paybond/kit/policy"; const { policy, report, effectivePolicyDigest } = await PaybondPolicy.loadEffective({ overlay: "./paybond.policy.yaml", gateway: paybond.harbor, }); const registry = policy.toToolRegistry();
Offline merge (best-effort CI):
const { policy } = await PaybondPolicy.mergeLocal({ base: "./org-agent-spend-v1.yaml", overlay: "./paybond.policy.yaml", });
Python parity:
from paybond_kit.policy import PaybondPolicy, resolve_policy_effective_remote result = await resolve_policy_effective_remote(overlay_doc, gateway_client) policy = PaybondPolicy.from_document(result.effective_policy)
Examples
Multi-team reference (org base and three business-unit overlays):
examples/enterprise-multi-team-policy/— YAML policies,validate.sh, and CI commands
Merge unit fixtures under kit/policy/examples/:
org-base-acme-agent-spend-v1.json— org basetenant-overlay-acme-travel-east.json— tenant overlay with overrides
Related
- Agent policy-as-code — flat v1 policies and registry workflow
- Agent policy validate — local and remote validation
- Gateway API — org policy CRUD and effective resolution endpoints