Run gateway serve on the inference host. Keep its provider registrations and
native Claude account directories there. Use one authoritative host when you
want every client to see the same configured models.
Keep model selection on that authoritative host. For example, load only these four Copilot models while preserving the other providers:
gateway discover copilot \
--select gpt-6.1-sol,gpt-5.6-terra,claude-sonnet-5,claude-opus-5.5 --load
GPT-5.6-Terra was the latest Terra offered by the registered Copilot account on
11 October 2026. Discovery without --load does not change the selection.
Include the selection when loading again; an unrestricted --load loads the
provider's full offered catalog.
The desktop and SSH adapters fetch this shared selection. Each device can also generate an opt-in CLI configuration in a separate home:
gateway_client_root="$HOME/.config/harness-gateway/clients"
gateway_codex_home="$gateway_client_root/codex"
mkdir -p "$gateway_codex_home"
gateway codex-config --model codex/gpt-6.1-sol \
> "$gateway_codex_home/config.toml"
CODEX_HOME="$gateway_codex_home" codex
Regenerate the CLI snapshot after changing the host's selection. This separate
home uses the secondary subscription routes and has its own settings and history.
The generated file is a complete configuration, not a named profile. The primary
config.toml stays unchanged.
An obsolete repo-local gateway.local.json overrides the installed configuration
when running development commands. Retire that file after migrating to the
installed configuration to keep one model-selection source.
Open an SSH forward from the client:
ssh -N -L 127.0.0.1:3458:127.0.0.1:3457 \
-o ExitOnForwardFailure=yes -o ServerAliveInterval=15 user@host
Install the gateway CLI on the client. Transfer only the gateway's client token over authenticated SSH into an owner-only file. Do not transfer provider tokens:
umask 077
mkdir -p .state
ssh user@host 'gateway token' \
> .state/remote-client-token
Fetch the host's catalog and generate client settings:
gateway codex-config --model claude-sonnet-4-6 \
--endpoint http://127.0.0.1:3458/v1 \
--token-file .state/remote-client-token > gateway.codex.toml
This command needs no local provider configuration or upstream login. It saves a
public catalog next to the token and writes TOML containing a credential-helper
command. Repeat it after the host changes its model selection, then restart Codex.
Use --catalog PATH to choose a different snapshot path. The token grants access
to all accounts configured on that daemon; issue it only to trusted machines.
The Codex client owns its workspace and executes tools locally. Moving inference to Studio does not move file edits to Studio. When Codex itself runs on Studio, its tools operate on Studio's workspace instead.
The MacBook-to-Studio Claude Max path has been tested with native Codex file reads, free-form patches, follow-up history, cancellation, and recovery. Studio has not yet registered a separate gateway Codex OAuth account. MacBook Pro 2 also passed the Claude/Codex 2 tool loop. Its authenticated reverse SSH forward is supervised by a user LaunchAgent on the inference host.
For the desktop adapter, set the client configuration port to the forwarded
loopback port. Use an absolute client state directory containing the private
client-token file. The adapter fetches fresh public metadata from the inference
host, so it does not need provider credentials or a local account discovery run.
CLI profile catalogs remain startup snapshots.
Installed clients can use a configuration without local providers:
gateway setup --client --port 3459 --token-file ./client-token
gateway tunnel install --tunnel-id host --host user@host \
--port 3459 --remote-port 3457
gateway doctor
gateway desktop register
Copy the client token through authenticated SSH with owner-only permissions.
gateway doctor verifies the forwarded public catalog. Each device needs its own
desktop registration; syncing a chat does not register its model provider.
The native control panel shows this client-only configuration as a read-only
shared catalog and identifies the serving host through authenticated
GET /v1/gateway-info. An older host without that endpoint must be updated to
show its catalog in the control panel; inference and the existing model endpoint
are unchanged. Connection and model-selection editing stays on the host.
Register the backend that owns the chat's workspace. Sharing the catalog does
not transfer local workspace files or automatically configure an SSH execution
backend that bypasses the desktop adapter.
For desktop SSH projects, run gateway ssh register --codex ORIGINAL_PATH on
the remote Mac. Then add its existing host alias under the client's SSH connection
settings. Those rows are native SSH connections: the desktop runs Codex on the
remote Mac, so the gateway models available in them come from that Mac's own
gateway ssh register and gateway configuration, not from the client's catalog.
The gateway listener on that Mac follows installs by itself: the first
connection made after an update starts a listener on the new release, and any
session already running finishes on the old one.
Only the listener owns upgrade retirement for Unix sessions. A session cannot
upgrade its containing process by disconnecting: reconnecting its native proxy
would return to that same loaded listener. Per-session idle upgrade watches are
therefore reserved for stdio adapters, whose parent actually starts a new process.
Managed listeners retire when no sessions remain, or an installed-release
bootstrap publishes a replacement alias without terminating existing sessions.
For drop diagnosis, correlate client connection-state timestamps with the remote
unix_session_end telemetry record. It includes a process-local sessionId,
fixed cause, numeric WebSocket closeCode, and durationMs. Causes distinguish
local session end/failure, listener shutdown, queue/protocol limits, socket errors,
and an otherwise unclassified transport close. A transport_closed/1006 record
alone does not prove a Wi-Fi, SSH, or peer fault; it requires client-side evidence.
No close reason, exception text, address, RPC body, or tool arguments are logged.
gateway diagnostics --since 1 groups them under connectionEnds by cause and
close code; use the underlying event timestamps to correlate both ends.
After a reboot, it also recovers its own dead socket when macOS has changed the
filesystem device number. See automatic reboot recovery
for ownership checks and the separate desktop-startup boundary.
On macOS, the SSH proxy gives the original Codex byte copier fresh stdout and
stderr pipes. Node forwards their opaque bytes with backpressure and waits for
output to drain before returning the native exit status. Inheriting a descriptor
Node already made nonblocking could make the native copier fail with
Resource temporarily unavailable (os error 35) when its output filled, producing
an abnormal WebSocket close even though the listener and shared engines survived.
The regression pauses the caller while the real signed native proxy sends a
4 MiB stream, then verifies every byte and its successful exit. No protocol frames,
tool calls or reconnects are replayed by this forwarding.
The app's Unix socket and native proxy must reach the gateway adapter on that
machine; the built-in Control other devices connection currently bypasses it. See
the adapter setup for command protection and removal.