AgentDoc Specification

Chapter 9 of the Common Agent Specification 0.9.0-draft · 2026-09-08 · standalone through 0.8.0-draft

An agent already describes itself in half a dozen places. Its card says what it does. Its registration says what it is. Its standing terms say what it charges and what it promises about your data. A directory listing says what somebody checked. A reputation report says how it has gone. Which interfaces it implements is a seventh thing, usually recorded nowhere at all.

Every one of those is reachable. None of them is reachable together, and nobody deciding whether to engage an agent wants six fetches and a mental merge. AgentDoc is one document that assembles them, served from a known location, in a form a program can act on and a person can read.

JavaDoc and Swagger did the same thing, and it is worth being precise about which part of it matters. Neither invented facts. Both took what was already true of a program and put it in one place, in two renderings: one for a machine, one for a reader. AgentDoc does that for an agent, with one addition neither of them needed. An API description has no interested party. An agent description is written by somebody selling something, so every part of an AgentDoc says where it came from.

As of 0.3.0-draft, the AgentDoc is no longer a standalone standard: it is Chapter 9 of the Common Agent Specification, which defines the agent the view describes, and this page renders that chapter in its own numbering. Where this page and that document disagree, that document governs. The authored side, the document an operator writes, is the Agent Descriptor, that specification's Chapter 6. It is transport-neutral; nothing here requires a particular network or vendor.

1. Motivation

Ask a practical question about an agent you are considering hiring. Can it do the work? Will it tell you it is busy? What does it charge? Where does it process the data? Has anybody checked any of that, or is it all the operator's own copy?

Today those answers live in different documents, published by different parties, in different formats, at different addresses, and several of them are optional. The reader who does the work of gathering them ends up holding a merged picture that exists only in their head, cannot be passed to anybody else, and is stale the moment they look away. One document is the answer to that.

1.1 An AgentDoc is assembled, never authored

The tempting version of this idea is a file an operator writes about their agent. That version fails, and hand-written API descriptions already showed how: they drift from the API they describe, then they mislead, and then people stop trusting the format rather than the file.

So an AgentDoc is generated, and this specification makes that structural rather than advisory: an AgentDoc MUST NOT contain a fact that is not present in a source it lists (§4.2). There is nowhere to type a claim. An operator who wants their AgentDoc to say something changes the source it would be assembled from: their Agent Descriptor for a standing fact, or the signed document for a binding one.

1.2 What it is not

It is not a new source of truth, and it is not a registry. The card, the terms, the listing, and the reputation report remain what they always were. An AgentDoc is a view, and a view that outlives its sources misleads while looking current, which is why §4.4 makes staleness visible rather than fatal.

It also does not compete with the A2A Agent Card. Where the two overlap, an AgentDoc restates the card and cites it (§9). Forking a format that already has adoption and a known address would help nobody.

2. Conformance language and terminology

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as described in RFC 2119.

  • AgentDoc: one assembled document describing one agent, in the shape §5 defines.
  • Subject: the agent an AgentDoc describes.
  • Assembler: whoever produced this AgentDoc by gathering the sources. It MAY be the agent's own operator, a directory, or an unrelated third party.
  • Source: a document or observation an AgentDoc was assembled from, listed in the AgentDoc itself with enough detail to be fetched again.
  • Section: one part of an AgentDoc's description of the subject, each naming the sources it came from.
  • Not-stated: a member the subject has published nothing about. Named explicitly (§6), never omitted and never defaulted.
  • Owner, Agent, Engagement: as defined in Agent SoW §2. Role, Interface: as defined in Agent Roles §3 and §14.

3. Where an AgentDoc lives

An agent reachable at a domain SHOULD serve its AgentDoc at:

https://<domain>/.well-known/agentdoc.json

beside the A2A Agent Card, which is already at /.well-known/agent-card.json. A reader who has one address has both.

Two things follow, and both are deliberate.

An AgentDoc MAY also be served by somebody who is not the subject. A directory that assembles AgentDocs for every agent it lists is a conforming assembler, and its documents are as valid as the subject's own, because §4 makes the sources checkable rather than asking anybody to be trusted. The location above is where the subject's copy goes, not a claim of exclusivity.

An agent that is not reachable at a domain, which is most agents on a mesh, has no well-known location to use. Its AgentDoc is served wherever its operator or its directory serves it, and the document is unchanged. The format does not depend on the address.

Every AgentDoc SHOULD also be available as a human page at the same path without the .json extension, rendered from the same document (§8).

4. The rules that make it worth reading

4.1 Every section names its sources

Each section of an AgentDoc carries from, listing the source identifiers it was assembled from. A section with no source does not conform. This is what lets a reader take any single line and go and check it.

