9.1 The discovery surface (/.well-known/rs2/*) and OpenAPI

Every tenant exposes a generated, read-only discovery surface describing what it offers. It's generated from the live config and filtered by the caller's read permission, so a client (or an AI agent) sees exactly the mounts it may use — no separate documentation to drift out of date.

The three endpoints

Endpoint Returns
GET /.well-known/rs2/services The mount catalogue plus a control block pointing generic tools at config, catalogue, mounts, and code — only mounts the caller may read
GET /.well-known/rs2/agent-surface {entities, actions, queries} — actions with their effect class and idempotency guidance, stored queries with their params schemas, and declared I/O schemas
GET /.well-known/rs2/openapi OpenAPI 3.1 for the tenant

Any non-GET on the surface is 405.

services — the catalogue

This is the entry point for a polymorphic client (Part 3): it reports each mount's pattern (the conversation shape — store, store-view, transform, api) and facets (optional capabilities within it). A client reads these to decide how to talk to a mount, rather than hard-coding service names (3.4). Spec stores also advertise specSubtree (.pipelines, .queries, or .templates) and, when needed, an authoring description — for example JSX + Preact compilation for templates. The control block points to whichever path the tenant mounted its services API; clients need not assume /services.

agent-surface — for tools and agents

The agent surface describes the tenant as entities, actions, and queries:

  • actions carry their effect class and idempotency guidance (idempotency: {header: "Idempotency-Key", honored: true}), so a caller knows what's safe to retry and how to dedupe (9.3).
  • queries carry their params JSON Schema, read live from the query store (6.5) — so an agent knows exactly how to invoke each.
  • actions and entities carry inputSchema/outputSchema when a wrapper, pipeline envelope, or custom-code manifest declares them.

Filter it with ?surface=<name> against each mount's x-expose metadata (a string or array; absent means exposed everywhere).

openapi — the standard contract

GET /.well-known/rs2/openapi is OpenAPI 3.1. Crucially, the schemas it references are the ones enforced at runtime — stored-query param schemas are the request-body schemas, store paths reference shared path-item shapes, and components.schemas.Problem describes the error body. Because it's generated from the same definitions the runtime enforces, there's no drift between the docs and behavior. Operations also carry x-effect and x-idempotency-key extensions.

Permission filtering

The surface only ever shows what the caller may read. An anonymous client sees the open mounts; an authenticated admin sees more. This means the discovery document doubles as an authorization-aware capability list — useful for building UIs that adapt to the logged-in user.

OPTIONS — probing a single path

The three endpoints above describe the whole tenant. To ask about one specific path, send OPTIONS to it. Any mounted path answers with a read-only description of the resolved mount — its pattern, facets, and schema hint — as a JSON body, plus an Allow header listing the methods it accepts:

OPTIONS /data/orders/42
→ 200  Allow: GET, HEAD, PUT, POST, DELETE, OPTIONS
   { "pattern": "store", "facets": ["schema", …], … }

This lets a generic client render or validate any path from a single round trip, without fetching the whole catalogue. (A genuine CORS preflight — OPTIONS with an Origin and the preflight headers — is answered as a preflight instead; 5.5.)

The next section covers the error format every one of these (and every other) endpoint uses on failure.


Part 8 — Custom Services · Manual home · Next: 9.2 Structured errors →