@poppykit/server 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/API.md +10 -3
  2. package/AUTH.md +120 -124
  3. package/CHANGELOG.md +13 -1
  4. package/CONFORMANCE.md +73 -0
  5. package/CONTRIBUTING.md +12 -11
  6. package/DELIVERY.md +2 -0
  7. package/INTEGRATIONS.md +74 -81
  8. package/OPERATIONS.md +142 -0
  9. package/README.md +11 -20
  10. package/RELEASING.md +2 -0
  11. package/SECURITY.md +2 -0
  12. package/STORAGE.md +56 -17
  13. package/dist/adapter-contract.d.ts +18 -0
  14. package/dist/adapter-contract.js +79 -0
  15. package/dist/auth/authenticator.d.ts +3 -1
  16. package/dist/auth/authenticator.js +34 -29
  17. package/dist/auth/authority.d.ts +8 -2
  18. package/dist/auth/authority.js +7 -2
  19. package/dist/auth/session.d.ts +47 -0
  20. package/dist/auth/session.js +94 -0
  21. package/dist/browser.d.ts +15 -16
  22. package/dist/browser.js +65 -33
  23. package/dist/conversation/service.d.ts +11 -1
  24. package/dist/conversation/service.js +39 -9
  25. package/dist/feedback.d.ts +1 -1
  26. package/dist/feedback.js +5 -5
  27. package/dist/index.d.ts +5 -1
  28. package/dist/index.js +3 -0
  29. package/dist/mcp.d.ts +1 -1
  30. package/dist/mcp.js +8 -4
  31. package/dist/network/discovery.d.ts +31 -13
  32. package/dist/network/discovery.js +103 -66
  33. package/dist/operations.d.ts +115 -0
  34. package/dist/operations.js +212 -0
  35. package/dist/postgres.d.ts +6 -0
  36. package/dist/postgres.js +72 -4
  37. package/dist/protocol/operations.d.ts +51 -0
  38. package/dist/protocol/operations.js +98 -0
  39. package/dist/protocol/session.d.ts +28 -0
  40. package/dist/protocol/session.js +93 -0
  41. package/dist/protocol/sse.d.ts +1 -0
  42. package/dist/protocol/sse.js +1 -1
  43. package/dist/protocol/wire.d.ts +8 -4
  44. package/dist/protocol/wire.js +37 -15
  45. package/dist/reference-auth/index.d.ts +10 -16
  46. package/dist/reference-auth/index.js +225 -430
  47. package/dist/sqlite.d.ts +11 -0
  48. package/dist/sqlite.js +84 -4
  49. package/examples/operations.mjs +18 -0
  50. package/examples/quickstart.mjs +8 -5
  51. package/migrations/RETIREMENT.md +77 -0
  52. package/package.json +5 -2
package/API.md CHANGED
@@ -5,13 +5,13 @@ completion for complete options and results; this map identifies the integration
5
5
 
6
6
  | Entry point | Main exports | Guide |
7
7
  | --- | --- | --- |
8
- | `@poppykit/server` | `createRequestAuthenticator`, `AuthorityError`, authority types | [authentication](AUTH.md) |
8
+ | `@poppykit/server` | `createSessionAuthority`, `createRequestAuthenticator`, `AuthorityError`, Session/authority types | [authentication](AUTH.md) |
9
9
  | `@poppykit/server` | `createConversationService`, `createConversationNotifications` | [delivery](DELIVERY.md) |
10
10
  | `@poppykit/server` | `Author`, `AuthorType`, `Message`, `RecordedMessage`, conversation/event types | [delivery](DELIVERY.md) |
11
11
  | `@poppykit/server` | `createBrowserSessions`, `createFeedbackHandler`, MCP metadata/error helpers | [integrations](INTEGRATIONS.md) |
12
12
  | `@poppykit/server/reference-auth` | `createReferenceIssuer`, `createMetadataResolver`, `createNodeTransport` | [authentication](AUTH.md) |
13
13
  | `@poppykit/server/sqlite` | `SqliteCompanyDatabase` | [storage](STORAGE.md) |
14
- | `@poppykit/server/adapter-contract` | adapter verification helpers | [storage](STORAGE.md) |
14
+ | `@poppykit/server/adapter-contract` | `runSessionAdapterContract`, `runBrowserCookieAdapterContract`, issuer/conversation adapter contracts | [storage](STORAGE.md) |
15
15
 