Sections are usually assembled from more than one source, and the members are not always from the same one. Where a member came from a different source than its section's other members, it carries its own pointer: any member MAY be accompanied by <member>_from, naming one source id. For example an offering's does is normally a sentence from the card while its inputs and price are clauses from a standing proposal, so it carries does_from and the rest are covered by the section's from.

This is a narrowing, never a widening. A member-level from MUST name a source already listed in the section's from, and its only job is to say which of them. An AgentDoc MUST NOT use it to cite a source the section does not.

4.2 An assembler adds no facts

An AgentDoc MUST NOT state anything that is not in a listed source. Reformatting, unit conversion, and restating a signed value in a section are all fine. Inference is not: an assembler that concludes an agent "probably handles European data" from a European address has manufactured a claim the agent never made, and the agent will be held to it.

Where an assembler wants to publish its own opinion about a subject, that is a recommendation and Agent Roles §9 already defines the role that produces one.

4.3 There is no summary grade

An AgentDoc MUST NOT carry a single overall score, badge, tier, or trust label for its subject.

This is the one rule most likely to be argued with, so here is the reasoning. The family already learned it once, in the Agent Listing Model: a listing's evidence tier is about who is speaking, and it is deliberately one value for the whole entry, because the day a per-field verified mark exists is the day a verified badge starts implying verified content. A publisher whose identity was checked is still the only source for what their agent can do.

An assembled document does not need a badge, because it has something better. It says where each part came from, and the reader can see that the price is from a signed standing proposal and the capability blurb is from a text field the operator typed. Provenance is the evidence. A badge is a summary of provenance that discards the part that mattered.

4.4 It says when it was assembled, and it goes stale

Every AgentDoc carries assembled_at, and every source carries when it was fetched. A reader MUST be able to tell how old the view is.

An AgentDoc MAY carry stale_after. Past that moment a reader SHOULD treat it as an old view rather than a false one: the sources it cites are still fetchable, and re-assembling is the remedy. An expired AgentDoc is not invalid, it is out of date, and those are different enough to be worth separate words.

4.5 What the assembler signs, and what it does not

An assembler MAY sign an AgentDoc with agentdoc-assembly-v1.

The signature means exactly one thing: this assembler gathered these sources at this time and reported them faithfully. It is not a claim that the subject's statements are true, and it MUST NOT be presented as one. An assembler signs its own work, never the subject's.

Where a source was itself signed, the AgentDoc records that separately, per source (§5.2). Those two signatures answer different questions and must never be shown as one.

5. The document

5.1 Top level

{
  "agentdoc": "v1",
  "subject": { "id": "…", "handle": "…", "name": "…" },
  "assembled_at": "2026-08-29T18:04:00Z",
  "assembled_by": "…",
  "stale_after": "2026-09-05T18:04:00Z",
  "sources": [ … ],
  "sections": { … },
  "not_stated": [ … ],
  "signatures": [ ]
}

subject.id is the agent's stable identifier, normally its public key. handle and name are conveniences and MAY be absent; id MUST NOT be.

assembled_by identifies the assembler. Where the assembler is the subject's own operator, it says so, because a self-assembled AgentDoc and a third-party one are different things to a reader and the difference should not require inference.

5.2 Sources

Each entry describes one thing the AgentDoc was built from:

{
  "id": "card",
  "kind": "a2a-card",
  "url": "https://example.com/.well-known/agent-card.json",
  "fetched_at": "2026-08-29T18:03:58Z",
  "digest": "sha256:…",
  "signature": "verified"
}

id is referenced by sections. kind names the sort of document, so a reader knows what rules govern it: a2a-card, agent-manifest, sow-standing-proposal, listing, reputation-report, roles-declaration, interface-definition, plugin-package, agent-descriptor, eval-record, and observation are defined here; others MAY be used and SHOULD be namespaced.

An interface-definition source is the published interface itself, fetched from the registry that publishes it. It describes the exchanges rather than the subject, and it is what §5.3.1 expands. Listing it is what keeps an expanded interface within §4.2: the exchanges are quoted from a document, not supplied by the assembler.

signature is one of verified, unsigned, failed, or not_checked. unsigned and not_checked are different facts and MUST NOT be collapsed: one says the document carried no signature, the other says this assembler did not look.

An observation source is something the assembler did rather than fetched: asking an agent whether it was free, and recording the answer and the moment. It carries at and what in place of url, and it is the only source kind that can go out of date within a minute, which is why §5.3's asked section carries its own timestamps.

5.2.1 Packaged agents as a source

Most agents will exist as a package before anybody writes them a document. plugin-package names one: a distributed bundle of instructions and tool declarations, the agent-plugins.org format being the common one. It is a legitimate source and this specification says exactly what may be taken from it, because the temptation to take more is strong and the package is not a document about the agent, it is the agent.

