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 by design: 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
there is nothing for you to configure.
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 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', autoMapModel: null }
}getAll() returns only the keys somebody wrote, so a workspace nobody
has configured answers with 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, which is what a platform-owned workflow asks for when nothing more specific is set. Picked during the guided first run. |
autoMapModel |
Model the built-in Auto-map workflow asks for, overriding defaultModel for that workflow alone. null means fall back to defaultModel. |
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. |
These settings pick models for platform-owned work only. They do not govern your agents: an agent names its own model in its own code. The built-in RAG ingest workflow also keeps its embedding model pinned, because stored vectors have a fixed width and swapping the model would invalidate them.
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. Asking for the model the
Auto-map workflow should use looks like this:
import { stackbone } from '@stackbone/sdk';
const { data: settings, error } = await stackbone.settings.getAll();
if (error) {
throw new Error(`Could not read workspace settings: ${error.message}`);
}
// autoMapModel overrides defaultModel; null on both means nobody has picked one.
const model = settings.autoMapModel ?? settings.defaultModel;
if (!model) {
throw new Error('No model configured. Pick one on the Workspace settings screen.');
}What's next
stackbone.configreads the configuration you declare for your own agent, with the same envelope and the same fallback pattern.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.