16
16
  Conversation workers claim accepted work, enforce account/scopes, publish replies
17
17
  and finish work through service operations. External effects require application
@@ -22,10 +22,17 @@ trusted public URLs, ingress limits, request cancellation and private-error hand
22
22
  Direct reference issuers now require `authorizationResultCipher` before
23
23
  `beginAuthorization`; same-decision `completeAuthorization` recovers the encrypted
24
24
  callback through its original validity window. See [AUTH.md](AUTH.md) for custody,
25
- revocation and one-time exchange limits. No package subpath or driver contract changed.
25
+ revocation and one-time exchange limits. SessionStore admission and BrowserCookieStore one-use authorization are new
26
+ custom-adapter contracts; see STORAGE.md.
26
27
 
27
28
  Run the [quickstart](examples/quickstart.mjs) without a listener or external service.
28
29
 
29
30
  The optional Postgres entry point ships its adapters, `createPostgresPool`,
30
31
  `postgresMigration`, `migratePostgres` and schema-version export; see [storage](STORAGE.md).
31
32
  TypeScript Postgres consumers also install `@types/pg@8.23.1` as a development dependency.
33
+
34
+ ## Business Operations v2
35
+
36
+ See [OPERATIONS.md](OPERATIONS.md) for the complete consent/effect contract. Root exports include `BusinessOperation`, `OperationApproval`, `OperationRequest`, `operationsV2`, `supportsOperations`, `parseBusinessOperation`, `parseOperationApproval`, `parseApprovalHeader`, `approvalHeader`, `mcpApproval`, `approvalMetaKey`, `captureApiOperationRequest`, `operationExpiry`, `operationRequiredResponse` and `operationToolError`.
37
+
38
+ Server exports `createBusinessOperations`, `BusinessOperationError`, `operationApiResponse`, `operationMcpResponse`, `operationPendingResponse`, `BusinessOwner`, `OperationRevision`, `BusinessOperationRecord`, `BusinessOperationStore`, `OperationInput`, `OperationOutcome` and `ExternalOperationEffect`. Both company databases expose `businessOperations(namespace)` and scoped `withTransaction`; the adapter-contract subpath exports `runBusinessOperationAdapterContract`. Conversation options accept `operations:metadata`, and `operationContext(work)` returns its accepted binding/approval.
package/AUTH.md CHANGED
@@ -1,126 +1,122 @@
1
1
  # Company authentication
2
2
 
