What Is an Agent Manifest, and Why Your API Needs One

What Is an Agent Manifest, and Why Your API Needs One

E
By Etzal Earth
12 min read

An API that is only documented in prose is invisible to a machine. A human developer lands on a docs site, reads the overview, works out the auth model, finds the endpoint that looks relevant, and infers from an example what the fields mean. An agent does none of that. It either receives a structured description of what is available or it does not know the API exists.

That structured description is the manifest. It is not a marketing artefact and it is not an alternative to documentation. It is the thing that determines whether an automated consumer can find a capability, call it correctly, and interpret what comes back.

The interesting part is the third one. Most manifest formats handle discovery and calling adequately. Almost none of them handle interpretation, and interpretation is where automated consumers cause damage.

Discovery is the precondition for everything

An agent operating with a set of tools works from a list. If a capability is not on that list, it does not exist, regardless of how good the underlying service is. There is no equivalent of a developer stumbling across a useful endpoint.

This is a harsher constraint than it first appears, because it applies at the granularity of individual capabilities rather than whole services. An API with twenty endpoints where the manifest describes twelve is an API with eight endpoints, from the perspective of every automated consumer. The other eight will never be called, and no error will ever be raised about them.

It also applies to conditions. If a capability exists only for certain regions, certain entity types, or certain time ranges, and the manifest does not say so, agents will call it universally and receive empty results. An empty result is not self-describing. It could mean the thing does not exist in the world, or that the API does not cover that area. An agent with no way to distinguish those will usually pick the first interpretation and report a fact about the world that is really a fact about coverage.

The design conclusion is that a manifest should describe not just what exists but where and when it applies. Coverage is part of the interface.

What a manifest has to contain

The mechanical parts are the obvious ones and they are where most formats stop.

  • The set of callable operations, each with a stable identifier, a name a model can reason about, and a description written for selection rather than for reference.
  • The parameters of each operation, with types, units, enumerated values where the vocabulary is fixed, ranges where they exist, and defaults for everything optional.
  • The shape of the response, described precisely enough that a consumer can plan what to do with it before calling, including which fields are always present and which are conditional.
  • The error taxonomy: what can go wrong, how it is signalled, and which failures are worth retrying.
  • Authentication, if any, and the scopes or permissions each operation requires.
  • Cost and latency characteristics, at least coarsely, so a caller with a budget can plan.

The part that gets omitted is the semantic contract: the rules that govern what the returned values mean. A field described only as a number of type integer tells a consumer how to parse it and nothing about how to use it.

The semantic contract answers questions like these. What exactly is being counted or measured, in operational terms rather than in a label. What is the provenance class, meaning whether the value was observed, aggregated from official records, or inferred by a model. What does absence signify, and specifically whether a missing field means zero, means unmeasured, or means suppressed. What spatial or temporal unit was the figure computed over, since a density computed per district and one computed per grid cell are not comparable and nothing in the numbers reveals the difference. How current is it, meaning the acquisition date of the underlying data rather than the response timestamp.

These are the things a careful human infers from documentation, examples, and a support conversation. An agent has none of those channels, so if the manifest does not carry them, the semantics are simply lost.

Side effects, and what is safe to retry

A property that human developers infer from an operation's name and a machine cannot is whether calling it changes anything.

An agent plans by trying things. It will call an operation to see what comes back, call it again with different arguments when the first result was not useful, and retry when a call times out without knowing whether the original request was processed. All of that is fine against a read. Against an operation with side effects it produces duplicated work, duplicated charges, or duplicated records.

The manifest should therefore declare, per operation, whether it is read-only, whether it is idempotent, and whether it costs money. Read-only means an agent can call it speculatively and in parallel without consequence, which is the licence a planner needs to explore. Idempotent means a retry after an ambiguous timeout is safe, which is the single most useful thing a caller can know when the network fails mid-request. Non-idempotent operations should say what mechanism makes a retry safe, usually a client-supplied request identifier the server deduplicates on, and the manifest should describe that parameter as required rather than optional.

The default assumption in the absence of a declaration is the dangerous one. A caller with no information tends to treat an operation as retryable, because retrying is what its transport library does automatically. An operation that is not safe to retry and does not say so will be retried.

Cost declaration belongs in the same block for the same reason. An agent that knows one operation is free and another triggers a paid lookup can order its plan to exhaust the free options first. An agent that cannot tell them apart will call them in whatever order the plan happened to produce.

The honesty contract belongs in the manifest

There is a specific ordering problem worth designing around. An agent reads the manifest before it reads any response. Whatever vocabulary the manifest establishes is the vocabulary it will use to interpret every number that follows.

That makes the manifest the right place to define what uncertainty means in this API, before any uncertain value is encountered. If responses carry a confidence field, the manifest should state the possible values, what each one licenses a consumer to do, and what none of them licenses. If unknown is a distinct state from zero, and it should be, the manifest has to say so explicitly, because the default behaviour of a naive consumer is to coerce a missing number to zero and continue.

