Provisioning Lifecycle Profile
Portable signed records for agent provisioning events. PEAC records what your system reported happened during credential issuance, secret storage, access grants, and certificate provisioning — observable evidence, not authorization.
Extension namespace: org.peacprotocol/provisioning-lifecycle (16th extension group). Profile 0.1. New in v0.14.2.
Observer scope
PEAC records what the caller system reports happened. Upstream authorization, validation, settlement, vault management, and lifecycle enforcement belong to the upstream system. A provisioning record proves what your code reported observing — not that the underlying provisioning system authorized or completed it.
Install
pnpm add @peac/schema @peac/protocol
Event Types
Ten registered type URIs cover the provisioning event surface. All use the *-observed suffix to make the observer-scope semantics explicit.
| Type URI suffix | What it records |
|---|---|
provisioning-catalog-observed | A provisioning catalog or offering was observed |
provisioning-provider-link-observed | A link to an upstream provisioning provider was observed |
provisioning-account-observed | A provisioning account or workload identity was observed |
provisioning-resource-observed | A provisioned resource was observed |
provisioning-credential-observed | A credential (API key, token, certificate) issuance or rotation was observed |
provisioning-payment-authorization-observed | A payment authorization for provisioning was observed |
provisioning-budget-observed | A budget allocation or limit was observed |
provisioning-subscription-observed | A subscription lifecycle event was observed |
provisioning-domain-observed | A domain registration, transfer, or release was observed |
provisioning-deployment-observed | A deployment lifecycle event was observed |
Sub-states (requested, provisioned, granted, revoked, cancelled) go in the sub_event field inside the extension object, not as separate type URIs.
Basic Usage
import { issue } from '@peac/protocol';
import { generateKeypair } from '@peac/crypto';
import { validateProvisioningLifecycle } from '@peac/schema';
const { privateKey } = await generateKeypair();
// Build the provisioning lifecycle extension object
const provisioningExtension = {
event_kind: 'provisioning-credential-observed',
sub_event: 'issued',
provider_ref: 'urn:provider:acme-vault:v1', // opaque ref, no raw IDs
storage_surface: {
kind: 'external_secret_store',
provider_ref: 'urn:vault:acme:prod',
surface_ref: 'urn:vault:acme:prod:slot:api-key-42',
material_redaction: 'never_capture', // never_capture | redacted_capture | hashed_capture
},
observed_at: new Date().toISOString(),
};
// Validate before issuing; fails closed on credential material
const validation = validateProvisioningLifecycle(provisioningExtension);
if (!validation.success) {
throw new Error(validation.error.issues[0].message);
}
// Issue the signed Wire 0.2 record
const { jws } = await issue({
iss: 'https://platform.example.com',
kind: 'evidence',
type: 'org.peacprotocol/provisioning-credential-observed',
sub: 'agent:ci-runner:prod',
pillars: ['provenance', 'compliance'],
extensions: {
'org.peacprotocol/provisioning-lifecycle': provisioningExtension,
},
privateKey,
kid: 'peac-2026-03',
});
// jws is a portable signed Wire 0.2 recordCredential Material Safety
The provisioning lifecycle validator includes a recursive credential-material scanner. It inspects every string field for patterns that suggest live credential material and rejects them with structured error codes.
provisioning.token_material_blockedBearer token / JWT compact pattern
provisioning.inline_credential_blockedInline credential in value field
provisioning.forbidden_key_nameForbidden top-level key (e.g. raw_key, secret_value)
provisioning.field_too_largeField exceeds byte limit (64 KB)
provisioning.opaque_ref_grammar_violationReference does not match opaque ref grammar
provisioning.invalid_storage_surfacestorage_surface.kind not in allowed enum
All sensitive references use the opaque reference grammar: urn:, ref:, did:, sha256:, peac:, or https:. Raw identifiers, inline secrets, and bearer tokens are always rejected.
Error Codes
21 stable error codes under the provisioning.* namespace. All are stable across patch versions.
inline_credential_blocked token_material_blocked forbidden_key_name field_too_large replacement_character_in_string structure_too_deep structure_too_large opaque_ref_grammar_violation invalid_storage_surface invalid_material_redaction invalid_event_kind invalid_sub_event invalid_scheme_id invalid_amount_minor invalid_observed_at invalid_retrieved_at invalid_expires_at invalid_currency unrecognized_field missing_required_field invalid_utf8 (fixture-loader only)
Conformance
| Requirement | Detail |
|---|---|
| PROV-LIFE-001 | event_kind MUST be one of the 10 registered provisioning event kinds |
| PROV-LIFE-002 | The recursive credential-material scanner MUST reject inline token or secret material |
| PROV-LIFE-003 | Sensitive references MUST match the opaque reference grammar (urn:, ref:, did:, sha256:, peac:, https:) |
| PROV-LIFE-004 | storage_surface.kind MUST be one of the allowed surface kinds |
| PROV-LIFE-005 | material_redaction MUST be one of never_capture, redacted_capture, hashed_capture |
| PROV-LIFE-006..010 | sub_event, timestamps (observed_at RFC 3339), amount and currency, and field-size invariants |
Conformance Section 31 (PROV-LIFE-001..010). Introduced in v0.14.2; current totals are 290 requirement IDs across 32 sections.
Links
Start recording provisioning events
Add portable signed records to your agent provisioning pipeline in minutes. The provisioning lifecycle profile integrates with any provisioning system — PEAC records what your code reports, without becoming the authorization layer.