3
- Integrating an existing issuer uses the core `ExternalAuthorityAdapter` and
4
- `createRequestAuthenticator`. It does not import, run, or persist the optional
5
- reference issuer. The host must describe its issuer's revocation visibility and
6
- order authorization checks with protected work. The reference issuer is a
7
- separate `/reference-auth` import and uses the shared company database coordinator
8
- for immediate revocation visibility.
9
-
10
- For draft 0.3 discovery configure `protectedResources`, including
11
- `https://company.example` (host only, no port/path/trailing slash), and
12
- `supportedScopes`, the company-defined account scopes. This replaces
13
- `poppyDomains` and `directScopes` in reference issuer options. Direct and Device
14
- use that same supported list; Device configuration no longer has a `scopes` field.
15
- Mediated retains its own subset. Publish descriptions in company `auth.scopes` or
16
- a listed OpenAPI document. Names starting with `poppy:` are reserved. Issuer
17
- metadata emits the mandatory session/refresh grants and enabled sign-in grants.
18
- Token exchange for Bearer-only MCP remains a later migration stage.
19
-
20
- Reference Direct sign-in uses `beginAuthorization` / `completeAuthorization`.
21
- The host authenticates the human and protects consent with its own browser
22
- session/CSRF controls; pass a high-entropy browser binding. Registered callback
23
- URLs must be HTTPS on the client metadata domain, or RFC 8252 HTTP loopback IP
24
- callbacks (`127.0.0.1` or `[::1]`). Registration matching permits only the loopback
25
- port to vary; exchange must repeat the actual authorization redirect exactly.
26
- Direct requests require `dpop_jkt`; codes retain it and exchange requires that
27
- Session Key. Missing bindings in old pending authorizations/codes fail closed.
28
-
29
- Direct hosts must configure `authorizationResultCipher: { seal, open }` with
30
- synchronous authenticated encryption and a durable protected key before calling
31
- `beginAuthorization`. Hosts already using the optional client provider can reuse
32
- its `createResultCipher` instance. Other hosts supply the same structural contract;
33
- no client package or database driver is loaded by the reference issuer.
34
-
35
- `completeAuthorization(id, browserBinding, decision)` commits one decision and
36
- an encrypted callback receipt atomically. Repeating the same decision returns
37
- the same URL after restart; changed browser/account/scopes/decision and stale
38
- account revocation/reset fail. Approval recovery expires at the earlier of the
39
- original authorization deadline and code expiry; denial uses the original deadline.
40
- Recovery never mints a replacement code or extends consent. The host must retain
41
- its authenticated owner/installation/session binding and chosen decision durably,
42
- then reconcile delivery outside transactions. Never retry an uncertain code exchange.
43
-
44
- `withCurrent` checks token, Session and grant expiry immediately before protected
45
- actions, including after body reads and long-poll waits. Streams close at token
46
- expiry and recheck current authority for each emitted frame; reconnect with fresh
47
- authentication. `withAccepted` intentionally ignores admission-token expiry while
48
- preserving the accepted scope ceiling, reset generation and configured revocation policy.
49
-
50
- Account Token rotation retains all issued hashes through the fixed grant lifetime.
51
- Replaying any ancestor revokes its entire lineage and signs its Sessions out;
52
- rotation never extends the grant. Client authentication remains mandatory, while
53
- Account Tokens can start Sessions with new keys; a Session never changes its key. Shared provider
54
- signing does not bind a copied refresh token to one provider enrollment. Keep
55
- tokens secret and serialize rotation; never retry a lost token response blindly.
56
- Bounded database cleanup removes hashes only after their lineage is expired,
57
- revoked or absent. No plaintext callback code is persisted.
58
-
59
- Pre-version-3 upgrade prerequisite: older issuers discarded ancestors beyond the previous hash.
60
- Those missing hashes cannot be reconstructed by this update. Before public
61
- enablement, revoke every pre-upgrade live lineage through the issuer's normal
62
- revocation/disconnect flow and require fresh consent, or prove it has expired.
63
- Until then, the full-ancestor guarantee applies only to newly created lineages.
64
- This update does not reset stored data or silently revoke legacy grants.
65
-
66
- Enable reference Device sign-in with `device: { endpoint, verificationUri,
67
- }`. Route the configured device endpoint to `deviceAuthorization`.
68
- On the human page call `beginDeviceAuthorization(userCode, browserBinding)` and
69
- show the client identity and requested scopes. After an authenticated explicit
70
- approve/decline action call `completeDeviceAuthorization`. Opening a link must
71
- never approve it. The token endpoint handles durable polling intervals, slowdown,
72
- denial, expiry, partial consent, one-use codes and the Session's sticky account.
73
- The first authenticated poll atomically binds the device code to its live Session
74
- Key, including pending/slow-down polls. Other keys receive `invalid_grant`.
75
- Old device records without the new binding slot require a fresh flow. Prefer
76
- Direct whenever viable; enable Device only for appropriate device constraints
77
- under RFC 10027. Verification links remain HTTPS on issuer/protected-resource hosts.
78
-
79
- Hosted consent can resolve `sessionForKey({ clientId, userId, sessionKey })` to the
80
- current company Session without treating a client's local Session ID as a server
81
- ID. It validates live client/User ownership and returns current account/scopes.
82
-
83
- Enable Mediated sign-in with `mediated: { endpoint, scopes, fields,
84
- authenticate, verifyCode }` and route that endpoint and its sign-in-ID children
85
- to `mediatedSignIn`. The SDK authenticates the Session Token and DPoP proof,
86
- validates declared fields, counts attempts before calling the host backend,
87
- and binds challenges to the initiating client, UserID and Session. The host
88
- verifies credentials in `authenticate` and may return an account plus a narrower
89
- scope list. It may instead return a challenge handle and safe delivery hint,
90
- then verify codes using `verifyCode`. Host hooks must not log or retain credentials
91
- and must enforce their own backend security and OTP delivery/verification.
92
-
93
- Credentials and codes exist only during the trusted handler call; the SDK clears
94
- input objects on exit, stores no passwords/codes and never includes them in
95
- responses. Backend errors return a safe unavailable code. Pending remote hooks
96
- are not automatically repeated after interruption. An operation left verifying
97
- expires; the user can explicitly start another sign-in subject to attempt limits.
98
-
99
- Defaults are five credential attempts per Session per minute, 100 per client per
100
- minute, five code attempts per challenge, and ten-minute sign-in expiry. Configure
101
- limits for your service and apply network-level limits before authentication.
102
- SQLite persists attempt windows and bounded tombstones; `cleanup` removes sign-in
103
- records only after their original expiry plus 30 seconds. A failed/expired code
104
- continues returning the same terminal status through that retained window.
105
-
106
- Each pending request captures a client revision. Account disconnect increments
107
- the revision and records that account's fence; later credential/consent results
108
- for that account cannot undo disconnect. Requests for other accounts sharing the
109
- same personal-agent client continue. A fresh explicit sign-in captures the new
110
- revision. Revision and per-account fence records remain until explicit issuer
111
- reset and never count as pending requests. Terminal method tombstones also do
112
- not consume pending quota.
113
-
114
- Issuer state is version 4. SQLite/PostgreSQL upgrade normalized version 3 under
115
- their writer lock; grant lineage survives. Earlier unsupported development versions
116
- still fail closed. See [STORAGE.md](STORAGE.md) for the exact upgrade behavior.
117
-
118
- Token admission selects an internal Session ID atomically by the DPoP thumbprint.
119
- It checks the client, User and optional assertion `agent_id` against the existing
120
- Session. Known ended keys return `invalid_grant`; key mappings/tombstones are
121
- retained indefinitely in this reference implementation. Token requests reject the
122
- old `session_id` parameter; responses omit `session_id` and `signed_in`.
123
-
124
- Advertise only configured methods in your `poppy.json`; `authorizationMetadata()`
125
- adds the device endpoint only when enabled. There is no login/consent UI, identity
126
- provider, CLI or application workflow in this package.
3
+ Resources own Poppy Sessions; OAuth issuers supply account grants. An existing
4
+ issuer implements `ExternalAuthorityAdapter` (introspection and current/accepted
5
+ authority policy) without importing the optional reference issuer. Its introspector
6
+ must validate exact resource audience, expiry, client/account identity, scope and
7
+ DPoP binding, and document revocation visibility and ordering with protected work.
8
+
9
+ Create a separate resource Session authority and use its combined policy:
10
+
11
+ ```ts
12
+ const sessions = createSessionAuthority({
13
+ companyId, metadata, store: database.sessions(companyId), coordinator: database,
14
+ accountPolicy: externalAuthority?.policy, now: Date.now,
15
+ maxSessionsPerClient: 10000, lifetimeSeconds: 86400,
16
+ });
17
+ const authenticator = createRequestAuthenticator({
18
+ sessions, authority: externalAuthority, now: Date.now,
19
+ endpoints: [{ origin: 'https://api.company.example', pathPrefix: '/conversations' }],
20
+ });
21
+ // Pass authenticator and sessions.policy to conversation/browser/feedback handlers.
22
+ ```
23
+
24
+ `companyId` is the verified issuer, or the Company's HTTPS domain without a slash
25
+ when issuerless. Signed-out Sessions require no authorization server or token.
26
+ The authenticator verifies the delegated ES256 Session JWT before using any of its
27
+ identity, audience, method/URL, token hash or continuity claims. Delegations accept
28
+ ES256 and PS384 root signatures, require a public P-256 delegated key and expire
29
+ within 24 hours. A root-signed Session JWT without delegation is rejected.
30
+ Client metadata fetches refuse redirects; hosts keep the supplied safe transport's
31
+ TLS/address and bounded-fetch checks. Operator signatures never replace these checks.
32
+
33
+ Sessions are keyed by exact client_id plus sid; User and optional Agent IDs cannot
34
+ change. Delegated keys can change on every request. Account grants and proof keys
35
+ do not identify Sessions. The resource remembers a previously used account and
36
+ returns invalid_session on account change. A request without an access token is
37
+ signed out, even when the Session used an account before. One account grant can
38
+ serve many Sessions. Introspection alone never establishes a Poppy User or sid.
39
+
40
+ Session lifetime defaults to one day, admission to 10,000 active Sessions per client.
41
+ Bundled stores serialize quota counts and creation across processes; overflow is
42
+ 429 with Retry-After until the earliest expiry. Ended/expired Sessions do not occupy
43
+ admission slots. Call bounded database cleanup for expired Session records; the
44
+ Company may forget ended Sessions under core 5.5. Recreated records get a fresh
45
+ instanceId, exposed as Principal.sessionInstanceId, so future ownership contracts
46
+ can distinguish them. Configure this cap on createSessionAuthority: passing the
47
+ old maxSessionsPerClient option to createReferenceIssuer fails with a relocation error.
48
+
49
+ `withCurrent` checks current Session instance/generation, validity, accepted scopes
50
+ and live account policy immediately before protected work. `withAccepted` preserves
51
+ the accepted scope ceiling and explicit work-revocation policy while allowing an
52
+ admission token to expire. A database coordinator orders authorization with writes;
53
+ a process mutex alone is insufficient across replicas. External effects still need
54
+ host idempotency and reconciliation. [Operations v2](OPERATIONS.md) provides separate durable business mechanics with explicit host effect contracts.
55
+
56
+ Authority errors expose response(): invalid_session is JSON/400; missing account
57
+ authority is an errorless Bearer/DPoP challenge/401 with scope; insufficient_scope
58
+ is 403, invalid_token is 401. Rate limits are JSON/429 with Retry-After. MCP helpers
59
+ include resource_metadata in OAuth challenges; see [INTEGRATIONS.md](INTEGRATIONS.md).
60
+
61
+ ## Optional reference issuer
62
+
63
+ Configure protectedResources with the Company domain identifier (no path, port or
64
+ slash) and supportedScopes. The issuer publishes refresh_token plus enabled
65
+ Direct/Device/Mediated grants; it does not issue signed-out Session tokens or
66
+ advertise token exchange. Scope names, including poppy-prefixed ones, are Company
67
+ policy; publish descriptions and optional hints. Resource-specific tokens use normal
68
+ sign-in/refresh with resource. Configure exact MCP resources and their DPoP policy.
69
+ The reference issuer chooses DPoP for its other account resources; an external issuer
70
+ can also supply Bearer grants through the core authenticator.
71
+
72
+ Direct uses beginAuthorization/completeAuthorization. The host authenticates the
73
+ human, protects consent/CSRF and supplies a high-entropy browser binding. Registered
74
+ redirects must be HTTPS on the client metadata domain or RFC 8252 loopback IP URLs;
75
+ only a loopback port can vary. PKCE and exact issuer response validation remain
76
+ required. OAuth dpop_jkt optionally binds the code to a proof key; it is not a Session.
77
+ Missing binding fields in legacy pending codes fail closed.
78
+
79
+ Direct also requires a synchronous authenticated authorizationResultCipher with a
80
+ durable protected key. Complete consent and an encrypted callback receipt commit
81
+ atomically. An identical decision recovers the same URL through its original validity
82
+ window; changed decisions, owners, revocation or expiry fail. Recovery never issues
83
+ a replacement code, extends consent or retries an uncertain token exchange.
84
+
85
+ Device configuration supplies endpoint and verificationUri. Serve deviceAuthorization
86
+ at that endpoint. The human page uses beginDeviceAuthorization then an explicit,
87
+ authenticated completeDeviceAuthorization decision. Opening a link does not approve.
88
+ Polling enforces pending/slowdown/denial/expiry and one-use codes, bound to client_id
89
+ rather than a Session or first polling key. Apply RFC 10027 risk controls in the host;
90
+ prefer Direct when it fits the device. Keep device codes private.
91
+
92
+ Mediated configuration supplies fields, scopes, authenticate and verifyCode. Advertise
93
+ `mediated-sign-in` version 1 and route the form grant at the normal token endpoint.
94
+ The credentials/code never arrive with a Session JWT or account token. Client-bound
95
+ continuations preserve the original scopes/resource/expiry. A code challenge is
96
+ HTTP400 code_required with sign_in_id, sent_to and expires_in; continuation uses
97
+ one_time_code without repeating credentials/scope. Hooks receive {issuer,clientId},
98
+ not Session identity, and must enforce backend/account/network throttles. Input
99
+ objects are cleared on exit; never log or retain credentials or OTPs.
100
+
101
+ An interrupted/throwing remote hook remains verifying, is never automatically
102
+ repeated and survives expiry/cleanup for host reconciliation. It continues counting
103
+ toward pending limits. No expiry timer proves a remote action failed. Defaults are
104
+ five credential attempts per client per minute, five code attempts per challenge,
105
+ 1000 pending requests globally and 100 per client; apply network limits before auth.
106
+ Client/account revision fences prevent late consent from undoing disconnect.
107
+
108
+ Refresh grants have a fixed lifetime; rotation never extends it. Retain every
109
+ ancestor hash through that lifetime so replay revokes the lineage. Client assertions
110
+ remain mandatory, independently of Sessions and proof-key rotation. Revocation
111
+ signs resources out according to live account policy without deleting Sessions.
112
+
113
+ Issuer record versions 3/4 upgrade to 5 under their writer lock, retaining generation,
114
+ Sessions/maps, grants/ancestor hashes, pending consent, uncertain hooks, replay,
115
+ nonces and encrypted recovery receipts. Only proven client/account associations
116
+ are backfilled. Unknown/conflicting legacy records are not reinterpreted. The retired browserSessions/sessionForKey and separate mediatedSignIn entry points
117
+ are removed. Browser joining uses resource Sessions and fixed approval snapshots;
118
+ mediated grants use token(). Retained legacy records remain available through
119
+ explicit storage reads for reconciliation.
120
+ See [STORAGE.md](STORAGE.md). Earlier unsupported versions fail closed.
121
+
122
+ Authentication lifecycle OperationRecord/operationId values never approve business operations. OAuth access consent, provider enrollment and mediated credential collection cannot supply business consent. [Operations v2](OPERATIONS.md) binds each actual user answer to the exact revision and request, and rechecks current Session/account authority for execution and protected replay.
package/CHANGELOG.md CHANGED
@@ -1,8 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ Local migration block2 adds Operations v2 codecs, negotiated API/MCP/conversation mechanics and durable revision ownership, execution claims, local atomic effects and host external reconciliation. See [OPERATIONS.md](OPERATIONS.md). This is a local SDK checkpoint, not full CLI integration or package publication.
4
+
5
+ ## 0.5.0 — current-spec core migration
6
+
7
+ Separate delegated resource Sessions from OAuth account grants; discover issuers and
8
+ service resources independently; support issuerless Companies, Bearer/DPoP tokens,
9
+ current mediated grants, code-only browser joining, current errors and feedback.
10
+ Client auth records upgrade to v3; reference issuer records upgrade to v5 without
11
+ resetting credentials or pending/recovery records. Stop old writers before opening
12
+ upgraded stores. Retired public APIs are removed; see [AUTH.md](AUTH.md) and
13
+ [STORAGE.md](STORAGE.md). Breaking local migration candidate; publication requires the recorded release gates.
14
+
3
15
  ## 0.4.0 — 2026-10-28
