AgentPKI

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:

  1. An intent claim on the passport token (§3)
  2. A site-side discovery document at /.well-known/agentpki-intent-policy.json (§4)
  3. Verifier behavior: read the policy, compute a match, return a verdict mod intent (§5)
  4. 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:


2. Summary of Additions to v0.2

Areav0.2 behaviorv0.3 addition
Passport claimsiss, sub, iat, exp, jti, tier, scope, optional cnfAdds optional intent claim (array of strings)
Site discovery/.well-known/agentpki-issuer.json, /.well-known/agentpki-crl.jsonAdds /.well-known/agentpki-intent-policy.json (site-published, not issuer-published)
Verifier responseverdict, passport, crl_fresh, replay_checkedAdds intent_match object, intent_policy_url echo
AuditNo specified shapeAdds the intent audit log format + witness model
Scope semanticsRBAC-style capabilities tokens can act onUnchanged. 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

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

FieldRequiredNotes
vyesInteger, currently 1
siteyesBare hostname, no scheme, no trailing slash
updated_atyesUnix seconds (UTC)
acceptednoArray of accepted intent objects; default []
deniednoArray of intent strings; default []
throttlednoArray of throttled intent objects; default []
contactnoObject with policy and/or abuse
policy_urlnoHuman-readable policy URL

4.4 Per-Intent Fields

For entries in accepted and throttled:

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:

  1. Run the standard v0.2 verification procedure (steps 1–10).
  2. If verdict is already deny (revoked, expired, bad-sig, etc.), return without performing intent match.
  3. Fetch https://<intent_check.site>/.well-known/agentpki-intent-policy.json, honoring the verifier’s KV-tier policy cache (default 300 s TTL).
  4. Read the passport’s intent claim. If absent, set declared intent to ["unspecified"].
  5. For each declared intent, apply the §4.5 disposition rules.
  6. Set the response’s intent_match field (§5.4).
  7. Set the overall response verdict to 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:

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:

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:

  1. Periodically polls the verifier’s /v1/intent-log
  2. Verifies each entry’s prev_hash chains correctly
  3. 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:

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)

IntentMeaning
monitorPeriodic health/price/availability checks. Low-frequency reads.
indexSearch-engine-style crawling for indexing.
archiveSnapshot for permanent preservation (Wayback-style).
extract-trainCollect content for AI model training. Sites typically throttle.
browse-catalogRead product/content catalog as a precursor to buying.
read-publicGeneric read of explicitly-public content.

7.2 Write-class (interactive)

IntentMeaning
purchaseBuy a product or service.
bookReserve a calendar slot, room, or appointment.
submit-formApply, register, send a contact form.
post-contentWrite a comment, review, message, or social post.
subscribeSign up for email/newsletter/feed.
reactLike, upvote, react, or share.

7.3 Higher-stakes

IntentMeaning
transact-fundsActually move money (banking-grade). Should require Mode B + min_tier ≥ 2.
act-on-behalfAgent acting as a verified human principal (impersonation grade).

7.4 Adversarial (most sites deny)

IntentMeaning
scrape-bulkHigh-volume content extraction beyond what robots.txt permits.
evade-rate-limitHonest declaration of rate-limit evasion (rare; useful for researchers).
automate-accountUnattended automation of a user account (e.g. follow/unfollow bots).
manipulate-rankVote, review, follower, or engagement gaming.

7.5 Special

IntentMeaning
unspecifiedImplicit 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

9.2 What v0.3 Does NOT Defend Against


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:

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

ImplementerBehavior with v0.3 changes
v0.1 verifierIgnores intent claim; treats token as v0.1 passport
v0.2 verifierIgnores intent claim; treats token as v0.2 passport with extra field
v0.3 verifier vs v0.1/v0.2 passportintent_match.declared_intents = ["unspecified"]; site policy applies
v0.3 verifier vs v0.3 passport, site has no policyVerdict unchanged from v0.2; intent_match.policy_present: false
v0.3 verifier vs v0.3 passport, site has policyFull 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:

  1. Phase 1 (this document) — Spec markdown
  2. Phase 2 — Verifier: parse intent claim, accept intent_check.site in requests, return intent_match in responses
  3. Phase 3.well-known/agentpki-intent-policy.json publishing: dashboard.agentpki.dev gains a “Site Policy” tab; demo.agentpki.dev hosts an example policy
  4. Phase 4 — Audit log: verifier’s POST /v1/verify writes to a KV-backed append-only chain; GET /v1/intent-log exposes it
  5. 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:

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:


16. References

16.1 Normative

16.2 Informative


End of v0.3-intent draft.