The public registry that makes 8th-Layer.ai AI-BGP a real protocol. Every member enterprise's L2 announces itself here; enterprises browse the directory to find each other; peering agreements are bilaterally signed and distributed through it. Once peering is established, traffic is direct L2-to-L2 and the directory is not in the data path.
This is the substrate that turns AI-BGP from "BGP-shaped" into a thing that actually composes when two enterprises with no prior relationship want their agent fleets to share knowledge.
Decision rationale:
docs/decisions/11-8th-layer-directory-as-aibgp-substrate.md(private design repo). Wire-format spec:docs/specs/directory-v1.md(same).
The directory holds public keys + signatures only — never private keys, never KU content, never consult traffic. Every consequential write (announce, peering-offer, peering-accept) is an Ed25519-signed envelope; the directory re-canonicalizes the payload via RFC 8785 (JCS), byte-compares against the client-supplied canonical form, then verifies the signature. A directory operator going rogue can drop or re-order records but cannot forge a peering — both signatures on a peering record are publicly verifiable offline by the receiving L2.
All under /api/v1/directory/. See the wire spec for full request/response shapes.
| Method | Path | Purpose |
|---|---|---|
POST |
/announce |
Register or update an enterprise's root record (signed by enterprise root key). |
GET |
/enterprises |
Browse the public roster. Honors visibility (public / discoverable-by-tag); never returns L2 endpoints. |
GET |
/enterprises/{id}/key |
Resolve an enterprise's registered root pubkey. |
POST |
/peering-offer |
Initiator's signed offer; held pending until the responder accepts. |
POST |
/peering-accept |
Responder counter-signs an existing offer. Activates the peering. |
GET |
/peerings/{id} |
Pull every peering this enterprise is a party to. Authenticated with a signed identity-proof body. |
Requires uv and Python 3.12.
make install # uv venv + install package + dev deps
make test # pytest
make lint # ruff check
make dev # uvicorn on :3001The default DB path in production is /data/directory.db; locally make dev writes to ./data/directory.db. Tests use tmp_path fixtures and never touch persistent state.
src/directory/
app.py FastAPI app + lifespan
schema.py Pydantic v2 wire models
crypto.py Ed25519 + RFC 8785 (JCS) helpers
store.py SQLite store + audit log
config.py env-var config
routes/
announce.py POST /announce
enterprises.py GET /enterprises, GET /enterprises/{id}/key
peering.py POST /peering-offer, POST /peering-accept, GET /peerings/{id}
Phase 2 — separate ECS Fargate stack with the directory. subdomain, behind its own ALB, in a different IAM scope from the cq-server (this is a different trust domain). Tracked in a follow-up issue once the L2-side client lands.
v2; spec stub lives in the design repo at docs/specs/directory-v1.md §"Federation (v2 forward-spec)". The v1 wire shape is forward-compatible.
Apache-2.0. See LICENSE.