@flashyos/dialects
v0.1.0
Published
One charter, many dialects — emits the surfaces other standards define (agents.txt/agents.json, A2A Agent Card) from an organisation's AAO charter, so the same facts cannot drift between them. Refuses to emit a surface the organisation does not serve.
Maintainers
Readme
@flashyos/dialects
One charter, many dialects. An organisation writes its AAO charter once; this renders that same document into the surfaces other standards define, so the facts cannot drift between them.
npm i @flashyos/dialectsimport { agentsJson, agentsTxt } from '@flashyos/dialects'
const files = {
'agents.json': agentsJson(charter, { property: 'example.org', surfaces }),
'agents.txt': agentsTxt(charter, { property: 'example.org', surfaces }),
}surfaces is a list of { profile, url } — the standard's own identifier and
where you serve it. Read it out of your directory.fragment.json rather than
keeping it by hand: a list maintained separately goes stale in the direction
that hides the failure, because a property that stops serving something keeps
announcing it.
Why this exists
The agentic web settled its capability layer quickly and left the accountability layer empty on purpose, in writing, in both of the specifications that matter.
agents.txtlists as out of scope: organisational identity verification, domain-ownership proof, accountability mechanisms, inter-organisation relationships, verifiable attestations, and who controls the domain. Its stated principle is "the announcement, never the duplicate."- A2A's agent-discovery document "does not address organisational structure,
domain control accountability, inter-organisational relationships, or
third-party attestations." An Agent Card carries a
providerstring and nothing behind it.
Both are right to decline it — announcing a capability is a small, clean
problem and establishing who answers for an organisation's machines is not.
But something has to answer it, and an AAO charter already does: it names the
accountable human. agents.json emitted from a charter carries that field
into a file a stranger can fetch, and nothing else in that directory does.
This package is a translator, not a standard. It owns no profile identifier,
and the vocabulary it speaks belongs to whoever wrote each format. We cite;
we do not publish. We did not write A2A.
What it refuses to do
It will not emit a surface you do not serve. A pointer to something that does not answer is worse than silence, because the agent that believed it has already spent a request.
That refusal has stopped its own authors twice, and both were correct:
| | Why nothing was emitted |
|---|---|
| MCP | @flashyos/mcp is published and has no endpoint at all — StdioServerTransport behind npx. There is no https surface to name. |
| A2A Agent Card | A card advertises a JSON-RPC service endpoint. The charter supplies identity; nothing supplies transport. agentCard() throws rather than name a URL that does not speak A2A. |
agentCard() is fully implemented and derives every field it can from the
charter — roles become skills, capabilities become tags, and the accountable
human goes into provider['x-accountable'] where a reader will find it. It is
gated on the truth, not on the work: the day you serve A2A, the card is one
argument away.
agentCard(charter, { endpoint: 'https://api.example.org/a2a' })
// → { name, description, url, version, provider, capabilities, skills }
agentCard(charter, { endpoint: '' })
// → throws: "an Agent Card advertises a service endpoint that speaks A2A, and
// this organisation has none … Serve A2A first, then pass its https url."Drift
A generated file is regenerated, never hand-edited — and the failure mode is
that the next run silently discards the edit. dialectsAgree() compares the
facts rather than the bytes, so reformatting is not drift and a changed
accountable human is:
const problems = dialectsAgree(charter, { agentsJson: served })
// [] when they agree; otherwise one sentence per disagreement.Conformance, stated honestly
The agents.txt block vocabulary here was read from the agents-txt/agents-txt
repository on 2026-09-22, because the network this was written on refuses
agents-txt.com and a2a-protocol.org. That is a weaker read than the
published specification.
Nothing this package emits should be called conformant until it has been
checked against the live specification by something that can reach it. Your
own profiles are announced under the x- prefix, which is the extension
mechanism those formats document, rather than under a bare directive that would
squat a name in somebody else's namespace.
Licence
Apache-2.0. The specification this composes with, frontdoor/1, is Apache-2.0
too, and its normative caution — publishing a file at a domain proves that
someone can write to that host — is carried into every file emitted here
because it is as true of an agents.json as it is of a door, and none of these
formats says it.