Concretely, a manifest that carries an honesty contract states things like: that a confidence marker accompanies every derived figure and is never absent; that a value of unknown means the system could not determine the quantity and must not be treated as zero, as an average, or as small; that figures marked low confidence should not be combined arithmetically with other low confidence figures without the result inheriting the lower confidence; that a refusal to answer is a successful response rather than an error condition.

There is a second-order benefit. Publishing the contract in a machine-readable form makes it testable. A contract that lives in prose can drift from behaviour indefinitely and nobody notices. A contract expressed as a manifest field can be checked against actual responses in continuous integration, which turns an aspiration into a constraint.

Versioning without breaking existing agents

Manifests change, and the consumers are automated systems that were built against a previous version and are not being actively maintained. The versioning discipline needed here is stricter than the one most APIs run.

The safe class of changes is additive. Adding a new operation, adding an optional parameter with a default, adding a field to a response. Existing consumers ignore what they do not know about and continue working. The overwhelming majority of manifest evolution can be made to fit this shape with a little discipline.

The dangerous changes are the ones that alter meaning without altering structure. Changing the unit of a field. Narrowing what a field counts. Changing the default of an optional parameter. Tightening a validation rule so previously valid calls now fail. None of these break a schema check, and all of them break consumers silently, producing wrong answers rather than errors. A semantic change to an existing field should be treated as a new field with a new name, with the old one retained and marked deprecated, however inelegant that feels.

Deprecation needs to be machine-readable rather than announced in a changelog nobody's agent reads. A deprecated flag on an operation or a field, with a replacement identifier and a date after which the behaviour changes, gives an automated consumer something it can act on: it can prefer the replacement, warn its operator, or at minimum record that it is depending on something scheduled for removal.

Version the manifest itself, and let a consumer request a specific version. An agent built against a known version and pinned to it is stable. An agent reading whatever the latest manifest says is at the mercy of every change, which is fine for a supervised system and unacceptable for an unattended one.

Generated, never hand-maintained

A hand-written manifest is accurate on the day it is written and drifts from that point forward. The drift is not visible, because nothing validates prose against behaviour, and it is not uniform: the parts that change most often, which are the interesting parts, drift fastest.

The consequence is worse for a manifest than for documentation. Stale documentation confuses a human who then investigates. A stale manifest silently causes an agent to call a parameter that no longer exists, interpret a field with the wrong unit, or ignore a capability that was added months ago. The agent has no mechanism for noticing that the description and the reality have diverged.

So the manifest should be derived from whatever the service already treats as authoritative: route definitions, validation schemas, response type definitions. If parameter validation is expressed as a schema at runtime, that schema is the truth and the manifest should be generated from it, not typed alongside it. When the two are generated from one source, an implementation change that is not reflected in the manifest is impossible rather than merely discouraged.

The semantic parts cannot be inferred from types, which is the honest limit of this approach. A generator cannot know that a field is in metres or that missing means unmeasured. Those have to be declared, but they can be declared next to the definition rather than in a separate document, as annotations that travel with the code. The generator then assembles them. The test that the arrangement is working is that a developer cannot add a field without being forced to say what it means.

It is worth adding a build step that fails when a capability lacks the semantic annotations. Making the manifest a hard requirement rather than a courtesy is the only reliable way to keep it complete once the service has more than a handful of contributors.

Documentation for humans, contract for machines

These are different artefacts with different success criteria, and treating one as a rendering of the other degrades both.

Documentation for humans is allowed to be selective, to teach in an order that builds understanding, to include worked examples, to explain motivation, and to leave out edge cases that would obscure the main path. Its success criterion is comprehension. A developer who reads it and comes away with a correct mental model has been well served, even if the document omitted half the parameters.

A contract for machines has the opposite obligations. It must be complete, because omission is invisibility. It must be uniform, because a consumer applies the same parsing logic to every entry. It must be precise about units, ranges, and absence, because there is no reader who will notice an ambiguity and ask. It cannot teach, motivate, or prioritise, because those depend on a reader building understanding over time, and there is no such reader.

The failure that comes from conflating them runs in both directions. A manifest written like documentation is chatty, incomplete, and inconsistent between entries. Documentation generated from a manifest is an exhaustive parameter table that teaches nobody anything and is functionally useless as an introduction.

Write both. Generate the manifest from the source of truth, write the documentation by hand for people, and accept that they overlap in content while differing entirely in what they are for.

The check that tells you it is real

There is a straightforward test of whether a manifest is doing its job, and it does not require any tooling.

Take the manifest alone, without the docs site, without the examples, without anyone to ask. Give it to a competent consumer who has never seen the service. Ask them to answer a real question using only what the manifest says, and then ask them what they would be willing to claim about the answer.

If they can find the right capability, call it correctly on the first attempt, and describe the limitations of the result without having been told any of that separately, the manifest is a contract. If they can call it correctly but cannot say what the number means or how much to trust it, the manifest is a schema, and the semantics still live in the heads of the people who built it. That gap is where automated consumers do their damage, and it closes only by writing the meaning down where the machine can read it.