stackbone.settings
Typed, read-only access to the workspace settings an operator edits in the dashboard. Your code asks for a key and gets the value in effect right now. There is no write path here: the dashboard owns the values.
Mental model
A workspace carries two sets of knobs, and they belong to two different people.
| Surface | Who decides the keys | Who writes the values |
|---|---|---|
stackbone.config |
You, in your own config.schema.ts. |
The dashboard. |
stackbone.settings |
The platform. Values its own built-in features read. | The dashboard. |
stackbone.settings covers the second kind. It offers no writes: a second,
unvalidated write path would let an agent overwrite a choice an operator made
in the UI.
The values live in your agent's own Postgres, and the SDK reads them over the
same handle as stackbone.database, so a read still
works when the control plane is unreachable. The runtime injects everything the
read needs, so you configure nothing.
Read one setting
import { stackbone } from '@stackbone/sdk';
const { data: model, error } = await stackbone.settings.get('defaultModel');
if (error) {
// Nobody picked a value, or the read failed. Fall back to your own default.
console.warn(`No workspace default model: ${error.code}`);
} else {
console.log(`Workspace default model: ${model}`);
}Reads never fill in defaults for you. That keeps "the operator picked nothing" apart from "the operator picked the value that happens to be the default".
| Situation | What you get |
|---|---|
| Nobody ever set the key | error.code: 'settings_not_found' |
| Set, then explicitly cleared | data: null |
| Set to a value | data: the stored value |
Read everything at once
import { stackbone } from '@stackbone/sdk';
const { data: settings, error } = await stackbone.settings.getAll();
if (error) {
console.warn(`Settings unavailable: ${error.code}`);
} else {
console.log(settings); // { defaultModel: 'openai/gpt-4o', judgeModel: null }
}getAll() returns only the keys somebody wrote. For a workspace nobody has
configured, you get an empty object. The result is a partial of
WorkspaceSettings, a type the SDK re-exports so your code and the dashboard
agree on the same key names:
import type { WorkspaceSettings } from '@stackbone/sdk';The keys today
| Key | What it controls |
|---|---|
defaultModel |
The workspace's general-purpose chat model. A platform-owned workflow asks for it when nothing more specific is set, and it is also the last fallback for your own agents and model keys. Picked during the guided first run. |
guardrailModel |
Model the model-backed guardrail checks ask for. null falls back to the platform default (openai/gpt-4o-mini). |
judgeModel |
Model that grades the rubric criteria of an eval suite, for every criterion that names no model of its own. null falls back to the platform default (openai/gpt-4o-mini). |
simulatorModel |
Model that plays the end user when an eval case needs a simulated reply. null falls back to the platform default (openai/gpt-4o-mini). Kept apart from judgeModel so grading stays independent. |
In Studio, an operator picks defaultModel under Settings › Workspace and
the other three on the cards of
Settings › Model defaults.
Three of those four keys pick models for platform-owned work only.
defaultModel reaches further: it is the last fallback for your own agents and
for every key your code names with
stackbone.models.use, after the
operator's pick and after the default written in the code. The built-in
RAG ingest workflow keeps its embedding model pinned,
because stored vectors have a fixed width and swapping the model would
invalidate them.
Three more keys govern how long the box keeps its own records. All are numbers, not model ids:
| Key | What it controls |
|---|---|
logRetentionDays |
How many whole days of log lines are kept, between 7 and 90. null means the platform default of 30 days. It never means "keep forever". |
logStorageBudgetGb |
A ceiling on the space the stored log lines may occupy, in whole gigabytes. Crossing it drops the oldest day early, never below the 7-day floor. null, the default, means no ceiling. |
eventRetentionDays |
How many whole days of events the box keeps for Widgets and Dashboards, between 7 and 400. null means the platform default of 90 days. An hourly job deletes older events, and never the most recent one. |
The list grows as the platform adds knobs. A workspace written by a newer version may carry keys an older reader has never heard of, and reading never fails because of them.
Errors
Every call returns the usual { data, error } envelope.
| Code | Means |
|---|---|
settings_not_found |
The key is valid but nobody has written it. Use your fallback. |
settings_invalid_request |
An empty key reached get(). |
settings_not_configured |
This agent's database predates the settings table. Run stackbone db migrate up. |
settings_unavailable |
The database read itself failed. |
database_not_configured |
This agent has no database, so there is no settings row to read. |
A failed read is rarely a reason to stop. For a knob with a sensible fallback,
treat any error as "nothing picked" and carry on. To pick the model a key of
your own code runs on, with the operator's pick first and defaultModel last,
use stackbone.models.use rather than reading
these settings yourself.
What's next
stackbone.configreads the configuration you declare for your own agent, with the same envelope and the same fallback pattern.stackbone.modelsresolves the model one key of your own code runs on, and falls back todefaultModelwhen nothing else names one.stackbone.aiis the client that calls the model these settings name.- Guardrails are the other thing an operator configures in the dashboard and your code never imports.