Locked settings (runtime.locked)
runtime.locked holds settings the publisher fixes for every
install of an app - unlike the rest of runtime, these are not
meant to be changed per-installer by default. The first field is
byok; byok_editable controls whether an installer may still
override it.
runtime:
locked:
byok: true
byok_editable: false # default - see "Editable vs hard-locked" below
Why this exists
Whether an app calls its provider directly (Local/BYOK - the installer's own key or a local server like Ollama) or through the Digitorn gateway is normally a per-install toggle, stored on the app's own row. That toggle defaults to off (gateway) on a brand-new install.
For an app whose brain is a local-only provider (Ollama, LM
Studio, vLLM), that default is wrong by construction: the gateway
has no route to the installer's own machine, so every call fails
until someone flips the flag by hand - once per daemon that ever
installs the app. runtime.locked.byok: true removes that manual
step: the publisher declares the routing the app actually needs,
and it is correct from the very first call, on every daemon.
byok: false is also valid - a publisher can just as well fix an
app to always route through the gateway, refusing local/BYOK
routing even if an installer's vault has a matching credential.
Where it's applied - and where it isn't
Applied once, at install time - not on every request.
internal/appmgr/install.go's InstallWithOpts is the single
choke point every install path goes through (Studio deploy, Hub
install, CLI install); when the compiled manifest declares
runtime.locked.byok, that value is written straight into the
app's own row (the same byok column the manual per-install toggle
flips by hand) as part of the same install transaction. There is no
separate "apply the lock" step, and nothing re-reads the YAML
after that.
Turn execution never touches the YAML for this. The agent
loop's actual routing decision reads app.Meta.BYOK - a plain
boolean already sitting on the in-memory RuntimeApp the daemon
keeps for every installed app. Adding locked did not add a
YAML parse, a database read, or a lock to that path; it changes
what value install seeds into a column that was already being
read for every LLM call.
An app that never declares runtime.locked.byok behaves exactly
as before this field existed - byok keeps whatever value it
already had (manual toggle, or the builder's "Test" button syncing
it), and a redeploy doesn't touch it. Declaring the lock is what
makes redeploys start re-asserting the value; leaving it
undeclared keeps byok a free-standing per-install setting.
Tracking an installer's override under byok_editable: true -
a redeploy needs to tell "the installer explicitly chose this"
apart from "this is still just the manifest's default" to decide
whether to reassert. BYOKUserSet on the app row is that marker:
the manual toggle (SetBYOK) sets it on every successful change,
and install only re-seeds byok from the manifest when it's still
false. Switching to a hard lock (byok_editable: false) always
reasserts and clears the marker, regardless of its value.
Editable vs hard-locked
byok_editable decides what "locked" actually means once an
installer has their own copy running:
falseor unset (default) - hard-locked. The installer cannot changebyokat all: their app settings toggle is disabled, and a direct attempt to flip it is rejected. Every redeploy reasserts the publisher's value regardless.true- editable.byokis only the default a fresh install starts from. The installer's own app settings toggle stays enabled, and once they change it, that choice survives future redeploys of the same manifest - it stops being silently reasserted. If the publisher later redeploys withbyok_editableremoved or set back tofalse, the hard lock reasserts itself and clears any installer override.
byok_editable also works with no pinned byok value at all -
runtime.locked.byok_editable: true alone grants editing without
fixing a starting value, which only matters on a cloud host (see
below); a desktop install is already fully editable with nothing
declared.
Desktop vs. cloud default
The default for an app that declares no lock at all - genuinely
nothing under runtime.locked - depends on where the daemon runs:
- Desktop / self-hosted (the default):
byokstays a fully free, per-install toggle. Nothing changed here from before this feature existed. - Cloud / multi-tenant (
server.cloud: truein the daemon's own config, not the app's): an undeclared lock defaults to non-editable instead. An installer on someone else's published app can't flip themselves to direct/BYOK routing unless the publisher explicitly allows it - either by pinning a value withbyok_editable: true, or by granting editability alone with no pinned value (runtime.locked.byok_editable: trueand nobyokkey at all).
An explicit byok_editable always wins over this default, on either
kind of host. A pinned byok value with no explicit byok_editable
is a hard lock everywhere, desktop or cloud, exactly as described
above - the desktop/cloud distinction only changes what "nothing
declared" defaults to.
Set from the builder
The Studio canvas never asks you to write this YAML by hand.
Switching the entry agent's Brain node between Gateway / Local
/ BYOK writes or clears runtime.locked.byok for you:
| Mode picked | Effect on runtime.locked.byok |
|---|---|
| Local or BYOK | Written as true |
| Gateway | Cleared (the whole locked block is removed if it's now empty) |
Only the entry agent's own brain drives this - a fallback brain or a secondary agent's brain never writes it, since routing is an app-wide decision, not a per-agent one.
When the entry agent's mode is Local or BYOK, its Brain panel also
shows a checkbox: "Let installers change this for their own
install". Unchecked (default) writes/keeps byok_editable unset -
a hard lock. Checking it writes byok_editable: true. Switching
back to Gateway clears byok_editable along with byok, so
relocking later starts from a hard lock again unless the checkbox
is re-ticked.
Client behavior when locked
The daemon exposes two views of the lock to the client:
- The app settings BYOK toggle reads
byok_lockedoff the app's detail row. Hard-locked disables the toggle outright, with a hint explaining it's fixed by the publisher; editable-locked leaves it enabled like an unlocked app. - The chat session's model picker reads a
locked_byokflag off the session-model endpoint - true only when hard-locked. It greys out and blocks (not hides) any model that would require switching the app's fixed routing mode, instead of the usual "want to enable BYOK?" prompt (that prompt would just be undone by the next redeploy). An editable lock behaves like an unlocked app here: nothing greyed out, since the app settings toggle is the one place that actually changes it.
Cross-references
- Setting this from Studio, in plain terms: Lock model routing
- Unlocked apps can still toggle BYOK by hand, per install - freely on desktop, only if the publisher granted it on a cloud host
- App-config block reference: App Configuration → runtime
- Credentials vault (what a BYOK app's own key actually resolves to): Credentials