--- title: 'stackbone.settings' description: 'Read-only access from your agent code to the workspace knobs an operator picks in the dashboard.' position: 9 --- # `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`](/docs/sdk/platform/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`](/docs/sdk/data/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 ```ts 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: ''` | ## Read everything at once ```ts 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: ```ts 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](/docs/sdk/humans/guardrails) 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](/docs/sdk/data/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: ```ts 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.config`](/docs/sdk/platform/config) reads the configuration you declare for your own agent, with the same envelope and the same fallback pattern. - [`stackbone.ai`](/docs/sdk/platform/ai) is the client that calls the model these settings name. - [Guardrails](/docs/sdk/humans/guardrails) are the other thing an operator configures in the dashboard and your code never imports.