Personal Agent Protocol draft 0.1 was published on 9 Oct 2026 · What goes in poppy.json →
poppy.json validator · draft 0.1

Validate your poppy.json

Paste a Personal Agent Protocol discovery document and check it against every document rule in the draft, before you publish it. Nothing is fetched or stored.

Already live? Check your domain instead: it also reads your sign-in server and APIs.

What it checks

Every document rule in draft 0.1

The same rules as the live check, run on the text you paste. Each result names the section of the specification it comes from.

Version

protocol_version is present and a version personal agents can read.

Organization

A name, and an organization.domain that is the host it is served on, after any redirects (www. counts).

Sign-in

auth where sessions need it, an HTTPS issuer, the sign-in types offered (direct, device, mediated), their scopes and custom scope names.

Routes

At least one of agent, apis or web, with the endpoints each one needs.

APIs

Each API's type (OpenAPI or MCP), URL and description.

Extensions

operations and other extensions carry a version and endpoint; custom ones use a domain prefix.

New to the file? What goes in poppy.json, field by field.

Common errors

poppy.json errors and how to fix them

The problems these checks report most often, what each one means and the fix. Paste means this validator finds it; Live means it needs the domain check.

Agents only read the file at https://{domain}/.well-known/poppy.json. A 404, a plain-HTTP URL or a redirect to HTTP all mean there is no document.

Fix: Serve the file at exactly /.well-known/poppy.json over HTTPS. Redirects are fine if every hop stays on HTTPS.

Usually an HTML error or login page served at the path, a trailing comma, or a top-level array.

Fix: Return one JSON object ({ … }) with Content-Type: application/json, and check it parses.

organization, auth (and its sign-in types and custom_scopes), agent, web and extensions are objects. Many servers encode an empty map as <code>[]</code>, which typed agents reject.

Fix: Send {} for an empty object. In PHP, use (object) [] or JSON_FORCE_OBJECT for that member.

The document speaks for the host that serves it, after any redirects. A scheme, a path, a different domain, or a missing or extra www. fails the match.

Fix: Use the host the file is finally served from: "domain": "www.yourcompany.com" if yourcompany.com redirects to www. Case is ignored; nothing else is.

auth is missing

Paste§3.1

Sessions need an OAuth issuer, so auth is required whenever the document lists agent, apis or a browser session endpoint.

Fix: Add "auth": { "issuer": "https://auth.yourcompany.com", "direct": { "scopes": ["poppy:read"] } }.

The issuer is where agents find your sign-in server and its metadata.

Fix: Set auth.issuer to your OAuth issuer as an HTTPS URL, written exactly as the server publishes it.

poppy:read and poppy:write belong to the protocol; custom scopes can't use that prefix.

Fix: Rename the scope (for example addresses) and describe it in auth.custom_scopes.

A document with no agent, apis or web gives an agent nothing to use.

Fix: List at least one route: your company agent (agent), your APIs (apis) or a website session (web).

Each entry in apis points the agent at an OpenAPI description or an MCP server.

Fix: Give every API a type (openapi or mcp) and an HTTPS url.

Not an error, but the description is how an agent picks the right API for a task.

Fix: Add a short description, such as "Orders, returns and exchanges".

Plain names are reserved for extensions the protocol defines, such as operations.

Fix: Name your own extensions with your domain, for example com.yourcompany.loyalty.

Agents fetch the issuer's OAuth Authorization Server Metadata (RFC 8414) to find its endpoints.

Fix: Publish it at the RFC 8414 well-known path for your issuer: /.well-known/oauth-authorization-server on the issuer's host.

Agents must refuse the document unless the two match exactly, so even a trailing slash on one side fails.

Fix: Copy the issuer value from your metadata into auth.issuer, character for character.

The issuer has to confirm each domain that names it. Without that, any domain could claim your sign-in server, so agents must not use the document.

Fix: Add "poppy_domains": ["yourcompany.com"] to your OAuth server metadata, listing every domain whose poppy.json names this issuer.

Personal agents sign DPoP proofs with an algorithm from this list (RFC 9449). Every company must publish it, and ES256 must be in it, so every agent has one algorithm it can rely on.

Fix: Add "dpop_signing_alg_values_supported": ["ES256"] to your OAuth server metadata, plus any other algorithms you accept.

Questions

About the validator

Is my poppy.json sent anywhere or stored?

No. The document is checked on our server and shown back to you in the same response. It is not saved, logged or added to the directory, and nothing in it is fetched.

What does the validator check?

Every rule of draft 0.1 that can be read from the document itself: protocol_version, the organization and its domain, auth with its issuer, sign-in types and scopes, the company agent, website and API routes, and extensions. Each result names the section of the specification it comes from.

What does it not check?

Anything that needs a request: that the file is served over HTTPS at /.well-known/poppy.json, that the issuer's OAuth metadata matches and lists your domain in poppy_domains, and that the OpenAPI and MCP descriptions you list can be reached. Enter your domain on the live check for those.

Is there an official JSON Schema for poppy.json?

Not yet. Draft 0.1 defines the document in prose, so this validator follows the rules as written, with the section for each one. If the authors publish a schema, we will check against it too.

Which version of the protocol does it use?

Personal Agent Protocol draft 0.1 (published 9 October 2026), with the changes merged into the specification through 16 October. The draft can change before 1.0, and the rules here change with it.