diff --git a/docs/faq.html b/docs/faq.html index 08489da5..4f1debbd 100644 --- a/docs/faq.html +++ b/docs/faq.html @@ -7,12 +7,12 @@ FAQ — Principal Agent Protocol - + - + @@ -63,7 +63,7 @@

Frequently Asked
Questions

Every protocol has real limitations. PAP's are documented here, alongside what's currently implemented, what's on the roadmap, and where the open design questions live.

-

13 questions · reviewed April 2026

+

15 questions · reviewed April 2026

@@ -74,24 +74,24 @@

Frequently Asked
Questions

+ + + - - - - +
- -
+ +
- -
+ +

- PAP gives you two controls for this. First, enable OHTTP in Settings — it wraps every request in RFC 9458 HPKE so even the relay hop sees nothing, not the query structure, not the property list. Second, set no_retention: true on any disclosure entry where you need the receiving agent to discard its copy of the receipt. When that flag is set, PAP requires the agent to run in a TEE — the retention constraint becomes cryptographically binding, not a promise. The risk isn't gone without these settings, but with them it's fully addressed. + The SAML bridge question assumes a hub-and-spoke model PAP is designed to make unnecessary. Instead of a central authority managing who has access, each agent protects itself — it declares what it requires, your orchestrator presents a cryptographically scoped mandate, and access is enforced at the edge with no IdP involved. When a mandate expires (default 8 hours), access stops without a deprovisioning call or a session token to revoke. For access tied to value exchange, the ecash layer issues blind-signed tokens using RFC 9474 RSABSSA-SHA384-PSS — the agent validates the token without learning who holds it, and receipts store only a commitment hash, never amounts or identities. What your security team actually needs maps to protocol mechanisms: access policy in mandate scope, audit trail in co-signed receipts (property type references, held locally by both parties), revocation through TTL decay.

- The underlying concern — and why both controls matter. - Each agent in - pap-agents declares exactly what it needs via - AgentMeta.requires_disclosure - (crates/pap-agents/src/executor.rs) — those property names are embedded - in the Mandate's DisclosureSet during Phase 2 of the handshake, bounding - the scope of what the agent is permitted to receive. The Phase 3 disclosure payload - carries the query inside that scope boundary. - SD-JWT (pap-credential/src/sd_jwt.rs) - hides claim values via per-claim salted hashes and is available as an optional - enhancement for credential-bearing payloads, but is not used in the current query - handshake path — claim structure is not hidden. The - recipient agent always learns which property slots were disclosed; - that is the intent of the handshake. Network-level visibility is configurable: - OHTTP (RFC 9458, HPKE DHKEM-X25519 + AES-128-GCM) is a setting in Papillon and - Chrysalis — when enabled, relay operators and passive observers see nothing. - Without it, transport encryption is present but query structure is visible to - the relay hop. + The IdP question carries a centralized assumption PAP is designed to make + unnecessary. Okta and Azure AD solve a hub-and-spoke problem: a central + authority that decides who gets access to what. PAP inverts this. Agents protect + themselves — they advertise what they require, + principals present cryptographically + scoped mandates, and the protocol enforces access at the edge without any central + authority in the loop.

- Receipts store property references, never values: pap-core/src/receipt.rs - holds disclosed_by_initiator: Vec<String> — strings like - "schema:Person.name". The receiving agent holds a co-signed copy after - every session. Across multiple sessions the pattern of which properties a principal - discloses to that agent can become a quasi-identifier even without any value leaving. - The no_retention flag on DisclosureEntry - (pap-core/src/scope.rs) addresses this: when set, the handshake requires - TEE attestation from the receiving agent before proceeding, making receipt discard - auditable rather than contractual. + The PAP-native pattern for enterprise agent access control: + An enterprise runs agents on Chrysalis. Each agent declares its + requires_disclosure — the minimum SD-JWT claims it needs to execute + (e.g. schema:Organization.schema:memberOf to verify employment, or + a schema:Role claim scoped to a department). A principal's orchestrator + presents only those claims via selective disclosure + (crates/pap-credential/src/sd_jwt.rs); the agent verifies the + claim against its policy and either accepts the mandate or rejects it. No IdP + is in the path. No central session store. The agent is the access control point.

- In healthcare and financial services, which properties were accessed is frequently - PHI or material non-public information in its own right — both controls are worth - enabling by default in those contexts. + For value exchange between agents, ecash receipts replace + identity-gated permissions. Instead of "does this principal have the + Analyst role in Okta?", access is structured as "does this principal hold a valid + payment proof for this action?" The ecash system (crates/pap-ecash/) + issues blind-signed RFC 9474 RSABSSA-SHA384-PSS tokens — the agent validates + the token without learning who holds it, and the receipt proves the exchange + occurred without linking it to an identity. This is more privacy-preserving + than role-based access and eliminates the revocation problem entirely: a spent + token is simply gone.

- What we're watching: The IRMA/Yivi - ZKP-based approach provides stronger structural privacy guarantees using W3C VCs. - A future spec section will evaluate ZKP-based disclosure as an optional enhancement - for cases where even TEE-attested no-retention is insufficient. + What security teams actually need is answered by the protocol, not + by an IdP bridge: access policy is encoded in mandate scope + (Scope::deny_all() baseline, cryptographically enforced containment); + audit trail is the co-signed receipt chain (property references, never values, + held by both parties locally); revocation is + TTL decay + (Active → Degraded → ReadOnly → Suspended) with no deprovisioning + step required. The threat model of "who has a live session token?" doesn't apply + to a system where every mandate expires by design.

