Machine config and native models
Select machine-local configuration, inspect native model availability and read how unattended launches use harness permissions.
Machine config
~/.yoke/config.json holds machine-local connections and tunables: which
environment is active, API URLs, local paths. Secrets for capabilities live
under ~/.yoke/secrets/ (not in the repo).
A connection's protected boolean means it holds real data, regardless of its
name or deployment target. Set it with yoke connection set ENV --protected;
clear it with --unprotected. yoke dev db-admin setup accepts the same flags.
Direct export/import and disposable database recipes honor this marker.
Stored connections using the previous prod key still read as protected;
the next config write normalizes that key. The old CLI flags are removed.
Relay service labels and state directories depend only on the canonical config
path and connection name. Changing protection cannot move a relay; several
protected HTTPS connections can each run their own relay. Installation retires
the former shared service only when its document proves the same config, machine
home and connection. It preserves the former state directory. Live or unknown
worker custody refuses as relay_shared_service_retirement_blocked; close those
worker sessions and retry installation. A malformed service document requires
ownership repair before retry. A database-admin door still uses its paired
HTTPS relay; protection alone does not identify that pairing.
For an isolated machine config, select its home before running a writer:
YOKE_MACHINE_HOME=/tmp/yoke-worker yoke env use local
Configure local in that home first. YOKE_MACHINE_HOME selects
config.json inside that directory and takes precedence over
YOKE_MACHINE_CONFIG_FILE. Without a home override, the config-file variable
selects a file; a relative value anchors under ~/.yoke, then the default is
~/.yoke/config.json. --config selects an explicit file; relative values
anchor under the selected machine home.
Writers refuse machine_config_not_owned when the target differs from the
selected config or resolves outside an explicit YOKE_MACHINE_HOME, including
through a symlink. Remove --config and retry with the selected config.
This check runs before config
locking or credential changes; readers may inspect an explicit foreign file.
Relay-launched sessions discard an inherited YOKE_MACHINE_CONFIG_FILE for
all harnesses and surfaces. They retain the selected machine home, and their
child processes inherit that environment. An explicit launcher environment
may select a shared config; set its machine home consistently. An isolated
worker never uses a steering machine's config-file override implicitly.
connection_projects stores one checkout per project on each named connection:
{"active_env": "hosted", "connection_projects": {
"hosted": [{"checkout": "/work/hosted-project", "project_id": 7}],
"self-hosted": [{"checkout": "/work/private-project", "project_id": 7}]
}}
Register with yoke --env hosted project register /work/hosted-project --project-id 7.
Connection selection follows --env, then YOKE_ENV, then the deepest
registered checkout containing the current directory (including its Git lanes).
Without a checkout match, a --project P or PREFIX-N item reference selects
its connection when registered on exactly one connection; otherwise active_env
remains the fallback. Slugs and prefixes use the existing project inventory on
registered connections; an unavailable inventory names the connection and asks
for --env ENV. Machine commands without a project reference use the fallback.
yoke env use ENV changes that fallback, without changing checkout routing.
yoke projects checkout-context reports connection and connection_source
after the project identity; --field retains its single-value output.
If equally deep checkouts match unrelated connections, selection refuses with
checkout_connection_ambiguous. Pass --env ENV, or register the checkout with
yoke --env ENV project register CHECKOUT --project-id N --reassign to remove
the same checkout from the other connections.
Numeric project IDs belong to that connection's universe; the same ID on another
connection has its own checkout. A paired HTTPS connection and its database-admin
connection share the HTTPS connection's map. An unmapped checkout reports the
registration command for the selected connection; it never borrows another map.
Removing a connection keeps checkout records. Moving an occupied project's
checkout requires --reassign to deliberately replace its routing on the
selected connection in this machine's config; --reassign also removes the same
checkout from other connection maps.
Reading config never rewrites it. On the first explicit project register, an
older flat projects list imports once under the configured active_env, even
when the command selects another connection. Set that default to the connection
that owns those old IDs before registering. The retained flat list is an inert
snapshot for an already installed older reader; new routing never falls back to
it, and later registrations update only connection_projects.
Unknown keys warn once per file/key as machine_config_key_unknown and are ignored.
Remove the key or use a release that supports it. Invalid known values still refuse;
extra settings do not disable commands or harness hooks.
The installer records settings.distribution as {"origin": "https://api.upyoke.com", "channel": "stable"} using the actual install selection. yoke update requires
that record and uses it in a fresh shell. Select or repair it explicitly with
yoke settings set distribution '{"origin":"URL","channel":"NAME"}'; run that command's
--help for flags. This does not change the active control-plane connection.
Relays connected to a private API host also require this record and install
from origin/simple/; they do not infer an index from the API host. See
Maintaining a private fork for artifacts and recovery.
Install and repair commands follow the connected hosted environment. Local and
self-hosted connections use settings.distribution.origin; serving processes
may declare their origin with YOKE_INSTALL_BASE_URL. Missing origin or channel
reports install_origin_unavailable and names yoke settings set distribution
instead of choosing Production. Browser onboarding receives its installation
command from the engine; an older engine without that field asks its operator
to update and restore the distribution origin.
Launch model choice does not live in machine config. An item launch takes the
item's workflow stage level and Yoke places it on one of that level's options —
see launching by level. A
level or an exact selection with --surface and the knobs below is an
override.
Other unnamed knobs on an explicit model selection take the vendor default. Preview combines equal requested/effective settings and shows
both when they differ, with each knob's source (level SENIOR option,
explicit launch request, or vendor default). Empty rows are omitted;
--json retains the complete record. The bound session shows
the effective ask beside provider-attested served facts. A machine file that
still carries a retired launch-default key keeps loading; yoke status warns
machine_config_key_retired, and the next config write removes the key.
yoke session-control launch preview --model M reports each machine's quota
in the pool M actually bills to, under REQUESTED MODEL POOL, and ranks
machines by that pool's meter rather than by whichever window reads lowest.
The human machine table appears when placement, eligibility or pool readings
decided the outcome; all candidates and relays remain available in --json.
yoke session-control launch create --idempotency-key K replays the launch already named by K. If its
session ended or was terminated, launch_replay_finished names that launch
and says no new worker started. Repeat create with a new key to relaunch.
A fresh item-bound create refuses item_has_live_worker while a live session
holds its claim or an earlier launch is pending or has a live session. The
refusal names the session and launch and leads with
yoke session-control session wake SESSION-ID: a worker whose process exited
still resumes the same session, claims and lane from its transcript (a desktop
session refuses the wake; message it instead). Terminate it only when that wake
reports the transcript gone or the resume gets no answer; a worker holding the claim itself is
told to release it before launching its own level-change successor. Same-key
replay still deduplicates.
--context-window accepts a token count or compact form such as 1m.
--list-models --surface SURFACE prints this machine's observed native
availability (below), plus accepted effort and context values. Claude maps context 1M to the
model's [1m] selector and effort to --effort; Codex maps effort to
-c model_reasoning_effort=... and refuses explicit context. Cursor passes an
exact advertised selector, such as cursor-grok-4.6-high; a separate matching
effort is encoded once, and a conflicting effort refuses. A base name plus
effort resolves only to an advertised variant. If a selector omits cursor-
and the matching prefixed selector is advertised, the refusal suggests it.
Cursor context is model-specific:
an explicit window requires that exact variant's native display label to name
it. Grok has no advertised 1M window; omit the context flag. A label establishes
a selectable option, never a served-session measurement, so unattested context
stays unknown. Preview and create use the chosen machine's native observations
for these checks. An unsupported combination is a preview refusal named for
the harness and knob, with a recovery step. A combination the
provider rejects at run time fails as model_combo_unsupported, retains a
bounded vendor message in launch evidence, and never retries under defaults.
Selectable models are observed, not declared
Which models a surface will accept is a fact about the account and build on one machine, so Yoke reads it from the surface rather than shipping a list. Each relay poll refreshes a per-surface reading and carries it on the heartbeat, so a model an account gains becomes visible to the fleet within about a minute rather than within a release.
Discovery is per surface, and a surface with no adapter says so:
| Surface | Route |
|---|---|
cursor-cli |
cursor-agent --list-models |
codex-cli |
codex app-server model/list |
| every other surface | none declared; the reading says so by name |
Shipping one vendor's CLI adapter proves nothing about the same vendor's desktop app or editor extension, so every known surface gets its own reading rather than inheriting a sibling's.
Each reading names its own status:
| Status | Meaning |
|---|---|
ok |
the surface answered just now; models is current |
stale |
the last attempt failed; models is what it last published |
unsupported |
Yoke declares no listing adapter for this surface |
unknown |
the surface has never answered |
Only ok and stale carry models. Neither unknown nor unsupported is
evidence that a model is unavailable — a caller routing work reads the
status before the list. A failed probe never empties a list that was
populated: it keeps the models with their original observation time and flips
the status to stale, because an unreachable surface has not withdrawn
anything.
Each model entry carries what its vendor published: the selectable token, a
display description, that model's own reasoning options and default, and any
replacement target with its retirement time. Reasoning options are per model
rather than per surface — one installed app-server offers ultra on its
newest model and not on the one beside it.
Availability carries no dependency on researched pricing or tier data. A model this machine can select today is reported today, whether or not anything else is known about it.
Read it three ways:
yoke relay probe-models [--surface S] [--json] # refresh this machine now
yoke session-control launch preview --list-models # accepted flags beside availability
yoke steering report get # changed sections in held scopes
The relay refreshes on its own cadence during normal polling;
yoke relay probe-models is the bounded refresh for when you need the answer
before the next poll.
Launched sessions run unattended
A session the launch plane starts is an autonomous worker with nobody
watching its terminal, so every launch and every wake engages the harness
permission bypass: Claude Code is launched with
--dangerously-skip-permissions, Codex CLI with approvals, sandbox, and hook
trust bypassed (--dangerously-bypass-approvals-and-sandbox plus
--dangerously-bypass-hook-trust; the app-server route uses equivalent
thread parameters where available), and Cursor with
--force alongside --trust. This is unconditional for launched sessions
and changes nothing about a session you start yourself.
One native gate can still refuse: Claude Code declines a bypassed background
launch until the machine has accepted the bypass disclaimer once. The launch
reports permission_bypass_unaccepted with the recovery step — run
claude --dangerously-skip-permissions interactively on that machine, accept
the prompt, then retry.