Skip to content
commission

Configuration reference — .commission.json

.commission.json is the canonical, git-committable configuration for a project. It lives at the repository root; every Commission command walks up from the working directory to find it, so agents never have to name the project.

JSON rather than YAML on purpose: commission’s whole agent-facing surface is already JSON — apply documents, --json output, the MCP contract — and the one file an agent writes should not be the odd shape out.

A minimal config is two keys:

{
  "version": 1,
  "project": "myapp"
}

Everything else is optional. Blocks you do not write behave as the defaults below, so a solo founder’s config stays two keys while an enterprise repo can declare actors, approval routing, workspace providers, and tracked context.

Rules

  • Strict. Unknown keys are refused, never ignored — a typo that silently does nothing is the failure this file exists to prevent. Refusals name the path, list the allowed keys, and suggest the nearest declared key.
  • Versioned. version is required. A file declaring a version this binary does not speak is refused with the upgrade command, never partially applied. A file with no version is the pre-versioned shape and is read as such: project, integrations, and notices only, with a notice.
  • Deterministic. No inference beyond the precedence chain below.

Notices

A pre-versioned file still loads, and says so once per process on stderr, naming the command that ends it:

warning: .commission.json predates config versioning — add "version": 1 to use the full configuration surface
  fix: commission config migrate --write

It is never printed under --json: stderr is part of a machine’s stream, so a pipeline sees byte-identical output whether or not the repo has migrated.

A repo that has deliberately not migrated turns it off in the file it already has — notices is one of the keys a pre-versioned file may carry, precisely so that declining to migrate does not require migrating:

{
  "project": "myapp",
  "notices": { "deprecations": false }
}

Self-documenting files

JSON has no comments, so point $schema at the generated JSON Schema and your editor supplies completion, hover documentation, and inline validation:

{
  "$schema": "https://commission.sh/schema/commission-config.schema.json",
  "version": 1,
  "project": "myapp"
}

Commission ignores $schema entirely — it is there for the editor.

Precedence

Lowest to highest — the last layer to set a key wins, and commission config explain <key> reports which one did:

  1. defaults
  2. db
  3. file
  4. local
  5. env
  6. flags

Objects merge key by key. Arrays replace wholesale and scalars replace — array merging is where config systems become unpredictable, so Commission does not do it.

.commission.local.json (the local layer) is for one machine and must not be committed; it may refine any setting but cannot declare project.

Environment overrides

An explicit table rather than a general convention:

variablesets
COMMISSION_PROJECTproject
COMMISSION_LEASEagentDefaults.lease
COMMISSION_BUDGETagentDefaults.budget
COMMISSION_WORKSPACE_STRATEGYworkspace.strategy

COMMISSION_CONFIG names a config file directly and skips the upward search.

Fields

