# Request Workspace Routing Matrix

> Canonical path: `specs/api/request-workspace-routing-matrix.md`
> Status: living-spec
> Scope: workspace identity and owner selection from a caller through Desktop
> and the split Gateway to the final Central, Workspace, or AGS owner.
> Related specs: [Server Profile Routing](./server-profile-routing.md),
> [Workspace Gateway](../deployment/workspace-gateway.md), and
> [Workspace-Owned URL Canonicalization](../deployment/workspace-url-canonicalization.md).

Deployment profile and request scope are independent. An `all` profile can host
every owner without turning a global request into workspace traffic. Conversely,
a workspace-owned request still requires one consistent workspace identity.

## Header contract

| Header | Contract |
| --- | --- |
| `X-AgentTeam-Route-Workspace-Id` (`R`) | Gateway placement hint, never authorization. |
| `X-Workspace-Id` (`W`) | Business workspace after authentication and validation. |
| `X-AgentTeam-Resolved-Workspace-Group-Id` | Gateway-only trusted placement result. For workspace-scoped traffic it names the group resolved for the authenticated workspace. Clients cannot choose it. |

For workspace traffic, path, `R`, `W`, authenticated or credential workspace,
placement, and the target server's managed workspace set must agree whenever
they are present. A mismatch fails closed. Desktop may replace untrusted `R/W`
with the selected server's workspace, and the split Gateway may replace them
again after placement. Those authoritative rewrites are not authorization.

## Four observation points

A caller screenshot proves only the first point. Routing investigations and
wire-level tests must keep these observations separate:

1. **Caller:** method, escaped URL, query, body, cancellation, authentication,
   and the two workspace headers before Desktop.
2. **Desktop:** headers after caller values are removed and any selected-server
   workspace is reconstructed.
3. **Split Gateway:** route family, selected owner, rewrite, placement result,
   and header validation or removal.
4. **Final upstream:** escaped path, query, authentication, final `R/W`, and the
   trusted resolved group received by Central, Workspace, or AGS. When a
   Workspace Server forwards to an embedded handler, record that private hop
   separately rather than treating the first proxy hop as the final wire.

## End-to-end matrix

| Request class | Caller and Desktop contract | Split Gateway decision | Final upstream contract |
| --- | --- | --- | --- |
| Canonical workspace URL, for example `/api/v1/workspaces/:id/kb/...` | Path supplies identity. Browser REST normally sends consistent `R=W=:id`; Desktop removes caller values and reconstructs them only when the selected server agrees with the path. | Classify the registered workspace subresource before the central workspace-management fallback; validate identity and placement. | Workspace owner receives the canonical path and authoritative `R=W`. A private MeshX forwarder may strip the prefix only after validation. |
| Header-routed compatibility, for example `/api/agents/...` | Caller supplies a workspace and Desktop reconstructs `R/W` only for its bounded workspace inventory. | Resolve an authenticated identity or placement; never invent a default for ordinary workspace REST. | Workspace owner receives authoritative `R=W`. |
| Approved Desktop compatibility rewrite, for example `/api/v1/kb/...` | Desktop supplies selected-server `R/W` while preserving method, escaped path, query, body, authentication, cancellation, and retry behavior. | Require valid identity, rewrite under `/api/v1/workspaces/:id`, and route as canonical workspace traffic. | Workspace owner receives the canonical URL and authoritative `R/W`; direct old URLs on the Workspace Server remain 404. |
| Central request | Ordinary control callers omit `R/W`; Web billing callers may send business `W` without `R`. For its bounded billing compatibility inventory, Desktop currently reconstructs selected-server `R=W`. | Central classification ignores `R/W` for owner selection, and the central proxy always removes `R`. | A Central handler may validate and use `W` only when its own business contract requires it; `W` is never placement authority. |
| Non-product AGS compatibility, including discovery/OpenAPI, meta/rate-limit, OAuth/device/connected login, OIDC, public-agent, analytics, and unqualified avatar routes | Standalone and `all` profiles retain their complete AGS behavior. Split clients cannot activate these routes with `R/W` or credentials. | Return 404 before identity resolution, placement, Central, Workspace, or AGS business handling. The split Gateway has no default AGS owner or empty compatibility handler. | No upstream receives the request. |
| Activated session-scoped AGS state: viewer-repository list and code/label search | These handlers read the selected embedded AGS instance's repository/collaborator, Git, or label state. An owning typed transport MUST supply an active-workspace candidate; Desktop MUST remove arbitrary values and reconstruct at most one candidate from validated Protocol identity. Current-user and user-token compatibility have no AgentTeam product caller and remain unsupported at the split edge. | The Gateway MUST classify the exact activated operation, authenticate the ordinary user bearer, authorize membership in the claimed workspace, reject a missing or conflicting claim, and then use ordinary workspace placement. These entries MUST NOT remain in a fixed-default allowlist or use the machine/Agent/App legacy resolver. | The placed Workspace Server receives authoritative `R=W` and the resolved group, re-authenticates the AgentTeam session, and projects the same user through the existing trusted-JWT bridge. Embedded AGS receives trusted business `W`; method, native path, query, and body remain intact across the private hop. |
| Named repository REST and raw content | AgentTeam product callers use `/api/v1/workspaces/:workspaceId/ags/<native-path>`. A bounded legacy ordinary-session transport may use the native URL only with an authenticated active-workspace claim. Repository credentials and anonymous reads require the canonical outer path unless a separate locator is approved. The `:owner` segment is a repository login, not routing authority. | For an ordinary bearer, authenticate the session and authorize its claimed path workspace. For a repository credential or anonymous read, use the canonical path only as a placement candidate; the target MUST verify the exact workspace/repository binding before AGS authorizes the credential or public read. Reject conflicts before placement and never guess from repository owner or a default group. | The placed Workspace Server receives authoritative `R=W` and the resolved group, re-authenticates sessions, and validates the repository binding. Embedded AGS receives trusted business `W`; the native method, path, query, body, and repository credential remain intact. |
| Git smart HTTP `/:owner/:repo.git/*` | AgentTeam product clone/fetch/push URLs use `/api/v1/workspaces/:workspaceId/ags/:owner/:repo.git/*`. Exact wire operations are `GET info/refs` with a supported service and `POST git-upload-pack` or `POST git-receive-pack`; capability follows service. Unqualified credential URLs remain unsupported until a credential locator is approved. | Strictly parse the credential, place only by the canonical path candidate, and require target-local workspace/repository binding before AGS validates repository capability. Never infer workspace from repository owner or a configured default group. | Active traffic preserves the smart-HTTP native suffix, query, streaming body, credential, and authoritative workspace context. Unknown methods/services/descendants or unqualified credentials reach no upstream. |
| Workspace-qualified avatar redirect | AGS repository DTOs may emit only `/api/v1/workspaces/:workspaceId/ags/avatars/:login` for the owner that produced the DTO. Unqualified `/avatars/*` remains non-product compatibility and returns 404 in split mode. | The canonical path selects one placed owner; only the exact registered GET is activated. Unknown methods or descendants return 404 without AGS business handling. | The same workspace owner serves the redirect, preserving the repository response → browser second-GET chain. |
| Unsupported AGS, `/api/graphql`, internal-only, or unknown route | No workspace header can make it valid; Desktop still removes untrusted `R/W`. | Return 404 before any upstream call. | No Central, Workspace, or AGS business handler receives the request. |

