Federation
document:docs/federationOne company catalog from catalogs each team owns, EventCatalog projects included, pinned to reviewed commits.
Federation
Section titled “Federation”Each team keeps its catalog with its code. The company site composes them into one catalog. Teams change their documentation through their own pull requests. The site only says which catalogs belong in it and which commit of each to build.
Sources
Section titled “Sources”A source is an autocatalog repository or an EventCatalog project.
- Repositories are enrolled as the company site describes:
every repository with a GitHub topic,
--repo <url>, or checkouts on disk. A monorepo can hold several catalogs, and each package that publishes one is found where it is, with no paths to configure. - EventCatalog projects are federated as they are. Any folder with an
eventcatalog.config.js(or.mjs,.cjs,.ts) is read as one source, named after its folder.ac siteimports it into a cache folder it owns, so nothing is written to the project’s checkout and nothing needs migrating. A project named like one of the site’s own pages, such ascatalog, publishes ascatalog-eventcatalog.
# A monorepo of EventCatalog projects, one company sitenpx autocatalog site ./catalogsReferences across catalogs
Section titled “References across catalogs”A team names what another team owns by id, as EventCatalog does. Nobody copies
the other team’s definition. ac from-eventcatalog and federated EventCatalog
projects keep these references in autocatalog.consumes.json, and you can
write them yourself:
{ "receives": [{ "service": "Warehouse Service", "id": "order-completed", "version": "^1.0.0" }], "sends": [{ "service": "Checkout Orchestrator", "id": "create-order" }]}The site resolves each one against everything composed:
| Pointer | Names an event | Names a command |
|---|---|---|
receives | the service consumes it | the service handles it |
sends | the service produces it | the service sends it |
id is bare or domain/id. version is an exact version, latest, or a
range: ^1.0.0, ~1.2, 1.x, >=1.0.0 <2.0.0, and || between
alternatives. Without one, or with latest, the newest stable release wins, and
a prerelease is chosen only when no release exists. A prerelease satisfies a
range only when the range names a prerelease of the same version, so ^1.0.0
never picks 1.1.0-beta.1. Earlier versions count: a repository that publishes
only contracts/ has the versions its git history declares, so ^1 picks
1.1.0 from history while the current contract is 2.0.0-beta.1.
A reference that names nothing, names an id two repositories publish, or asks
for a version nobody publishes is reported with what does exist, and left out.
It doesn’t block the build. Use domain/id to settle an id two domains share.
When two repositories publish the same domain/id, only removing one copy
settles it. Until then, each consumer declared for that event in
autocatalog.consumes.json is drawn on both copies, so drift in either
repository still names it.
Resolved references are relationships in the company graph, so
ac drift --consumers https://catalog.acme.dev/catalog.json names the
Fulfillment team when a Payments change breaks the event it receives.
Pin what you build
Section titled “Pin what you build”A federated site built from every branch’s latest commit changes whenever any team merges. Pin it instead:
npx autocatalog federation lock --topic catalog --owner acmeautocatalog.lock.json records each enrolled repository’s URL, commit and tree:
{ "spec": "autocatalog/lock-v1", "repositories": [ { "name": "payments", "url": "https://github.com/acme/payments.git", "commit": "a4c68dc7ae8115f3b971b32bb00112db0a41b620", "tree": "8f27448fa2e2ab4753954d89dd595ac49d6486cc", "lockedAt": "2026-11-03T08:46:05.360Z" } ]}Commit it. While it exists, ac site builds exactly those commits. It checks
each tree against the lock and leaves out, by name, a repository whose locked
commit can’t be checked out or whose tree differs. A repository enrolled since
the lock was written is reported and left out until you lock again.
--unlocked builds the latest commits instead, and --lock <file> names
another lock, which must exist.
To move one pin and keep the rest, pass --only payments. A repository that
moved to a new URL keeps its pin and takes the new URL. When no enrolled
repository can be cloned, lock fails and leaves the lock as it was.
Private repositories need GITHUB_TOKEN or GH_TOKEN. The command sends the
token as a header, over HTTPS to github.com or the host in
GITHUB_SERVER_URL, and to no other host a lock or --repo names. It never
writes the token into a URL or .git/config, or prints it in an error.
Check the federation
Section titled “Check the federation”npx autocatalog federation statussource kind pinned events commands services referencescart-and-checkout eventcatalog a4c68dc today 2 6 4 2/2fulfillment eventcatalog a4c68dc today 7 3 7 2/2payments eventcatalog a4c68dc today 8 1 6 1/1…
Every source composed, and every reference resolves.It lists each source’s pin and age (a project inside a pinned repository
carries that repository’s pin), what it contributes, and how many of its
references resolve. It then lists sources left out and why, ids two
repositories both define, and references that don’t resolve. It exits 1 when a
source is left out or an id has two owners. --format json gives the same
report for scripts.
Views and federations of federations
Section titled “Views and federations of federations”The same team repositories can feed several sites, such as a company view and
a business-unit view, each with its own topic or --repo list and its own lock.
A site can also join another site’s graph without rebuilding its pages:
npx autocatalog site --topic payments-unit --owner acme \ --index https://catalog.acme.dev/catalog.jsonThe other site’s resources and relationships join this site’s graph. They fill in what this site lacks and never replace what it has. References here can resolve to them, and maps can draw them.
A worked example
Section titled “A worked example”examples/federation
has five team repositories that use only autocatalog, a company site holding
the lock, a repository that duplicates another’s event and one that doesn’t
compile. pnpm verify:federation runs lock, status, site, --index and
drift --consumers against them.
Compared with EventCatalog Federation
Section titled “Compared with EventCatalog Federation”| EventCatalog Federation | autocatalog | |
|---|---|---|
| Licence | Enterprise (Scale) | MIT |
| Sources | EventCatalog projects | autocatalog repositories and EventCatalog projects, side by side |
| Enrolment | federation add per source | a GitHub topic, --repo, or checkouts on disk; a monorepo’s catalogs are found without paths |
| Pinning | eventcatalog.lock | autocatalog.lock.json, with each tree verified at build |
| Cross-catalog references | by id, with versions | by id or domain/id, with versions and ranges; events and commands |
| Unresolved references | reported | reported with what does exist; ambiguity named |
| Ownership conflicts | block the build | federation status exits 1 and names both repositories; the site still builds, and a repository that doesn’t compile is left out by name |
| Graph-only sources | reference mode | --index: another site’s /catalog.json |
| After composition | documentation site | the same site, plus breaking-change gates, consumer impact and delivery checks across every federated catalog |