Derivable: the name, the version, the description, and the tool list split by transport. That split is the one thing in a package a buyer genuinely needs and cannot get elsewhere: a tool that runs as a local process is the provider's own machinery and says nothing about the buyer's risk, while a tool reached over a URL means content leaves the building, which is a fact about where the work happens. A package's skill descriptions MAY be carried as sells prose, marked as prose like any description.

Never derivable, and an assembler MUST NOT infer them: price, pricing arrangement, inputs, deliverables, refusals, jurisdictions, retention, interfaces, or admission. A package states none of these, and a document that appears to have them because a package was read is stating the assembler's guesses in the subject's voice, which §4.2 forbids.

Never carried at all: env values, command, args, cwd, and header values. These are bindings and machinery, and they are the members most likely to hold a secret. The rule is the §5.3.4 one, applied at the point of import.

An importer produces a draft, never an AgentDoc. A tool that reads a package and asks its author the questions the package cannot answer is a good tool, and what the author types MUST land in a signed card or standing proposal, from which an AgentDoc then assembles. Writing those answers straight into an AgentDoc would make the importer the one place in the system where a claim can be typed into a format built on there being nowhere to type one. §4.2 is what the format rests on, and it would be lost at exactly the moment the format got popular.

5.2.2 A declared role as a source

A roles-declaration source is a role's published contract, fetched from the registry that publishes it, listed because the subject itself declares the role: the role's standard offering name appears among the offerings on the subject's own card or manifest. The declaration lives in the card or manifest source already listed; this source is the contract that declaration points at.

An assembler MUST NOT list a role the subject has not declared. Behaving like a bookkeeper, being named like one, or matching one's description is not a declaration; the offering name on the subject's own registration is.

What the source fills, and at what strength. It fills the role section with the role's name and definition URL, which is that section's normal content. It MAY fill the matching inherited sections by citation: the asked exchanges from the role's primary interface (an interface-definition source, exactly as §5.3.1 already expands one), the role's refusals into refuses, and the role's handling rules into handling. Every member filled this way enters at the declared state and never higher, because a declared role is the subject's claim about itself: claiming the role is claiming the contract, and nobody has checked either. An evaluation record (§5.2.4) is what moves an inherited member past declared. It fills nothing else: a role says nothing about the subject's identity, price, address, or standing.

An inherited refusal carries kind: "role", a third value beside prose and clause (§5.3.3): stronger than a sentence in a description, because the subject staked a standard name on it, and weaker than a signed clause, because no counterparty holds it.

The vocabulary is shared with the roles registry on purpose: the same section and member names appear there in the imperative (what a holder must do) and here in the indicative (what this subject declares it does). The registry owns the must-form and this specification owns the does-form, and neither restates the other's.

5.2.3 The Agent Descriptor as a source

An agent-descriptor source is the subject's own Agent Descriptor: the operator's standing description of the agent, and the primary location for its metadata. Where one exists, it is the authored source for the sections it covers, and an assembler SHOULD prefer it over any projection of it.

What it fills: the one-sentence description, the offerings with their inputs and outputs into sells, interaction and the shape members into shape, the refusal prose into refuses (as kind: "prose"), the declared role and interfaces (which the assembler then resolves as §5.2.2 and §5.3.1 describe), the hosting regions, the standing systems into reaches, the shapes it reads into told, and the per-caller limits. Every member enters at the declared state, because a descriptor is the operator's word about their own agent.

Two rules travel with it. The source entry records the descriptor's digest, because a signed proposal references a descriptor at a digest, and a reader must be able to tell whether the document assembled here is the one a signature meant. And where a projection of the descriptor (a card or a manifest) disagrees with the descriptor itself, an assembler MUST NOT merge them silently: the descriptor's value is carried, and the disagreement is reported, because a projection that has drifted from its source is a defect a reader needs to see.

5.2.4 An evaluation record as a source

An eval-record source is a signed verdict from a conformance evaluation of the subject: an agent-eval-record-v1 document as the agent evaluator role defines it, naming the subject, the package or contract it was graded against by digest, and a per-case result.

It is the checking source: the one kind of document that can move an inherited or declared member to confirmed or failed. The mapping is per case and never wholesale. A passing case on an exchange or a refusal confirms that member, with the record's timestamp. A failing case marks it failed, and §5.3.1's rule holds here too: a recorded failure MUST NOT be silently downgraded to declared. A verdict whose overall answer is that the subject does not conform does not erase the subject's declarations; it sits beside them, case by case, which is exactly what a reader deciding whether to trust the subject needs to see.

An assembler MUST verify the record's signature against the evaluator key inside it and record the result in signature like any source, and MUST NOT treat an unsigned verdict as confirmation of anything.

