@poppykit/server 0.3.1 → 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 (57) hide show
  1. package/API.md +11 -3
  2. package/AUTH.md +120 -95
  3. package/CHANGELOG.md +18 -0
  4. package/CONFORMANCE.md +73 -0
  5. package/CONTRIBUTING.md +13 -10
  6. package/DELIVERY.md +21 -1
  7. package/INTEGRATIONS.md +72 -69
  8. package/OPERATIONS.md +142 -0
  9. package/README.md +14 -17
  10. package/RELEASING.md +2 -0
  11. package/SECURITY.md +2 -0
  12. package/STORAGE.md +57 -2
  13. package/dist/adapter-contract.d.ts +18 -0
  14. package/dist/adapter-contract.js +90 -11
  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 -13
  22. package/dist/browser.js +80 -46
  23. package/dist/conversation/service.d.ts +18 -8
  24. package/dist/conversation/service.js +60 -28
  25. package/dist/feedback.d.ts +1 -1
  26. package/dist/feedback.js +5 -5
  27. package/dist/index.d.ts +6 -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 +51 -22
  32. package/dist/network/discovery.js +159 -69
  33. package/dist/network/redirect.d.ts +3 -0
  34. package/dist/network/redirect.js +38 -0
  35. package/dist/network/tasks.d.ts +23 -0
  36. package/dist/network/tasks.js +45 -0
  37. package/dist/operations.d.ts +115 -0
  38. package/dist/operations.js +212 -0
  39. package/dist/postgres.d.ts +6 -0
  40. package/dist/postgres.js +92 -6
  41. package/dist/protocol/operations.d.ts +51 -0
  42. package/dist/protocol/operations.js +98 -0
  43. package/dist/protocol/session.d.ts +28 -0
  44. package/dist/protocol/session.js +93 -0
  45. package/dist/protocol/sse.d.ts +1 -0
  46. package/dist/protocol/sse.js +1 -1
  47. package/dist/protocol/wire.d.ts +20 -15
  48. package/dist/protocol/wire.js +70 -22
  49. package/dist/reference-auth/index.d.ts +17 -12
  50. package/dist/reference-auth/index.js +252 -386
  51. package/dist/reference-auth/store.d.ts +2 -1
  52. package/dist/sqlite.d.ts +11 -0
  53. package/dist/sqlite.js +104 -6
  54. package/examples/operations.mjs +18 -0
  55. package/examples/quickstart.mjs +10 -6
  56. package/migrations/RETIREMENT.md +77 -0
  57. package/package.json +5 -2
package/API.md CHANGED
@@ -5,12 +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
+ | `@poppykit/server` | `Author`, `AuthorType`, `Message`, `RecordedMessage`, conversation/event types | [delivery](DELIVERY.md) |
10
11
  | `@poppykit/server` | `createBrowserSessions`, `createFeedbackHandler`, MCP metadata/error helpers | [integrations](INTEGRATIONS.md) |
11
12
  | `@poppykit/server/reference-auth` | `createReferenceIssuer`, `createMetadataResolver`, `createNodeTransport` | [authentication](AUTH.md) |
12
13
  | `@poppykit/server/sqlite` | `SqliteCompanyDatabase` | [storage](STORAGE.md) |
13
- | `@poppykit/server/adapter-contract` | adapter verification helpers | [storage](STORAGE.md) |
14
+ | `@poppykit/server/adapter-contract` | `runSessionAdapterContract`, `runBrowserCookieAdapterContract`, issuer/conversation adapter contracts | [storage](STORAGE.md) |
14
15
 
15
16
  Conversation workers claim accepted work, enforce account/scopes, publish replies
16
17
  and finish work through service operations. External effects require application
@@ -21,10 +22,17 @@ trusted public URLs, ingress limits, request cancellation and private-error hand
21
22
  Direct reference issuers now require `authorizationResultCipher` before
22
23
  `beginAuthorization`; same-decision `completeAuthorization` recovers the encrypted
23
24
  callback through its original validity window. See [AUTH.md](AUTH.md) for custody,
24
- 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.
25
27
 
26
28
  Run the [quickstart](examples/quickstart.mjs) without a listener or external service.
27
29
 
28
30
  The optional Postgres entry point ships its adapters, `createPostgresPool`,
29
31
  `postgresMigration`, `migratePostgres` and schema-version export; see [storage](STORAGE.md).
