Skip to main content

PAP and PACT, side by side

Two consent protocols let a person's own agent work with a business for them: the Personal Agent Protocol (PAP, draft 0.3, Sierra and Meta; personalagentprotocol.org) and PACT (1.0, Decagon and Instinct). They answer the same questions — which agent is this, for whom, and how far may it go — in different ways, and one application can use both in the same task.

What each carries​

PAP (draft 0.3)PACT 1.0
The business is found atits domain: https://{domain}/.well-known/poppy.json, the organization's domain checked, its OAuth issuer's metadata checkedan A2A Agent Card URL; the interface chosen by binding and version (HTTP+JSON, 1.0)
The agent proves itself withits client metadata and same-domain JWKS; a short-lived Session Token bound to the Session's own DPoP key (the Session Key)a personal-agent JWT (ES256), iss the platform, its JWKS registered once with the Provider
The person isa pairwise id per company, signed out until neededsub, a stable opaque id per person, in every JWT
Signing in at the businessDirect (OAuth with PKCE), Device (RFC 8628) as the issuer's grant_types_supported offers them, or Mediated (pap.protectedInput); an Account Token afterwardsDevice code (RFC 8628), the personal-agent JWT as client authentication; a delegation token
What the person allowsscopes asked at sign-in; may be fewer than askedscopes from the card's deviceCode flow; may be fewer than asked, read back from scope
Asking for moreinsufficient_scope on the conversationTASK_STATE_AUTH_REQUIRED with pact.missingScopes (a step-up)
How the agent talks to the businessconversations with the company's agent or a person, OpenAPI, MCP, a browser joined to the SessionA2A messages (message:send), one contextId per agent, person and Brand
A consequential actionthe Operations extension: an exact revision, approved by the person, performed at most oncethe business acts within the granted scopes; every reply under delegation carries a signed receipt (pact.receipt)
What is keptthe operation, its revision and its confirmationthe receipt: grant, scopes used, actions, verified before it is kept
In Agent Runtimesthe PAP SDK's plugins (pap.*), PapPersonalAgentCapability, pap.connections and pap.company in the Appspecagent_runtimes.protocols.pact (pact.*), pact.connections in the Appspec

Both keep the person's credentials at the business: the agent shows the business's own link and code, never asks for a password in the conversation, and holds nothing a model reads.

One task, both protocols​

examples/protocols/pap_and_pact/app.py is an application, Atlas, asked where is my jacket order, and when do I fly? The order is at Manzanita Outfitters, a PAP company (the PAP SDK's demo world); the flight at Example Air, a PACT Brand (the local Provider). Atlas signs in at each one's own page with one read scope, asks, and writes one record:

python examples/protocols/pap_and_pact/app.py
Where is my jacket order, and when do I fly?
Manzanita Outfitters: Your order ord_7Hk2: Ridge Jacket, size M, delivered.
Example Air Support: Your booking AB123 flies on 2026-11-02.

The record:
{"protocol": "PAP", "counterpart": "Manzanita Outfitters", "event": "company discovered", ...}
{"protocol": "PAP", "counterpart": "Manzanita Outfitters", "event": "sign-in asked", "error": "insufficient_scope"}
{"protocol": "PAP", "counterpart": "Manzanita Outfitters", "event": "signed in", "scopes": ["orders:read"], ...}
{"protocol": "PAP", "counterpart": "Manzanita Outfitters", "event": "answered", ...}
{"protocol": "PACT", "counterpart": "Example Air Support", "event": "card read", "profile": "delegated", ...}
{"protocol": "PACT", "counterpart": "Example Air Support", "event": "sign-in asked", "scopes": ["bookings:read"]}
{"protocol": "PACT", "counterpart": "Example Air Support", "event": "signed in", "scopes": ["bookings:read"], ...}
{"protocol": "PACT", "counterpart": "Example Air Support", "event": "receipt verified", "scopes_used": ["bookings:read"], ...}
{"protocol": "PACT", "counterpart": "Example Air Support", "event": "answered", ...}

The receipt reaches the record through pact.receiptStore: Atlas's host contributes its record there below the plugin's in-memory default, as a Datalayer host contributes the application's record. It runs in one process, with no network and no model, against local test counterparts.

What never reaches a model​

Neither protocol's codes or tokens are in the answer or the record: the test (test_protocols_pap_and_pact.py) collects both user codes and the PACT delegation token as the businesses and the host handled them, and checks that none of them, nor any compact JWT, is in what the tool returns.

On Datalayer​

An application reaches a PAP company through the MCP gateway's pap toolset (pap.connections) and a PACT Brand through its pact toolset (pact.connections); both are decided by the application's Rules from the tools' action classes, and the tokens are held by IAM, never by the runtime.