5.3 Sections

Every section is optional. An absent section means the subject published nothing to build it from, and §6 requires that absence be named.

SectionWhat it holds
identityWho it is. Name, operator, address, and what signs for it.
shapeWhat it is. Whether it is a service or a person's own agent, what it runs on, whether it is one process or a fleet behind one identity.
askedWhat it can be asked. The largest section, and the one a caller acts on. Defined in full in §5.3.1.
roleThe standard role it holds, if any.
sellsWhat it actually does. Each offering with what the client furnishes, what comes back, and what it costs. Defined in full in §5.3.2.
toldWhat a caller may send along with a job and this agent will read, from the Descriptor's can_use member: each a published shape by schema, the fields of that shape the agent honors, whether one is required, and what those fields change about the result. Every entry enters at declared and stays there, because what an agent records about its own job confirms nothing about itself.
accessHow you reach it at all. Where a message is sent, what a caller presents, and who is let in. Defined in full in §5.3.4.
refusesWhat it will not do, and what it hands to a person rather than deciding. Drawn from its declared scope, its role's refusals, and its terms. This section is usually the most useful one on the page and is usually the emptiest, which is itself worth seeing.
reachesThe standing systems it runs with, from the Descriptor's systems member: a role, an access level, and what the access is for; and the spending ceilings its package suggests per system.
leavesThe records a job leaves behind, from the Descriptor's records member: each a name, when it is written, and the file it lands in. What an evaluation checks a real job left, and what a client can ask for afterwards.
handlingWhere it processes data and how long it keeps it, cited to the terms that promise it.
standingWhat third parties have published about it: reputation reports, attestations, directory checks. Carried, never audited, and attributed.

5.3.1 The asked section, in full

This is the section a caller actually acts on, and it is the reason an AgentDoc is worth fetching rather than reading a description. Everything else tells a reader what an agent is. This tells them what they can send it and what will come back.

An interface entry names the interface, the version, where its definition lives, and every exchange that definition publishes, each with its own state. It MUST NOT be reduced to a name and a version: a reader who has to go and fetch the interface definition to find out what they may send has not been given a description at all.

"asked": {
  "from": ["card", "iface-worker", "probe"],
  "interfaces": [
    {
      "name": "interface-worker",
      "version": "v1",
      "definition": "https://agentroles.ai/worker.html",
      "declared_in": "card",
      "exchanges": [
        {
          "id": "free",
          "asks": "are you free?",
          "answer_carries": ["free", "reason when not", "job when not"],
          "state": "confirmed",
          "confirmed_at": "2026-08-29T18:04:00Z",
          "confirmed_by": "probe"
        },
        {
          "id": "estimate",
          "asks": "what would this take?",
          "answer_carries": ["can (CAN|CANNOT|UNSURE)", "commitment", "note"],
          "state": "declared"
        }
      ]
    }
  ]
}

Three rules govern it.

The exchange list comes from the interface definition, and the definition is a source. An assembler does not invent the exchanges; it resolves the published interface and lists what that publication says, citing it like any other source (kind: "interface-definition"). This keeps §4.2 intact: the exchanges are facts from a document, not the assembler's summary of one.

State is per exchange, never per interface. An assembler that asked one exchange and got a conforming answer has confirmed one exchange. Marking the whole interface confirmed on that basis is exactly the overclaiming §4.2 forbids, in the place a reader is most likely to rely on it. The states are declared (the subject says it implements this and nobody checked), confirmed (this assembler asked and got a conforming answer, with the timestamp and the observation that did it), and failed (this assembler asked and the answer did not conform, which is a fact worth carrying and MUST NOT be silently downgraded to declared).

A declared interface with no exchanges listed does not conform. If the assembler could not resolve the definition, it says so with the interface present and its exchanges absent, and names the interface in not_stated. Silently emitting a bare name reads as a complete answer.

5.3.2 The sells section, in full

§5.3.1 says how to hand work over and follow it. This section says what the work is. They are different questions and a reader needs both: an agent can be perfectly answerable about a job it was never able to do.

Each offering carries what the client furnishes, what comes back, and what it costs, quoted from the standing proposal that offers it.

"sells": {
  "from": ["card", "terms"],
  "offerings": [
    {
      "name": "clause-review",
      "does": "Reads a contract and reports unusual or one-sided clauses.",
      "inputs": [
        { "name": "contract", "media_type": "application/pdf", "when": "per_task" },
        { "name": "house-positions", "media_type": "text/markdown", "when": "standing" }
      ],
      "deliverables": {
        "per_task": [
          { "name": "clause-report", "media_type": "application/pdf" },
          { "name": "flags", "media_type": "application/json" }
        ],
        "interim": [
          { "name": "summary", "media_type": "application/pdf",
            "recurrence": { "every": "month", "due_by_day": 5 } }
        ]
      },
      "price": "12000 XCR per document",
      "arrangement": "per_task",
      "minimum": 50,
      "does_from": "card",
      "steps": [
        { "id": "read-the-contract", "name": "Read the contract",
          "inputs": [ { "name": "contract", "media_type": "application/pdf" } ],
          "outputs": [ { "name": "clause list", "media_type": "application/json" } ] },
        { "id": "flag-the-clauses", "name": "Flag the clauses" }
      ]
    }
  ]
}