- -
+ +

- The relay runs wherever you deploy it — colocated with your own node, not on Baur Software infrastructure. If you don't configure one, the protocol falls back to a direct connection: relay_url is optional, and when it's absent, the handshake continues without it. Privacy degrades — query structure becomes visible at the relay hop — but the session never breaks, and scope enforcement, expiring mandates, and co-signed receipts all work exactly the same. + Most enterprise software achieves compliance by adding controls on top of a general-purpose system. PAP's compliance properties are protocol invariants — they hold because of how the cryptography works, not because someone configured them correctly. No central server. Receipts store property type references like "schema:Person.dateOfBirth", never the values. Every session runs under a mandate your device signed, specifying the exact agent, actions, data types, and duration. Access decays automatically without a deprovisioning step. For no-retention requirements, set no_retention: true on disclosure entries and the protocol requires the receiving agent to run in a TEE, making retention constraints auditable and binding. The 34 pre-built health and finance catalog agents (15 health, 19 finance) all require zero personal disclosure — public data sources only — giving you a no-PHI baseline to build from before you add anything sensitive.

- OHTTP relay capability is built into - Papillon and - Chrysalis — it runs - colocated with each deployment, not on Baur Software infrastructure. - When OHTTP is configured, there is no external relay operator to capture traffic. - The decentralization is topological: the relay lives alongside your own node. + Most enterprise software achieves compliance by adding controls on top of a + general-purpose system. PAP's compliance properties are protocol invariants — + they hold because of cryptographic enforcement, not configuration. Here is what that + means per framework.

- relay_url in pap-transport/src/ohttp.rs is typed - Option<String>. When absent, the protocol falls back to a direct - connection — privacy degrades but the handshake never breaks. The core guarantees - (SD-JWT selective disclosure, ephemeral session DIDs, deny-by-default mandates) - do not depend on OHTTP being enabled. + HIPAA — Minimum Necessary Rule: The mandate's DisclosureSet + (crates/pap-core/src/scope.rs) specifies exactly which + schema: properties an agent may receive. An agent requesting schema:SSN when the mandate permits + only schema:dateOfBirth is filtered out by the marketplace before any + session is established — the over-disclosure attempt never reaches the transport layer. + For no-retention requirements, set no_retention: true on disclosure + entries; the session can be backed by a Trusted Execution Environment + (crates/pap-tee/) — the TEE provides enclave measurement attestation + that the session ran in an isolated environment, making the retention commitment + auditable and binding rather than contractual-only. Audit trail: co-signed receipts in + pap-core/src/receipt.rs record property type references + ("schema:Person.schema:dateOfBirth"), never values — satisfying + §164.312(b) while being safer than access logs containing real data.

- When the relay is active, it uses - RFC 9458 - HPKE: DHKEM(X25519, HKDF-SHA256) + AES-128-GCM (RFC 9180). Relay operators and - passive observers cannot link IP addresses to query content or SD-JWT disclosure - structure. + GDPR — Purpose Limitation and Erasure: A PAP mandate is + structured, machine-enforceable consent: the principal signs which agent may act, + which actions it may take (Scope::deny_all() baseline), which properties + it may see, and for how long. Non-renewal of a mandate initiates the decay state + machine (Active → Degraded → ReadOnly → Suspended): access cryptographically + expires without any deprovisioning step. The episode store + (papillon-shared/src/episode_db.rs) is a local SQLite database under + the principal's sole control — no platform coordinates erasure. Portability: PAP uses + no central registry; the principal's did:key is self-sovereign and moves + to any compatible orchestrator. +

+

+ PCI-DSS — Access Control and Payment Privacy: + Mandate scope containment is cryptographically enforced at every delegation step + (Scope::contains() in pap-core/src/scope.rs); a child mandate + cannot exceed its parent's scope or TTL regardless of configuration. For payment + agents (schema:PayAction), mandates carry payment proofs from the ecash + system (crates/pap-ecash/) using RFC 9474 RSABSSA-SHA384-PSS blind signatures — + the vendor cannot link the signing operation to the redemption, and receipts store + only a commitment hash, never amounts or card data. +

+

+ SOC2 Type II in summary: CC3.1 (access control) — deny-by-default + scope, TTL bounds. CC6.1 (logical controls) — ephemeral session keys, automatic + credential expiry. CC7.1 (audit records) — immutable co-signed receipts. Privacy + use limitation — no_retention flag enforces purpose limitation at + protocol level, with optional TEE attestation for stronger assurance. These map + to protocol mechanisms, not to policy documents that can drift. +

+

+ Pre-built catalog agents exist for both verticals: healthcare agents cover FDA FAERS, + ClinicalTrials, PubMed, and MedlinePlus + (crates/pap-agents/catalog/health/); finance agents cover Nasdaq, ECB, + Treasury, and World Bank data (crates/pap-agents/catalog/finance/). + All public-data agents require zero personal disclosure + (requires_disclosure: []), giving you a no-PHI-exposure baseline to + build from.

- -
+ +

