Dobby reads built-in defaults, then dobby.config.json in the code folder (it can only tighten safety keys), then your private file (dobby config path prints where it is). A later layer wins. Run dobby config show for the merged result. dobby config set <key> <value> changes one setting in your private file after checking it against this schema (dobby config unset <key> puts it back to the default); the dashboard's Settings page does the same.
timezone
| Key |
Type |
Default |
Notes |
timezone |
string |
your system's time zone |
the clock Dobby reads times and daily hours in; an IANA name like Asia/Kolkata (the default is this Mac's own). |
timezoneLabel
| Key |
Type |
Default |
Notes |
timezoneLabel |
string |
its short name, like PDT |
shown after clock times ("14:03 IST") |
quietHours
notifications go out silent
| Key |
Type |
Default |
Notes |
quietHours.start |
integer (0–23) |
23 |
|
quietHours.end |
integer (0–23) |
8 |
|
eveningPostHour
| Key |
Type |
Default |
Notes |
eveningPostHour |
integer (0–23) |
21 |
the daily usage post in #system-status |
github
| Key |
Type |
Default |
Notes |
github.owner |
string |
"" |
the person whose @dobby PR chat is answered ("" = nobody) |
github.accounts |
list of string |
[] |
users/orgs whose repos get reviewed |
github.mergeMethod |
squash | merge | rebase |
unset |
how Dobby merges a PR (default squash) |
github.deleteBranch |
boolean |
unset |
delete the PR branch after Dobby merges it (default true) |
github.mirrorPublic |
boolean |
unset |
mirror tickets as issues on public repos too (default false: the backlog stays private until you say) |
board
board.issues false: new tickets are not filed as GitHub issues (existing ones still sync status and close). dobby add --no-issue does it per ticket.
| Key |
Type |
Default |
Notes |
board.issues |
boolean |
unset |
|
clientNames
| Key |
Type |
Default |
Notes |
clientNames |
list of string |
[] |
real clients: tickets naming them are never agent work (policy rule client-name) |
clientProjects
| Key |
Type |
Default |
Notes |
clientProjects |
list of string |
[] |
the projects those client rules apply to |
frontDeskDenyMcp
| Key |
Type |
Default |
Notes |
frontDeskDenyMcp |
list of string |
[] |
MCP servers the front desk may never call (the owner's money, health or shopping apps) |
watchJobs
other launchd jobs the hourly health check watches: label prefixes, and long-running ones (no pid = died)
| Key |
Type |
Default |
Notes |
watchJobs.prefixes |
list of string |
unset |
|
watchJobs.daemons |
list of string |
unset |
|
paths
| Key |
Type |
Default |
Notes |
paths.projects |
string |
~/projects |
where project clones live |
paths.projectRoots |
list of string |
unset |
more folders that hold project clones; setup looks in these too (each must be inside your home folder) |
paths.data |
string |
~/.local/share/dobby |
Dobby's data dir (DOBBY_DIR still wins) |
paths.memory |
string |
~/.claude/projects/<your home folder>/memory |
the owner's Claude Code memory folder (dobby company) |
paths.usageCli |
string |
"" |
the claude-code-usage-limits reader; "" = the copy bundled in node_modules |
paths.dashboardDist |
string |
"" |
the built dashboard app (DOBBY_DASHBOARD_DIST still wins) |
paths.agentRules |
string |
unset |
your own rules file, appended to every agent's rules after Dobby's |
Agent tooling (dobby tools). A tool's rules reach agents only when it is on AND found on this machine. Absent = graphify, rtk, caveman, ponytail on (free); jev on only when safety.classifier is "jev" (paid: opt in).
| Key |
Type |
Default |
Notes |
tools.graphify |
boolean |
unset |
|
tools.rtk |
boolean |
unset |
|
tools.caveman |
boolean |
unset |
|
tools.ponytail |
boolean |
unset |
|
tools.jev |
boolean |
unset |
|
discord
| Key |
Type |
Default |
Notes |
discord.hq |
list of string |
4 entries |
channels in the HQ category |
discord.apps.<name>.label |
string |
unset |
|
discord.apps.<name>.ideas |
boolean |
unset |
|
discord.extraChannels |
map of string to list of string |
{} |
more channels in an app's category |
providers
Model providers and routing (docs/manual/providers.md). Absent = unused: Dobby calls claude exactly as before. strip, not strict: an unknown key here warns and is ignored like everywhere else, instead of discarding the whole file.
| Key |
Type |
Default |
Notes |
providers.enabled |
boolean |
false |
off = Dobby keeps calling claude exactly as today |
providers.acp |
boolean |
unset |
ACP harnesses (gemini-cli...) in live routing; off until verified against a real agent |
providers.providers.<name>.enabled |
boolean |
true |
|
providers.providers.<name>.keyEnv |
list of string |
unset |
pool of key NAMES, values stay in the environment |
providers.providers.<name>.baseUrl |
string |
unset |
relay or custom endpoint |
providers.providers.<name>.headers |
map of string to string |
unset |
|
providers.providers.<name>.strategy |
fill_first | round_robin | least_used |
fill_first |
|
providers.providers.<name>.limit.dailyUsd |
number > 0 |
unset |
|
providers.providers.<name>.limit.dailyRuns |
integer > 0 |
unset |
|
providers.roster |
list of object |
unset |
replaces/extends the seed roster by name |
providers.main |
string |
unset |
|
providers.roles.<name>.primary |
string |
unset |
|
providers.roles.<name>.fallback |
list of string |
unset |
|
providers.roles.<name>.effort |
low | medium | high |
unset |
|
providers.roles.<name>.maxCostUsd |
number (0+) |
unset |
|
providers.policy.allowUnsafe |
list of unsandboxed-builders | sensitive-below-top | private-remote | owner-data-to-providers |
[] |
|
review
The PR reviewer (docs/manual/reviews.md): overrides of its DEFAULTS (everything on, safety limits kept). Absent = the defaults. provider: who gates merges (docs/manual/external-reviewer.md); absent = "local", Dobby's own reviewer.
| Key |
Type |
Default |
Notes |
review.auto |
on | drafts | off |
off |
on = auto-review every open PR, drafts too; drafts = auto-review all but drafts (what Dobby always did); off = only on request |
review.includePaths |
list of string |
[] |
globs; non-empty = only these files are reviewed |
review.excludePaths |
list of string |
[] |
globs never reviewed (lockfiles, generated code) |
review.branches |
list of string |
[] |
base-branch globs auto-reviewed; empty = every base branch |
review.skipLabel |
string |
no-review |
a PR with this label is not auto-reviewed ("" = none) |
review.mentionOnly |
boolean |
false |
no auto reviews; only @<handle> review (turns commands on) |
review.handle |
string |
dobby |
On a public repo @dobby may be a real GitHub user who gets pinged: pick a handle you control (a bot account, your org's name). |
review.botLogin |
string |
"" |
also answer @<botLogin> <verb> (the GitHub App or bot account you review as); "" = only the handle |
review.commands |
boolean |
true |
PR comment commands from users with write access |
review.fullReviewsPerDay |
integer (0+) |
3 |
full review per PR per day |
review.maxPerScan |
integer (1+) |
4 |
auto reviews per review-scan |
review.maxChats |
integer (0+) |
3 |
owner @foreman chat answers per scan |
review.maxCommandsPerScan |
integer (0+) |
5 |
commands, thread questions and learnings handled per scan |
review.ask |
boolean |
true |
@<handle> ask and replies in our review threads get an answer |
review.describe |
boolean |
true |
@<handle> describe fills an EMPTY PR description (off: the suggestion goes in the walkthrough) |
review.maxFindings |
integer (0+) |
0 |
0 = no cap (ranked, most severe first) |
review.strictness |
chill | default | assertive |
default |
|
review.riskBump |
boolean |
false |
a haiku/sonnet pick on a diff touching riskPaths becomes opus |
review.riskPaths |
list of string |
29 entries |
|
review.contextPack |
boolean |
true |
callers, tests and history of the changed files from graphify-out/graph.json, when present |
review.contextFiles |
integer (1+) |
10 |
changed files the context pack covers |
review.learn |
boolean |
true |
a 👎 or "won't fix" reply on our thread = a "known intentional" hint for later reviews of the repo |
review.maxLearnings |
integer (1+) |
30 |
kept per repo, newest first |
review.fix |
boolean |
true |
@<handle> fix queues the open high/medium findings as a builder ticket (never pushes itself) |
review.fixesPerDay |
integer (0+) |
1 |
@<handle> fix per PR per day (the 2 auto-fix rounds per PR still apply) |
review.jevReplies |
boolean |
false |
Send replies in our threads to Jev (redacted) to tell a "won't fix" from a question. Off: no Jev call; every reply that is not a plain "thanks" is answered as a question and never becomes a learning (comment text stays on the Mac). |
review.repos |
map of owner/name to review settings |
unset |
the same keys as review, for one repo |
review.provider |
local | external | both |
unset |
|
review.external |
coderabbit | greptile | copilot |
unset |
|
review.externalCheck |
string |
unset |
|
review.externalBots |
list of string |
unset |
|
review.externalFix |
boolean |
unset |
|
review.externalFixCap |
integer (0–10) |
unset |
|
review.externalTimeoutMin |
integer (1+) |
unset |
|
ticketBudget
Token savings. Every key is absent by default = Dobby behaves as before; the private config turns each on. ticketBudget: most one ticket may spend, by size, in percent-of-the-week points (usdPerWeekPoint dollars = 1 point; default 26, measured). Over it, the ticket goes to the owner.
| Key |
Type |
Default |
Notes |
ticketBudget.S |
number > 0 |
unset |
|
ticketBudget.M |
number > 0 |
unset |
|
ticketBudget.L |
number > 0 |
unset |
|
ticketBudget.usdPerWeekPoint |
number > 0 |
unset |
|
pacing
pacing.fallbackBuildsPerDay: builds started per day (configured timezone) while the Claude usage cannot be read (default 3). pacing.weekCap: most of your weekly plan Dobby may use, in percent; the rest is always yours (default 95).
| Key |
Type |
Default |
Notes |
pacing.fallbackBuildsPerDay |
integer (0+) |
unset |
|
pacing.weekCap |
integer (10–100) |
unset |
|
scout
scout: the Talent Scout's daily run, at scout.hour. enabled false = never runs on its own (dobby scout still works); hour = when its 7-hour window opens, configured timezone (default on, 23).
| Key |
Type |
Default |
Notes |
scout.enabled |
boolean |
unset |
Whether the Talent Scout runs on its own each day. |
scout.hour |
integer (0–23) |
unset |
The hour its 7-hour window opens, in your time zone. |
lead
lead.onboardPromote: what happens to the first backlog of a newly onboarded project. ask (default) = dobby init <project> shows the tickets the Lead would queue (up to 3) and asks; with --yes, no terminal or a scheduled start nothing is queued until you run dobby queue <id>. auto = the Lead queues them as before. none = never at onboarding.
| Key |
Type |
Default |
Notes |
lead.onboardPromote |
ask | auto | none |
unset |
What happens to the first tickets of a new project. ask: you choose which to queue. auto: the Lead queues them. none: nothing is queued. |
stats
stats: opt-in crash reports and usage stats (docs/manual/stats.md). Both are off until you say yes; no answer is off. DO_NOT_TRACK, DOBBY_STATS=off and CI force them off. stats.crashes: send the error class, the place in Dobby's own code and the command when Dobby fails (never the message). stats.usage: send how far setup got and daily counts (what you can see with dobby stats show). stats.endpoint: where they go (default: the owner's collector, dobby-stats.nimitharia1.workers.dev); empty string = nothing is sent.
| Key |
Type |
Default |
Notes |
stats.crashes |
boolean |
false |
|
stats.usage |
boolean |
false |
|
stats.endpoint |
string |
the owner's collector; "" sends nothing |
|
retryLimit
| Key |
Type |
Default |
Notes |
retryLimit |
integer (1+) |
unset |
builds one ticket may use before it goes to the owner instead of being rebuilt. |
builderContextCeiling
| Key |
Type |
Default |
Notes |
builderContextCeiling |
integer (20000+) |
unset |
tokens of context at which a builder run is ended and continued in a fresh run with a short handoff. |
shipPreflight
| Key |
Type |
Default |
Notes |
shipPreflight |
boolean |
unset |
before a builder starts, check gh auth, the remote, push access and the verify command; a failure blocks the ticket with the reason. On by default; false = off. |
sameFailure
| Key |
Type |
Default |
Notes |
sameFailure |
boolean |
unset |
a failure with the same cause as the last build's goes to the owner instead of another build. |
harnessInstall
| Key |
Type |
Default |
Notes |
harnessInstall |
boolean |
unset |
when a build changes a dependency manifest, Dobby runs the project's install step itself (with network) before verify. |
installDomains
| Key |
Type |
Default |
Notes |
installDomains |
list of string |
unset |
hosts an install may reach from inside the sandbox, besides the public package registries (a private registry). |
freshRetries
| Key |
Type |
Default |
Notes |
freshRetries |
boolean |
unset |
a retry or fix build starts a fresh run (Tester notes + work so far in the prompt) instead of resuming the old, large session. |
recoverOutput
| Key |
Type |
Default |
Notes |
recoverOutput |
boolean |
unset |
a builder whose output cannot be read is recovered from its session transcript instead of counting as a wasted build. |
deployOnFailure
| Key |
Type |
Default |
Notes |
deployOnFailure |
notify | ticket | fix |
unset |
what a failed deploy does. notify (default) = the Retry card only; ticket = also a top-priority fix ticket; fix = that ticket is built at once (dobby run <id>), one message, and the fix's merge deploys again. One open fix per project. |
deployFrom
| Key |
Type |
Default |
Notes |
deployFrom |
checkout | worktree |
unset |
checkout (default) = the project's deploy_dir, pulled; worktree = a fresh worktree of origin/ from the project's repo for each deploy (its .env* files copied in), removed afterwards, so no separate release checkout is needed. |
mergeChecks
| Key |
Type |
Default |
Notes |
mergeChecks |
all | required |
unset |
which PR checks gate a merge. required (default) = the repo's required checks only (every check but Dobby's review when it requires none); all = every check. DOBBY_CHECKS=all|required overrides. |
reviewCap
| Key |
Type |
Default |
Notes |
reviewCap |
number (1–100) |
unset |
the 5-hour % review-scan may use, when looser than the builders' pace cap (reviews unblock merges). Unset = the builders' cap, as before. The week stays under pacing.weekCap either way. |
billing
billing: plan (default) = a Claude Pro/Max sign-in, paced by its 5-hour and weekly windows. apiKey = no plan: every run, builders included, pays by the token through DOBBY_API_KEY, capped at dailyUsd per 24 hours and weeklyUsd per 7 days (the plan limits pacing.weekCap and the 5-hour pace do not apply; over the cap, dobby limits says Paused). workspaceId: the Console workspace id (wrkspc_...), for an organisation-level key not scoped to a workspace; sent as the anthropic-workspace-id header. Not a secret.
| Key |
Type |
Default |
Notes |
billing.mode |
plan | apiKey |
unset |
|
billing.dailyUsd |
number > 0 |
20 |
|
billing.weeklyUsd |
number > 0 |
unset |
|
billing.workspaceId |
string |
unset |
|
billing.planUsd |
number > 0 |
unset |
|
| Key |
Type |
Default |
Notes |
costComment |
boolean |
unset |
false = no cost comment on Dobby PRs (default on). billing.planUsd = what the owner pays for the plan; only the receipt card reads it. |
safety
Safety (README "Safety"). preset: strict (every sensitive category waits for the owner) | balanced | autonomous. rules: per-category override of the preset: auto (normal review, then merge) | review (strict Opus review) | owner (needs-you card, no fix, no merge) | never (agents do not touch it). classifier: model (default) | jev | none. jev = the TypeSafe classifier (@typesafe-ai/sdk), optional: needs JEV_API_KEY in the environment, else the model is used. none = words only. unsure: what a classifier that cannot decide means: ask (send the owner a card) | allow (go on, at most a strict review).
| Key |
Type |
Default |
Notes |
safety.preset |
strict | balanced | autonomous |
balanced |
|
safety.rules |
map of migrations.schema | migrations.data | payments | auth | secrets | deploys | config | client-sites | releases to auto | review | owner | never |
{} |
|
safety.classifier |
jev | model | none |
model |
|
safety.unsure |
ask | allow |
ask |
|
safety.everyMerge |
auto | review | owner |
unset |
everyMerge: the floor for every merge, including changes in no category: auto | review (strict review) | owner (draft PR, the owner merges). Unset = the preset's (strict: owner, else auto). deploy: after a merge, ask (a Deploy tap; also when unset) | auto (deploy at once, only when you set it). |
safety.deploy |
auto | ask |
unset |
|
migrated
What dobby migrate found in the setup it migrated (a record; nothing reads it). Secret key NAMES only. launchdJobs is the file names of the com.dobby.* and com.foreman.* launch agents that were in ~/Library/LaunchAgents when it ran; Dobby does not install, remove or read them from here (dobby jobs does that).
| Key |
Type |
Default |
Notes |
migrated.at |
string |
unset |
|
migrated.projects |
list of string |
unset |
|
migrated.secretKeys |
list of string |
unset |
|
migrated.discord |
map of string to string |
unset |
|
migrated.launchdJobs |
list of string |
unset |
|