steps carries the offering's delivery steps, quoted from the Descriptor (Section 12.3) in the same shape as the offering and in order. A renderer shows them under the offering and never as offerings, and a caller MUST NOT send a step that is not also offered: what is for sale is the offering, and the steps are how it is delivered.

inputs carries name, media_type and when, which is per_task or standing. deliverables splits into per_task, the artifacts attached to each completed task, and interim, the engagement-level obligations the provider owes on a schedule whether or not the client asked. Each interim entry carries either a single due instant or a recurrence. All of these are Agent SoW's own members and this specification does not redefine them: it quotes them, and where that standard changes, this one follows.

minimum is a floor the offering's terms set, in whatever unit the price names. arrangement is the pricing arrangement the standing proposal declares. does is the one line description and carries does_from under §4.1, because it normally comes from the card while the clauses around it come from the terms.

Three things about this, and the first is why it belongs here at all.

These are not descriptions, they are obligations. Agent SoW grades both enforced. A task arriving without a required per-task input does not fail and is not silently attempted: it moves to input_required naming what is missing. A task claiming completion without every named deliverable, in the media type the clause names, is a failed task. So an AgentDoc reader is looking at what the runtime will hold the provider to, not at a brochure.

Form is enforced and quality is not, and an AgentDoc MUST NOT blur that. The document can say a PDF called clause-report will arrive. Nothing here says it will be any good; that is what reputation is for, and it belongs in standing.

does is prose and is marked as such. A one line description of the work comes from a text field somebody typed, usually the card's skill description. It sits next to inputs and deliverables that are signed clauses, and the section's provenance MUST make the difference visible rather than presenting one sentence and one clause as the same kind of claim.

An offering whose standing proposal names no inputs or no deliverables lists neither and names them in not_stated. An agent that has not said what it needs from you, or what you get back, has not promised either.

5.3.3 The remaining sections

The other six are small, and this is what they hold. Every one of them takes from like any section, and every member is optional: a member the subject never stated is absent here and named in §5.4, never guessed at.

"identity": {
  "from": ["card"],
  "name": "Clause Review",
  "operator": "Lawworks Ltd",
  "url": "https://lawworks.example"
},

"shape": {
  "from": ["card"],
  "interaction": "service",
  "harness": "...",
  "fleet": true
},

"role": {
  "from": ["card"],
  "name": "role-bookkeeper",
  "definition": "https://agentroles.ai/bookkeeper.html"
},

"refuses": {
  "from": ["card"],
  "statement": "Anything outside clause-review. It does not give legal advice.",
  "kind": "prose"
},

"reaches": {
  "from": ["descriptor"],
  "systems": [
    { "role": "crm", "access": "read", "needs": "the records the answers come from" }
  ]
},

"handling": {
  "from": ["terms"],
  "processed_in": ["eu", "de"],
  "retention_max_days": 30,
  "promises": ["no_training"]
},

"standing": {
  "from": ["bureau"],
  "reports": [
    { "by": "https://agentreputations.com", "url": "...", "as_of": "2026-08-01" }
  ]
}

Four notes, each of which is a rule rather than a preference.

interaction is the service-or-personal axis, not a description of the software. Whether one process answers or a fleet behind one identity does is fleet, and it is separately optional, because plenty of agents have never said.

refuses.kind is prose or clause. Almost every refusal in the wild is a sentence in a description field, and one that is actually a term in a signed proposal is a materially stronger thing. An AgentDoc that cannot tell which it has does not guess: it omits kind and the reader treats it as unknown.

refuses.hands_over carries the cases the subject hands to a person rather than deciding, from the Descriptor's escalates (Section 12), each a sentence and each prose.

reaches.ceilings carries the spending ceilings the subject's package suggests per reached system, as suggested: the host that installed the agent set the one in force, and an AgentDoc MUST NOT present a suggestion as the limit.

leaves.records carries the Descriptor's records as declared, and an evaluation record is what confirms a real job left them.

handling members are quoted from Agent SoW, like sells. promises is that standard's list and this one adds nothing to it.

standing carries other people's documents and audits none of them. Each entry says who published it, where it is, and what it was as of. An AgentDoc MUST NOT summarise, average, or grade what it finds there, which would be the summary grade §4.3 forbids, arrived at indirectly.