- Getting a fake agent into the Chrysalis mesh takes real calendar time, not just compute. A new peer needs three vouches from existing members, each of whom can only vouch for three peers per year — and must themselves have been active for at least 90 days before they can vouch for anyone. New peers spend 60 days in a probationary state. The trust graph also checks path diversity: if your three vouchers all trace back through the same cluster of ancestors, the registration is rejected. You can't manufacture trust quickly; you have to earn it slowly. + The hard parts are protocol invariants, not configuration. There's no central PAP server — nothing to breach at the platform level. Every session runs under a time-limited permission that decays on its own (Active → Degraded → ReadOnly → Suspended). Receipts store which types of data were accessed — "schema:Person.dateOfBirth" — never actual values. The episode store is local SQLite under your control. For stricter requirements — HIPAA no-retention policies, MiFID audit windows — those are configurable at deployment. Set no_retention: true on a disclosure entry and the protocol requires the receiving agent to run in a TEE, making the retention constraint cryptographically auditable rather than contractual.

- Vouch-based peer admission. Joining the Chrysalis mesh is not free — - it requires existing trusted peers to stake their reputation on you. - pap-federation/src/registry.rs enforces: + Receipts contain property references only, never values + (pap-core/src/receipt.rs: Vec<String> of strings like + "schema:Person.name"). Each party holds their own copy locally — + receipts are never stored by a platform. There is no central data controller. + The compliance behaviors below are programmable at the deployment layer, + not gaps in the spec.

- 3 vouches required to register a new peer. - Each existing peer may issue at most 3 vouches per year — a rate budget that - makes flooding expensive. A peer must be registered for at least - 90 days before it can vouch for anyone. - New peers enter a 60-day probationary period with limited permissions. + GDPR Article 17 (right to erasure): The episode store + (episode_db.rs) is a local SQLite database under the principal's + sole control. A GDPR-compliant deployment can implement a retention policy or + deletion API directly against the local DB — there is no platform or third party + to coordinate with. Immutability of the co-signed receipt is the default because + it provides the strongest accountability, but the deployment controls the store.

- Diverse trust paths (require_diverse_paths) are specified in the policy struct - and are being enforced now — ensuring N vouchers don't all route through the same - small set of ancestors, preventing a captured clique from bootstrapping unlimited new peers. + HIPAA Minimum Necessary: Property type references in receipts + can themselves constitute PHI. Knowing MedicalCondition was disclosed + reveals a medical relationship even without the value. A PAP-HIPAA deployment + profile can restrict which schema: types are loggable and configure + receipt retention periods — the mandate scope mechanism already enforces property-type + minimisation at handshake time.

- This is a social-graph approach rather than proof-of-stake or proof-of-work. The rate - constraints make a Sybil flood expensive in terms of calendar time and peer relationships, - not compute or tokens. + MiFID II / Dodd-Frank: Ephemeral session DIDs are the default + for privacy; a regulated deployment can configure session DID persistence and + set mandate TTL to cover 7-year reconstruction windows. The protocol does not + prevent long retention — it makes short retention the default. Financial agent + deployments configure what they need.

- -
+ +

- The protocol doesn't depend on Schema.org being controlled by anyone in particular. The action field in a mandate is a plain string — any namespace-prefixed identifier is valid. Schema.org is the default because it's widely understood and makes agents discoverable to everyone, but a financial compliance action, a FHIR operation, or a lab protocol step can be expressed as operator:FhirReadAction without touching Schema.org at all. The governance capture risk is real for the interoperability layer — agents that want to be universally discoverable benefit from Schema.org alignment. Agents targeting a specific vertical can use the operator: namespace freely. + Meaningful work, not a one-liner. PAP doesn't sit on top of your stack — it sits below it, as the trust layer your orchestration calls into before any agent executes. That means wrapping your existing agent dispatch paths with mandate issuance, connecting your session handling to the 6-phase handshake, and deciding how much of Chrysalis you self-host alongside your current infrastructure. None of that is inherently complicated, but it requires deliberate architecture, not a drop-in install.

- Schema.org is a collaborative, open-community project founded by Google, - Microsoft, Yahoo, and Yandex to create a shared structured-data vocabulary. The schema - is community-governed; contributions come from across the web industry. - Google drives significant adoption through rich-result support, but it does not have unilateral - control over the vocabulary. + The fastest path in is Python:

+
pip install pap-protocol

- The protocol is not locked to Schema.org. - ScopeAction.action in crates/pap-core/src/scope.rs is a - plain string — any namespace-prefixed URI is valid. Spec §17.6 reserves three - prefixes: schema: (Schema.org, standard interoperability baseline), - operator: (implementation-defined, for agent operator custom vocabulary), - and pap: (reserved for PAP specification extensions). A financial - compliance action, a FHIR operation, or a laboratory protocol step can be expressed - as operator:FhirReadAction or pap:ClinicalTrialEnrollAction - without touching Schema.org at all. + Pre-built wheels for Linux x86_64/aarch64, macOS universal2, and Windows x64 — no Rust toolchain needed. From there, docs/integration-guides/langchain-crewai-mcp.md walks through wiring PAP mandate issuance into a LangChain chain, a CrewAI crew, or an MCP server. The guide is 1,293 lines of annotated examples covering async, concurrent handshakes, and error propagation.

- crates/pap-core/src/extensions.rs implements spec sections 9.1–9.4: - Continuity Tokens (cross-session encrypted state, §9.3) and Auto-Approval Policies - (§9.4) are the first shipped protocol-level extensions. The conditions - field in ScopeAction is an opaque JSON map for arbitrary - protocol-level constraints not representable in Schema.org. Dynamic agent definitions - (crates/pap-agents/src/dynamic.rs) accept any action and return-type - strings, so custom-vocabulary agents ship without a spec change. + SDK coverage across languages: The core is Rust (crates/pap-core/), but production bindings exist for TypeScript (packages/pap-ts/, pure native async, zero Rust dependency), Python (PyO3, async-safe), C (crates/pap-c/, stable cdylib/staticlib), C# (via the C FFI layer), and Java (via the C FFI layer). If your stack is one of those, you're not writing FFI yourself.

