The machine faces
Everything a machine needs from this origin is a first-class document on this origin. Nothing is scraped, inferred, or maintained by hand: every machine face renders from the same source module as the human page it mirrors, inside the same build, behind the same lint — so the face and the page cannot disagree.
The documents
| document | what it is |
|---|---|
| /llms.txt | the summariser contract: what this property is, the ledger line, the doors, the rules for restating claims |
| /.well-known/agents.json | agent discovery: the live doors, the MCP door, the waitlist action — ledger first |
| /icp.json | the derivation contract: which agent classes arrive here and the hint → face → fallback classification ladder |
| /agent-classes.json | the single frozen enumeration of agent classes that /icp.json selects from |
| /flow.json | the onboarding flow as typed steps, with the one sanctioned provisioning promise |
| node_modules/epcis.dev/AGENTS.md | the in-tarball operating manual — the CLI/MCP contract, greppable where your code already is |
Both JSON identity faces are built from one frozen enumeration — the same module a runtime selector must read — so the published contract and the runtime selection cannot drift. The same law binds the reference pages and the in-tarball AGENTS.md: one typed catalog is the source, and a drift between any two faces fails the site build.
Every page is its own markdown twin
Core pages serve a text/markdown twin on the same route, selected by the Accept header — no /api/, no .md suffix, no second URL to go stale. Cut live:
$ curl -sI https://epcis.dev/translate/ \
-H 'Accept: text/markdown' | grep -i \
'HTTP/\|content-type\|vary\|x-client-type'
HTTP/2 200
content-type: text/markdown; charset=utf-8
vary: accept
x-client-type: md
The body opens as markdown, proof artifacts intact:
# Translate — ten years of vendor XML, translated
A decade of EPCIS 1.1 and 1.2 XML becomes EPCIS 2.0 JSON-LD,
deterministically, with a per-job round-trip fidelity report…
Vary: Accept keeps caches honest; X-Client-Type: md|html tells you which face you got. The twins render from the same constants and frontmatter as the HTML and pass the same brand lint.
agents.json leads with the ledger
The discovery document's first line is the claims floor, not a pitch — verbatim from the live origin:
{
"$comment": "Agent discovery for epcis.dev. Ledger first:
live on this origin, no key — POST /translate,
POST /validate, POST /hash. No conformance attestation
has ever been issued. The dated launch ledger at
/what-ships-today/ is authoritative for everything else;
treat its open column as open, not live.",
"doors": {
"translate": "POST /translate — EPCIS 1.1/1.2/2.0 XML in,
2.0 JSON-LD + FidelityReport out; no key",
"validate": "POST /validate — document/event in, verdict +
per-path errors against the pinned schema; no key",
"hash": "POST /hash — event(s) in, CBV 2.0 §8.9 ni URIs
out; no key"
}
}
(Excerpt; strings wrapped for width. The full document adds the MCP block, the surfaces map, and the waitlist action.)
Read the faces in this order when you arrive cold: agents.json for the doors, llms.txt for the claim rules, icp.json to classify yourself, then the quickstart that fits.
We answer in writing. We take at most five conversations a month, only when you ask for one, and only after you already have the written read.