## Durable route-family rules

- **Workspace:** only registered canonical workspace subresources and bounded
  compatibility families route by workspace. Exact registered methods are
  generated with `go run ./cmd/agentteam-route-contract`; this document does not
  duplicate that inventory.
- **Central:** authentication, identity, organization, administration,
  workspace management, and other registered control-plane routes never use
  `R` for owner selection.
- **Non-product AGS compatibility:** discovery/OpenAPI, meta/rate-limit,
  OAuth/device/connected login, OIDC, public-agent, analytics, and unqualified
  avatar routes are not activated at the split edge. They return 404 with zero
  upstream work; this does not remove their complete Standalone/`all`-profile
  capability. Repository DTOs may expose only the separately activated,
  workspace-qualified avatar redirect.
- **Repository data plane:** registration-derived operation capability is
  distinct from disabled compatibility routes. Repository operations retain
  their native protocol path but resolve a trusted business workspace and use
  normal workspace placement. In a Workspace-profile deployment this selects
  that workspace's server and embedded AGS, not one deployment-wide AGS instance.
  The Gateway MUST combine registration-derived operation capabilities with its
  deployment activation policy. Desktop transports MAY identify the AGS
  transport family, but MUST never own a second operation classifier.
- **Session-scoped AGS state:** viewer-repository list and code/label search are
  the activated AgentTeam product operations. They use a session plus explicit
  workspace claim, ordinary workspace placement, and target-side session
  re-authentication; they are not workspace-free merely because their native
  URL lacks a repository owner/name. Current-user and user-token compatibility
  remain 404 until a AgentTeam product caller and activation contract exist.
- **`/api/v3`:** the namespace alone is not an operation or workspace
  classifier. Non-product compatibility operations are unsupported at the
  split edge; separately activated repository operations use authenticated
  workspace placement, and everything else fails closed. A typed AGS transport MAY supply a
  candidate selected workspace, but
  Gateway operation capability and authenticated authority MUST be the only
  inputs that determine whether it is used.
- **`/api/graphql`:** unsupported in split mode until it has a storage-aware
  owner contract. It carries no workspace identity and reaches no upstream.
- **Unknown operations:** a known prefix does not authorize an unknown method
  or descendant. Client headers cannot change support or owner selection.

The canonical implementation owners are:

