TL;DR: A card nobody can find is not a card. The catalog faf cards writes now names who publishes it, keys every row the way the specs say to, and can be written as the ARD manifest agent search engines read.

In Plain English

Old state. You published a catalog of your agent's cards, and it was technically valid — but it never said who published it, and its row names were built from whatever your homepage happened to be. Search engines for agents either skipped it or filed it under the wrong owner.

Fix. Name the publisher. Key every row off the domain your .fafa actually declares. Write the file the agent search engines come looking for.

New state. The same command writes a catalog that reads as discoverable, with identifiers both specs accept.

npm install -g faf-cli@7.16.1 faf cards --target catalog,ard

The receipt

This edition exists because of one line. Here is the identifier faf-cli used to emit for an agent whose short name was Weather Bot:

urn:air:acme.example:a2a:Weather Bot

The AI Catalog validator accepts that. ARD's conformance tool rejects it outright — three errors, "does not match RFC 8141 URN pattern". Same file, same line, two verdicts. A URN may not carry a space, and a display name is free text.

It was also keyed to the wrong publisher: the host of your homepage, rather than the domain your .fafa declares. So a catalog could name one publisher at the top and file every row under another.

Both are fixed, and both paths — the CLI and the library — now derive one identifier. An identifier is a catalog's primary key. It was worth fixing before anyone was holding a reference to it.

Naming who publishes

AI Catalog reads a catalog at Level 1 minimal until it names a host. With a host, it reads as Level 2 discoverable. faf cards --target catalog wrote the first; now it writes the second.

displayName is the field that earns the level — and an empty one is invalid, not merely minimal. So a .fafa that names nobody gets no host at all: a minimal catalog that validates beats a discoverable one that doesn't.

On a catalog you share with other publishers, host is the one key faf adds, and only when the catalog names none. A host already there is yours, and stays byte for byte.

Where the manifest actually lives

faf cards --target ard writes /.well-known/ard.json — the rows plus the search hints registries index on, read from your .fafa: metadata.cards.keywords become tags, metadata.cards.examples become representative queries.

Choosing that path took reading both the spec and its tooling, because they disagree. The ARD prose still points at /.well-known/ai-catalog.json; ARD's own conformance CLI says a consumer MUST fetch /.well-known/ard.json and calls the other one the predecessor. The tool is newer than the document, so faf writes what consumers are told to fetch — and --target catalog,ard writes both.

One more thing the tool taught us: a manifest with no representative queries is valid and unfindable, because the semantic index is built from that field. Rather than write a card nobody can find, faf cards now says so in one line and names the key to fill in.

Bounds

  • Specs move, and these two are early. ARD says "Proposal"; its prose and its conformance tool currently disagree about the well-known path. We wrote to the tool and said why.
  • A schema URL upstream is missing. A Server Card carries a $schema, and the spec names one URL for it. That URL returns 404 today. We write it as the spec names it; it resolves when upstream publishes the file.
  • Identifiers changed. If your .fafa declares a domain other than its homepage host, or its name was never a handle, your rows get different identifiers than 7.15 wrote. That is the fix, and it is a breaking one for anything holding the old key.
  • Windows ships, Windows isn't gated. faf-cli runs on Windows and builds a Windows binary; there is no Windows job in CI, by a documented decision. A real pre-merge Windows gate is a tracked follow-up.

Try it

Install:

npm install -g faf-cli@7.16.1 faf cards --check

Try (no install):

npx --yes faf-cli@7.16.1 --version

--check prints the cards without writing them. Same CLI under the shorter name: npm i -g faf@7.16.1. More: docs.faf.one/cards · release notes · repo.

Technical details

  • Version: 7.16.1 (September 16, 2026)
  • Packages: faf-cli and faf (same bits) · Homebrew
  • New target: faf cards --target ard → /.well-known/ard.json
  • Checked with: ai-catalog-cli v0.2.2 · ARD conformance CLI v0.9.1
  • Tests: 2050 passing