Every key of the runs settings file (harness.json), where it is read from, how it is decoded, and each key's type, default and meaning, with the nested shapes.
harness.json is the runs settings file: the models, presets and roles for every run, and the tools, formatters and servers they use.
The file is the --harness-config flag, else the desk.json harness_config value, taken from the project when relative. There is no default path: with neither set, no file is read. Each linked project still launches with its own record's slug, workspace and checks and smith's defaults for the rest; without a linked project the desk's own harness launches nothing. See desk-json.
decodeHarnessConfigWarn decodes it strictly. An unknown key, a second JSON value or a null file stops the core. A model registry or preset that does not validate is refused at decode.
The top-level secrets key still loads and is ignored. It gives a warning.
routes.research loads as the old name of routes.challenge. It gives a warning. It is refused only when both are set and differ. The table of renamed keys (renamedFields) is empty, so no key is refused with a hint.
A tool or mcp server secret still holding an op:// ref gives a warning.
Every key in this file applies live: a saved change is read without a restart. Only the choice of which file is read (harness_config) is a restart setting.
Every role can change runtime. The work role takes claude or codex; intake, plan, review and close take claude, codex or grok. An empty runtime means claude.
The reviewer must differ from the worker. A pinned model wins over the role's tags, and a pin that belongs to another runtime is skipped.
none: the shipped quick, balanced, thorough, max, lean and heavy
A preset of a shipped name replaces that preset; any other name is added. Each is validated at decode.
presets entries
key
type
default
meaning
presets[].name
string
none
The preset's name.
presets[].level.floor
number
0
The lowest registry rank a role's model may have.
presets[].level.ceiling
number
0: no ceiling
The highest rank.
presets[].level.prefer
highest or lowest
highest
Whether the strongest or the cheapest model in the band wins.
presets[].level.effort
low, medium, high or max
none
The effort asked of claude and codex.
presets[].pins
object of role to model
none
A model for a role; it wins over the level.
presets[].role_tags
object of role to tags
none
Replaces the tags a role asks for under this preset.
presets[].routes.challenge
off, on or auto
off
The step before the plan. The old key research loads as this.
presets[].routes.review
off, on or auto
off
The first model review.
presets[].routes.second_review
off, on or auto
off
A further review by a different model.
presets[].max_revise_loops
number
not checked
The revise-loop cap.
presets[].checks
list of check ids
nil: run them all
Narrows the check set; it can never empty it.
presets[].budgets.max_output_tokens
number
0: no budget
The output-token budget.
presets[].budgets.max_searches
number
0: no budget
The search budget.
presets[].limits
object of role to limits
none: the template's own
Per role: max_output_bytes, max_memory_bytes, active_deadline (a positive duration) and max_attempts. A zero field keeps the template's.
presets[].max_asks
number
3
How often the work node may ask a stronger model; 0 turns the ask tool off.
The shipped lean is level prefer lowest and resolves intake claude-sonnet-5-5, plan claude-opus-5-5, work claude-sonnet-5-5, review claude-opus-5-5 and close claude-haiku-4-5-20251001. The shipped heavy is lean with role_tags work [code, reasoning]: work claude-opus-5-5, and review claude-fable-5-1 because review must differ from work. Both have challenge, review and second_review off and max_revise_loops 2, and pin nothing. balanced stays the default.
max_parallel
type
default
meaning
number
1
How many writer runs go keeps live at once, each in its own worktree. Not the scheduler's options.max_parallel.
mcp_servers
type
default
meaning
list of server objects
none
External MCP servers a role may be granted as mcp:<id>. A project's entries replace the global ones with the same id.
mcp_servers entries
key
type
default
meaning
mcp_servers[].id
string
none
Lower-case letters, digits, _ and -; cannot start with smith; unique.
mcp_servers[].command
string
none
A stdio server smith spawns. Exactly one of command or url.
mcp_servers[].args
list of strings
none
Only with command.
mcp_servers[].secrets
object of env name to env:NAME
none
Only with command; the name cannot be PATH or HOME.
mcp_servers[].url
string
none
An http(s) server smith connects to.
mcp_servers[].headers
object
none
Only with url; a value is an optional literal prefix and one trailing env:NAME.
mcp_servers[].tools
list of strings
nil: every tool the server lists
The allowlist.
mcp_servers[].mutating
list of strings
none
Tools that access: read hides; each must be in tools when that is set.
mcp_servers[].access
read
unset
read hides the mutating tools.
tools
type
default
meaning
list of tool objects
none
Commands that tool nodes run, by id. Only this file declares them, never a template or a model. A project's local half replaces them whole.
tools entries
key
type
default
meaning
tools[].id
string
none
Letters, digits, ., _, -; unique.
tools[].command
string
none
Required.
tools[].args
list of strings
none
tools[].timeout
duration string
not checked
Must be positive when set.
tools[].env
object
none
A token-shaped value is refused.
tools[].secrets
object of env name to env:NAME
none
A secret reaches a tool only as a ref.
tools[].output_schema
string, a path
none
Absolute or ~/.
tools[].retries
number
0: none
Cannot be negative.
tools[].workspace
read or empty
empty: a scratch folder
read makes the run's workspace the tool's working folder.
format
type
default
meaning
list of formatter objects
none
Run on the worker's changed files just before the work is sealed. Every project's scope inherits it.
format entries
key
type
default
meaning
format[].id
string
none
Required; unique.
format[].executable
string
none
Required.
format[].args
list of strings
none
The changed files are appended.
format[].match
string
empty: every changed file
A path.Match pattern on a changed file's base name.