5.3.4 The access section, in full

asked says how to hand work over. sells says what the work is. This section says whether you can get to the agent at all, which is the question that comes before both and which nothing in this family could answer until the standards it quotes grew the members.

It carries two different facts, and merging them is the mistake it exists to prevent. schemes is what a caller presents. admission is who gets in. A caller can satisfy every scheme an agent publishes and still be refused, because the scheme says what to present and the policy decides who is admitted.

"access": {
  "from": ["card", "manifest"],
  "admission": "screened",
  "admission_from": "manifest",
  "schemes": [
    { "id": "mesh", "transport": "mesh", "type": "mesh-identity" },
    { "id": "gateway-key", "transport": "http", "type": "apiKey",
      "in": "header", "name": "X-Api-Key",
      "description": "issued by the operator once admitted" }
  ],
  "statement": "Open to any registered agent; paid work needs a signed agreement.",
  "statement_from": "card"
}

The two <member>_from pointers are §4.1 at work, and this section is the clearest case for them: the policy is a manifest fact and the sentence beside it is a card fact, so the section lists both sources and each member names which of them it came from.

admission is the closed set open, allowlist, screened, negotiated. schemes and admission are quoted from the subject's manifest or card (AgentMesh §8.12) and this specification defines neither: it quotes them, and where that standard changes, this one follows. statement is the free-text sentence beside the policy, carried as prose, exactly as refuses.statement is. Where both are present they are shown together and neither is treated as the summary of the other.

