Skip to content

x/* Family

The x/* layer exists so optional or faster-moving capabilities can evolve without redefining the stable-root learning path. These families are not accidental overflow directories; they are the intended home for work that is real, app-facing, and useful, but too capability-specific to become part of the narrow default path.

Synced from `specs/task-routing.yaml`

Primary entry families

14

  • x/tenant
  • x/fileapi
  • x/messaging
  • x/gateway
  • x/rest
  • x/websocket
  • x/frontend
  • x/observability
  • x/openapi
  • x/resilience
  • x/rpc
  • x/data
  • x/ai
  • x/validate

Synced from `specs/repo.yaml`

All extension paths

Default routing intent: Change product capability, business feature, protocol adaptation, or extension behavior.

  • x/tenant
  • x/ai
  • x/data
  • x/fileapi
  • x/frontend
  • x/gateway
  • x/messaging
  • x/observability
  • x/openapi
  • x/resilience
  • x/rest
  • x/rpc
  • x/validate
  • x/websocket

Primary entry families and all extension paths are shown separately so subordinate paths do not get mistaken for default entrypoints.

The following families have reached beta status: API frozen between minor release refs, backed by two consecutive release refs, exported API snapshots, and owner sign-off.

Family Status Promoted Recommended entry
x/gateway beta v0.2.0 proxy, rewrite, balancing, edge transport
x/observability beta v0.2.0 exporter, tracer, collector, adapter wiring
x/rest beta v0.2.0 resource controller and CRUD route conventions
x/websocket beta v0.2.0 WebSocket hub and explicit route registration
x/tenant beta v1.1.0 resolution, policy, quota, rate limit, session
x/frontend beta v1.1.0 static and embedded asset serving
x/messaging beta v1.1.0 app-facing queue, pubsub, scheduler, webhook service

For the full maturity dashboard including selected beta surfaces within experimental families, see Extension Maturity.

Start with an x/* family when the work is primarily about reusable capability behavior rather than the smallest canonical service shape.

That usually means the task involves one or more of these:

  • protocol adaptation or edge behavior
  • tenant, gateway, messaging, data-topology, or observability policy
  • app-facing reusable capability surfaces that should stay optional
  • behavior that would make a stable root learn product or family semantics

If the task is still about the default bootstrap path, explicit lifecycle wiring, or transport primitives that every service should understand, you probably are not ready to start in x/* yet.

Use this quick test before you pick an extension family.

  1. Is the change clearly capability-specific rather than part of the smallest runnable service path?
  2. Would placing it in a stable root force that root to learn family policy, provider choices, or topology decisions?
  3. Is there already a primary family entrypoint that matches the task more honestly than a narrow subordinate package?

When the answer is yes, x/* is usually the right starting layer.

Concrete extension-family examples from the current repository

Section titled “Concrete extension-family examples from the current repository”

The current repository already exposes several clear family-level entry rules.

Extension family Start here when the work is about Do not start here when the work is really about
x/rest reusable CRUD transport behavior, query parsing, pagination rules, and repository-backed resource wiring service bootstrap, gateway topology, business repository ownership, or domain validation
x/messaging app-facing queue, pubsub, scheduler, or webhook orchestration at the family level the smallest runnable service path, stable abstractions, or a task already known to be only x/messaging/mq or x/messaging/pubsub
x/observability exporter wiring, telemetry adapters, buffered metrics inspection, rolling metrics helpers, and broader diagnostics integration transport-only request middleware primitives such as request IDs, tracing hooks, or access logging
x/rpc RPC server lifecycle helpers, outbound connection pooling, and HTTP-over-RPC transcoding alongside standard routes service discovery for backends (use x/gateway/discovery), or importing a concrete gRPC runtime into x/rpc
x/openapi generating OpenAPI 3.1 document structures from router.RouteInfo values and operation hints, without external dependencies handler reflection-based schema inference, runtime Swagger UI, or YAML parsing
x/validate explicit BindJSON/Bind call sites in handlers that decode JSON and return structured contract.APIError responses middleware-level pre-validation, tag-based struct validation frameworks, or global validator instances

These examples matter because they show that x/* is not just a place to move code away from stable roots. Each family is supposed to become a discoverable entrypoint with a clear ownership story.

Once you know the work belongs to an extension family, continue with the most honest family entrypoint instead of staying in the abstract.

If the work mainly touches Open this primer next Why this primer matters
reusable CRUD controller behavior, shared pagination rules, and resource-route standardization x/rest Primer it turns the family rule into a concrete split across app-local wiring, repository code, and domain validation
app-facing queue, pubsub, scheduler, and webhook orchestration x/messaging Primer it shows when to start at the family entrypoint and when it is safe to dive into narrower siblings
RPC server lifecycle, outbound connection pooling, or HTTP-over-RPC gateway x/rpc Primer it covers which surfaces are caller-owned and which lifecycle helpers x/rpc provides
OpenAPI 3.1 document generation from registered routes x/openapi Primer it explains the route-driven generation model and where the CLI integration boundary sits
explicit JSON binding and caller-owned validation in handlers x/validate Primer it clarifies when to use BindJSON vs Bind, how errors map to contract.APIError, and why validation stays in handlers
stable-surface decisions that might still belong in root packages Stable Roots it is the right backtrack when the change is still really about default-path ownership

A few repository-backed examples make the split more practical.

  • Start in x/rest when the task is “standardize CRUD or resource API shape.” Keep explicit route binding in app-local wiring, keep repository ownership in the repository layer, and keep domain validation outside x/rest.
  • Start in x/messaging when the task is app-facing messaging orchestration. Only drop into x/messaging/mq, x/messaging/pubsub, x/messaging/scheduler, or x/messaging/webhook after the task is already known to be that narrow.
  • Start in x/observability when the task is export wiring or broader telemetry integration. Leave transport-only request instrumentation in stable middleware/*.
  • Start in x/gateway when the problem is proxy or edge transport behavior, not reusable resource-controller behavior.

The repository tries to prevent a few common mistakes.

  • do not use x/* as a generic excuse to hide unclear ownership
  • do not redefine the canonical reference path from an extension family
  • do not start from a subordinate package when a primary family already exists
  • do not move transport contracts, lifecycle ownership, or the smallest bootstrap path out of the stable surface just because the implementation feels advanced

The point of x/* is not novelty. The point is to keep capability-specific work explicit and discoverable without expanding the default contract every service has to carry.

A useful rule is to compare the first question you are trying to answer.

  • If the question is, “How should the canonical service boot and route requests?” stay with Stable Roots and Reference App.
  • If the question is, “Which capability family should own this optional or fast-moving behavior?” start here.

That is the real boundary between default-path ownership and extension-family ownership.