- The governance capture risk is real for the interoperability layer — - agents that want to be universally discoverable benefit from Schema.org alignment. - Agents targeting a specific vertical or operator deployment can use the - operator: namespace freely. Schema.org is the default, not the ceiling. + What the integration actually involves: +

+

+ Mandate issuance — wrap your existing "start agent task" calls to issue a PAP mandate first. The mandate specifies agent DID, action type, required disclosures, and TTL. Your orchestrator holds the principal's Ed25519 keypair and signs it. This is the core integration point. +

+

+ Chrysalis registry — self-hostable alongside your current infrastructure. You can run a single-node Chrysalis deployment for your own agents before joining the federated mesh. The admission controls (vouching, probationary periods) are configurable per-deployment. Chrysalis docs → +

+

+ Handshake transport — HTTP or WebSocket. Both are standard. The HTTP path is stateless per-phase (retry-safe); the WebSocket path shares one connection across all six phases (lower overhead for interactive sessions). Swap in your existing transport client. +

+

+ For production deployments at scale, we work directly with teams on the integration — evaluating existing agent architecture, defining the mandate issuance points, and delivering working implementations. Work with us →

- +

- The mandate chain enforces scope cryptographically at every delegation step. Each child's scope must be a strict subset of its parent's, its TTL can't exceed its parent's, and the whole chain is hash-linked so nothing can be forged or reordered. An agent cannot ask for more than it was granted, regardless of how the request is phrased. The narrower residual risk: a sequence of zero-disclosure micro-actions — each individually below the approval threshold — could collectively achieve something a single equivalent request would have surfaced for review. The cryptographic bounds still hold at each step. The gap is at the semantic layer, not the authorization layer. + This is the right question to ask, because at first glance they do look similar. OAuth scopes define what an access token permits. Audit logs record what happened. PAP mandates define what this specific request permits — and co-signed receipts record what happened bilaterally, during the session, signed by both parties. The structural difference is when enforcement happens and who holds the proof.

- Scope containment is cryptographically enforced at every delegation step. - pap-core/src/scope.rs contains() verifies that a child - mandate's - action set is a strict subset of its parent's. mandate.rs verify_chain() - binds each delegation to its parent by hash — you cannot forge a valid chain that expands scope. - TTL cannot exceed the parent mandate either. + OAuth is issuance-time policy. PAP is request-time cryptographic scope.

- Auto-approval has a further constraint: it triggers only when - requires_disclosure.is_empty() (canvas.rs). No action that - requires any disclosure from the principal can be auto-approved — the user always sees - the approval gate. + An OAuth access token is issued at login with a fixed scope (e.g. read:contacts write:calendar). Every request made with that token during its lifetime can use the full scope — regardless of which specific action is being taken, which agent is handling it, or how much data the current operation actually requires. Scope is set once at the authorization server, not per-request.

- The narrower residual risk: a sequence of zero-disclosure sub-actions that individually - pass auto-approval could collectively achieve an effect that a single equivalent request - would have surfaced for explicit consent. The cryptographic scope bounds still apply to each - step; the gap is at the semantic composition layer. + A PAP mandate is issued per request, signed by the principal's device-bound Ed25519 key. It specifies the exact agent DID, the exact schema:*Action type permitted, the exact set of data properties the agent may see (nothing more), and a TTL. An agent that receives a mandate for schema:SearchAction cannot use it to perform schema:CreateAction, even if both are conceptually within the user's overall permissions. Scope is cryptographically bound to the individual request. +

+

+ OAuth tokens are bearer tokens. PAP mandates are principal-signed and hash-linked. +

+

+ An OAuth bearer token can be used by any holder — if it's stolen or forwarded, the recipient has full access until expiry. The authorization server cannot distinguish the original caller from a downstream service holding the same token. +

+

+ A PAP mandate is signed by the principal's did:key and hash-linked to its parent in the delegation chain (mandate.rs verify_chain()). A delegated mandate — one an orchestrator issues to a sub-agent — is cryptographically constrained to be a strict subset of its parent's scope and TTL (Scope::contains()). You cannot forward a mandate and silently expand what it permits. The chain is immutable and verifiable. +

+

+ Audit logs are after-the-fact. Co-signed receipts are bilateral and produced during the session. +

+

+ An audit log is written by the service — unilaterally, after execution. It records what the service says happened. The principal has no cryptographic proof of what was actually disclosed or executed; they have to trust the service's log. +

+

+ A PAP co-signed receipt is produced at Phase 5 of the handshake, before the session closes. Both the orchestrator and the agent sign it. Both parties hold a local copy. It records which property types were disclosed (never values), which action was executed, and links to the mandate that authorized it. Neither party can later deny what occurred — and no platform holds the receipts. They're local to the participants. +

+

+ OAuth doesn't bound multi-step agent delegation. PAP's chain containment does. +

+

+ When an orchestrator delegates to a sub-agent, which delegates to another sub-agent, OAuth has no mechanism to enforce that each step stays within the original scope. Each layer can be issued its own token with potentially broader permissions, or tokens can be forwarded with the full original scope intact. The authorization model is flat. +

+