Beside them, address is where a message to the subject is sent (its handle, quoted from the registrar's card, which is the source that says so) and protocol names the transport it answers on; an assembler that holds the card and no access declaration carries the address and names access.schemes and access.admission in not_stated, because knowing where the door is says nothing about who it opens for.

Three rules govern it.

Silence, and "nothing required", are different, and both must be printed. Schemes present and non-empty means the subject said what to present. "schemes": [] means it said there is nothing to present. An absent access section means it never said, and §5.4 names it in not_stated like any other silence. A renderer MUST NOT show the third as the second. This is §6 applied where getting it wrong is worst: an agent that never described its door rendering as an agent with an open one is an invitation to send credentials to something nobody has checked.

An AgentDoc carries shapes and MUST NOT carry bindings, even when a source does. A published scheme is a requirement, not an address. No credential, token, key, account or tenant identifier, or per-caller URL or path may appear here. This rule binds the assembler and not only the subject, and the distinction matters: a directed Agent SoW proposal (§12.1.1 of that standard) legitimately names a counterparty's real repository or endpoint, because it is a term between two identified parties. An AgentDoc is a public document. An assembler that reads such a source MUST NOT copy those values into this section, and MUST NOT do so on the grounds that the source it came from was signed. A signature attests who said it, never that publishing it is safe.

A scheme list is alternatives. A caller satisfies any one of them. This is quoted from AgentMesh §8.12 rather than decided here, and it is stated because a renderer that presents a list as a checklist tells a reader they need credentials they do not need.

What the agent needs granted, which is not here

The other direction, what the agent asks you to grant so it can do the work, is deliberately not a member of this section. It is per-offering, not per-agent, and Agent SoW already types it: an input of kind: "shared_resource" with an access level, a when, and a via naming how the grant is made (§5.3.1 of that standard). It therefore rides in sells (§5.3.2) with the rest of what an offering asks for.

What this specification adds is a rendering rule, in §8: a grant MUST NOT be listed among the files a client sends. "Upload a PDF" and "give our agent read on your ticket system until you revoke it" are not the same sentence, and an offering that presents them as one has told the reader less than the page appears to say.

5.4 What is not stated

not_stated is an array of section or member paths the subject has published nothing about, for example ["role", "handling.retention_max_days"].

This exists because silence is the most common answer in this whole family and the easiest one to lose. A missing field renders as nothing at all, and nothing at all looks like a document that simply did not mention an unimportant detail. Naming it makes the reader see the agent declined, or never got round, to say where it processes your data.

6. Silence never resolves to the flattering value

An assembler MUST NOT substitute a default for a member the subject has not stated, and MUST NOT choose the reading that favours the subject.

An agent that has said nothing about retention has not promised to delete anything. An agent with no published price is not free. An agent that has not declared an interface does not implement it, whatever its prose says. An unreadable or malformed member is not-stated, not the safe-sounding value: a typo must never manufacture a promise.

Where a reader needs a default in order to act, the default belongs to the reader's own policy, applied by the reader, visibly. It does not belong in a document that describes somebody else.

7. What the subject controls

A subject MUST be able to correct an AgentDoc about itself, and the mechanism is already the design: change the signed source, and the next assembly changes with it. An assembler that continues to publish a section citing a source that has since changed, without re-fetching, is not conforming.

A subject MUST NOT be able to compel an assembler to omit a source it lawfully holds, or to remove not_stated entries. An AgentDoc that a subject can edit directly is the hand-written file §1.1 exists to prevent.

8. The human rendering

An AgentDoc SHOULD be renderable as a page, from the same document, with no additional input.

The rendering MUST show, for every section, which sources it came from, and MUST show not_stated as visibly as it shows what was stated. A renderer that hides absence produces exactly the flattering picture §6 forbids, by omission rather than by assertion.

The rendering MUST show when the AgentDoc was assembled, and where stale_after is present it SHOULD show that too. A reader who cannot see how old a view is has the one problem §4.4 exists to prevent, and a renderer is the easiest place to lose it, because a timestamp is the first thing a tidy-up removes.

The rendering MUST NOT introduce a badge, score, or trust mark that the document does not contain (§4.3).

Two rules apply to what an agent asks for, and both exist because the difference they preserve is invisible once it is lost.

Undeclared reach is not an empty reach. The reaches section holds the standing systems the subject runs with: a role, never a vendor or an address, an access level, and what the access is for. Where it is absent the rendering MUST show it as not stated and MUST NOT present the subject as touching nothing, because an agent that has said nothing about what it reaches has not promised it reaches nothing. Its members enter at declared like every authored claim, and a record that probes them moves them like any other.

A grant is not a file. Where an offering's inputs include a shared_resource (§5.3.2, quoting Agent SoW §5.3.1), the rendering MUST show those separately from inputs the client simply sends, and within them MUST show standing grants above per-task ones. A standing grant is the only thing on the page that is still true after the work is finished.

An undeclared door is not an open one. Where the access section is absent, the rendering MUST show it as not stated (§5.3.4) and MUST NOT render it as though nothing were required.

9. Relationship to the A2A Agent Card

The card is a source, and normally the first one. An AgentDoc restates card members in its sections and cites the card; it never contradicts it. Where the card carries family extensions, the terms extension in particular, the AgentDoc follows them to the documents they commit to and lists those as further sources.

An AgentDoc is therefore a superset of a card's content and a subset of a card's reach: the card is fetched by tools that have never heard of this specification, and it MUST remain valid and useful on its own. Nothing here asks an operator to stop publishing a card, or changes what a card means.

10. Conformance testing

Mechanical, and unusually easy for a document of this kind, because an AgentDoc makes claims about its own construction.

Given an AgentDoc and the ability to fetch its sources, a harness checks: that every section's from names sources that exist in the document; that every listed source is fetchable and, where a digest is recorded, matches it; that every fact in every section appears in one of that section's cited sources; that no member of the document is a summary grade; that assembled_at and per source fetched_at are present; that a member absent from every source appears in not_stated rather than being silently missing; and that no not-stated member has been given a default.

The one thing a harness cannot check is whether the subject's statements are true, and no version of this specification will claim otherwise.

11. Out of scope

  • Whether the subject is any good. AgentDoc reports what was said and by whom. Judgment is a matchmaker's job and quality is the reputation bureau's.
  • The formats of the sources. AgentDoc cites documents defined elsewhere and does not redefine any of them.
  • Discovery. Finding agents is a directory's job. This describes one agent to somebody who already has its address.
  • Access control. An AgentDoc is a description, not a credential, and grants nothing.
  • Deciding to engage. That is an act, taken with a reader's own key, on terms the sources define.

12. Signature tags

  • agentdoc-assembly-v1: an assembler's statement that it gathered the listed sources at the stated time and reported them faithfully (§4.5). Signed with the family convention: the ASCII tag, one newline, then the JCS (RFC 8785) canonical JSON with signatures removed.

signatures is an array, so an AgentDoc MAY carry more than one, and each entry has the same shape:

{ "tag": "agentdoc-assembly-v1", "by": "ed25519:2c88...70fa", "sig": "..." }

by is the signer's public key, which for this tag is the assembler's own. sig is the detached signature over the bytes described above, encoded the way the rest of the family encodes them. An entry whose tag a reader does not recognise is skipped, not treated as a failure: an unknown signature is somebody else's business.

The subject signs nothing here. Its statements are signed in their own documents, which is where a reader should go to check them, and saying so is what the format is for.

v0.1.0-draft (2026-08-29): first draft. Section 4 is where the design is decided; argue with 4.2 and 4.3 first. The first decides whether this stays a view or becomes another place to type a claim, and the second decides whether it stays useful or becomes a badge people optimise for.

v0.2.0-draft (2026-08-29, later): the asked section becomes the centre of the document rather than one row in a table (§5.3.1). In the first draft it was a name and a version per interface, which is not enough: a caller still had to go and fetch the interface definition to learn what they were allowed to send. It now carries every exchange the definition publishes, with what each answer must carry, and the interface definition is itself a listed source (interface-definition) so the expansion stays inside §4.2 rather than becoming the assembler's summary. State moved from per interface to per exchange, because an assembler that asked one exchange has confirmed one exchange and marking the whole interface confirmed is overclaiming in the one place a reader is most likely to act on it. A third state, failed, is carried rather than quietly downgraded to declared.

v0.3.0-draft (2026-08-30): the sells section gets the same treatment asked got, and for the same reason (§5.3.2). It was a name and a price, which describes the transaction and not the work: a reader could see that a clause review costs 12,000 XCR without learning that it wants a PDF and returns a report and a JSON list of flags. Each offering now carries what the client furnishes and what comes back, quoted from the standing proposal, with the media types. This is deliberately not a new vocabulary: Agent SoW §5.3 and §5.4 already define inputs and deliverables and grade both enforced, so what an AgentDoc shows here is what the runtime will actually hold the provider to. Form is enforced and quality is not, and the section says so rather than letting a named deliverable read as a promise that it will be good.

v0.4.0-draft (2026-08-30): the specification catches up with its own worked example, which had got ahead of it. The example was using members this document never defined, which meant a second implementer would have had to guess at them, so: §5.3.3 gives real shapes for the five sections that until now were a sentence each, §5.3.2 gains interim deliverables and minimum, and §12 says what a signature entry looks like rather than only naming its tag. §4.1 generalises the one thing the example had invented outright: a member MAY carry <member>_from naming which of its section's sources it came from, which is a narrowing and never a widening. §8 now requires a rendering to show when the document was assembled, because the page had quietly dropped that in a tidy-up and nothing here had stopped it.

v0.8.0-draft (2026-09-01): the reaches section. The descriptor's standing systems now have a home: what the subject runs with, as shapes (a role, an access level, a purpose), never a vendor or an address. Absent renders as not stated, never as touching nothing (§8). This is the section a grantor reads before granting anything, which is why it exists.

v0.7.0-draft (2026-08-31, later): the Agent Descriptor becomes an official source (§5.2.3). The Descriptor is the operator's standing description of the agent and the primary location for its metadata, so where one exists an assembler prefers it over any projection of it, records its digest, and reports rather than merges when a card or manifest has drifted from it. Its members enter at declared like every authored claim. The evaluation record moves to §5.2.4.

v0.6.0-draft (2026-08-31): a declared role becomes a source, and an evaluation becomes the check. A subject that advertises a standard role's offering name has pointed at a whole contract, and §5.2.2 lets an assembler fill the matching sections by citation from it, every inherited member entering at declared and never higher, because claiming a role is a claim. §5.2.3 adds the evaluation record as the source that moves members past declared: a signed conformance verdict confirms or fails them case by case, and a failure is carried, never downgraded. Refusals gain a third kind, role, between a sentence in a description and a signed clause. The vocabulary is shared with the roles registry deliberately: the registry owns the must-form and this specification owns the does-form.

v0.5.0-draft (2026-08-30): how you reach it at all, and what a package may be read for. The document could say what an agent does, what it charges, what it refuses and where it processes data, and could not say whether reaching it took an API key, an invitation, or nothing. New §5.3.4 adds the access section, carrying two facts that must never merge: schemes is what a caller presents, admission is who gets in, and satisfying every scheme and still being refused is normal rather than a fault. Both are quoted from AgentMesh §8.12, which grew them for this. Three rules travel with it. Silence and "nothing required" are different and both are printed, because an agent that never described its door must never render as one with an open door. An AgentDoc carries shapes and never bindings, and that binds the ASSEMBLER, not only the subject: a directed Agent SoW proposal may lawfully name a real endpoint, and copying it into a public document is not made safe by the source having been signed. And a scheme list is alternatives, so a renderer must not present it as a checklist. The other direction, what the agent asks you to grant, deliberately gets no member here: Agent SoW §5.3.1 now types it as a shared_resource input with a via, so it rides in sells with the rest of what an offering asks for, under a new §8 rule that a grant is never listed among the files a client sends. New §5.2.1 adds plugin-package as a source kind, because most agents will be packaged before they are documented. It names what may be derived (name, version, description, and the tool list split by transport, which is the one thing a package tells a buyer that nothing else does), what may never be inferred (price, inputs, deliverables, refusals, jurisdictions, retention, interfaces, admission), and what is never carried at all (env, command, args, cwd, header values). It also settles the question the format would otherwise lose: an importer produces a DRAFT of a signed source, never an AgentDoc, or the importer becomes the one place a claim can be typed into a format built on there being nowhere to type one.