.cadence/config.yaml
.cadence/config.yaml is Cadence’s per-repo settings file. It lives at the repo root under .cadence/ and tells the commands where your designs and plans live, how plans get split and committed, which audits run, and how parallel execution behaves. Every key has a built-in default, so the file only needs to hold the values you want to change.
The canonical default for every key (with inline comments) ships at defaults/config.default.yaml. Your repo’s .cadence/config.yaml overrides only what differs from those defaults. There is no need to copy the whole file.
Local overrides: config.local.yaml
Section titled “Local overrides: config.local.yaml”When a team commits .cadence/config.yaml to share settings, personal preferences need somewhere else to live. That place is .cadence/config.local.yaml: a gitignored sibling file holding only the keys you personally override. Resolution reads three layers in order, and the last layer that defines a key wins for that key:
- Plugin defaults (
defaults/config.default.yaml) - The repo’s
.cadence/config.yaml(the team’s settings) - Your
.cadence/config.local.yaml(yours alone, never committed)
The local file is sparse: it contains only overrides, carries no config_version, and the config migrator never touches it. A typical one is a few lines:
execute: max_parallel: 2 # this laptop can't take the team default worktree_confirm: falseauthoring: design_mode: all-at-onceKeys intended for local override are the per-person, per-machine ones: execute.max_parallel, execute.worktree_confirm, authoring.max_parallel, authoring.design_mode, authoring.plan_mode, mockups.dir, and the validate.browser_* and advisors.* keys. Everything else (paths, statuses, audits, plan policy, the whole worktree: section) is team policy: a local override of those still works, but Cadence prints a one-line notice so the divergence is never silent.
config_version
Section titled “config_version”A single top-level integer that records which config schema this file was written against. It drives migration detection when Cadence’s schema changes.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
config_version | Schema version of this file; used to detect when a migration is needed. | 8 | Integer |
Where Cadence reads and writes documents. Paths are relative to the repo root. Commands resolve <paths.designs> / <paths.plans> from here, so changing these moves the whole document tree.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
paths.designs | Folder that holds design folders. | docs/designs | Repo-relative path |
paths.plans | Folder that holds plan folders. | docs/plans | Repo-relative path |
paths.future | Folder for “future” / parking-lot notes (e.g. thought-partner /c-brainstorm notes). | docs/future | Repo-relative path |
paths.config | Folder that holds this config and Cadence’s working state. | .cadence | Repo-relative path |
storage
Section titled “storage”Where Cadence keeps its artifacts (brainstorm stubs, designs, and plans). The backend is filesystem by default, exactly today’s behavior; setting backend: notion moves those artifacts into two Notion databases instead, leaving source code and git commits untouched. The whole storage block is team policy: it belongs in the committed .cadence/config.yaml, never in the personal .cadence/config.local.yaml overlay.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
storage.backend | Which backend stores designs, plans, and stubs. filesystem keeps them as markdown folders under paths.*; notion stores them as rows in two Notion databases. | filesystem | filesystem | notion |
storage.notion.root_page | The Notion page Cadence provisions the two databases under. A page URL or id you own, shared with the official Notion MCP’s integration. Required when backend is notion. | "" (empty) | Notion page URL or id |
storage.notion.designs_db | The Designs database id. Left empty by you; auto-filled on the first Notion-mode run, then committed so the team shares it. | "" (empty) | Notion database id (auto-filled) |
storage.notion.plans_db | The Plans database id. Left empty by you; auto-filled on the first Notion-mode run, then committed so the team shares it. | "" (empty) | Notion database id (auto-filled) |
With backend: filesystem (the default) the notion.* keys are ignored and nothing changes. To opt in, set backend: notion, fill notion.root_page, and leave the two *_db keys empty: the first Notion-mode run creates the databases and writes their ids back into the committed config. See the Notion mode reference for the full setup walkthrough.
mockups
Section titled “mockups”Where mockup HTML files are written. A design that opts into the 95-visual-contract slot stores its mockups as local HTML files, on every storage backend, and records each version’s file:// URL in the 95 index.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
mockups.dir | The directory mockup HTML is written to. A relative value resolves against the repo root; an absolute one is taken as given. The directory is created when missing. | null (unset) | Path, or null |
How null resolves depends on the backend:
mockups.dir | Backend | Resolves to |
|---|---|---|
| set | either | <mockups.dir>/<slug>/ |
null | filesystem | <paths.designs>/<slug>/mockups/, the design’s own subfolder |
null | notion | Unresolvable, so /c-design asks once before writing version 01 |
How /c-plan shapes the plan it writes.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
plan.tdd | Whether plans bake in a test-driven workflow (write the test, then the code). | true | true | false |
plan.commit_cadence | How often the plan commits during execution. | per-task | per-task (other cadences are judgment-based) |
plan.parallel_grain | The finest granularity at which tasks within one plan may run in parallel. per-file keeps each file to one lane; in-file allows lanes to split work within a single file. Not set in the defaults file. Add it under plan to opt in. | unset (per-file behaviour) | per-file | in-file |
There are deliberately no split thresholds. Whether and where to split a plan into phase docs is a judgment call /c-plan makes, not a number you tune. See Parallelism and worktrees for how grain relates to execution lanes.
execute
Section titled “execute”How /c-execute drives a plan to implemented code, including the parallel-lane machinery. The 01-… / 02-… files inside a single plan are its phases; the keys below govern how those phases run, in lanes that may use git worktrees.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
execute.branch_check | Refuse to start unless you’re on an appropriate branch. | true | true | false |
execute.auto_resolve_drift | Auto-resolve drift between plan and code instead of surfacing it for a decision. | false | true | false |
execute.parallel | Master switch for parallel execution. When false, execution is the legacy sequential path (sub-agents, no worktrees) and execute.mode is ignored. | true | true | false |
execute.mode | Pre-flight execution-mode gate: ask presents parallel lanes (recommended) vs inline sequential, parallel runs the lane engine, inline runs every task in the PM session itself — no worktrees, no implementer sub-agents (the completion audit stays a sub-agent). | ask | ask | parallel | inline |
execute.max_parallel | Maximum concurrent implementer lanes (one worktree per lane). Reviewers are uncapped. | 4 | Positive integer |
execute.worktree_confirm | Show a one-time pre-flight confirmation before creating worktrees. | true | true | false |
execute.resume_on_dirty_tree | Allow resuming execution when the working tree is dirty. | false | true | false |
See Parallelism and worktrees for the model behind lanes and the max_parallel cap. Where lane worktrees live and how they merge back is governed by the worktree section below.
worktree
Section titled “worktree”The shared git-worktree lifecycle: where worktrees live, how branches go home, the merge lock, and the optional repo-specific hooks. Two commands read this section: /c-worktree (the interactive lifecycle) and /c-execute (its parallel lanes use dir and integrate, and its merge-on-land honors the lock).
| Key | Controls | Default | Allowed values |
|---|---|---|---|
worktree.dir | Where worktrees are created: interactive /c-worktree worktrees and /c-execute lane worktrees alike. Relocated from execute.worktree_dir. | .cadence/worktrees | Repo-relative path |
worktree.integrate | History policy when a worktree branch merges back. Relocated from execute.integrate. | rebase-ff | rebase-ff | merge-commit |
worktree.merge_lock | Whether local merges acquire the shared repo-global merge lock, so concurrent merges serialize instead of colliding. Honored by /c-worktree’s local-merge exit and /c-execute’s lane landings; /c-worktree’s PR exit performs no local merge and never takes it. | true | true | false |
worktree.lock_stale_threshold | Seconds after which a held lock is reported stale and surfaced as a “steal it?” question. Never auto-stolen. | 600 | Positive integer (seconds) |
Six optional shell-command hooks let a repo plug its own scripts into fixed lifecycle points. Every hook is null by default, and a null hook means that lifecycle phase simply does not exist; with all hooks empty, /c-worktree runs its generic core only.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
worktree.hooks.provision | Runs after git worktree add (dependency install, env files, similar setup). | null | Shell command string or null |
worktree.hooks.provision_verify | Runs after provision to assert the worktree environment is usable; non-zero surfaces the output and offers repair / remove / keep. | null | Shell command string or null |
worktree.hooks.port_assign | Allocates a dev port for the worktree. Must print the port to stdout. | null | Shell command string or null |
worktree.hooks.port_release | Frees the worktree’s port at cleanup. | null | Shell command string or null |
worktree.hooks.dev_server | Starts the worktree’s dev server. | null | Shell command string or null |
worktree.hooks.deploy_guard | Exits non-zero when a deploy is not allowed from the current location; the deploy is then refused. | null | Shell command string or null |
How hooks run
Section titled “How hooks run”- Environment. Every hook runs with
WT_PATH(absolute worktree path),MAIN_ROOT(absolute main-worktree path), andBRANCH(the worktree’s branch) exported.dev_serveradditionally getsDEV_PORT, captured fromport_assign’s stdout or read back fromgit config branch.<branch>.devPort. - Working directory.
provision,provision_verify,port_assign, anddev_serverrun with cwd =$WT_PATH.port_releaseruns with cwd =$MAIN_ROOT(the worktree may already be removed).deploy_guardruns in the directory the deploy was attempted from: that location is what it judges. - Stdout. Only
port_assign’s stdout carries meaning (the assigned port, persisted asgit config branch.<branch>.devPort). Every other hook’s output is informational and shown to you.provision’s stderr is shown at create time even on a zero exit, so a best-effort provisioner’s warnings surface immediately rather than at the first push. - Non-zero exit.
provision: surfaced, with an offer to remove the half-created worktree.provision_verify: surfaced, with an offer to repair (re-runprovision, then re-verify), remove the worktree, or keep it as-is.port_assign: surfaced; the lifecycle continues without a port, and the dev-server phase is then unavailable.dev_server: surfaced.port_release: surfaced, but cleanup continues.deploy_guard: the deploy is refused, with an explanation of the merge-first-then-deploy-from-main flow.
See the /c-worktree reference for the phase-by-phase lifecycle these keys drive.
authoring
Section titled “authoring”How doc-generator agents run when /c-design materializes a design folder. These agents do not use worktrees (they only write docs), so they are cheap to parallelize.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
authoring.max_parallel | Maximum concurrent doc-generator agents. | 6 | Positive integer |
authoring.design_mode | Standing default for how /c-design writes child docs: ask prompts you, all-at-once generates in parallel, one-by-one writes sequentially with a review per doc, inline writes every doc in the main session with no sub-agents or pauses. | ask | ask | all-at-once | one-by-one | inline |
authoring.plan_mode | Standing default for how /c-plan writes plan docs: ask prompts you, all-at-once generates in parallel, inline writes every doc in the main session. | ask | ask | all-at-once | inline |
advisors
Section titled “advisors”Opt-in advisor personas that can weigh in during brainstorm and design. Disabled by default.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
advisors.enabled | Whether advisors are offered at all. | false | true | false |
advisors.roster | The set of advisor personas available when enabled. | [] (empty) | List of advisor entries |
See Advisors for what advisors are and how the roster is defined.
naming
Section titled “naming”Conventions for naming design/plan folders.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
naming.date_format | Date stamp used in folder slugs. | YYYY-MM-DD | Date format string |
naming.slug_case | Casing for the slug portion of folder names. | kebab | kebab (and similar case styles) |
status
Section titled “status”The allowed status values for design and plan documents. The order matters: it is the lifecycle progression Cadence expects.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
status.design | Valid statuses for a design. | [draft, in-review, approved, completed, superseded, on-hold] | List of status strings |
status.plan | Valid statuses for a plan. | [draft, in-progress, implemented, completed, superseded, on-hold] | List of status strings |
frontmatter
Section titled “frontmatter”Frontmatter requirements Cadence enforces on documents it writes.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
frontmatter.required | Frontmatter keys that must be present on every document. | [title, created, updated, status, tags] | List of key names |
audits
Section titled “audits”Which checks /c-audit (and the completion auditor) run, split into blocking checks, non-blocking warnings, and an optional set. The build_validator sub-block configures the build check.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
audits.default | Audit checks that run and block on failure. | checkbox-completeness, oos-justification, deferred-comment-scan, code-behind-checkbox, design-intent-alignment, build-validator, merge-integrity | List of audit names |
audits.warnings | Checks that run but only warn (non-blocking). | file-map-honesty, design-plan-consistency, validation-doc-presence | List of audit names |
audits.optional | Checks available but off by default. | [] (empty) | List of audit names |
audits.build_validator.command | Shell command the build-validator audit runs. null means no build command is run. | null | Shell command string or null |
audits.build_validator.expect_zero_exit | Treat a non-zero exit from the build command as a failure. | true | true | false |
plain_english
Section titled “plain_english”How Cadence writes the plain-English narrative that accompanies designs.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
plain_english.section_callout | Add a callout marking the plain-English section. | true | true | false |
plain_english.always_write_00a | Always write the 00a plain-English companion doc. | true | true | false |
plain_english.length_target | Target word-count range for the narrative. | "400-700" | Range string |
Rules for out-of-scope (OOS) entries in designs and plans.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
oos.require_rationale | Require a written rationale for each out-of-scope item. | true | true | false |
oos.require_wikilink | Require a wikilink (pointer) for each out-of-scope item. | true | true | false |
validate
Section titled “validate”How /c-validate walks a plan’s 96-validation.md post-deploy, including how it runs browser/automated checks.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
validate.reset_checkboxes_on_rerun | Clear validation checkboxes when validation is re-run. | true | true | false |
validate.browser_driver | Which driver runs browser-based checks. auto detects, playwright forces Playwright, manual walks you through by hand. | auto | auto | playwright | manual |
validate.browser_command | The CLI test command Cadence delegates browser checks to. | "npx playwright test" | Shell command string |
validate.browser_env_preamble | Optional shell snippet run before the browser command (e.g. to set env vars). null means none. | null | Shell snippet string or null |
find_bugs
Section titled “find_bugs”Defaults for /c-find-bugs.
| Key | Controls | Default | Allowed values |
|---|---|---|---|
find_bugs.default_baseline | The git ref bug-finding diffs against by default. | main | Git ref |
find_bugs.exclude | Paths excluded from the bug scan. | [node_modules, dist, build, __pycache__, target, .next, vendor] | List of paths |
A realistic config
Section titled “A realistic config”This repo dogfoods Cadence, and its own .cadence/config.yaml is a good example of the “override only what differs” pattern. It keeps the default paths and audits, bumps execute.max_parallel to 5, and opts into plan.parallel_grain: in-file. The trimmed shape below shows the blocks that have arrived over the last few schema bumps: worktree: (relocated out of execute: in config_version: 4), storage: (new in 5), execute.mode (new in 7), and mockups: (new in 8). Each of those bumps is additive, so scripts/migrate-config.js appends the new block or key verbatim and leaves your values and comments alone:
config_version: 8paths: designs: docs/designs plans: docs/plans future: docs/future config: .cadence
plan: tdd: true commit_cadence: per-task parallel_grain: in-file
execute: branch_check: true auto_resolve_drift: false max_parallel: 5 resume_on_dirty_tree: false parallel: true worktree_confirm: true mode: ask
worktree: dir: .cadence/worktrees integrate: rebase-ff merge_lock: true lock_stale_threshold: 600
advisors: enabled: false roster: []
storage: backend: filesystem notion: root_page: "" designs_db: "" plans_db: ""
mockups: dir: null # filesystem backend: the design's own mockups/ subfolder