Settings¶
How defaults cascade from the operator to workspaces to agents, and who may
change what. Built: the catalog is crates/api/src/settings/mod.rs, the rows are
setting_overrides, and the walk is SettingsStore::resolve, called once per
turn in prepare_turn. It holds nine settings, listed under
What is in it.
Settings that only mean something to a model -- temperature,
reasoning_effort, context_budget -- are moving to a cascade keyed by model
as well as level; see models.md.
The shape¶
A catalog in code and overrides as rows. The same split as authorities and roles.
The catalog lists every setting: its key, its type, its default, and who may override it. It changes when the code changes, because a setting nothing reads is noise and a value nothing names cannot be set.
The rows hold overrides, one per level that has chosen to differ:
system (operator) temperature = 0.3 the default everyone inherits
workspace (Kestrel) temperature = 0.1 override on: a row exists
agent (Invoicer) -- override off: no row, inherits
Resolution walks up: the agent's row, else the workspace's, else the system's, else the catalog default. Three settings are about a model -- temperature, effort and the conversation's size -- and may also be chosen for one model at any level; how that cascades, and why the gateway resolves two of them, is in models.md. An agent made from a template has one level more, and it wins over all of these: the values its template fixes (agent-templates.md). Turning an override off deletes the row, so that level falls back to whatever is above it. There is no "copy the default down" step, which is what lets an operator change a system value and have it reach every workspace that never chose otherwise.
A setting that is a ceiling¶
Most of these are preferences: a temperature, a budget, how much an agent may
read. approve_new_hosts is not -- it says an agent may not reach a host nobody
reviewed without somebody's word, and it is a setting for a reason worth
stating, because the alternative looked plausible.
The per-operation approvals in approvals.md are declared in the frontmatter of the skill file documenting an operation, which is right for them: a skill adding a rule about its own endpoint can only make the platform stricter. A ceiling cannot work that way. It has to hold for an agent with no skills at all, and a workspace must not be able to escape it by publishing a skill that omits a line. So it cascades like everything else here, and the API turns it into ordinary gates when it prepares a turn.
Who may override¶
Part of the catalog, not of the roles. Each setting is operator-only, workspace-overridable -- which may also be overridden per agent -- or an operator ceiling.
An operator ceiling is for a feature a deployment may need to forbid: the
operator's value bounds what a workspace may choose, so a workspace may be
stricter and never looser. An operator who turns it off turns it off
everywhere, and a workspace asking to turn it back on is refused rather than
saved and ignored; one who leaves it on leaves each workspace free to turn it
off for itself. A row a workspace wrote before the operator turned it off is
bounded when read, so it does not get through either. Stricter means earlier
in the choice's options, which are listed strictest first. It stops at the
workspace: a ceiling is about the people using the product, so an agent's page
does not offer it and a template cannot fix it. Dictation is one;
auto_approve_max_risk (auto-approval.md) is the other.
- Every setting in the catalog today: temperature, reasoning effort, file access for both scopes, new-host approval, model calls per turn, context budget and session naming. All workspace-overridable.
- Model routing: operator-only. The operator certified a workflow against a model and pays for it; a workspace switching models breaks both. A workspace that brings its own key gets model choice within what the operator has certified, and that is a routing feature (see routing.md), not a setting.
- Storage retention per scope, when built: operator-only default, workspace may shorten.
What the UI does with it¶
A settings page reads the catalog and shows each setting's effective value and where it came from: "platform default", "set by this workspace", "set for this agent". Beside each workspace-overridable setting is an Override checkbox. Off, the value is shown grayed and inherited. On, it becomes editable and a row is written. The agent editor uses the same component for agent-level overrides.
The point is that a workspace who does not know what temperature is never sees a blank number they are expected to invent. They see a value that is already right and a checkbox they can leave alone. Only the operator has to understand every setting, and the operator is the one who set the defaults.
Skills as a level¶
When skills exist, a skill sits between workspace and agent in the walk and may pin settings: an invoice skill certified at low temperature and high reasoning effort declares that, and an agent running the skill gets those values however the workspace configured itself. A skill's pins are declared in its frontmatter, because they are facts about the skill; who is billed for running it is not, and never belongs there.
What is in it¶
Temperature, reasoning effort and model calls per turn began here, moved out
of the agent's free-form policy JSON, where they had no defaults above the
agent and no way for an operator to set them once. The rest arrived with the
features they govern. Storage retention comes when scopes do. Every setting
below is workspace-overridable, and so overridable per agent too.
| Key | Label | Default | Choices |
|---|---|---|---|
temperature |
Temperature | unset, left to the provider | 0 to 2 in steps of 0.1, or unset |
reasoning_effort |
Thinking before answering | low |
none (Off), none_repeat_prompt (Off, with prompt repetition), low, medium, high |
agent_file_access |
Agent files | read_write |
none, read, read_write |
workspace_file_access |
Workspace files | read |
none, read, read_write |
approve_new_hosts |
Approve new hosts | reach_freely |
reach_freely (Reach freely), approve_new_hosts (Ask for approval) |
max_tool_rounds |
Model calls per turn | 100 | 0 to 10,000; zero is no limit |
max_written_bytes |
File writes per turn | 1 GiB | 0 to 1 TiB, in bytes; zero is no limit |
context_budget |
Conversation size sent to the model | 400,000 bytes, or two bytes a token of the model's window where less | 1,000 to 100,000,000 bytes; at most two bytes a token of the window |
session_naming |
When to name a conversation | after_first_turn |
after_message, after_first_turn, after_second_turn |
dictation |
Dictation | on |
off, on; an operator ceiling, per workspace only |
auto_approve_max_risk |
Auto-approval | none |
none, low, medium, high; an operator ceiling, per workspace only |
Where each is explained in depth:
reasoning_effort: the repetition choice is below.agent_file_access,workspace_file_access: theagent/andworkspace/scopes in storage.md. Session files are always read and write, and an agent can always read what it may write.approve_new_hosts: above, and egress.md.max_tool_rounds: a runaway guard, not a budget; nothing more to it.max_written_bytes: the same, for files. Counted as bytes are sent, so a write that would cross it is refused before anything lands. Requests through the gateway and listings of storage have fixed limits of their own, a thousand each per turn, in the runtime rather than here.context_budget: compaction.md.session_naming: below, since nothing else covers it.dictation: the microphone in the message box, using the browser's own speech recognition, which in most browsers sends the audio to the browser's maker to transcribe. On by default, since that custodian already sees everything typed into the page; see who may override for why it is a ceiling.
The endpoints are /v1/settings (workspace), /v1/platform/settings
(operator) and /v1/agents/{id}/settings (agent), each returning every
setting with its effective value, where it came from, what this level would
inherit, and whether this level has its own row. PUT sets a row, DELETE
removes it.
Session naming¶
A conversation nobody has titled is named by a model, as a background job
queued when a turn finishes (crates/api/src/naming.rs). The setting decides when,
and how much of the conversation the model is shown:
- After the first message (
after_message): queued when the first turn ends, but the namer is shown only what the person wrote. Cheapest and quickest, and as vague as the opening message is. - After the first reply (
after_first_turn, the default): queued at the same point, with the reply in view, so the title says what the exchange turned out to be about. - After two exchanges (
after_second_turn): waits until the session has two non-empty replies. Usually the best title, later.
Either way the namer checks again before it writes, so a title a person set while the job waited is kept. With no chain for naming -- its own, or assistant's, which it borrows -- sessions go unnamed whatever this says.
Prompt repetition¶
"Thinking before answering" has one choice that is not a level of effort:
Off, with prompt repetition (none_repeat_prompt). Thinking is off, and
the turn's prompt is sent twice:
A model reads its prompt one token at a time, each able to look only at what came before it, so the start of a question is read without knowing how it ends. A second copy is read with all of the first in view. Google found this improves answers when a model does not deliberate, and does little when it does -- thinking re-reads the question anyway (Leviathan, Kalman and Matias, 2025). So it is offered as what a model gets instead of thinking, not alongside it.
Only the prompt this turn answers is repeated. The system prompt and earlier
messages are not: repeating the history would double what each round costs
to restate what the model already answered. It is found by its text rather
than its position, since a turn resumed after an approval does not end on its
prompt; a prompt nobody typed, such as a wake, is sent once. And it changes
only what the model is sent, never the stored conversation -- see repeated
in crates/api/src/worker.rs.
The cost is the prompt's tokens a second time, on every round of the turn. After the first round they are part of a cached prefix where the provider caches (caching.md).
What is deliberately not a setting¶
- Anything the agent could read or change. The sandbox receives resolved values on the turn and nothing else, the way it receives credentials.
- Authorities and roles, which have their own tables and their own rules.
- Routing rows, which are ordered lists with credentials attached, not scalar values, and are documented separately.
- Memory. "This customer pays three months late" is a fact the agent learns, scoped to a workspace, stored as an agent- or workspace-scope file. It is read into prompts, not resolved as a default.
A generic key-value store with a generic editor would be the quick way to build this and the wrong one: the catalog is what keeps the page honest about types, defaults and who may touch what. Purpose-built features that happen to store their "who may override" bit in one place is the intended layering.