AgentPKI Protocol v0.3 — Intent Extension
Status: Draft (active) Date: 2026-06-08 Editors: AgentPKI Project License: Apache License 2.0 Supersedes: v0.2 (additive — see §11 Backward Compatibility) Repository: github.com/agentpki/spec
Abstract
This document specifies AgentPKI v0.3 Intent Extension, an additive layer over v0.2 that lets AI agents declare — at signing time — what they intend to do on a target site, and lets sites publish a machine-readable policy describing which intents they accept. A verifier reads both, computes a match, and surfaces the result in the standard verify response. A public append-only audit log makes intent declarations queryable after the fact.
The core motivating problem: today an agent presents a verified identity but no declared purpose. A site can prove “Anthropic-issued, kid X” but cannot prove “this bot is here to purchase, not to scrape-bulk.” Adversarial bots and well-meaning bots are cryptographically indistinguishable at the trust layer.
v0.3 specifies four additions:
- An
intentclaim on the passport token (§3) - A site-side discovery document at
/.well-known/agentpki-intent-policy.json(§4) - Verifier behavior: read the policy, compute a match, return a verdict mod intent (§5)
- An append-only public intent audit log format (§6)
It also defines a canonical intent vocabulary (§7) so issuers, sites, and agents agree on what each verb means.
No breaking changes. v0.2 implementations continue to interoperate. Passports without an intent claim and sites without a policy document behave exactly as in v0.2.
Status of this Document
This is a v0.3 working draft. The features specified here are scheduled for staged rollout on verify.agentpki.dev, @agentpki/sdk, and the agentpki CLI through Q3 2026. This document publishes the wire-format rules to invite review and bridge-building with adjacent protocols (Anthropic MCP, A2A, Kite, IETF AIP drafts).
The protocol follows the v0.1 versioning rule: pre-1.0 may carry breaking changes between minor versions; v0.3 specifically is additive to v0.2 and therefore non-breaking. v0.2 SDKs talking to v0.3 verifiers will see the new response fields absent or null.
The latest version, errata, and conformance test vectors are maintained at:
https://agentpki.dev/spec/v0.3-intent
1. Conventions and Terminology
This document inherits terminology and conformance keywords (MUST, SHOULD, MAY per RFC 2119) from v0.1 §1. New terms introduced in v0.3:
- Intent — A short, machine-readable verb identifying what an agent expects to do on a target site (e.g.
purchase,monitor,extract-train). See §7 for the canonical vocabulary. - Intent declaration — The agent’s bind of one or more intents to the passport via the
intentclaim, signed at mint time. The agent CANNOT mutate intent after mint. - Intent policy — A site-published document at
/.well-known/agentpki-intent-policy.jsonlisting accepted, denied, throttled, and require-attestation intents. - Intent match — The deterministic computation
match(declared_intent, policy) ∈ { allow, deny, throttle, require_attestation }. - Intent audit log — An append-only public ledger of (agent_id, site, intent, timestamp, verdict) tuples, hash-chained for tamper evidence.
- Witness — Any third party that mirrors the audit log and can attest to its integrity.
2. Summary of Additions to v0.2
| Area | v0.2 behavior | v0.3 addition |
|---|---|---|
| Passport claims | iss, sub, iat, exp, jti, tier, scope, optional cnf | Adds optional intent claim (array of strings) |
| Site discovery | /.well-known/agentpki-issuer.json, /.well-known/agentpki-crl.json | Adds /.well-known/agentpki-intent-policy.json (site-published, not issuer-published) |
| Verifier response | verdict, passport, crl_fresh, replay_checked | Adds intent_match object, intent_policy_url echo |
| Audit | No specified shape | Adds the intent audit log format + witness model |
| Scope semantics | RBAC-style capabilities tokens can act on | Unchanged. scope answers “what can”; intent answers “what for” |
No breaking changes. The wire format of the passport token itself is byte-identical to v0.2. The token MAY add a new claim only when both issuer and agent opt in.
3. The intent Claim
3.1 Wire Format
The intent claim is an OPTIONAL passport payload field. It is a non-empty array of intent strings drawn from §7’s vocabulary (or x-* extension strings).
{
"v": 1,
"iss": "anthropic.com",
"sub": "agent:anthropic.com/claude-purchase-bot-v3",
"iat": 1780935600,
"exp": 1780939200,
"jti": "...",
"tier": 1,
"scope": ["read:articles", "write:orders"],
// v0.3 addition — declared intents
"intent": ["purchase", "browse-catalog"]
}
3.2 Constraints
- The
intentclaim, if present, MUST be a JSON array of 1–8 strings. - Each string MUST match
^[a-z][a-z0-9-]{1,32}$OR start withx-(for unregistered extensions). - Strings MUST be unique within the array.
- The order is significant — the FIRST intent is the primary intent; subsequent intents are secondary capabilities the agent reserves the right to use within the same session.
- The total serialized intent claim MUST NOT exceed 256 bytes.
3.3 Mutability
An intent claim is bound to the passport at signing time and cannot be changed without minting a new token. This is by design — sites must be able to trust that the declared intent is the actual intent for the lifetime of the token. Agents that need to change intent (e.g. transition from monitor to purchase) MUST mint a new token.
3.4 Multiple Intents
An agent MAY declare multiple intents. The verifier returns a match for each declared intent against the site policy; downstream callers decide whether any-match or all-match semantics apply. The recommended default is primary-match — the first intent MUST be accepted; secondary intents that the policy denies SHOULD trigger a warning but not a deny.
3.5 Default Behavior
If a passport has no intent claim, the verifier treats the request as if the declared intent were unspecified. Sites SHOULD reject unspecified in any policy that has narrow accepted intents — see §4.5.
4. Site Intent Policy Document
4.1 Discovery
A site that wishes to participate in intent matching publishes a JSON document at:
https://<site>/.well-known/agentpki-intent-policy.json
The document MUST be served with Content-Type: application/json and SHOULD set a Cache-Control header (recommended: public, max-age=300, stale-while-revalidate=3600).
If the document is absent or returns a non-2xx response, the verifier MUST treat the site as having no policy — see §5.3.
4.2 Document Format
{
"v": 1,
"site": "example.com",
"updated_at": 1780935600,
// Intents the site explicitly accepts. Order is informational.
"accepted": [
{
"intent": "monitor",
"rate_limit": { "rpm": 60 },
"require_attestation": false
},
{
"intent": "purchase",
"rate_limit": { "rpm": 10 },
"require_attestation": true,
"min_tier": 2
},
{
"intent": "browse-catalog",
"rate_limit": null
}
],
// Intents the site explicitly denies. Verifier returns deny on match.
"denied": [
"scrape-bulk",
"evade-rate-limit",
"manipulate-rank",
"x-spam-comments"
],
// Intents the site throttles aggressively but does not block.
"throttled": [
{ "intent": "extract-train", "rate_limit": { "rpm": 1, "daily": 1000 } }
],
// Optional contact for site policy questions, abuse, exemption requests.
"contact": {
"policy": "mailto:[email protected]",
"abuse": "mailto:[email protected]"
},
// Optional canonical URL where the human-readable version of this policy lives.
"policy_url": "https://example.com/bots"
}
4.3 Required vs Optional Fields
| Field | Required | Notes |
|---|---|---|
v | yes | Integer, currently 1 |
site | yes | Bare hostname, no scheme, no trailing slash |
updated_at | yes | Unix seconds (UTC) |
accepted | no | Array of accepted intent objects; default [] |
denied | no | Array of intent strings; default [] |
throttled | no | Array of throttled intent objects; default [] |
contact | no | Object with policy and/or abuse |
policy_url | no | Human-readable policy URL |
4.4 Per-Intent Fields
For entries in accepted and throttled:
intent(string, required) — must match §7 vocabulary orx-*rate_limit(object or null, optional) —{ rpm?, daily? }require_attestation(boolean, optional, defaultfalse) — when true, the verifier requires Mode B (signed request) for this intentmin_tier(integer 1–3, optional) — requires issuer tier ≥ N for this intent
4.5 Disposition Rules
The intent-match result is computed as:
if intent ∈ policy.denied:
→ deny
elif intent ∈ policy.throttled:
→ throttle (carry rate_limit)
elif intent ∈ policy.accepted:
if require_attestation and request.mode != "B":
→ require_attestation
elif passport.tier < accepted.min_tier:
→ deny (tier_too_low)
else:
→ allow (carry rate_limit)
elif "*" ∈ policy.accepted: # accept-all wildcard
→ allow
else:
→ unmatched (no rule — caller decides default)
4.6 Wildcard
A policy MAY contain an accepted entry with intent: "*" to mean “any intent not explicitly denied.” This is the recommended pattern for low-stakes informational sites.
4.7 Document Signing (Optional)
A site MAY sign its policy document by including a signature field whose value is an Ed25519 signature over the canonical JSON of the document with the signature field removed. The signing public key MUST be discoverable via the site’s regular issuer directory (if the site is also an AgentPKI issuer) or via an intent_policy_signing_key field in a .well-known/agentpki-issuer.json extension.
Signed policies prevent on-path policy tampering. This is OPTIONAL for v0.3.
5. Verifier Behavior
5.1 Request Flow
The standard POST /v1/verify request gains an OPTIONAL intent_check field:
{
"token": "v4.public...",
"mode": "A",
"intent_check": {
"site": "example.com" // hostname to fetch the policy for
}
}
If intent_check.site is absent, the verifier MAY infer it from the request URL (Mode B) when available. If neither is available, no intent match is performed.
5.2 Verification Procedure
When intent_check is requested:
- Run the standard v0.2 verification procedure (steps 1–10).
- If verdict is already
deny(revoked, expired, bad-sig, etc.), return without performing intent match. - Fetch
https://<intent_check.site>/.well-known/agentpki-intent-policy.json, honoring the verifier’s KV-tier policy cache (default 300 s TTL). - Read the passport’s
intentclaim. If absent, set declared intent to["unspecified"]. - For each declared intent, apply the §4.5 disposition rules.
- Set the response’s
intent_matchfield (§5.4). - Set the overall response
verdictto the MOST RESTRICTIVE per-intent disposition:deny > require_attestation > throttle > allow > unmatched.
5.3 Missing Policy
If the policy document is unreachable, malformed, or 404, the verifier MUST:
- Set
intent_match.policy_present: false - Set
intent_match.disposition: "no_policy" - NOT downgrade the v0.2 verdict —
allowfrom v0.2 remainsallow
Sites without a policy are treated as “accept everything” by default. This preserves backward compatibility — a site that does not deploy v0.3 sees no behavior change.
5.4 Response Schema Additions
{
// ── all v0.2 fields unchanged ──
"verified": true,
"verdict": "allow",
"passport": { ... },
// ── v0.3 additions ──
"intent_match": {
"policy_present": true,
"policy_url": "https://example.com/.well-known/agentpki-intent-policy.json",
"policy_updated_at": 1780935600,
"declared_intents": ["purchase", "browse-catalog"],
"per_intent": [
{
"intent": "purchase",
"disposition": "require_attestation",
"reason": "policy.accepted.purchase requires Mode B"
},
{
"intent": "browse-catalog",
"disposition": "allow",
"rate_limit": null
}
],
"overall": "require_attestation"
}
}
5.5 Backwards Compatibility
Verifiers that do not implement v0.3 MUST simply ignore the intent_check field in the request, and MUST NOT emit the intent_match field in the response. Clients SHOULD treat a missing intent_match as “not checked,” not “matched without restrictions.”
6. Intent Audit Log
6.1 Purpose
The audit log makes it possible to prove what a bot declared at the moment it acted on a site, after the fact. This is the accountability primitive: if a bot declares monitor but a forensic review shows it was actually doing vote-manipulation, the log entry plus the original signed passport are sufficient to revoke the agent’s reputation publicly.
6.2 Log Entry Format
Each log entry is a JSON object:
{
"ts": 1780935600,
"agent_id": "agent:anthropic.com/claude-purchase-bot-v3",
"issuer": "anthropic.com",
"jti": "abc123...",
"site": "example.com",
"intent": ["purchase", "browse-catalog"],
"verdict": "allow",
"intent_overall": "require_attestation",
"verifier_id": "agentpki-verifier-edge",
"prev_hash": "<sha256 hex of previous entry's canonical JSON>"
}
The prev_hash field forms a hash chain. The genesis entry has prev_hash: "0000…" × 64.
6.3 Canonicalization
For hashing, the canonical JSON serialization is:
- UTF-8, no whitespace
- Keys sorted lexicographically
- Numbers as decimal integers (no scientific notation, no fractional)
- The
prev_hashfield is INCLUDED in the hash input of the NEXT entry
6.4 Distribution
Verifiers participating in the public log SHOULD expose:
GET /v1/intent-log?after=<unix_ts>&limit=<n>
Returning entries in chronological order. The reference verifier targets a 100/page default, 1000 max.
6.5 Witness Model
Anyone MAY mirror the log. A witness is any party that:
- Periodically polls the verifier’s
/v1/intent-log - Verifies each entry’s
prev_hashchains correctly - Publishes a signed checkpoint stating “I have seen entries [a, b]”
Witnesses prevent a verifier from rewriting history after the fact. This is the same model as Certificate Transparency (RFC 6962).
6.6 Privacy
The log MUST NOT contain:
- Token payloads beyond the listed fields
request.body_sha256or any Mode B request content- Source IPs
- User-agent strings
- Any data the agent did not include in its passport
Agents that wish to remain unaudited can decline to declare an intent — but most sites will then deny them (per §4.5 unmatched + denied-unspecified patterns).
7. Canonical Intent Vocabulary
Intent strings are short verbs describing what a bot is here to do. The canonical set, with informational categorization:
7.1 Read-class (least adversarial)
| Intent | Meaning |
|---|---|
monitor | Periodic health/price/availability checks. Low-frequency reads. |
index | Search-engine-style crawling for indexing. |
archive | Snapshot for permanent preservation (Wayback-style). |
extract-train | Collect content for AI model training. Sites typically throttle. |
browse-catalog | Read product/content catalog as a precursor to buying. |
read-public | Generic read of explicitly-public content. |
7.2 Write-class (interactive)
| Intent | Meaning |
|---|---|
purchase | Buy a product or service. |
book | Reserve a calendar slot, room, or appointment. |
submit-form | Apply, register, send a contact form. |
post-content | Write a comment, review, message, or social post. |
subscribe | Sign up for email/newsletter/feed. |
react | Like, upvote, react, or share. |
7.3 Higher-stakes
| Intent | Meaning |
|---|---|
transact-funds | Actually move money (banking-grade). Should require Mode B + min_tier ≥ 2. |
act-on-behalf | Agent acting as a verified human principal (impersonation grade). |
7.4 Adversarial (most sites deny)
| Intent | Meaning |
|---|---|
scrape-bulk | High-volume content extraction beyond what robots.txt permits. |
evade-rate-limit | Honest declaration of rate-limit evasion (rare; useful for researchers). |
automate-account | Unattended automation of a user account (e.g. follow/unfollow bots). |
manipulate-rank | Vote, review, follower, or engagement gaming. |
7.5 Special
| Intent | Meaning |
|---|---|
unspecified | Implicit when the passport has no intent claim. |
* (in policy accepted only) | Wildcard meaning “any intent not explicitly denied.” |
x-<vendor>-<verb> | Vendor-specific extension. Sites MAY recognize a subset. |
7.6 Vocabulary Evolution
New intents are added through the spec process. Vendor-specific extensions use the x- prefix and are NOT guaranteed to be portable across sites. The next vocabulary review is planned for v0.4.
8. Site Patterns
8.1 Default-Deny Marketplace
A high-stakes commerce site might publish:
{
"v": 1,
"site": "marketplace.example",
"updated_at": 1780935600,
"accepted": [
{ "intent": "browse-catalog", "rate_limit": { "rpm": 120 } },
{ "intent": "purchase", "rate_limit": { "rpm": 10 }, "require_attestation": true, "min_tier": 2 }
],
"denied": ["scrape-bulk", "extract-train", "manipulate-rank", "automate-account"]
}
Effect: any well-behaved purchase bot can transact; scrapers and engagement-farms are cryptographically rejected.
8.2 Open Public-Data Site
A news archive accepting any non-abusive read:
{
"v": 1,
"site": "archive.example",
"updated_at": 1780935600,
"accepted": [ { "intent": "*" } ],
"throttled": [
{ "intent": "extract-train", "rate_limit": { "rpm": 1, "daily": 5000 } }
],
"denied": ["manipulate-rank"]
}
Effect: indexers, archivers, monitors, and model trainers all welcome — but trainers get throttled to a reasonable share.
8.3 Social Platform
A platform that wants explicit declarations:
{
"v": 1,
"site": "social.example",
"updated_at": 1780935600,
"accepted": [
{ "intent": "read-public", "rate_limit": { "rpm": 600 } },
{ "intent": "post-content", "rate_limit": { "rpm": 6 }, "require_attestation": true, "min_tier": 2 }
],
"denied": ["unspecified", "automate-account", "react", "manipulate-rank"]
}
Effect: bots must explicitly declare to read; engagement bots cannot mask as readers; reactions and follows from bots are blocked.
9. Threat Model
9.1 What v0.3 Defends Against
- Misrepresented intent at execution time. An agent declares
monitorand actsmonitor; if it acts differently, forensic review against the audit log + reputation system flags the discrepancy. - Generic bot allow-lists. v0.2 sites that trusted “any AgentPKI bot” can now narrow to “AgentPKI bots that declared purchase, not scrape.”
- Cross-site reputation washing. A bot that declares
manipulate-rankon Site A is cryptographically visible to Site B that subscribes to the audit log — no need to share private signals.
9.2 What v0.3 Does NOT Defend Against
- Out-of-band lying. An agent can declare
monitorand executepurchaseif the site does not check. v0.3 provides the cryptographic infrastructure for accountability; sites must actually consult it. - Sybil intent declarations. An agent can rotate
jtis to get fresh “first time we’ve seen this combo” status. Audit log + reputation models partly address this but v0.3 alone does not. - Vocabulary disagreement. Two sites may interpret
extract-traindifferently. v0.3 standardizes the vocabulary; interpretation drift remains a coordination problem. - Policy spoofing on path. Without signed policies (§4.7, optional), an on-path attacker can rewrite a site’s policy document. HTTPS + DNSSEC are the v0.3 baseline defense.
10. Bridges to Adjacent Protocols
10.1 Anthropic MCP
MCP tools declare their capabilities at advertisement time, but not the purpose the calling agent is bringing those capabilities to. An MCP server can read the calling agent’s intent claim and apply server-side policy: “this tool requires purchase intent.” Reference adapter shipped in Q3 2026.
10.2 A2A (Agent-to-Agent)
A2A has no analog of intent today. v0.3 intent declarations are a natural fit for A2A’s agent_purpose extension point.
10.3 robots.txt
robots.txt is the legacy site-side policy file for bots. v0.3 explicitly does NOT replace robots.txt — both can coexist:
robots.txtgoverns what paths bots may visitagentpki-intent-policy.jsongoverns what bots may do on the paths they visit
Sites SHOULD treat them as orthogonal.
10.4 IETF AI-Preferences (AIP)
AIP focuses on training-data opt-out. v0.3 intent extract-train provides a finer-grained opt-in/throttle alternative to AIP’s binary block, while remaining compatible — sites can publish both.
11. Backward Compatibility
| Implementer | Behavior with v0.3 changes |
|---|---|
| v0.1 verifier | Ignores intent claim; treats token as v0.1 passport |
| v0.2 verifier | Ignores intent claim; treats token as v0.2 passport with extra field |
| v0.3 verifier vs v0.1/v0.2 passport | intent_match.declared_intents = ["unspecified"]; site policy applies |
| v0.3 verifier vs v0.3 passport, site has no policy | Verdict unchanged from v0.2; intent_match.policy_present: false |
| v0.3 verifier vs v0.3 passport, site has policy | Full match procedure applies |
A v0.3-aware client SHOULD prefer a v0.3 verifier but MAY use a v0.2 verifier with degraded behavior (no intent match).
12. Security Considerations
12.1 Policy Document Integrity
In v0.3 baseline, the integrity of agentpki-intent-policy.json relies on HTTPS. Sites whose policies need cryptographic integrity SHOULD adopt the optional signature field from §4.7. Until then, DO NOT trust intent policies pulled over insecure transports.
12.2 Audit Log Censorship Resistance
A verifier could theoretically refuse to log a particular agent’s intent declaration. The witness model (§6.5) makes this detectable: if witness A reports entries [1..1000] and the verifier’s public log skips entry 500, the discrepancy is provable. We recommend deployers run independent witnesses against the reference verifier.
12.3 Intent Inflation
Agents may declare more intents than they actually use, hoping to slip a denied intent into a primary-match. The “most restrictive disposition” rule (§5.2 step 7) explicitly prevents this — declaring purchase along with scrape-bulk against a site that denies scrape-bulk yields an overall deny.
12.4 Replay of Intent Audit Entries
Audit log entries themselves are not signed by the agent — they record what the verifier observed. The cryptographic anchor is the original token (which is signed). Mirrored audit logs MUST cross-reference the token’s jti and iss to validate that an entry actually corresponds to a real signed declaration.
12.5 Privacy of Bot Operators
Operators who treat bot identity as confidential should NOT use intent declarations against sensitive sites — declared intents are public by design in the audit log. v0.3 is incompatible with full bot anonymity.
13. Implementation Phasing
The reference implementation lands in five phases:
- Phase 1 (this document) — Spec markdown
- Phase 2 — Verifier: parse
intentclaim, acceptintent_check.sitein requests, returnintent_matchin responses - Phase 3 —
.well-known/agentpki-intent-policy.jsonpublishing: dashboard.agentpki.dev gains a “Site Policy” tab; demo.agentpki.dev hosts an example policy - Phase 4 — Audit log: verifier’s
POST /v1/verifywrites to a KV-backed append-only chain;GET /v1/intent-logexposes it - Phase 5 — SDK helper (
intent: ["purchase"]mint option), CLI subcommand (agentpki intent declare …,agentpki intent audit …)
Each phase is independently useful and ships incrementally.
14. Open Issues for Review
The following are intentionally unresolved in this draft and invite community input:
- Vocabulary granularity. Is
purchasetoo coarse? Shouldpurchase-physicalandpurchase-digitalbe separate? - Audit-log retention. Default is “forever”; should sites be able to declare a maximum log lifetime?
- Cross-issuer intent endorsement. Should one issuer be able to vouch for another issuer’s bot’s intent? (e.g. an audit firm certifies that AcmeBot’s stated intent matches its observed behavior)
- Off-protocol intent declarations. Should agents be able to declare intent mid-session via a verifiable side channel for long-lived sessions?
Comments and PRs welcomed at github.com/agentpki/spec/issues.
15. IANA Considerations
This document requests no immediate IANA registry actions. A future revision MAY request:
- An IANA registry for AgentPKI intent verbs
- An
application/agentpki-intent-policy+jsonmedia type registration - An
.well-known/agentpki-intent-policy.jsonwell-known URI registration
16. References
16.1 Normative
- v0.1 specification — passport format, verification procedure
- v0.2 specification — operational extensions
- RFC 2119 — Key words for use in RFCs to Indicate Requirement Levels
- RFC 8785 — JSON Canonicalization Scheme (JCS) — used for §6.3 canonicalization
- RFC 9421 — HTTP Message Signatures — Mode B baseline
- PASETO v4.public — passport token format
16.2 Informative
- RFC 6962 — Certificate Transparency — witness model inspiration
- Anthropic Model Context Protocol — bridge target
- A2A Protocol — bridge target
- robots.txt — orthogonal site-side policy file
- IETF AIP drafts — training opt-out, complementary to intent
extract-train
End of v0.3-intent draft.