+ PAP mandate chains are cryptographically monotone-decreasing: scope at step N+1 is always a strict subset of scope at step N. A child mandate cannot add permissions its parent doesn't have. This is enforced in pap-core/src/scope.rs at every verify_chain() call — it's not a policy setting. Multi-step agent pipelines cannot silently accumulate permissions as the chain grows.

- +
- -
+ +
+
+

+ No — and the reason is that the model is structurally isolated from anything security-critical. It has one job: pick one of the action strings you handed it. It receives your query text and a list of permitted action types from the agent catalog. It cannot see your mandate, your session keys, your principal identity, or any previously disclosed values. Its output must match one of the strings it was given — a hallucinated action is discarded. What the model controls is routing: which catalog agent handles your query. What it cannot touch is the mandate that governs what that agent is allowed to do. Those are signed by your device-bound key, which the model never sees. If you prefer no model at all, LlmProvider::None gives you the full protocol running deterministically. +

+

+ The LLM touches exactly one function in the PAP stack. + The LlmClient trait in crates/pap-agents/src/llm.rs exposes two methods: + classify_intent(text, candidate_actions) and complete(system, user). + That's the entire surface. The model receives the user's query string and a pre-computed list + of allowed schema:*Action strings. It does not receive — and cannot request — + mandate contents, scope, TTL, session DIDs, disclosure sets, or the principal's keypair. +

+

+ Its output is validated before use. The return value of + classify_intent must match one of the strings in candidate_actions. + A hallucinated action that isn't on the list is discarded. The model controls which + catalog agent handles the query. It cannot alter the mandate that governs what that agent + is allowed to do — mandates are signed by the principal's device-bound Ed25519 key, + which the model never sees. +

+

+ The four canonical LLM attack paths: + Prompt injection — succeeds only at routing the query to the wrong catalog + agent; it cannot forge the Ed25519 signature that authorizes scope. Context + exfiltration — the model only receives query text, never the mandate or session keys. + Session correlation — each session generates a fresh + ephemeral session DID discarded + at close; the model sees the query text, never the session DID. Scope escalation + — child mandates are cryptographically constrained to a subset of their parent's scope + (Scope::deny_all() baseline, contains() enforcement); + no model output can extend this. +

+

+ The default is on-device. LlmProvider::BuiltIn runs inference + locally via Candle — no network call, no external endpoint, no logs leaving the device. + External providers (Mistral, Ollama, OpenAI-compatible) require the user to explicitly + configure an API key and endpoint URL. Even with an external provider, only query text + travels to the endpoint. For deployments requiring network-layer query privacy, + OHTTP (RFC 9458) with real HPKE decouples the IP address from the request content. +

+

+ The LLM is also optional. The full 6-phase PAP handshake executes + deterministically via URL fast-path and BM25 semantic index without any model. + Setting LlmProvider::None gives a fully functional, cryptographically + sound protocol runtime. The model enhances intent resolution for ambiguous queries; + it gates no security decision. +

+
+
+ + +
+ +
+

+ The mandate chain enforces scope cryptographically at every delegation step. Each child's scope must be a strict subset of its parent's, its TTL can't exceed its parent's, and the whole chain is hash-linked so nothing can be forged or reordered. An agent cannot ask for more than it was granted, regardless of how the request is phrased. The narrower residual risk: a sequence of zero-disclosure micro-actions — each individually below the approval threshold — could collectively achieve something a single equivalent request would have surfaced for review. The cryptographic bounds still hold at each step. The gap is at the semantic layer, not the authorization layer. +

+

+ Scope containment is cryptographically enforced at every delegation step. + pap-core/src/scope.rs contains() verifies that a child + mandate's + action set is a strict subset of its parent's. mandate.rs verify_chain() + binds each delegation to its parent by hash — you cannot forge a valid chain that expands scope. + TTL cannot exceed the parent mandate either. +

+

+ Auto-approval has a further constraint: it triggers only when + requires_disclosure.is_empty() (canvas.rs). No action that + requires any disclosure from the principal can be auto-approved — the user always sees + the approval gate. +

+

+ The narrower residual risk: a sequence of zero-disclosure sub-actions that individually + pass auto-approval could collectively achieve an effect that a single equivalent request + would have surfaced for explicit consent. The cryptographic scope bounds still apply to each + step; the gap is at the semantic composition layer. +

+
+
+ + +
+ -
-

- The hard parts are protocol invariants, not configuration. There's no central PAP server — nothing to breach at the platform level. Every session runs under a time-limited permission that decays on its own (Active → Degraded → ReadOnly → Suspended). Receipts store which types of data were accessed — "schema:Person.dateOfBirth" — never actual values. The episode store is local SQLite under your control. For stricter requirements — HIPAA no-retention policies, MiFID audit windows — those are configurable at deployment. Set no_retention: true on a disclosure entry and the protocol requires the receiving agent to run in a TEE, making the retention constraint cryptographically auditable rather than contractual. -

-

- Receipts contain property references only, never values - (pap-core/src/receipt.rs: Vec<String> of strings like - "schema:Person.name"). Each party holds their own copy locally — - receipts are never stored by a platform. There is no central data controller. - The compliance behaviors below are programmable at the deployment layer, - not gaps in the spec. -

-

- GDPR Article 17 (right to erasure): The episode store - (episode_db.rs) is a local SQLite database under the principal's - sole control. A GDPR-compliant deployment can implement a retention policy or - deletion API directly against the local DB — there is no platform or third party - to coordinate with. Immutability of the co-signed receipt is the default because - it provides the strongest accountability, but the deployment controls the store. -

-

