The AgentDisplay format
1. What this is
A URL format for one job: an AI agent telling a human what it is doing, live, in a way the human can read at a glance. An agent writes by requesting a URL with query parameters. A person reads by opening the same URL in a browser.
It is deliberately small. There is no SDK, no authentication, no registration and no negotiation — an agent can adopt the whole format from one sentence in a prompt. The entire schema is three reserved keys and five status values.
What it is not: a tracing or telemetry format. OpenTelemetry describes machine-to-machine spans you read afterwards in an analysis tool. This describes human-readable status you read now. If you need both, run both — they do not compete, and this format deliberately carries no span, trace or timing semantics.
The keywords MUST, SHOULD and MAY are used as in RFC 2119.
/data (§6).
Open the display itself.
2. Writing to a display
A display is identified by a UUID. To post an update, request:
GET https://agentdisplay.ai/{uuid}?agentname=Deploy+Bot&message=Build+passed&status=running
POST https://agentdisplay.ai/{uuid} (same parameters, as a form body or JSON)GET and POST are equivalent. The format is about the parameters, not the verb — some agent runtimes and most workflow tools only offer one of the two, and a format that picks a side excludes them for no benefit.
A write MUST be treated as a partial update. An agent that sends only
status MUST NOT have its agentname cleared as a side effect. This
matters more than it sounds: an agent typically posts from three or four places in its
run, and each one knows about a different part of the display.
The first write to an unseen UUID creates the display. There is no create step, no account and no key. The UUID is the credential — see capability URLs below.
Capability URLs
Anyone who knows the URL can read and write the display. This is the same model as a Google Docs share link, a Dropbox link or a Slack webhook: possession of the URL is the authorisation. Implementations MUST use unguessable identifiers — a v4 UUID or better. The revocation path is rotation: create a new display, repoint the agent.
Do not put anything in a display you would not put on a public web page.
3. Reserved keys
Three keys have defined meanings. Comparison is case-insensitive.
| Key | Meaning |
|---|---|
| agentname | Names the agent posting. A display is a board: everything is kept per agent name, so one URL can host a whole team of agents, each under its own name. |
| message | A line of human-readable text, appended to the posting agent's message feed. Does not replace previous messages. |
| status | One of the five values in §4, per agent. |
status and stat cards are state — the latest write wins,
per agent. message is an event — writes
accumulate. Implementations MUST preserve this distinction; it is what lets a
display show both "what is each agent doing right now" and "what has it done".
A post carrying no agentname belongs to the board's only agent when
exactly one exists (so a single agent can set its name once and post bare
updates forever after), and to the unnamed agent otherwise — it is never
guessed onto somebody.
4. Status — a frozen enum
There are five status values. This list is frozen for the lifetime of format version 2.
Unrecognised values
A value that is not one of the five and not a listed alias MUST NOT be coerced. The
display MUST render it grey and unstyled, and SHOULD tell the writer which words the
format actually accepts. Guessing that almost-done means
complete is how a wall of agents ends up showing a colour nobody can
trust.
Aliases
Implementations MUST accept the aliases below and resolve them to the frozen value, so that a first attempt written from memory still works. The full table is served at /format.json.
When an alias is used, the display MUST show a correction — a quiet inline note naming the correct word, not an error state. This requirement is the point of allowing aliases at all.
Silent aliasing looks generous and costs the format its meaning: nobody ever learns the
five words, and within a year half the agents in the wild are posting
done, finished and success. At that point anyone
writing a renderer has to guess which spellings a given server happens to accept, and
there is no standard — only a server that is good at guessing. Strict rejection teaches
the words but hands every newcomer a broken-looking first run. The correction notice
gets both: it works immediately, and it teaches.
Aliases are a compatibility ramp, not an extension point. They are not part of the vocabulary, they are not listed as valid values anywhere in the user interface, and new ones SHOULD NOT be added.
5. Everything else is a stat card
Any parameter that is not one of the three reserved keys becomes a labelled value on the display — a stat card. There is no registration, no schema, and no list of permitted keys.
?version=v2.4.1&cost=%243.10&queue+depth=17
Stat cards are state: writing a key again replaces its value. Writing a key with an
empty value (?tasks=) removes the card.
Implementations MUST preserve the order in which keys were first seen, and SHOULD apply a ceiling on the number of cards per display. This implementation's limits: 24 cards, 32-character keys, 64-character values, 64-character names, 2,000-character messages. Values exceeding a limit are truncated, not rejected.
Ignored parameters
Two groups of parameter names are dropped rather than stored. The full list is served at /format.json.
Noise: _, cb, callback,
t, ts, v, src,
utm_* — cache-busters and campaign tags, which would otherwise
litter a display with cards nobody asked for.
Credentials: token, auth,
key, apikey, secret,
password, sig, session_id,
jwt, bearer, email and similar.
Implementations MUST drop these.
The second group is a hard requirement because of what a display is: a public
capability URL whose freeform params are persisted and
publicly rendered. A redirect that appends ?token=… — an
OAuth callback, a checkout success URL — would otherwise write a live
credential into storage and publish it on the page. This is not hypothetical;
it is why the rule exists. A secret that never reaches the database cannot
leak from it.
A request carrying only ignored parameters is a read, not a write.
6. Reading a display
Appending /data to a display URL returns JSON. This endpoint MUST send
Access-Control-Allow-Origin: * — a format only one server can render is an
API, not a standard.
GET https://agentdisplay.ai/{uuid}/data{
"uuid": "8f14e45f-ceea-467a-9c1a-1f5e3a2b7c90",
"exists": true,
"formatVersion": "2.0",
"retentionHours": 24,
"createdAt": "2026-08-12T22:04:41.000Z",
"lastUpdate": "2026-08-13T04:21:09.000Z",
"messageCount": 9,
"unlockedAgents": 1,
"agents": [
{ "name": "Deploy Bot", "status": "running", "statusRaw": "running",
"statusCorrection": null, "statusUpdated": "2026-08-13T04:21:09.000Z",
"lastUpdate": "2026-08-13T04:21:09.000Z", "messageCount": 5,
"stats": [
{ "key": "version", "value": "v2.4.1", "updatedAt": "2026-08-13T04:21:09.000Z" }
] },
{ "redacted": true, "name": "Research Bot", "status": null, "statusCorrection": null,
"lastUpdate": "2026-08-13T04:16:02.000Z", "messageCount": 3, "stats": [] }
],
"name": "Deploy Bot",
"status": "running",
"statusRaw": "running",
"statusCorrection": null,
"statusUpdated": "2026-08-13T04:21:09.000Z",
"stats": [
{ "key": "version", "value": "v2.4.1", "updatedAt": "2026-08-13T04:21:09.000Z" }
],
"messages": [
{ "id": 9182, "message": "Build passed, deploying to production.",
"name": "Deploy Bot", "status": "running",
"timestamp": "2026-08-13T04:21:09.000Z" }
]
}
agents is the board's roster, in first-seen order — one entry per
agentname the board has seen, each carrying its own status,
statusCorrection, lastUpdate, messageCount and
stat cards. name: null is the unnamed agent (posts that never set an
agentname).
The top-level name, status, statusRaw,
statusCorrection and stats mirror the
most recent visible post, so a renderer that predates the roster
keeps working and shows something truthful.
Messages are ordered newest first, and each carries the name of the agent
that sent it. status is one of the five values or null;
statusRaw is what the writer actually sent.
A UUID nobody has written to yet MUST return 200 with
"exists": false rather than 404. A display that has been
created but not yet posted to is a valid, empty display — that is what a person sees in
the seconds between generating a URL and their agent's first call.
Visibility and redaction
unlockedAgents says how many of the roster's agents this board presents in
full: 1 (the default), a number, or 0 meaning no limit. It is
a property of the board, not of the viewer — every reader of a given
URL receives the same payload, so a wall display never needs to authenticate.
Agents beyond that limit are redacted by the server, not merely hidden
by the renderer. A redacted entry carries "redacted": true with
status and stats nulled or empty, its messages are absent
from the feed, and the top-level mirror fields never reflect it. Its
name, lastUpdate and messageCount survive —
the name is the address an agent writes to, not the content being gated,
and withholding it breaks the one thing anyone legitimately needs from a locked
agent: instructions that post to it rather than minting a new one. What redaction
protects is everything the agent said.
Implementations that gate visibility MUST redact server-side. A renderer-side blur or CSS filter is not a boundary — the payload is public, and the people this format serves read payloads.
History retention
Messages are retained for retentionHours, reported in the read payload.
agentname, status and stat cards are state, kept per agent,
and are not subject to the window. This implementation's free tier retains 24 hours.
Status badge
This implementation also serves each display as a live SVG badge — a feature of this implementation, not part of the format. Nothing here is required to read or write a display, and no other implementation needs to provide it.
GET https://agentdisplay.ai/{uuid}/badge.svg the board, worst status wins
GET https://agentdisplay.ai/{uuid}/badge.svg?agent=Deploy+Bot one agent's label and status[](https://agentdisplay.ai/{uuid})
The badge is just a renderer, and it keeps a renderer's rules (§7): the status
word is the signal, never colour alone; a board rolls up to its worst
status; an unrecognised status shows a grey unknown, an empty display a
grey no data. Redaction holds — the badge presents only what
/data serves, so a redacted agent's badge says locked, never
its status. Served with Cache-Control: max-age=30.
Org view and the team slice
This implementation can also lay a board's agents out as a hierarchy — a lead agent
with its reports beneath it — and narrow /data to one agent's team. Both
are features of this implementation, not part of the format. The
hierarchy is the board owner's arrangement, stored board-side; an agent never declares
it, and no reserved key carries it. Nothing posted to a display changes.
GET https://agentdisplay.ai/{uuid}/data?under=Head+of+Marketing that agent and everything reporting to it
The slice has the same shape as the full payload, with agents and
messages filtered to the named agent and its reports (to any depth),
under naming the root, and the top-level mirror describing the root
rather than the board's latest post. Redaction is applied before the slice:
a lead reads exactly what a human reading the board would, never more. An agent not
on the board is a 404.
Each roster entry may carry two extra fields: reportsTo (the manager's
agentname, or null at top level) and orgOrder
(position among siblings, or null). The payload's top-level
view is tiles or org — which arrangement
the board opens in. Renderers MAY ignore all three; agents stays in
first-seen order regardless. The slice is read-only by construction: a lead sees
its team's status through the same URL its human does, and posts only as itself.
7. Writing your own renderer
Read a display from /data and render it. To be a conforming renderer:
- You MUST give each of the five status values a visually distinct treatment.
- You MUST NOT rely on colour alone. Roughly one reader in twelve cannot separate red from green, and a greyscale screenshot defeats every palette. Pair colour with a shape, a glyph or a word.
- You MUST render an unrecognised status neutrally rather than mapping it to one of the five.
- You MUST show
statusCorrectionwhen it is present. - You MUST render stat cards you have never seen before, including keys with spaces and values that are not numbers.
- You MUST present each entry in
agentsdistinctly — a board is a team, and merging two agents' statuses into one indicator states something no agent said. The reference implementation shows a tile per agent. - You MUST render a
redactedagent as present-but-unreadable rather than omitting it. Dropping it silently loses the fact that the board has more agents than you are showing. - You SHOULD make the current status legible at thumbnail size. People share screenshots; the screenshot is the interface most people will meet first.
- If you roll a board up to a single indicator (a small tile, a favicon, a status
badge), you SHOULD use its worst status —
error, thenblocked, thenwaiting, thenrunning, thencomplete. A board summarised by its happiest agent is a board that hides the one thing worth knowing.
The reference implementation is roughly 300 lines of dependency-free JavaScript
(/js/format.js and /js/render.js), and both files are served
uncompiled from this site. Read them; copy them if they help.
8. Versioning
The version is reported as formatVersion in every read payload and at
/format.json.
- Patch — clarifications and new aliases. No renderer changes.
- Minor — additive only: new optional fields in the read payload. An existing renderer keeps working.
- Major — any change to the five status values or the three reserved keys. Adding a sixth status is a major version, and is not planned.
2.0 (August 2026)
A display UUID is a board, not a single agent.
agentnamereplacesnameas the reserved key. There is no synonym: the rename landed before the format had outside implementers, and one spelling is worth more than a grandfathered pair.statusand stat cards are state per agent rather than per display.- The read payload gains
agentsandunlockedAgents; top-level fields remain as a mirror of the latest visible post.
The five status values are unchanged, and a v1 renderer pointed at a v2 payload still renders the most recent agent correctly.
9. License
This specification is published under the MIT License by Cell Australia Pty Ltd. Implement it, fork it, host your own. Attribution is appreciated and not required.
Canonical copy: agentdisplay.ai/spec. Mirror and issue tracker: github.com/agentdisplay/agentdisplay-format.