0157-native-model-catalog-routing
August 16, 2026 · View on GitHub
Status: accepted Date: 2026-07-29 Area: harness Scope: How Construct routes models selected by a harness or its native subagents without replacing the harness's delegation machinery.
Decision
Construct publishes available route/model pairs into a supported harness's
native model catalog by default. Running construct new <harness> is the
scope of this integration: Construct discovers usable provider logins and
declared endpoints, then injects a session-local catalog without requiring
per-harness model configuration. Routing and publication remain separately
configurable opt-outs.
Each published entry has a stable, human-readable, collision-safe model id in Construct's namespace that reversibly identifies both the route and target model. It contains exactly one slash for Codex metadata lookup and percent-encodes separators inside either component. The harness carries that id on every model request, including requests made by native subagents. The proxy resolves it per request:
- A valid Construct id selects its encoded route and model.
- A native model id uses the session's manually pinned route, if one is armed.
- A native model id with no pin goes to the exact origin named by the harness, retaining its native credential.
- A malformed, unavailable, or stale id in Construct's namespace fails closed. It is never sent to the native provider.
Construct integrates through a session-scoped native mechanism and never
edits the harness's persistent configuration. Codex receives a generated
catalog override. Claude receives a loopback Anthropic gateway URL whose
/v1/models response is consumed by Claude Code's native gateway discovery.
The Claude adapter enables loopback discovery only for that child process
and does not displace a user-configured ANTHROPIC_BASE_URL. Native catalog
entries remain present alongside Construct entries. Claude's gateway source
subtitle is harness-owned and may be generic, so each published display name
also identifies Construct explicitly. Construct primes Claude's native
gateway-model cache and uses a non-auth session capability for loopback
requests; it does not install an API key or auth token, so a claude.ai login
remains authoritative and its organization connectors remain available.
Operator definitions that select a published route/model pair persist the
ordinary construct-<route>/<model> id as their harness-neutral routing
authority. When a operator creates a session, Construct materializes that id
for the selected harness, including Claude's required claude-construct-
prefix. A client must never reduce a route-aware operator selection to the
target model name alone.
Reason
The harness already owns model selection and delegation. Publishing routes as native models lets its built-in picker, configuration, and subagent scheduler choose different models without Construct inventing a parallel delegation system or pinning an entire session to one target.
A request-carried alias is also more precise than mutable session state: concurrent parent and subagent requests can select different routes without racing over a shared pin.
Session-scoped generated catalogs preserve the user's native catalog and avoid durable edits that could affect harnesses launched outside Construct. Keeping endpoint selection in proxy transport preserves the origin-safety rule in 0113.
Consequences
- Publication advertises only routes that are currently selectable for the harness. Credentials never appear in catalog entries or model ids.
- Installed harnesses are useful discovery signals, but a model is published only when Construct can verify a usable credential or a configured endpoint. A binary alone does not imply model access.
- Subscription credentials are discovered read-only from supported harness-owned stores. Custom API endpoints remain explicitly declared because they cannot be inferred safely.
- The published id, not display text or catalog order, is the routing authority.
- A operator may change between supported native-catalog harnesses without losing its selected route; the durable id is adapted when each new session starts.
- Request selection overrides a manual session pin for that request only. The pin remains unchanged for native model ids and future requests.
- Catalog-enabled sessions inspect only the harness's fixed model host. Other destinations remain blind tunnels.
- Request compression is decoded before model-id inspection and translation, then forwarded with framing that matches the decoded body.
- Codex catalog sessions use a session-local OpenAI-compatible provider that keeps Codex's active native authentication and corresponding HTTPS origin while disabling Responses-over-WebSocket. Construct's proxy supports the HTTPS/SSE transport; it must not let a routed picker selection first escape to the harness's fixed WebSocket endpoint and fail before fallback.
- After inspecting a native request with no pin, Construct normally reconstructs it to the observed origin and preserves end-to-end credentials while removing proxy and hop-by-hop headers. Claude subscription sessions use the session-token exchange described below.
- Claude's gateway discovery requires an API-shaped credential. When Claude Code already has an API credential, Construct preserves it. For a subscription session, the adapter presents the session capability token to the loopback gateway and the router exchanges native Claude selections for the detected Claude OAuth route. The capability is valid only for its owning session.
- Claude's loopback gateway is excluded from that child's proxy settings so discovery reaches the listener directly instead of recursively proxying through the same listener.
- A user-configured Claude gateway remains authoritative; Construct does not add its own rows to that gateway's picker.
- Routed requests remove the harness's native credential and apply only the selected route's credential.
- Generated catalogs use conservative capabilities unless the shared model registry explicitly supplies richer metadata.
- Codex publication pins the session-local catalog to the v1 multi-agent surface. The v2 surface may encrypt a child task for the native ChatGPT backend, which makes the task unreadable to a routed provider.
- A bounded featured subset may be prioritized for native delegation schemas, while the complete available set remains selectable in the picker.
Non-Goals
- Reimplementing a harness's subagent scheduler or model picker.
- Editing global harness configuration.
- Inferring provider capabilities from model names.
- Automatically choosing a route by price, latency, or availability.
Examples
A Codex parent remains on its native model while a native subagent selects
kimi-k2.5 · kimi from the same model catalog. The subagent request carries
the readable Construct id construct-kimi/kimi-k2.5, so only that request
is translated and routed to Kimi. The parent's concurrent native request
still goes to the origin Codex selected.
A Claude session opens /model and sees
gpt-5.6-sol · codex-oauth · Construct as a gateway entry next to Claude's
built-in rows. Selecting it carries
claude-construct-codex-oauth/gpt-5.6-sol on the request, allowing the same
Claude session or one of its native subagents to select the Codex route
without changing the parent's model.