Portable registration
Portable registration
Document shape
AHP-REG-001 — MUST. A portable registration document declares the selected snapshot as its protocolVersion and contains an ordered, non-empty hooks array.
A portable registration document is a JSON object with an ordered hooks array.
{
"protocolVersion": "draft",
"hooks": [
{
"id": "com.example.policy",
"transport": {
"type": "http",
"url": "https://policy.example.com/agent-hooks"
},
"authentication": {
"type": "bearer",
"tokenEnv": "AHP_POLICY_TOKEN"
},
"subscriptions": [
{
"events": ["tool.before"],
"mode": "intercept",
"timeoutMs": 750,
"failurePolicy": "fail-closed",
"content": {"default": "metadata"}
}
]
},
{
"id": "com.example.local-review",
"transport": {
"type": "stdio",
"command": "/usr/local/bin/local-review",
"args": ["serve"],
"lifecycle": "persistent"
},
"subscriptions": [
{
"events": ["tool.before"],
"mode": "intercept",
"timeoutMs": 500,
"failurePolicy": "fail-open",
"content": {"default": "metadata"}
}
]
}
]
}
Backend fields
| Field | Requirement | Semantics |
| `id` | REQUIRED | Unique reverse-DNS backend identifier within the document. |
| `transport` | REQUIRED | Exactly one supported transport configuration. |
| `authentication` | Optional endpoint authentication | Credential reference; never a literal credential. |
| `subscriptions` | REQUIRED | Non-empty array of event subscriptions. |
| Field | Requirement | Semantics |
| `events` | REQUIRED | Non-empty array of exact event names, whole-family wildcards such as `tool.*`, or `*`. No arbitrary patterns. |
| `mode` | REQUIRED | `intercept` or `observe`. |
| `timeoutMs` | Intercept only | Required positive integer deadline. |
| `failurePolicy` | Intercept only | Required `fail-open` or `fail-closed`. |
| `content` | REQUIRED | Flat selection object with a required `default` and optional category-name keys, each set to `body`, `metadata`, or `omit`. See [content upload](/docs/spec/draft/content-upload/). |
| `includeNative` | OPTIONAL | Boolean; defaults to `false`. |
AHP-REG-002 — MUST. A harness sends an event to a backend only when that backend has a subscription whose events array matches the event name exactly or through a supported wildcard and whose mode matches the delivery method, except for best-effort observation of uncalled intercept subscriptions after short-circuit settlement.
For normal dispatch, hooks/intercept matches intercept mode and hooks/observe matches observe mode. After short-circuit settlement, remaining uncalled matching intercept subscriptions receive best-effort hooks/observe as defined in observation delivery. Exact selectors match only the named event; family wildcards match that event family, and * matches all supported events for the mode. Intercept wildcards select only advertised interceptable boundaries. There is no arbitrary matcher language or separate enabled subscription state. Absent a matching subscription or that short-circuit observation rule, the harness MUST NOT send that event to the backend.
stdio transport fields
A stdio transport contains:
type: exact valuestdiocommand: executable path or nameargs: optional string arraylifecycle:persistentorper_eventcwd: optional backend working directoryenv: optional object of literal string environment variables for the backend process; see process environment
HTTP transport fields
An HTTP transport contains:
type: exact valuehttpurl: absolute endpoint URL Authentication supports the configured endpoint bindings in capabilities and authentication. Bearer authentication uses exactly one oftokenEnvortokenRef; credentials are never literal values. Upload authentication is configured independently.
Native harness configuration
A harness MAY translate this registration model into its native configuration format. It may still claim protocol conformance if the resulting order, subscriptions, timeout, failure, transport, and credential semantics are equivalent.
Forward compatibility and local identity
Subscriptions and subscription identifiers are harness-local configuration, not wire identity. Receivers MUST ignore unknown registration/configuration fields, MUST validate recognized fields, and MAY warn about ignored fields. Unknown fields do not change dispatch, authorization, or supported effect/operation semantics.
Endpoint discovery example
This HTTP backend deliberately omits an explicit identity binding. The client attempts the endpoint and, if challenged, uses standard OAuth protected-resource discovery subject to its own trust and identity policy. The upload endpoint does so independently. Neither absence authorizes credential inheritance.
{
"protocolVersion": "draft",
"hooks": [{
"id": "org.example.policy",
"transport": {"type": "http", "url": "https://hooks.example/events"},
"subscriptions": [{
"id": "tool-policy",
"events": ["tool.before"],
"mode": "intercept",
"timeoutMs": 1000,
"failurePolicy": "fail-closed",
"content": {"default": "metadata"},
"upload": {"endpoint": "https://uploads.example/bytes", "timeoutMs": 5000, "maxBytes": 1048576}
}]
}]
}
For a static upload secret, explicitly set upload.auth to
{"type": "bearer", "tokenRef": "secrets/policy-upload"}. This deployment-managed
reference is not a URL or a secret value. Resolution failure MUST NOT switch to
OAuth; an event secret is not a substitute. An explicit OAuth preset can constrain
issuer, resource, client, flow, and scopes without requiring every registration to
predeclare OAuth before encountering an endpoint challenge.