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.

FamilyStatusPromotedRecommended entry
x/gatewaybetav0.2.0proxy, rewrite, balancing, edge transport
x/observabilitybetav0.2.0exporter, tracer, collector, adapter wiring
x/restbetav0.2.0resource controller and CRUD route conventions
x/websocketbetav0.2.0WebSocket hub and explicit route registration
x/tenantbetav1.1.0resolution, policy, quota, rate limit, session
x/frontendbetav1.1.0static and embedded asset serving
x/messagingbetav1.1.0app-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 familyStart here when the work is aboutDo not start here when the work is really about
x/restreusable CRUD transport behavior, query parsing, pagination rules, and repository-backed resource wiringservice bootstrap, gateway topology, business repository ownership, or domain validation
x/messagingapp-facing queue, pubsub, scheduler, or webhook orchestration at the family levelthe smallest runnable service path, stable abstractions, or a task already known to be only x/messaging/mq or x/messaging/pubsub
x/observabilityexporter wiring, telemetry adapters, buffered metrics inspection, rolling metrics helpers, and broader diagnostics integrationtransport-only request middleware primitives such as request IDs, tracing hooks, or access logging
x/rpcRPC server lifecycle helpers, outbound connection pooling, and HTTP-over-RPC transcoding alongside standard routesservice discovery for backends (use x/gateway/discovery), or importing a concrete gRPC runtime into x/rpc
x/openapigenerating OpenAPI 3.1 document structures from router.RouteInfo values and operation hints, without external dependencieshandler reflection-based schema inference, runtime Swagger UI, or YAML parsing
x/validateexplicit BindJSON/Bind call sites in handlers that decode JSON and return structured contract.APIError responsesmiddleware-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 touchesOpen this primer nextWhy this primer matters
reusable CRUD controller behavior, shared pagination rules, and resource-route standardizationx/rest Primerit turns the family rule into a concrete split across app-local wiring, repository code, and domain validation
app-facing queue, pubsub, scheduler, and webhook orchestrationx/messaging Primerit 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 gatewayx/rpc Primerit covers which surfaces are caller-owned and which lifecycle helpers x/rpc provides
OpenAPI 3.1 document generation from registered routesx/openapi Primerit explains the route-driven generation model and where the CLI integration boundary sits
explicit JSON binding and caller-owned validation in handlersx/validate Primerit 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 packagesStable Rootsit 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.