- HIPAA Minimum Necessary: Property type references in receipts - can themselves constitute PHI. Knowing MedicalCondition was disclosed - reveals a medical relationship even without the value. A PAP-HIPAA deployment - profile can restrict which schema: types are loggable and configure - receipt retention periods — the mandate scope mechanism already enforces property-type - minimisation at handshake time. -

-

- MiFID II / Dodd-Frank: Ephemeral session DIDs are the default - for privacy; a regulated deployment can configure session DID persistence and - set mandate TTL to cover 7-year reconstruction windows. The protocol does not - prevent long retention — it makes short retention the default. Financial agent - deployments configure what they need. -

-
-
- - -
+ +

- No — and the reason is that the model is structurally isolated from anything security-critical. It has one job: pick one of the action strings you handed it. It receives your query text and a list of permitted action types from the agent catalog. It cannot see your mandate, your session keys, your principal identity, or any previously disclosed values. Its output must match one of the strings it was given — a hallucinated action is discarded. What the model controls is routing: which catalog agent handles your query. What it cannot touch is the mandate that governs what that agent is allowed to do. Those are signed by your device-bound key, which the model never sees. If you prefer no model at all, LlmProvider::None gives you the full protocol running deterministically. -

-

- The LLM touches exactly one function in the PAP stack. - The LlmClient trait in crates/pap-agents/src/llm.rs exposes two methods: - classify_intent(text, candidate_actions) and complete(system, user). - That's the entire surface. The model receives the user's query string and a pre-computed list - of allowed schema:*Action strings. It does not receive — and cannot request — - mandate contents, scope, TTL, session DIDs, disclosure sets, or the principal's keypair. + PAP gives you two controls for this. First, enable OHTTP in Settings — it wraps every request in RFC 9458 HPKE so even the relay hop sees nothing, not the query structure, not the property list. Second, set no_retention: true on any disclosure entry where you need the receiving agent to discard its copy of the receipt. When that flag is set, PAP requires the agent to run in a TEE — the retention constraint becomes cryptographically binding, not a promise. The risk isn't gone without these settings, but with them it's fully addressed.

- Its output is validated before use. The return value of - classify_intent must match one of the strings in candidate_actions. - A hallucinated action that isn't on the list is discarded. The model controls which - catalog agent handles the query. It cannot alter the mandate that governs what that agent - is allowed to do — mandates are signed by the principal's device-bound Ed25519 key, - which the model never sees. + The underlying concern — and why both controls matter. + Each agent in + pap-agents declares exactly what it needs via + AgentMeta.requires_disclosure + (crates/pap-agents/src/executor.rs) — those property names are embedded + in the Mandate's DisclosureSet during Phase 2 of the handshake, bounding + the scope of what the agent is permitted to receive. The Phase 3 disclosure payload + carries the query inside that scope boundary. + SD-JWT (pap-credential/src/sd_jwt.rs) + hides claim values via per-claim salted hashes and is available as an optional + enhancement for credential-bearing payloads, but is not used in the current query + handshake path — claim structure is not hidden. The + recipient agent always learns which property slots were disclosed; + that is the intent of the handshake. Network-level visibility is configurable: + OHTTP (RFC 9458, HPKE DHKEM-X25519 + AES-128-GCM) is a setting in Papillon and + Chrysalis — when enabled, relay operators and passive observers see nothing. + Without it, transport encryption is present but query structure is visible to + the relay hop.

- The four canonical LLM attack paths: - Prompt injection — succeeds only at routing the query to the wrong catalog - agent; it cannot forge the Ed25519 signature that authorizes scope. Context - exfiltration — the model only receives query text, never the mandate or session keys. - Session correlation — each session generates a fresh - ephemeral session DID discarded - at close; the model sees the query text, never the session DID. Scope escalation - — child mandates are cryptographically constrained to a subset of their parent's scope - (Scope::deny_all() baseline, contains() enforcement); - no model output can extend this. + Receipts store property references, never values: pap-core/src/receipt.rs + holds disclosed_by_initiator: Vec<String> — strings like + "schema:Person.name". The receiving agent holds a co-signed copy after + every session. Across multiple sessions the pattern of which properties a principal + discloses to that agent can become a quasi-identifier even without any value leaving. + The no_retention flag on DisclosureEntry + (pap-core/src/scope.rs) addresses this: when set, the handshake requires + TEE attestation from the receiving agent before proceeding, making receipt discard + auditable rather than contractual.

- The default is on-device. LlmProvider::BuiltIn runs inference - locally via Candle — no network call, no external endpoint, no logs leaving the device. - External providers (Mistral, Ollama, OpenAI-compatible) require the user to explicitly - configure an API key and endpoint URL. Even with an external provider, only query text - travels to the endpoint. For deployments requiring network-layer query privacy, - OHTTP (RFC 9458) with real HPKE decouples the IP address from the request content. + In healthcare and financial services, which properties were accessed is frequently + PHI or material non-public information in its own right — both controls are worth + enabling by default in those contexts.

- The LLM is also optional. The full 6-phase PAP handshake executes - deterministically via URL fast-path and BM25 semantic index without any model. - Setting LlmProvider::None gives a fully functional, cryptographically - sound protocol runtime. The model enhances intent resolution for ambiguous queries; - it gates no security decision. + What we're watching: The IRMA/Yivi + ZKP-based approach provides stronger structural privacy guarantees using W3C VCs. + A future spec section will evaluate ZKP-based disclosure as an optional enhancement + for cases where even TEE-attested no-retention is insufficient.