30
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,97 +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
- Reference Direct sign-in uses `beginAuthorization` / `completeAuthorization`.
11
- The host authenticates the human and protects consent with its own browser
12
- session/CSRF controls; pass a high-entropy browser binding. Registered callback
13
- URLs must be HTTPS on the client metadata domain and exactly match registration.
14
-
15
- Direct hosts must configure `authorizationResultCipher: { seal, open }` with
16
- synchronous authenticated encryption and a durable protected key before calling
17
- `beginAuthorization`. Hosts already using the optional client provider can reuse
18
- its `createResultCipher` instance. Other hosts supply the same structural contract;
19
- no client package or database driver is loaded by the reference issuer.
20
-
21
- `completeAuthorization(id, browserBinding, decision)` commits one decision and
22
- an encrypted callback receipt atomically. Repeating the same decision returns
23
- the same URL after restart; changed browser/account/scopes/decision and stale
24
- account revocation/reset fail. Approval recovery expires at the earlier of the
25
- original authorization deadline and code expiry; denial uses the original deadline.
26
- Recovery never mints a replacement code or extends consent. The host must retain
27
- its authenticated owner/installation/session binding and chosen decision durably,
28
- then reconcile delivery outside transactions. Never retry an uncertain code exchange.
29
-
30
- `withCurrent` checks token, Session and grant expiry immediately before protected
31
- actions, including after body reads and long-poll waits. Streams close at token
32
- expiry and recheck current authority for each emitted frame; reconnect with fresh
33
- authentication. `withAccepted` intentionally ignores admission-token expiry while
34
- preserving the accepted scope ceiling, reset generation and configured revocation policy.
35
-
36
- Account Token rotation retains all issued hashes through the fixed grant lifetime.
37
- Replaying any ancestor revokes its entire lineage and signs its Sessions out;
38
- rotation never extends the grant. Client authentication remains mandatory, while
39
- Session Tokens can move to a new DPoP key as the protocol permits. Shared provider
40
- signing does not bind a copied refresh token to one provider enrollment. Keep
41
- tokens secret and serialize rotation; never retry a lost token response blindly.
42
- Bounded database cleanup removes hashes only after their lineage is expired,
43
- revoked or absent. No plaintext callback code is persisted.
44
-
45
- Upgrade prerequisite: older issuers discarded ancestors beyond the previous hash.
46
- Those missing hashes cannot be reconstructed by this update. Before public
47
- enablement, revoke every pre-upgrade live lineage through the issuer's normal
48
- revocation/disconnect flow and require fresh consent, or prove it has expired.
49
- Until then, the full-ancestor guarantee applies only to newly created lineages.
50
- This update does not reset stored data or silently revoke legacy grants.
51
-
52
- Enable reference Device sign-in with `device: { endpoint, verificationUri,
53
- scopes }`. Route the configured device endpoint to `deviceAuthorization`.
54
- On the human page call `beginDeviceAuthorization(userCode, browserBinding)` and
55
- show the client identity and requested scopes. After an authenticated explicit
56
- approve/decline action call `completeDeviceAuthorization`. Opening a link must
57
- never approve it. The token endpoint handles durable polling intervals, slowdown,
58
- denial, expiry, partial consent, one-use codes and the Session's sticky account.
59
-
60
- Enable Mediated sign-in with `mediated: { endpoint, scopes, fields,
61
- authenticate, verifyCode }` and route that endpoint and its sign-in-ID children
62
- to `mediatedSignIn`. The SDK authenticates the Session Token and DPoP proof,
63
- validates declared fields, counts attempts before calling the host backend,
64
- and binds challenges to the initiating client, UserID and Session. The host
65
- verifies credentials in `authenticate` and may return an account plus a narrower
66
- scope list. It may instead return a challenge handle and safe delivery hint,
67
- then verify codes using `verifyCode`. Host hooks must not log or retain credentials
68
- and must enforce their own backend security and OTP delivery/verification.
69
-
70
- Credentials and codes exist only during the trusted handler call; the SDK clears
71
- input objects on exit, stores no passwords/codes and never includes them in
72
- responses. Backend errors return a safe unavailable code. Pending remote hooks
73
- are not automatically repeated after interruption. An operation left verifying
74
- expires; the user can explicitly start another sign-in subject to attempt limits.
75
-
76
- Defaults are five credential attempts per Session per minute, 100 per client per
77
- minute, five code attempts per challenge, and ten-minute sign-in expiry. Configure
78
- limits for your service and apply network-level limits before authentication.
79
- SQLite persists attempt windows and bounded tombstones; `cleanup` removes sign-in
80
- records only after their original expiry plus 30 seconds. A failed/expired code
81
- continues returning the same terminal status through that retained window.
82
-
83
- Each pending request captures a client revision. Account disconnect increments
84
- the revision and records that account's fence; later credential/consent results
85
- for that account cannot undo disconnect. Requests for other accounts sharing the
86
- same personal-agent client continue. A fresh explicit sign-in captures the new
87
- revision. Revision and per-account fence records remain until explicit issuer
88
- reset and never count as pending requests. Terminal method tombstones also do
89
- not consume pending quota.
90
-
91
- Issuer state is version 3. Older development state is refused without mutation;
92
- there is no automatic migration. Follow the explicit stop/backup/reset procedure
93
- in [STORAGE.md](STORAGE.md) only for state you choose to discard.
94
-
95
- Advertise only configured methods in your `poppy.json`; `authorizationMetadata()`
96
- adds the device endpoint only when enabled. There is no login/consent UI, identity
97
- 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,5 +1,23 @@
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
+
15
+ ## 0.4.0 — 2026-10-28
16
+
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.
18
+
19
+ Local migration candidate only. Publication and deployment require separate approval.
20
+
3
21
  ## 0.3.1
