Appearance
Space routes
A Matrix Space has a public path. Apps under that Space are reached at:
/<routeKey>/<appName>/<asset-path>
/<publicNamespace>/<appName>/<asset-path>The two grammars are alternatives — both refer to the same Space, with publicNamespace = space.<routeKey> (the typed namespace form). RouteKey is a v1 alias for the user-facing "Space path" terminology.
RouteKey grammar
/<routeKey>/<appName>/<asset-path>Where:
routeKey: dot-delimited DNS-label-style identifier, e.g.alt.stories.ghost-stories.funny.appName: lowercase kebab-case.
Per parseRouteKeyWebappRoute in projects/matrix-3/packages/system-gateway-http/src/http-routing.ts:
typescript
const ROUTE_KEY_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/;A routeKey must:
- Match this regex.
- NOT match the public-namespace pattern (
space.*,domain.*,system.*) — those are typed namespaces handled separately. - NOT be in the reserved set:
api, auth, login, logout, signup, setup, settings, apps, app, assets, static, branding, nats-ws, matrix, system, admin, root, support, docs, help, billing, status, healthz, well-known, favicon.ico, manifest.json, hivecast, open-matrix, me.
Public-namespace grammar
/<publicNamespace>/<appName>/<asset-path>
/<publicNamespace>/apps/<appName>/<asset-path>Where publicNamespace is one of:
space.<routeKey>(the canonical typed form for a Space)domain.<...>(reserved, target state for domain claims)system.<...>(reserved, system namespace)
typescript
const PUBLIC_NAMESPACE_PATTERN =
/^(space|domain|system)\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/;Both forms (/<publicNamespace>/<appName>/ and /<publicNamespace>/apps/<appName>/) work. The first is the user-friendly form; the second forces the explicit apps/ segment that's safer for auto-generated tools.
Dispatch order
In _dispatch (http-listener.ts):
1. parsePublicNamespaceWebappRoute(path) ← typed namespace tried first
2. parseRouteKeyWebappRoute(path) ← routeKey alias second
3. parseExplicitAuthorityWebappRoute(path) ← email-prefixed third
4. /apps/<appName>/... ← generic app lastA path that parses as both a public namespace and a routeKey is dispatched as the public namespace.
Mapping to internal routes
When a Space route parses successfully, the URL is rewritten internally to /apps/<appName>/<asset-path> and the gateway issues an asset request as if it were a generic /apps/ URL. The Space identity is carried in metadata (the route record's routeKey / publicNamespace) for HTML rewriting, so emitted HTML keeps the Space-prefixed URL form.
HTML rewriting
When the asset response is HTML, the gateway rewrites every reference to /apps/<appName>/... to /<routeKey>/<appName>/... (or the public-namespace equivalent) so navigation stays inside the Space's URL prefix. rewriteWebappHtmlResponse (http-routing.ts:251-273) does this with simple prefix substitution.
This means: a package's static HTML can use plain /apps/chat/... references; the gateway rewrites them at serve time so the Space prefix is preserved.
Trailing-slash redirects
If the path is /<routeKey>/<appName> (no trailing slash, no asset path), the parser sets requiresTrailingSlashRedirect: true. The handler then issues a 302 to add the trailing slash. This avoids relative-URL breakage in the rendered HTML.
See also
Source:
projects/matrix-3/packages/system-gateway-http/src/http-routing.ts:97-167,projects/matrix-3/packages/system-gateway-http/src/http-routing.ts:350-392.