| Concern | Source of truth |
| --- | --- |
| Caller header construction | `web/src/agentteam/api/core.ts` and workspace-specific API helpers. |
| Desktop trust boundary | `desktop/internal/api/gateway.go`. |
| AGS registered capability | The AGS router MUST own method-plus-pattern registration and its real authentication scope (public, optional-auth, or authenticated). Registration metadata MUST expose operation capabilities without importing split-deployment policy. |
| AGS split activation | Gateway composition MUST own an explicit operation-and-authority-mode activation overlay. An activated key MUST exist in AGS registration metadata; unlisted modes are not activated at the split Gateway and this does not remove their all-profile AGS capability. An empty overlay needs no handler, matcher, descriptor, or compatibility shell. Existing anonymous and repository-credential contracts require a trustworthy locator before split activation and MUST then preserve their established behavior. |
| Desktop AGS transport | A typed caller/transport owner MAY mark an AGS request and carry the validated Protocol workspace as a candidate. Desktop MUST NOT classify individual AGS operations; unsupported operations MUST discard the candidate. Any static cross-module artifact MUST derive from the registration owner and be checked for exact equivalence; this contract does not require such an artifact when a direct dependency is sufficient. |
| AgentTeam synthetic raw | One shared exact parser MUST own decoded path, optional raw path, repository, and read capability. Its split activation MUST still follow the authority-mode policy. |
| Authenticated request workspace | `internal/gateway/workspace_identity.go` and its private resolver endpoint. |
| Workspace-to-group placement | `internal/workspace/router` plus the placement `Resolver`. |
| Split owner selection | `internal/gateway/gateway.go`. |
| Legacy Desktop rewrites | `internal/gateway/legacy_desktop_workspace_routes.go`. |
| Canonical workspace families | `internal/gateway/workspace_routes.go` and route-contract output. |

Do not create another endpoint-by-endpoint classifier in Web, Desktop, or this
spec. New workspace APIs use canonical workspace paths; AGS support remains
owned by AGS and the split Gateway.

## Required verification

Wire-level tests must prove:

1. canonical and approved legacy workspace requests reach the correct Workspace
   owner with consistent authoritative `R/W` while preserving HTTP semantics;
2. split non-product AGS compatibility requests, including the six
   discovery/OpenAPI GETs and their wrong-method, descendant, slash-alias, and
   `OPTIONS` variants, return 404 with zero identity, placement, Central,
   Workspace, or AGS business calls;
3. viewer repositories, code search, label search, repository branches, tags,
   and contents preserve exact native method, escaped path, query, and body
   while a trusted workspace selects placement; the target re-authenticates an
   ordinary AgentTeam session and reaches embedded AGS with trusted identity and
   business `W`. Current-user and user-token requests return 404 before identity
   or placement. At least two
   workspaces mapped to different groups must reach different upstreams;
4. operation-by-authority-mode tests preserve existing successful and error
   contracts on the canonical outer path: target-local repository binding plus
   AGS authorization protects repository credentials; anonymous repository reads
   retain public 200, private 404/401, and anonymous-write 401 behavior; and Git
   retains credential fetch/push wire and status semantics. Session, credential,
   and anonymous modes prove zero configured-default routing, zero group fanout,
   and one selected owner. Unqualified credentials fail before placement until a
   separate credential locator is approved;
5. missing, malformed, unauthorized, or conflicting repository workspace
   identity and placement-resolution failure return a stable 4xx/5xx as
   appropriate with zero AGS upstream calls; forged `R/W` cannot change owner;
   an ordinary bearer session without a claim or without membership also fails
   before placement, and one repository request performs only a bounded
   authentication/authorization lookup rather than resource-dependent fanout;
   malformed or conflicting `R/W` is rejected before resolver, placement, or
   upstream invocation;
6. Central owner selection ignores `R/W`, the Central upstream never receives
   `R`, and each Central handler validates or ignores business `W` according to
   its own contract;
7. `/api/graphql` and unsupported AGS operations return 404 with zero upstream
   calls; and
8. delivery configuration preserves the complete embedded MeshX/AGS surface in
   Standalone/`all` profiles while a Workspace profile exposes only separately
   activated product operations through a workspace-qualified seam.

Focused executable checks include:

```bash
go run ./cmd/agentteam-route-contract
GOMAXPROCS=2 go test -p 1 -count=1 ./internal/gateway ./internal/router ./internal/resource/server ./internal/server
(cd desktop && GOMAXPROCS=2 go test -p 1 -count=1 ./internal/api)
```

Changes to a source-of-truth classifier must update the corresponding matrix
row and behavior-facing test in the same change.

Registered AGS operations must produce method-plus-pattern capabilities with the
actual AGS authentication scope. Split-edge activation is a separate Gateway
overlay keyed by operation and authority mode; bidirectional coverage proves
that every activated key maps to one real registration without overlap.
Temporary implementation status MAY be tracked in a non-normative migration
ledger. Such a ledger does not define or override this contract.