4
22
 
5
23
  Support Node 24.21.0 and later within Node 24 under the owner-accepted runtime policy.
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,30 +1,33 @@
1
1
  # Contributing
2
2
 
3
- Follow the live draft 0.2 [specification](https://personalagentprotocol.org/docs/0.2/spec)
4
- and [guides](https://personalagentprotocol.org/docs/0.2/guides). Tests/snapshots are
5
- supporting evidence. Demo/business workflows and individual extensions are excluded.
3
+ Follow the live draft 0.3 [specification](https://personalagentprotocol.org/docs/0.3/spec)
4
+ and [guides](https://personalagentprotocol.org/docs/0.3/guides). Tests/snapshots are
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).
6
9
  Code is [MIT](LICENSE); confirm rights for third-party contributions.
7
10
 
8
11
  Use Node 24.21.0, TypeScript 5.9.3 and @types/node 24.10.0.
9
12
  Install the packageManager-pinned pnpm and run pnpm install --frozen-lockfile --ignore-scripts.
10
13
 
11
14
  ```sh
12
- npm run typecheck
13
- npm run build
14
- npm run typecheck:tests
15
- npm test
16
- 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
17
20
  ```
18
21
 
19
22
  First-party tests/workers/verification helpers are canonical `.mts`. The existing
20
23
  compiler checks the whole strict program before emitting ignored adjacent `.mjs`.
21
24
  Failed builds remove stale outputs; no loader/type stripping substitutes for checking.
22
- 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,
23
26
  integration, validation). Groups are exhaustive/disjoint. LF source bytes are enforced
24
27
  by Git attributes. Generated test code is outside the npm allowlist; production tests
25
28
  import built/installed JavaScript. Release/build tools and examples may remain JS.
26
29
 
27
- `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
28
31
  line/branch/function reports under `coverage/` (summary.txt, lcov.info, report.json,
29
32
  raw/). Metrics cover loaded first-party dist JS: no production source maps or TS
30
33
  remapping; node_modules excluded, unloaded modules listed. Raw subprocess reports
package/DELIVERY.md CHANGED
@@ -1,8 +1,13 @@
1
1
  # Conversation delivery and transport
2
2
 
3
- The SDK targets Personal Agent Protocol draft 0.2. Company content, messages,
3
+ Conversation messages and authorization events now use draft 0.3. Company content, messages,
4
4
  unknown events and partial text remain untrusted data for the host application.
5
5
 
6
+ Account-history access requires explicit, nonempty company `historyScopes` in
7
+ `createConversationService`, for example `['orders:read']`. There is no protocol
8
+ read-scope default. The configured scopes and account/owner checks apply to HTTP
9
+ reads and worker history; sending alone grants no read access.
10
+
6
11
  ## Client interoperability
7
12
 
8
13
  Clients keep immutable retry targets/message IDs, explicitly acknowledge named
@@ -76,3 +81,18 @@ Pruning is explicit operator policy, never automatic data loss. It preserves old
76
81
  message receipts and cursor identity. Concurrent reads see a coherent snapshot or
77
82
  `cursor_expired`. Invalid/expired waited-POST cursors are rejected before accepting
78
83
  the new write; an existing message ID still returns its original receipt.
84
+
85
+ ## Unreleased draft 0.3 breaking change
86
+
87
+ Protocol messages use `author: { type: 'agent' | 'human' }`; company authors may
88
+ also carry `id`, `name` and an HTTPS `image`. Responder checks use `author.type`,
89
+ and only the server assigns recorded `role`. Authorization events always use
90
+ `insufficient_scope` and name required scopes, including signed-out requests.
91
+
92
+ Conversation state version 2 requires an explicit clean reset of old runtime
93
+ state; SQLite/PostgreSQL reject version 1. Stop old writers and clear history,
94
+ receipts, cursor identities, work, client outboxes and retry handles together.
95
+ Preserve required configuration. No historical conversion or dual wire format is
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.