carlos / platform Public
The instance-report contract (/.carlos/instances)
Some CARLOS apps are internally plural: one route on the platform, many instances inside the app (Kass and its training instances, titogo and its event routers). The platform's registry sees the route; only the app knows its insides. This contract lets an app volunteer that knowledge to the console. It is entirely optional — an app that doesn't implement it renders in the console exactly as before.
What the app exposes
GET /.carlos/instanceson its public host (the same host the platform routes to it). Response:
- Status
200, body a JSON array of instance objects:
[
{"slug": "riders-2026", "status": "ready", "region": "eu-west-1"},
{"slug": "spring-camp", "status": "ready", "region": "eu-west-1"},
{"slug": "trial-run", "status": "archived", "detail": "read-only since June"}
]slug(string, required): the instance's stable short name. Entries without a slug are dropped.status(string, recommended): one short word — the console renders it verbatim. Use the platform's route-status vocabulary where it fits (ready,starting,failed) plus whatever the app means (archived,migrating).region(string, optional): where the instance's data lives.detail(string, optional): one short human sentence.- Unknown fields are ignored; the contract may grow additively.
Limits: at most 100 instances and 64 KiB of body are read; beyond either, the report is treated as absent.
The endpoint must serve non-secret operational metadata only. It is unauthenticated by design (the console calls through the public host, like any visitor), so anything an app would not put on a status page does not belong in it. Apps that want the console table implement the endpoint; apps that don't, 404 — both are correct behavior.
What the console does
- Polls the app's first ready, non-static route that has not opted into hibernation (routes sort by host). Hibernatable hosts are never polled: a poll could wake them, and the console must never wake an app to draw a table.
- Uses a 1.5 s timeout and treats anything but a fast, valid
200— connection refused, timeout, non-200, junk JSON, oversized body — as "not reporting". Not reporting is silent: the app page shows the ordinary route-level view, nothing more. - Caches per host for 30 s (successes and failures alike), so page reloads don't drum on tenants.
- Renders the instance count and a slug/status/region/detail table in an "Instances" section on the app page.