roscoe.yaml is Roscoe's configuration file. It declares the AI models the editor exposes, optionally pins server ports, and sets default retry / timeout values for executors that don't override them. Reach for it when you want to add a new model to the picker, run multiple Roscoe installs side-by-side on custom ports, or change the default retry budget for AI nodes globally.
You don't write it from scratch. roscoe init seeds a fully-commented template, and everything below is optional; uncomment the keys you want to override.
Where it lives#
Roscoe reads two files and merges them:
| Source | Path | Purpose |
|---|---|---|
| Global | ~/.roscoe/roscoe.yaml |
Personal defaults, applied to every project |
| Project | <repo>/.roscoe/roscoe.yaml |
Team-shared overrides, committed with the repo |
Project values win over global, key by key. Sections (models, ports, defaults) merge shallowly; arrays inside a section (e.g. models.available) replace wholesale rather than concatenating. If you set models.available in the project file, the global list is ignored: you're declaring the full team-allowed set.
roscoe init creates both files when run inside a git repo (with all keys commented out so the implicit defaults apply). Edit them by hand, or use the Settings page (/settings) in the web UI (see /docs/running/web-ui). The file watcher picks up changes on the next reload and broadcasts an SSE event so open browser tabs refresh without a manual reload.
Schema#
The file is parsed strictly: unknown keys fail validation. Every section is optional; omit a section to fall back to defaults.
models#
Controls the model picker in the workflow editor and the runner's model allowlist. The runner refuses to execute a workflow whose ai_agent, ai_judge, consensus, or map node references a model not in available.
| Key | Type | Constraint |
|---|---|---|
available |
string[] |
At least one entry |
default |
string |
Must appear in available |
ports#
Override the ports each Roscoe surface listens on. Each is an integer in 1..65535.
| Key | Service | Env equivalent |
|---|---|---|
api |
apps/server REST API (dev mode) |
ROSCOE_API_PORT |
web |
apps/web Vite dev server |
ROSCOE_WEB_PORT |
serve |
roscoe serve combined-port default |
ROSCOE_PORT |
Precedence per service: CLI flag > env var > roscoe.yaml > built-in fallback. See /docs/configuration/environment.
defaults#
Defaults applied to executors that don't set their own value.
| Key | Type | Constraint | Default | Notes |
|---|---|---|---|---|
maxRetries |
integer |
0..5 |
1 |
Per-AI-node attempt budget on transient errors and validator misses. Set on a node directly to override. |
timeoutMs |
integer |
>= 1000 |
300000 |
Per-request ceiling for the underlying LLM call (SDK or CLI). Applies to ai_agent, ai_judge, and per-agent inside consensus. Override per node with timeoutSeconds. The Settings UI accepts this in seconds and stores as milliseconds. |
timeoutMs is a total per-request budget: the SDK is configured with
maxRetries: 0 so the configured value is not stacked. The executor's
own withTimeout wraps each backend call with a 5 s grace over
timeoutMs so that a hang surfaces as Node "X" exceeded timeoutMs of N
(canonical executor error) rather than a backend-specific message.
For consensus, map, and round_robin, the per-agent (or per-branch,
per-match) deadline defaults to min(120_000, timeoutMs). Each sub-call gets
at most 2 minutes by design, capped further if you've configured a lower
default. A node-level timeoutSeconds overrides this entirely; it's the only
way to grant a sub-call more than 120s.
Any AI node (ai_agent, ai_judge, consensus) can override timeoutMs
for itself with a timeoutSeconds field (see the per-node docs). This is the
knob to raise for long-running steps such as tool-enabled
ai_agent edits.
updates#
Controls the auto-update behaviour of roscoe serve. Defaults are tuned for
the common case (check every 6 hours, pre-download in the background); set
channel: off to opt out entirely on a CI host or a developer machine
that you don't want auto-fetching binaries.
| Key | Type | Default | Constraint | Behaviour |
|---|---|---|---|---|
channel |
enum |
'stable' |
stable | beta | off |
Release channel. off disables the manifest poll entirely. beta is reserved for a future opt-in pre-release track. |
autoDownload |
bool |
true |
— | When a newer release is found, download + sha256-verify the binary into ~/.roscoe/updates/pending/roscoe so install is a near-instant rename. |
checkIntervalHours |
float |
6 |
0.01 .. 168 |
How often roscoe serve polls the release manifest. The actual interval is jittered by about ±8% (±30 min at the default 6h) to avoid release-day herd effects. |
Override globally for one-off runs with ROSCOE_DISABLE_UPDATE_CHECK=1
(stops the poll without editing config).
analytics#
Controls product telemetry through two independent switches, both on by default. Toggling one never affects the other.
enabled controls usage data: coarse, categorical signals about how
workflows run — whether a workflow came from a repo or the global library, how a
run was started, whether it finished, and bucketed duration/cost ranges. Usage
data never sends workflow names, prompts, node names, file paths, repo or project
names, git refs, or any content, and every event suppresses your IP address.
crashReports controls crash reports — sent when Roscoe hits an error, so
bugs can be found and fixed. A crash report carries the error type and message;
file paths and other PII are stripped before sending, but an error message can
occasionally name a workflow or node.
The identifier on every event is a random per-install id stored in
~/.roscoe/analytics-id (not derived from anything about you), so the data is
minimized and pseudonymous — not "anonymous". Turn either off in Settings →
Telemetry, or here.
| Key | Type | Default | Constraint | Behaviour |
|---|---|---|---|---|
enabled |
bool |
true |
— | Set to false to stop usage data (does not affect crashes). |
crashReports |
bool |
true |
— | Set to false to stop crash reports (does not affect usage data). |
Environment overrides always win over these settings: DO_NOT_TRACK=1 or
ROSCOE_ANALYTICS=off hard-disable both regardless of config.
pricing#
Per-model list-price overrides used to cost runs. Roscoe records each run's cost:
for a claude -p (CLI / subscription) call it uses the CLI's own cache-aware
total_cost_usd; for a metered API (SDK) call, and for the subscription
API-equivalent ("would've cost $X") estimate, it prices the token usage against
these rates. Built-in defaults ship for the current Claude families, so this
section is optional: set it only to correct a rate or price a model Roscoe
doesn't know yet. An unknown model is estimated at the Sonnet rate and logs a
one-time warning until you add it here. Edit these in the Settings → Models
table or directly in YAML.
pricing is an object keyed by model id (matched case-insensitively as a
substring, so claude-haiku-4-5 covers claude-haiku-4-5-YYYYMMDD). Each value
is { input, output } in USD per million tokens.
| Key | Type | Constraint | Notes |
|---|---|---|---|
input |
number |
>= 0 |
USD per 1M input tokens |
output |
number |
>= 0 |
USD per 1M output tokens |
pricing:
claude-opus-4-8:
input: 15
output: 75Cache read/write multipliers are not user-configurable. See /docs/running/cli for capping a run's cost.
Worked example#
# yaml-language-server: $schema=./roscoe-config.schema.json
#
# Roscoe project configuration. All keys are optional — uncomment to override.
# Project-level (.roscoe/roscoe.yaml) values win over global (~/.roscoe/roscoe.yaml).
models:
available:
- claude-haiku-4-5
- claude-sonnet-5
- claude-opus-4-8
default: claude-sonnet-5
ports:
api: 8080 # apps/server (dev)
web: 3000 # apps/web Vite dev server
serve: 7777 # roscoe serve combined-port default
defaults:
maxRetries: 1
timeoutMs: 300000
updates:
channel: stable # 'stable' | 'beta' | 'off'
autoDownload: true
checkIntervalHours: 6
analytics:
enabled: true # usage data; false stops it (crash reports unaffected)
crashReports: true # crash reports; false stops them (usage data unaffected)
pricing:
# USD per 1M tokens; overrides the built-in defaults for run costing.
claude-opus-4-8:
input: 15
output: 75The seeded template ships with every key commented out so a fresh install behaves identically to a missing file. Uncomment only the lines you actually want to pin.
See also#
- /docs/configuration/environment — env var overrides for ports and paths.
- /docs/configuration/llm-backends — how the model field is dispatched at runtime.
- /docs/configuration/workflow-sources — the same global / project layering applied to workflow files.
- /docs/running/web-ui — editing
roscoe.yamlfrom the Settings page.