# Changelog

What changed in each version of the specification, extensions, and guides, newest first. Each published version stays at its own URL, such as [/docs/0.1/spec](/docs/0.1/spec).

## Draft 0.2

In progress, at [/docs/spec](/docs/0.2/spec). This list grows until 0.2 is published. Changes marked "Breaking" can require an implementation that followed the 0.1 text to change.

- **Breaking: HTTPS everywhere.** Every URL the protocol defines or exchanges is an HTTPS URL, including API and MCP URLs, metadata endpoints, and extension endpoints, which 0.1 didn't cover. Personal Agents don't use other URLs from a Company, and Companies reject them from a Personal Agent. Website pages a Personal Agent browses aren't covered ([3](/docs/0.2/spec#discovery)).
- **Breaking: Versions before 1.0.** Each 0.x version can break the one before, so a Personal Agent uses only a `poppy.json` whose `major.minor` version it supports. 0.1 promised that newer minor versions wouldn't break older Personal Agents, which 0.2 doesn't keep. That promise now starts at 1.0 ([3.1](/docs/0.2/spec#fields)).
- **Breaking: Which domain `poppy.json` speaks for.** `organization.domain` is the host that serves the document after any redirects, not the host the Personal Agent requested. Domains are compared ignoring case only, so a leading `www.` is no longer ignored, and the `poppy_domains` check also ignores case. A Company that uses a provider has the provider serve the document on the Company's own domain ([3](/docs/0.2/spec#discovery), [3.1](/docs/0.2/spec#fields), [3.2](/docs/0.2/spec#oauth-server)). [Issue #5](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/5)
- **Breaking: One issuer per Company.** An issuer represents exactly one Company. A provider that hosts several Companies gives each its own issuer, even on shared servers, so they don't share User IDs or Account Tokens. The spec also says where the metadata is for an issuer with a path, as RFC 8414 defines ([3.2](/docs/0.2/spec#oauth-server), [4.2](/docs/0.2/spec#starting-sessions), [9.4](/docs/0.2/spec#assertion-audience)). [Issue #3](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/3)
- **Which Company a document speaks for.** Section 3 now explains in one place how `poppy.json` and the issuer's metadata confirm each other, and 3.2 lists `issuer` and `poppy_domains` among the metadata fields. The issuer is compared exactly and domains ignoring case. The redirect example now matches the example document. The rules themselves don't change ([3](/docs/0.2/spec#discovery), [3.2](/docs/0.2/spec#oauth-server), [9.3](/docs/0.2/spec#trust)).
- **Breaking: DPoP algorithms.** Companies accept DPoP Proofs signed with `ES256`. They may list the algorithms they accept in `dpop_signing_alg_values_supported` in their OAuth metadata, and the list then includes `ES256`. A Company whose issuer serves other OAuth clients can leave the field out, since it tells them the issuer supports DPoP. Personal Agents sign with `ES256` or an algorithm from the list ([3.2](/docs/0.2/spec#oauth-server)). [Issue #12](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/12)
- **Breaking: `extension_required` responses.** At the token endpoint and at endpoints this protocol or an extension defines, the error is a JSON body. At APIs, it goes in the `WWW-Authenticate` header. It's listed in the token endpoint and API error tables. An MCP server returns it only to refuse the Personal Agent entirely, never for a single tool ([3.3](/docs/0.2/spec#extensions), [4.2](/docs/0.2/spec#starting-sessions), [6](/docs/0.2/spec#apis)).
- **Breaking: Assertion audience.** In 0.1, a client assertion's `aud` wasn't specified, and a Session assertion's was the Company's token endpoint. Both are now the Company's `auth.issuer`, and Companies reject any other `aud` ([4.1](/docs/0.2/spec#agent-identity), [4.2](/docs/0.2/spec#starting-sessions), [9.4](/docs/0.2/spec#assertion-audience)). [Issue #2](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/2)
- **User IDs for anonymous browsing.** A Personal Agent may give a User a new User ID for each anonymous browsing session, like a private browser window, and never signs in with it. Personal Agents must keep the mapping of each User's IDs across Companies confidential: no publishing it and no sharing it with third parties, other than service providers that process it for them ([4.2](/docs/0.2/spec#starting-sessions)). [Issue #11](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/11)
- **Breaking: DPoP Proof checks.** Companies MUST validate every proof as RFC 9449 §4.3 describes. That adds checks that the request has exactly one `DPoP` header, `typ` is `dpop+jwt`, `alg` is an asymmetric algorithm the Company accepts and never `none`, and `jwk` holds no private key. In 0.1, every endpoint had to reject a reused `jti`. Now only the token endpoint must, and APIs and conversation endpoints may. A Company can judge the acceptance window by when it issued the proof's `nonce`, not only by `iat`. Companies don't need to support `dpop_jkt`. Where the spec is silent, RFC 9449 applies ([4.3](/docs/0.2/spec#sending-tokens)).
- **Breaking: DPoP errors at APIs and conversations.** `invalid_dpop_proof` and `use_dpop_nonce` come with HTTP 401 and the `WWW-Authenticate: DPoP` header. At the token endpoint they're OAuth errors with HTTP 400 ([4.3](/docs/0.2/spec#sending-tokens), [6](/docs/0.2/spec#apis)).
- **DPoP at MCP servers.** An MCP server supports DPoP by listing `dpop_signing_alg_values_supported` in its protected resource metadata. Personal Agents then use a DPoP Session Token there, issued for the server's `resource`. The server still accepts Bearer tokens for MCP clients without DPoP, and rejects a DPoP token sent as a Bearer token. New MCP servers should support DPoP ([4.3](/docs/0.2/spec#sending-tokens), [6](/docs/0.2/spec#apis)). [Issue #6](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/6)
- **`rate_limited` body.** At the token endpoint and at endpoints this protocol or an extension defines, such as conversations and Mediated Sign-In, the body is `{"error": "rate_limited"}`. APIs and the website keep their own bodies ([4.3](/docs/0.2/spec#sending-tokens)).
- **Breaking: A Session stays tied to its account.** Once a Session has been signed in to an account, it can only be signed in to that account again, even after sign-out. This applies to every sign-in type, and to using an Account Token with a signed-out Session ([4.4](/docs/0.2/spec#sign-in), [4.8](/docs/0.2/spec#account-tokens), [4.9](/docs/0.2/spec#sign-out)). [Issue #8](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/8)
- **Breaking: Mediated Sign-In responses.** Every status comes with HTTP 200, and submitting a code to a `failed` or `expired` sign-in returns the same status again. Problems with the request are errors with a JSON body: `invalid_scope` and `account_mismatch` (400), and `sign_in_not_found` (404) for a sign-in that is unknown or that another Session started ([4.7](/docs/0.2/spec#mediated-sign-in)).
- **Breaking: Mediated Sign-In credentials.** After a sign-in ends, Personal Agents MUST discard the credentials or keep them only in a credential store the User chose, such as a password manager. They MUST NOT keep them anywhere else, including model context and logs. After the User or the Company revokes their access, they SHOULD NOT sign in again with stored credentials unless the User asks ([4.7](/docs/0.2/spec#mediated-sign-in)). [Issue #5](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/5)
- **Work after a token expires.** A Session Token expiring isn't a sign-out, and work the Company accepted with a valid token can continue. When access is revoked, the Company may stop work in progress that uses the account, or let it finish ([4.9](/docs/0.2/spec#sign-out)). [Issue #15](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/15)
- **Sessions from plain MCP clients.** A Session started by an MCP client that doesn't implement this protocol has no User ID, can't continue signed out, and ends when its sign-in does ([6](/docs/0.2/spec#apis)).
- **Conversation query parameters.** `cursor` and `wait` are query parameters, as the 0.1 examples showed, on reads and on the `POST` requests that send a message or hand off. `wait` is a whole number of seconds ([7.3](/docs/0.2/spec#sending-messages), [7.5](/docs/0.2/spec#reading-events)).
- **Breaking: Messages.** `role` is listed as a message field, set by the Company. A `message` event holds the message as it was sent, and every accepted message is recorded, including one with only `context` ([7.4](/docs/0.2/spec#message-fields), [7.5](/docs/0.2/spec#reading-events)).
- **Long polling.** A Company that caps `wait` holds the request for its cap instead of rejecting it ([7.5](/docs/0.2/spec#reading-events)).
- **Breaking: Read fields.** Every successful read includes `conversation_id` and `events`, as the examples showed, along with `cursor`, `has_more`, `status`, and `responder`. `events` is empty when there are none ([7.5](/docs/0.2/spec#reading-events)). [Issue #13](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/13)
- **Streaming.** When a request has both `Last-Event-ID` and `cursor`, `Last-Event-ID` wins ([7.6](/docs/0.2/spec#streaming)).
- **Repeated requests.** Handing off a conversation that is already queued or with a person, or closing one that is already closed, returns the current state and changes nothing ([7.9](/docs/0.2/spec#handoff), [7.12](/docs/0.2/spec#closing)).
- **`user_requested`.** The event doesn't change `status` or `responder` ([7.10](/docs/0.2/spec#direct-conversations)).
- **Conversation errors.** Conversations add `invalid_request` (400) and `rate_limited` (429) ([7.13](/docs/0.2/spec#conversation-errors)).
- **Feedback.** A new section 8 lets a Company list a `feedback.endpoint` in `poppy.json`. With a Session Token, Personal Agents can report a User's task that the Company offers no way to do through this protocol. A report has a `kind`, which is `missing` for now, the `task`, and a `description` without identifiers, and isn't for errors ([3.1](/docs/0.2/spec#fields), [8](/docs/0.2/spec#feedback)). [Issue #9](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/9)
- **Breaking: Security considerations.** A new section 9 covers content from Companies and prompt injection, secrets and the model, what a domain vouches for, and why assertions name the issuer. It adds requirements for Personal Agents: they MUST treat content from a Company as data, not instructions, and MUST NOT act at one Company, or send it information, because another Company's content asked. References move to section 10 ([9](/docs/0.2/spec#security), [9.1](/docs/0.2/spec#untrusted-content)). [Issue #4](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/4)
- **Operations.** Personal Agents should show the User the values in an operation's `terms` next to its `summary`, or check that they agree, before asking for approval ([Operations 5.1](/docs/0.2/extensions/operations#approval)). [Issue #4](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/4)
- **Guides.** Sign DPoP Proofs with ES256, which every company accepts. A company's token endpoint keeps a replay cache shared by every server, and its APIs may keep one too. A client or Session assertion's `aud` is the company's `auth.issuer`. Personal agents keep Mediated Sign-In credentials only in a credential store the user chose, and don't sign in with them again after the user disconnects. Companies ask for a one-time code on a personal agent's first mediated sign-in after the user disconnected it ([Guides](/docs/0.2/guides)). [Issue #5](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/5)
- **Guides: key refetches, rate limits, and running work.** Companies refetch a personal agent's keys at most once per interval, counting failures, and charge per-agent rate limits only after the signature checks pass. Accepted work isn't stopped because a session token expired, and work that can take consequential actions stops right away when access is revoked ([Rotating keys](/docs/0.2/guides#both-key-rotation), [Rate limits](/docs/0.2/guides#both-rate-limits), [Token lifetimes and sign-out](/docs/0.2/guides#company-lifetimes)). [Issue #15](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/15)
- **Guides: hosting several companies.** A new section for providers that host several companies, with an example of which storefronts share an issuer, metadata for an issuer with a path, and keeping each company's tokens and records apart on shared servers. Personal agents key user IDs and account tokens by the full `auth.issuer` ([Hosting several companies](/docs/0.2/guides#company-hosting), [User IDs](/docs/0.2/guides#agent-user-ids)). [Issue #3](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/3)
- **Guides: user ID privacy.** Personal agents tell users that companies recognize them across signed-out visits and that signing in links those visits to their account. A new list covers anonymous browsing: a new user ID and DPoP key for each session, discarded when it ends ([User IDs](/docs/0.2/guides#agent-user-ids)). [Issue #11](https://github.com/personal-agent-protocol/personal-agent-protocol/issues/11)

## Version 0.1

Published October 9, 2026, the first published draft. It's frozen at [/docs/0.1/spec](/docs/0.1/spec).

---

Licensed under the [Apache License 2.0](https://personalagentprotocol.org/license).