4
16
 
5
- Target pinned Personal Agent Protocol draft 0.3. Break discovery, proof-key grants, author, browser joining and MCP Token Exchange contracts. Upgrade issuer state 3→4; stop old writers and reset conversation state to version 2. Require explicit company history scopes.
17
+ Historical snapshot of Personal Agent Protocol draft 0.3; the current live contract supersedes this entry. Break discovery, proof-key grants, author, browser joining and MCP Token Exchange contracts. Upgrade issuer state 3→4; stop old writers and reset conversation state to version 2. Require explicit company history scopes.
6
18
 
7
19
  Local migration candidate only. Publication and deployment require separate approval.
8
20
 
package/CONFORMANCE.md ADDED
@@ -0,0 +1,73 @@
1
+ # Current protocol contract
2
+
3
+ The normative source is the [live draft 0.3 specification](https://personalagentprotocol.org/docs/0.3/spec)
4
+ and [Mediated Sign-In v1](https://personalagentprotocol.org/docs/0.3/extensions/mediated-sign-in).
5
+ The numbered URL is not a content pin. On 2026-10-31 the six migration sources were
6
+ re-fetched and matched their initial snapshots byte for byte. SHA-256 identities:
7
+
8
+ - Core: 0c8586c0477f523abe39b47e5a20232fc8128c24bf17bb78fff69133f97f9bb9
9
+ - Mediated v1: 68074a6178bf4c78f09b2a88313a4067fa9e4143a338f205a63d2d884ca09f94
10
+ - Guides: fe10657eca0b464c19cc198f3876d30f5055d8a5cb423cd147affe805206ecdd
11
+
12
+ The workspace requirement matrix and exact commands, tree hashes and focused test
13
+ receipts live in jobs/protocol-migration. Focused checks do not certify an installed
14
+ release or any deployed service. Operations v2 SDK mechanics are implemented with opt-in host contracts;
15
+ full candidate, native and cross-package release gates remain separate.
16
+
17
+ ## Host contracts and recommendations
18
+
19
+ The [guides](https://personalagentprotocol.org/docs/0.3/guides) use SHOULD for each
20
+ recommendation, including items without uppercase words. The SDK supplies protocol
21
+ mechanics; hosts retain the following responsibilities:
22
+
23
+ - Keep signing, transport and the SecretStore outside model tools. Redact identity,
24
+ authorization, cookie and credential headers before host logging or telemetry.
25
+ Secure credential storage is mandatory. Bundled auth imports private keys as
26
+ non-extractable CryptoKeys, but serializes keys to the host vault for durable
27
+ recovery; it does not promise hardware-backed, non-exportable key custody.
28
+ - Show the verified Company name/domain after discovery redirects and on sign-in
29
+ forms. Explain stable pairwise signed-out recognition in the privacy notice.
30
+ Request the fewest task scopes, treat absent/unknown hints conservatively, and
31
+ obtain User consent for access and for human-operated Direct/Device sign-in.
32
+ - Prefer Direct, then Device where viable. Assess RFC 10027 device-flow risk,
33
+ confirm the visible user code, protect consent pages against CSRF/framing, and
34
+ apply account/network abuse limits. Mediated v1 is transitional; do not use saved
35
+ credentials to undo a disconnect. TrustedInput must isolate credentials and OTPs.
36
+ - Isolate an agent browser's storage per Session, load only its own join code,
37
+ submit promptly, rejoin after sign-in, and close its storage when the Session ends.
38
+ Joined cookies retain the authorized account/scope snapshot. The website must
39
+ prioritize that cookie and use current policy on every request; signed-in joins
40
+ must clear any earlier ordinary login. Signed-out joins preserve it. Website
41
+ logout must invalidate/remove the joined cookie through the host integration.
42
+ - Apply account/scope checks at every application tool and channel. Do not trust
43
+ model/Company prose as permission or put secrets in messages/feedback. Decide
44
+ task exclusions, interface choice, human handoff wording and report frequency.
45
+ - Keep deployment TLS, public-URL proxy reconstruction, internal credentials, bot
46
+ recognition, network throttles, key publication/rotation and tenant issuer
47
+ separation correct. RateLimit headers and scheduling/backoff across independent
48
+ tasks are host policies; SDK Retry-After state is connection-scoped.
49
+ - Operator signatures use a host HttpTransport/edge integration implementing the
50
+ deployment's RFC 9421/Web Bot Auth profile. Sign only after the body, DPoP and
51
+ Poppy-Session/Authorization headers are final; verify Session identity separately.
52
+ Protect forwarded verification results and never share operator private keys.
53
+ - Blind signing is not implemented by the bundled provider. A host requiring it
54
+ must supply blind client assertions and delegations together, with device-made
55
+ random jti values, and fail closed if PS384 is unavailable. No ES256 privacy
56
+ downgrade is automatic. Company verification accepts PS384 independently.
57
+ - Local/provider delegations use coarse half-hour issuance times and expire one
58
+ hour after that bucket (30–60 minutes remaining on creation). Custom providers
59
+ must keep their delegation valid and within the documented client lifetime bound.
60
+ Verification deliberately avoids another sensitive delegation cache; bounded
61
+ metadata/JWKS caches remain, at the cost of extra signature work per request.
62
+ - Supply the application's idempotency/reconciliation for external effects, durable
63
+ multi-host ownership/liveness, orphan-secret sweeps with a grace period, and
64
+ retention appropriate to its data. Conversation receipts are not business-effect
65
+ deduplication. Never reset active or uncertain work to make a test pass.
66
+
67
+ See [AUTH.md](AUTH.md), [STORAGE.md](STORAGE.md) and [INTEGRATIONS.md](INTEGRATIONS.md)
68
+ for the concrete callback/store contracts. A host integration must validate these
69
+ boundaries in its real browser, issuer, vault, gateway and deployment environment.
70
+
71
+ Operations source re-fetch: 2026-10-31, HTML SHA256 e69ade54433ece3fb2bd1ff6c441fecd11acc749eb6bac8b33939420d1f2b9eb, unchanged from block1. Core and guide hashes are unchanged as well. [Business Operations](OPERATIONS.md) defines trusted UI/business semantics, durable adapters and external idempotency/reconciliation obligations. Focused SQLite/PostgreSQL and process-crash evidence belongs to block2; full stable-candidate/package/platform gates remain block3. No deployed host or arbitrary network exactly-once claim is made.
72
+
73
+ Source revalidation on 2026-11-01 found all six core/current/changelog/Operations/mediated/guides pages byte-identical to the 2026-10-31 snapshots. A numbered draft URL remains mutable. Final candidate verification and external platform limits are recorded in the workspace migration STATUS; package publication is established only by its release receipt.
package/CONTRIBUTING.md CHANGED
@@ -1,32 +1,33 @@
1
1
  # Contributing
2
2
 
3
- Follow the pinned draft 0.3 [specification](https://personalagentprotocol.org/docs/0.3/spec)
3
+ Follow the live draft 0.3 [specification](https://personalagentprotocol.org/docs/0.3/spec)
4
4
  and [guides](https://personalagentprotocol.org/docs/0.3/guides). Tests/snapshots are
5
- supporting evidence. This unreleased checkout has completed only the discovery
6
- stage of migration; auth, wire/storage and integrations still need their stages.
7
- Demo/business workflows and individual extensions are excluded.
5
+ supporting evidence. Core protocol, Mediated Sign-In v1 and [Operations v2](OPERATIONS.md) are in scope.
6
+ Operations capability publication requires complete host consent/effect integration.
7
+ Application business workflows remain host responsibilities. Source fingerprints and
8
+ recommendation boundaries are in [CONFORMANCE.md](CONFORMANCE.md).
8
9
  Code is [MIT](LICENSE); confirm rights for third-party contributions.
9
10
 
10
11
  Use Node 24.21.0, TypeScript 5.9.3 and @types/node 24.10.0.
11
12
  Install the packageManager-pinned pnpm and run pnpm install --frozen-lockfile --ignore-scripts.
12
13
 
13
14
  ```sh
14
- npm run typecheck
15
- npm run build
16
- npm run typecheck:tests
17
- npm test
18
- npm run check:docs
15
+ pnpm run typecheck
16
+ pnpm run build
17
+ pnpm run typecheck:tests
18
+ pnpm test
19
+ pnpm run check:docs
19
20
  ```
20
21
 
21
22
  First-party tests/workers/verification helpers are canonical `.mts`. The existing
22
23
  compiler checks the whole strict program before emitting ignored adjacent `.mjs`.
23
24
  Failed builds remove stale outputs; no loader/type stripping substitutes for checking.
24
- Run `npm run build:tests` before `node scripts/run-checks.mjs GROUP` (unit, contracts,
25
+ Run `pnpm run build:tests` before `node scripts/run-checks.mjs GROUP` (unit, contracts,
25
26
  integration, validation). Groups are exhaustive/disjoint. LF source bytes are enforced
26
27
  by Git attributes. Generated test code is outside the npm allowlist; production tests
27
28
  import built/installed JavaScript. Release/build tools and examples may remain JS.
28
29
 
29
- `npm run coverage` builds production and checked tests, then writes native Node
30
+ `pnpm run coverage` builds production and checked tests, then writes native Node
30
31
  line/branch/function reports under `coverage/` (summary.txt, lcov.info, report.json,
31
32
  raw/). Metrics cover loaded first-party dist JS: no production source maps or TS
32
33
  remapping; node_modules excluded, unloaded modules listed. Raw subprocess reports
package/DELIVERY.md CHANGED
@@ -94,3 +94,5 @@ state; SQLite/PostgreSQL reject version 1. Stop old writers and clear history,
94
94
  receipts, cursor identities, work, client outboxes and retry handles together.
95
95
  Preserve required configuration. No historical conversion or dual wire format is
96
96
  provided. An accepted request's fingerprint is never rewritten.
97
+
98
+ Business-operation retries use the operation ID and approved revision, independently of message/work IDs. A conversation acceptance is not proof the action completed. [Operations v2](OPERATIONS.md) preserves uncertain claims/attempts through timeout, process death, expiry and restart. A different operation returned on retry does not establish the earlier outcome.