Skip to content
RoutineOS
Esc
↑↓navigate↵open⌘Jpreview
On this page

Settings

Typed values people tune on the Desk without editing the prompt. How they are declared, stored, snapshotted on each run, and used as filters.

What it is

A setting is a typed value a person can change without touching the prompt: which markets to search, which title keywords count, which companies to ignore, how many Inbox messages to allow per run. Settings are declared in routine.toml, stored in the store, and edited on the Desk.

Why it exists

People steer routines all the time. If steering means editing a prompt, only the builder can do it, every change risks breaking something else, and nobody can say later what a run was told. Settings make steering safe: each value has a type and a range, lint checks it, the Desk shows a proper control, and each run records exactly which values it used.

Settings are owned by people. A run never writes them. If a run thinks a value should change, it proposes the change in the Inbox; see Learning.

How it works

Three layers

  1. Static: the defaults in routine.toml, versioned with the routine.
  2. Per routine: the values in settings/<producerId> under values, edited on the Desk.
  3. Per run: one-off overrides when a run is triggered by a request.

The prompt reads layer 2, falls back to layer 1 when the document is missing (a missing document is treated as a first run), and the write step snapshots the values used onto the run document as settingsUsed. A later edit never changes what an earlier run is shown to have used.

Seeding

seed writes the defaults to settings/<producerId> and settings/workspace only when they are absent. Reseeding never overwrites a saved value.

Filters

A list setting with role = "include" or role = "exclude" filters records, through a settingFilters entry in the definition that names the field it checks.

  • Include keeps only records whose field matches an entry. An empty include list keeps everything.
  • Exclude drops records whose field matches an entry.
  • Text fields match case-insensitive substrings: commerce matches Ecommerce Developer. Other field types match whole values, case-insensitive for strings.

A filtered record is not deleted. It is written with status: "dropped" and a reason: not in <setting> for an include miss, excluded by <setting> for an exclude hit. A record a person chose to keep is never dropped by a filter.

The substring rule came from a pilot run (2026-10-29-0438) in which whole-word matching dropped two Ecommerce roles.

Changing a setting

On the Desk Settings page a person edits a value and saves. The page writes settings/<producerId> and shows “Saved. Applies from the next run.” Page writes are last-writer-wins, and the page says so.

Worked example

Hiring Signals declares five settings:

[[setting]]
name = "title_keywords"
type = "list"
role = "include"
label = "Title keywords"
default = ["Shopify", "headless", "commerce", "AI automation"]
cost_note = "each keyword adds a search per market"

[[setting]]
name = "max_inbox_per_run"
type = "number"
label = "Inbox messages per run"
default = 5
min = 0
max = 20
cost_note = "no extra cost; more messages ask more of your attention"
Setting Type Default Filters
markets list, include AU, US, CA, NZ, PH role market
title_keywords list, include Shopify, headless, commerce, AI automation role title
excluded_companies list, exclude none (example northwind.example) company domain, role company_domain
lookback_days number, 1 to 30 7 none
max_inbox_per_run number, 0 to 20 5 caps the Inbox

In the Quickstart run, “Graduate Data Analyst” contains none of the title keywords, so it was written as dropped with the reason not in title_keywords, and the run recorded droppedByReason: {"not in title_keywords": 1}.

Reference

Setting keys

Key Applies to Notes
name all Required. Name by effect, not mechanism
type all Required. toggle, number, choice or list
default all Required. Number defaults must sit inside min and max; choice defaults must be in choices
label all Text the Desk shows next to the control
example all A sample value shown as a hint
cost_note all What turning it up costs
min, max number Range; lint enforces
choices choice The allowed values
role list include or exclude; makes the list a filter

Workspace settings

settings/workspace holds settings for the whole Desk. Seed writes:

{"values": {"notifications": "inbox", "quietHours": {"from": "", "to": ""}, "mergePolicy": {"company": "merge", "role": "merge"}},
 "updatedAt": "<seed time>", "updatedBy": "seed"}

Setting values.learning: false in it turns learning off for the workspace; see Learning.

Never learnable

A setting whose name, with case and separators removed, contains push, gate, send, alert, permission, budget, maxruns or capoverride can never be changed by a proposal of any shape.

Common pitfalls

  • Rules in the prompt instead of a setting. If a person will ever change it, it is a setting, and if it filters records, it is a filter. The model does not reliably apply prose rules on every record.
  • An include list emptied by accident. An empty include list keeps everything. The Desk refuses to accept a proposal that would empty one.
  • Expecting a change mid-run. A saved value applies from the next run.
  • Two people editing at once. Page writes are last-writer-wins. The second save replaces the first.
  • Naming a setting alert_threshold and expecting learning to tune it. The name contains alert, so it is never learnable. Rename it if learning should touch it.

Was this page helpful?