keytyperequireddescription
$schemastringnopath or URL to commission-config.schema.json — ignored by commission, used by editors for completion and hover docs (JSON has no comments, so this is how the file documents itself)
version1yesconfig format version — RC1 speaks 1
projectstringyesthe Commission project slug this repo belongs to; prefixes every task id
executionobjectno
execution.defaultAutonomy“autonomous” | “supervised” | “human_only”noautonomy for tasks that declare none
execution.preferredActorstringnobiases selection; never blocks another eligible actor
execution.mayExecutestring[]noroles or capabilities required to claim a task here (empty = anyone)
execution.requireApprovalobject[]noapprovals every task must collect before done; per-task policy adds to this
execution.requireApproval[].rolestringnoany actor holding this role may satisfy it
execution.requireApproval[].actorstringnoonly this specific actor may satisfy it
execution.requireApproval[].kind“approval” | “verification”noapproval is a judgement call; verification is a human confirming something is true
execution.requireApproval[].reasonstringnoshown in the refusal so the requirement explains itself
execution.reviewPolicymap<string, object[]>noextra approvals keyed by gate name, e.g. { released: [{ role: owner }] }
workspaceobjectno
workspace.strategy“in-place” | “worktree”noin-place: work in the checkout (default) · worktree: a git worktree per task
workspace.dirstringnowhere worktrees live, relative to the repo root (default .worktrees)
workspace.providersstring[]noordered environment provider chain, e.g. [gitenv] or [vault, dotenv]
workspace.portsobjectnodeterministic, collision-free port allocation for parallel workspaces
workspace.ports.range[number, number]yesinclusive [start, end]
workspace.ports.perTasknumbernoports allocated per task (default 1)
workspace.setupobject[]noordered steps run after the workspace exists
workspace.setup[].namestringyesshown in the event log and in failures
workspace.setup[].runstringyesshell command, executed in the prepared workspace
workspace.setup[].timeoutMsnumbernodefault 120000
workspace.setup[].optionalbooleannoa failure warns instead of aborting prepare
workspace.teardownobject[]noordered steps run before the workspace is removed
workspace.teardown[].namestringyesshown in the event log and in failures
workspace.teardown[].runstringyesshell command, executed in the prepared workspace
workspace.teardown[].timeoutMsnumbernodefault 120000
workspace.teardown[].optionalbooleannoa failure warns instead of aborting prepare
contextobjectno
context.trackstring[]nocommitted guidance to version and fingerprint, e.g. [CLAUDE.md, .claude/, docs/adr/]
context.ignorestring[]noglobs excluded from the tracked set
context.bundleBudgetnumbernodefault token budget for context bundles; unset = no truncation
context.warnOnDriftbooleannowarn when tracked guidance changed since a task was claimed (default true)
actorsobject[]no
actors[].namestringyesmatches COMMISSION_ACTOR, and appears in events and claims
actors[].kind“human” | “agent”yeshumans own judgment; agents own execution
actors[].rolesstring[]nonamed roles this actor holds, e.g. [owner, approver]
actors[].capabilitiesstring[]nowhat this actor can do, e.g. [implement, test, document, review]
actors[].autonomy“autonomous” | “supervised” | “human_only”noper-actor ceiling; the task policy cannot exceed it
actors[].defaultbooleannothe actor assumed when COMMISSION_ACTOR is unset
providersmap<string, object>nonamed provider entries, referenced by workspace.providers
providers.<name>.type“dotenv” | “exec” | “gitenv” | “doppler” | “onepassword” | “vault”yeswhich built-in provider implementation backs this entry
providers.<name>.envstringnothe provider’s environment/stage name, e.g. dev or staging
providers.<name>.appstringnothe provider’s app/scope name, when it has one
providers.<name>.filesstring[]nodotenv: files to materialize
providers.<name>.runstringnoexec: command that emits KEY=VALUE lines on stdout
providers.<name>.pathstringnovault/1password: the secret path or item reference
providers.<name>.optionsmap<string, string>noprovider-specific passthrough options
integrationsobjectno
integrations.jiraobjectno
integrations.jira.baseUrlstringnothe declared Jira site; a mismatch is refused
integrations.jira.statusMapmap<string, string>nocommission status → this site’s status name
integrations.jira.fieldsmap<string, string>nocustom-field ids, e.g. { rank: customfield_10019 }
integrations.jira.projectsstring[]noissue-key prefix allowlist, e.g. [RTB, SUP]
integrations.githubobjectno
integrations.github.reposstring[]noowner/name repos this project may bind to
integrations.github.autoCloseOnMergebooleannoclose a task when its PR merges (gates still apply)
integrations.github.branchPrefixstringnodefault commission/
integrations.selection“severity” | “sprint” | “due” | “priority” | “rank” | “age”[]noordered work-selection policy for next and ready
notificationsobjectno
notifications.onApprovalRequestedbooleanno
notifications.onBlockingQuestionbooleanno
notifications.onDivergencebooleanno
notifications.channelsobject[]no
notifications.channels[].type“exec” | “webhook”yesexec runs a command; webhook POSTs the inbox item
notifications.channels[].targetstringyesthe command or URL
notifications.channels[].eventsstring[]noinbox item kinds to deliver (default: all enabled)
noticesobjectno
notices.deprecationsbooleannoprint deprecation notices on stderr (default true) — set false in a repo that has deliberately not migrated; the alternative is to run ‘commission config migrate —write’ and be done with them
gatesmap<string, string[]>nogate profiles: gate name → required evidence kinds, e.g. { shipped: [test, commit] }
agentDefaultsobjectno
agentDefaults.leasestringnodefault claim lease, e.g. 30m, 2h, 1d, or 0 for none
agentDefaults.actorstringnoactor assumed when COMMISSION_ACTOR is unset
agentDefaults.budgetnumbernodefault —budget for next and show
agentDefaults.requireNoteOnDonebooleannorefuse done without at least one note (default false)
branchobjectno
branch.prefixstringnobranch name prefix (default commission/)
branch.templatestringnobranch name template; supports {id} and {slug} (default {id}-{slug})
branch.basestringnobranch new work forks from, e.g. main
commandpurpose
commission config showthe fully merged, effective config
commission config validate [file]exit 0 or 2 — usable in CI
commission config explain <key>the value, the layer that set it, and what it overrode
commission config initwrite a minimal .commission.json for this repo
commission config migratebring a pre-versioned file up to version 1
commission config pathwhich files were considered, in order

This page is docs/reference/config.md in the Commission repository, rendered in place — the site keeps no copy of it. It is generated by scripts/generate-config-reference.ts, so it is exhaustive, and editing it by hand is reverted by the next run.