- -
+ +

- The SAML bridge question assumes a hub-and-spoke model PAP is designed to make unnecessary. Instead of a central authority managing who has access, each agent protects itself — it declares what it requires, your orchestrator presents a cryptographically scoped mandate, and access is enforced at the edge with no IdP involved. When a mandate expires (default 8 hours), access stops without a deprovisioning call or a session token to revoke. For access tied to value exchange, the ecash layer issues blind-signed tokens using RFC 9474 RSABSSA-SHA384-PSS — the agent validates the token without learning who holds it, and receipts store only a commitment hash, never amounts or identities. What your security team actually needs maps to protocol mechanisms: access policy in mandate scope, audit trail in co-signed receipts (property type references, held locally by both parties), revocation through TTL decay. -

-

- The IdP question carries a centralized assumption PAP is designed to make - unnecessary. Okta and Azure AD solve a hub-and-spoke problem: a central - authority that decides who gets access to what. PAP inverts this. Agents protect - themselves — they advertise what they require, - principals present cryptographically - scoped mandates, and the protocol enforces access at the edge without any central - authority in the loop. + The relay runs wherever you deploy it — colocated with your own node, not on Baur Software infrastructure. If you don't configure one, the protocol falls back to a direct connection: relay_url is optional, and when it's absent, the handshake continues without it. Privacy degrades — query structure becomes visible at the relay hop — but the session never breaks, and scope enforcement, expiring mandates, and co-signed receipts all work exactly the same.

- The PAP-native pattern for enterprise agent access control: - An enterprise runs agents on Chrysalis. Each agent declares its - requires_disclosure — the minimum SD-JWT claims it needs to execute - (e.g. schema:Organization.schema:memberOf to verify employment, or - a schema:Role claim scoped to a department). A principal's orchestrator - presents only those claims via selective disclosure - (crates/pap-credential/src/sd_jwt.rs); the agent verifies the - claim against its policy and either accepts the mandate or rejects it. No IdP - is in the path. No central session store. The agent is the access control point. + OHTTP relay capability is built into + Papillon and + Chrysalis — it runs + colocated with each deployment, not on Baur Software infrastructure. + When OHTTP is configured, there is no external relay operator to capture traffic. + The decentralization is topological: the relay lives alongside your own node.

- For value exchange between agents, ecash receipts replace - identity-gated permissions. Instead of "does this principal have the - Analyst role in Okta?", access is structured as "does this principal hold a valid - payment proof for this action?" The ecash system (crates/pap-ecash/) - issues blind-signed RFC 9474 RSABSSA-SHA384-PSS tokens — the agent validates - the token without learning who holds it, and the receipt proves the exchange - occurred without linking it to an identity. This is more privacy-preserving - than role-based access and eliminates the revocation problem entirely: a spent - token is simply gone. + relay_url in pap-transport/src/ohttp.rs is typed + Option<String>. When absent, the protocol falls back to a direct + connection — privacy degrades but the handshake never breaks. The core guarantees + (SD-JWT selective disclosure, ephemeral session DIDs, deny-by-default mandates) + do not depend on OHTTP being enabled.

- What security teams actually need is answered by the protocol, not - by an IdP bridge: access policy is encoded in mandate scope - (Scope::deny_all() baseline, cryptographically enforced containment); - audit trail is the co-signed receipt chain (property references, never values, - held by both parties locally); revocation is - TTL decay - (Active → Degraded → ReadOnly → Suspended) with no deprovisioning - step required. The threat model of "who has a live session token?" doesn't apply - to a system where every mandate expires by design. + When the relay is active, it uses + RFC 9458 + HPKE: DHKEM(X25519, HKDF-SHA256) + AES-128-GCM (RFC 9180). Relay operators and + passive observers cannot link IP addresses to query content or SD-JWT disclosure + structure.

- -
+ +

- Most enterprise software achieves compliance by adding controls on top of a general-purpose system. PAP's compliance properties are protocol invariants — they hold because of how the cryptography works, not because someone configured them correctly. No central server. Receipts store property type references like "schema:Person.dateOfBirth", never the values. Every session runs under a mandate your device signed, specifying the exact agent, actions, data types, and duration. Access decays automatically without a deprovisioning step. For no-retention requirements, set no_retention: true on disclosure entries and the protocol requires the receiving agent to run in a TEE, making retention constraints auditable and binding. The 34 pre-built health and finance catalog agents (15 health, 19 finance) all require zero personal disclosure — public data sources only — giving you a no-PHI baseline to build from before you add anything sensitive. + Getting a fake agent into the Chrysalis mesh takes real calendar time, not just compute. A new peer needs three vouches from existing members, each of whom can only vouch for three peers per year — and must themselves have been active for at least 90 days before they can vouch for anyone. New peers spend 60 days in a probationary state. The trust graph also checks path diversity: if your three vouchers all trace back through the same cluster of ancestors, the registration is rejected. You can't manufacture trust quickly; you have to earn it slowly.

- Most enterprise software achieves compliance by adding controls on top of a - general-purpose system. PAP's compliance properties are protocol invariants — - they hold because of cryptographic enforcement, not configuration. Here is what that - means per framework. + Vouch-based peer admission. Joining the Chrysalis mesh is not free — + it requires existing trusted peers to stake their reputation on you. + pap-federation/src/registry.rs enforces:

- HIPAA — Minimum Necessary Rule: The mandate's DisclosureSet - (crates/pap-core/src/scope.rs) specifies exactly which - schema: properties an agent may receive. An agent requesting schema:SSN when the mandate permits - only schema:dateOfBirth is filtered out by the marketplace before any - session is established — the over-disclosure attempt never reaches the transport layer. - For no-retention requirements, set no_retention: true on disclosure - entries; the session can be backed by a Trusted Execution Environment - (crates/pap-tee/) — the TEE provides enclave measurement attestation - that the session ran in an isolated environment, making the retention commitment - auditable and binding rather than contractual-only. Audit trail: co-signed receipts in - pap-core/src/receipt.rs record property type references - ("schema:Person.schema:dateOfBirth"), never values — satisfying - §164.312(b) while being safer than access logs containing real data. + 3 vouches required to register a new peer. + Each existing peer may issue at most 3 vouches per year — a rate budget that + makes flooding expensive. A peer must be registered for at least + 90 days before it can vouch for anyone. + New peers enter a 60-day probationary period with limited permissions.

- GDPR — Purpose Limitation and Erasure: A PAP mandate is - structured, machine-enforceable consent: the principal signs which agent may act, - which actions it may take (Scope::deny_all() baseline), which properties - it may see, and for how long. Non-renewal of a mandate initiates the decay state - machine (Active → Degraded → ReadOnly → Suspended): access cryptographically - expires without any deprovisioning step. The episode store - (papillon-shared/src/episode_db.rs) is a local SQLite database under - the principal's sole control — no platform coordinates erasure. Portability: PAP uses - no central registry; the principal's did:key is self-sovereign and moves - to any compatible orchestrator. + Diverse trust paths (require_diverse_paths) are specified in the policy struct + and are being enforced now — ensuring N vouchers don't all route through the same + small set of ancestors, preventing a captured clique from bootstrapping unlimited new peers.

- PCI-DSS — Access Control and Payment Privacy: - Mandate scope containment is cryptographically enforced at every delegation step - (Scope::contains() in pap-core/src/scope.rs); a child mandate - cannot exceed its parent's scope or TTL regardless of configuration. For payment - agents (schema:PayAction), mandates carry payment proofs from the ecash - system (crates/pap-ecash/) using RFC 9474 RSABSSA-SHA384-PSS blind signatures — - the vendor cannot link the signing operation to the redemption, and receipts store - only a commitment hash, never amounts or card data. + This is a social-graph approach rather than proof-of-stake or proof-of-work. The rate + constraints make a Sybil flood expensive in terms of calendar time and peer relationships, + not compute or tokens.

+
+
+ + +
+ +

- SOC2 Type II in summary: CC3.1 (access control) — deny-by-default - scope, TTL bounds. CC6.1 (logical controls) — ephemeral session keys, automatic - credential expiry. CC7.1 (audit records) — immutable co-signed receipts. Privacy - use limitation — no_retention flag enforces purpose limitation at - protocol level, with optional TEE attestation for stronger assurance. These map - to protocol mechanisms, not to policy documents that can drift. + The protocol doesn't depend on Schema.org being controlled by anyone in particular. The action field in a mandate is a plain string — any namespace-prefixed identifier is valid. Schema.org is the default because it's widely understood and makes agents discoverable to everyone, but a financial compliance action, a FHIR operation, or a lab protocol step can be expressed as operator:FhirReadAction without touching Schema.org at all. The governance capture risk is real for the interoperability layer — agents that want to be universally discoverable benefit from Schema.org alignment. Agents targeting a specific vertical can use the operator: namespace freely.

- Pre-built catalog agents exist for both verticals: healthcare agents cover FDA FAERS, - ClinicalTrials, PubMed, and MedlinePlus - (crates/pap-agents/catalog/health/); finance agents cover Nasdaq, ECB, - Treasury, and World Bank data (crates/pap-agents/catalog/finance/). - All public-data agents require zero personal disclosure - (requires_disclosure: []), giving you a no-PHI-exposure baseline to - build from. + Schema.org is a collaborative, open-community project founded by Google, + Microsoft, Yahoo, and Yandex to create a shared structured-data vocabulary. The schema + is community-governed; contributions come from across the web industry. + Google drives significant adoption through rich-result support, but it does not have unilateral + control over the vocabulary. +

+

+ The protocol is not locked to Schema.org. + ScopeAction.action in crates/pap-core/src/scope.rs is a + plain string — any namespace-prefixed URI is valid. Spec §17.6 reserves three + prefixes: schema: (Schema.org, standard interoperability baseline), + operator: (implementation-defined, for agent operator custom vocabulary), + and pap: (reserved for PAP specification extensions). A financial + compliance action, a FHIR operation, or a laboratory protocol step can be expressed + as operator:FhirReadAction or pap:ClinicalTrialEnrollAction + without touching Schema.org at all. +

+

+ crates/pap-core/src/extensions.rs implements spec sections 9.1–9.4: + Continuity Tokens (cross-session encrypted state, §9.3) and Auto-Approval Policies + (§9.4) are the first shipped protocol-level extensions. The conditions + field in ScopeAction is an opaque JSON map for arbitrary + protocol-level constraints not representable in Schema.org. Dynamic agent definitions + (crates/pap-agents/src/dynamic.rs) accept any action and return-type + strings, so custom-vocabulary agents ship without a spec change. +

+

+ The governance capture risk is real for the interoperability layer — + agents that want to be universally discoverable benefit from Schema.org alignment. + Agents targeting a specific vertical or operator deployment can use the + operator: namespace freely. Schema.org is the default, not the ceiling.