How it works
Updated 19 August 2026
Everything on this page follows from two facts. State them once and the rest of the protocol stops looking like machinery and starts looking inevitable.
Many apps will exist, and that is fine. In every emergency, teams build their own boards, maps and directories — often several for the same city. The 2026 ecosystem directory lists twenty-one of them. Unification is not coming, and the protocol does not ask for it: every app keeps its own product, its own users and its own database. What changes is that their records stop being trapped inside them.
The data is sensitive. These records sit next to people in their worst week. So the shared layer carries places and facts — never people. No names, no phone numbers, no personal contact, excluded by a join prohibition, not by good intentions.
The published copy
An app joins the network by publishing two things:
- A manifest at
/.well-known/cabuya.json— one JSON file that says who you are, what you publish, and under which licence. - A feed — your records in the shared schema, at a URL the manifest
declares. The URL is yours to choose, and a static file and a read API
are the same feed: the spec’s
equivalence rule makes them
byte-compatible per record, so a plain file at a stable URL is the floor,
not a lesser option.
places.jsonis an example filename, not a rule.
Nothing internal changes. Your tables, your primary keys and your product stay exactly as they are — the feed is a translated copy, produced by a small serializer, and the data model guide shows how to organize new apps so that translation is nearly free.
How a record travels
Another app fetches your feed and re-displays your records under the six consumption rules. Two of them shape what a person actually sees:
-
Attribution travels with the record. Every record carries its
publisher_idand its own geography —municipality_code,municipality_text,neighborhood_text, coordinates and their precision. So the canonical way a consumer displays a foreign record is:{name} — by {publisher} · {municipality}, {neighborhood}
A reader in Cali sees a Pereira record and sees that it is a Pereira record, published by someone else — attribution and location survive every hop.
-
Every action button leads back to the origin. Each record carries
public_url: the publisher’s own page for it. Contact values never travel in feeds, so a consumer’s buttons — “I can help”, “call the shelter”, “details” — link out to the app that owns the record. That is what makes the no-contact rule workable instead of merely prohibitive: the feed moves the fact, the origin resolves the help.
The registry sits to one side of all this. It lists who exists and what the validator measured; no data passes through it, and inclusion is not endorsement.
What installing the agent skill produces
The agent skill teaches a coding agent the whole protocol offline and walks your app through adoption. Concretely, an adopter ends up with:
https://your-app.org/.well-known/cabuya.json— the manifest.https://your-app.org/cabuya/places.json— the feed (that example URL, or any URL you prefer; file or endpoint).- In the repo: the crosswalk from your existing columns to the shared schema
and the serializer that produces the feed — proposed file by file, approved
by you; a short note at the repo root that explains the integration to
whoever finds it months later; and a
.cabuya/adoption.jsonprogress ledger. Those last two are the only files the skill writes on its own, and both are deletable. - The loop: run the validator against your URLs, read what it measured, fix, repeat.
This is what the two documents look like, trimmed (the quickstart carries both in full):
// your-app.org/.well-known/cabuya.json — the manifest
{
"publisher_id": "example-app",
"license": "CC-BY-4.0",
"feeds": [
{ "name": "places", "entity": "place",
"url": "https://example.org/cabuya/places.json" }
]
}
// one record from the feed
{
"name": "Coliseo Municipal",
"place_kind": "shelter",
"municipality_text": "Pereira",
"lifecycle_status": "active",
"public_url": "https://example.org/places/coliseo"
}
It never migrates your internal data model. If your app is still on the drawing board, the data model guide is the shape to start from.
The levels, in plain language
Conformance is measured by the validator, never declared — and the levels are membership classes, not grades. One sentence each:
- L0 — Listed. Your app appears in the registry. A pull request.
- L1 — Linked. Your records link out to other apps’ pages. Under an hour.
- L2 — Publishes. Your feed is live and others can read it. One afternoon for a small app.
- L3 — Serves and consumes. You also read other apps’ feeds and show their records. Days.
- L4 — Federates. Reads and writes flow both ways. Depends on the app.
Two classes never climb past L1, on purpose: apps whose records are irreducibly personal (missing persons, reunification — link-out only, permanently), and apps that simply choose not to publish. Both are listed, and both are respected members. Staying at a level is a position, not a failure.
What the protocol carries today — and what is proposed
Version 0.1 ships one entity: place — shelters, collection centres,
hospitals, water and food points, and the other places aid runs on. Help
requests and offers with quantities (need/offer), damage reports, and a
publisher coverage declaration are proposed for v0.2 in
RFC 0002 — a draft under open review, not something you can
publish yet. The site will say so the day that changes, and not before.