Settings live in three places, by who has to agree on them and their shape: a value the whole team shares goes in beads config; a list the team shares goes in .claude/sdlc.md; anything true only on this machine goes in .claude/sdlc.local.md. /sdlc:init creates all three with defaults, and changes them when run again with options, for example /sdlc:init --integration epic-merge --parallel 3.
Beyond these, an epic or a task can override part of the project's settings for itself, in its own beads metadata. scripts/settings.sh prints every project-wide value; scripts/settings.sh <key> prints one; scripts/settings.sh sources prints the docs sources. /sdlc:status shows the same values.
YAML frontmatter in the main checkout. It is personal to this machine, so keep it out of git (/sdlc:init adds .claude/*.local.md to .gitignore).
---
parallel: 3
workflow: build
---| Key | Default | Read by | Meaning |
|---|---|---|---|
parallel |
2 |
settings.sh, sdlc:dispatch |
workers running at a time on this machine |
workflow |
unset | hooks/session-start.sh |
build: a SessionStart hook tells new sessions in this project to start new work with /sdlc:build. Any other value, or unset, does nothing |
Stored in the beads database, so every machine and person dispatching the repository sees the same values.
bd config set custom.dispatch.integration epic-merge
bd config set custom.dispatch.target main
bd config set custom.dispatch.review none| Key | Default | Read by | Meaning |
|---|---|---|---|
custom.dispatch.integration |
direct |
run-task.sh |
direct, epic-merge or epic-pr; see integration |
custom.dispatch.target |
the main checkout's current branch, else main |
run-task.sh, settings.sh |
branch the work ends up in |
custom.dispatch.review |
agent |
finish-task.py |
none, agent or human: review level for a task with no review metadata of its own; see reviews |
custom.dispatch.debug |
unset | verify.sh |
free text a failed verify command prints for the worker, naming the debugging skill or command to reach for, e.g. use the debugging-python skill or pytest -x --pdb |
custom.dispatch.ccn |
15 |
analyse-branch.sh, metrics.sh (via /sdlc:review) |
cyclomatic complexity a function may reach before it's a finding |
custom.dispatch.function_length |
100 |
analyse-branch.sh, metrics.sh (via /sdlc:review) |
lines of code a function may reach before it's a finding |
custom.dispatch.analysis |
off |
supervise.py |
off or auto: whether the supervisor runs the branch analysis on its sweeps |
Set on an epic bead, they override the project-wide beads config for that epic only.
| Key | Default | Read by | Meaning |
|---|---|---|---|
dispatch_integration |
falls back to custom.dispatch.integration |
run-task.sh |
this epic's integration mode; set with bd update <epic> --set-metadata dispatch_integration=epic-pr before the epic's first dispatch — it has no effect afterward |
review |
none |
finish-task.py |
this epic's own review level, applied to the epic diff (target...epic-branch) by the integration task before it merges or opens the pull request. Never falls back to custom.dispatch.review, so an epic with no review metadata skips review entirely |
Set by create-task.sh (used by /sdlc:create-task and /sdlc:split), or by hand with bd update <task> --set-metadata <key>=<value>.
| Key | Read by | Meaning |
|---|---|---|
execution_agent_type |
run-task.sh (put in the worker's prompt) |
the installed agent (Agent tool) the worker hands the implementation to. Doesn't change which CLI agent runs the worker session |
execution_suggested_model |
start-worker.sh |
--model for the worker session; with none set, the worker's own agent frontmatter (sdlc:worker/sdlc:integrator/sdlc:analyst) decides |
execution_reasoning_effort |
start-worker.sh |
--effort for the worker session |
review |
finish-task.py |
this task's review level (none, agent or human), overriding custom.dispatch.review |
verify |
run-task.sh (required before dispatch), verify.sh, finish-task.py |
the command that must exit 0 for the task to be considered done |
scope |
put into the worker's prompt and into /sdlc:review's summary |
comma-separated path prefixes the task changes; informational, not enforced by any script |
complexity |
start-worker.sh, shown in the worker prompt |
small, medium or large; large runs the worker on opus unless execution_suggested_model is set, and makes it coordinate sonnet subagents instead of implementing |
Without execution_agent_type/execution_suggested_model/execution_reasoning_effort, the worker is a plain sdlc:worker session on its default model (sonnet), or opus for a large task. Its execution mode comes from complexity (see agents/worker.md) and overrides any delegation rule in the project's CLAUDE.md.
run-task.sh builds the worker's prompt from a template. The plugin's defaults are templates/worker-prompt.md and templates/integration-prompt.md (the latter for an epic's integration task). A file of the same name in .config/sdlc/ of the project's main checkout replaces the default. An override that exists but can't be read fails the dispatch before the task is claimed (exit 2).
Placeholders are rendered by scripts/render-template.py:
{{id}},{{title}}and any other top-level field ofbd show <task> --json{{metadata.<key>}}for a task metadata key{{epic.id}},{{epic.title}},{{epic.description}}for the nearest epic above the task{{base}},{{branch}},{{target}},{{epic}}from--var NAME=VALUE: the branch the worktree starts from, the task's branch, the dispatch target branch, and the epic id (empty without an epic)
A missing or null value renders empty, and a line whose placeholders all rendered empty is dropped, so an optional line is one line per placeholder. An unclosed {{ is left as written.
The sources key lists places /sdlc:prior-art searches before the repository, in the order given. Shared ones go in .claude/sdlc.md (committed); paths that exist only on this machine go in .claude/sdlc.local.md. /sdlc:init creates sdlc.md with an empty list.
---
sources:
- name: Engineering wiki
via: notion
where: https://www.notion.so/acme/Engineering-1a2b
holds: designs and ADRs before 2025
- name: Product vault
via: path
where: ~/vaults/acme
holds: product notes, meeting summaries
---| Field | Meaning |
|---|---|
name |
how the source is named in the prior-art report |
via |
path for a directory on disk; otherwise the word that finds the tool that reaches it, such as notion, drive, confluence or jira. The plugin installs no such tool; when none matches, the report says the source was unreachable |
where |
the directory, URL or folder name; a value starting with ~/ expands to $HOME |
holds |
what the source can answer, so it's skipped for questions it can't |
A listed source is consented: /sdlc:prior-art searches it without asking, in headless sessions too. See prior art for how sources are searched.
Hooks are optional: sdlc works with none configured. /sdlc:hooks reads the project (manifests, lock files, CI, task runners, git hook managers) and proposes wt hooks for what sdlc itself triggers:
pre-start = "pnpm install --frozen-lockfile"
[pre-merge]
lint = "npm run lint"
typecheck = "npm run typecheck"
test = "npm test"| Hook | Triggered by | Purpose |
|---|---|---|
pre-start |
a task's worktree is created (run-task.sh via wt switch --create) |
install dependencies from the lock file, generate env files, before the worker starts |
[pre-merge] |
before a task merges (finish-task.py, and the project's own wt merge) |
the project's fast checks (type check, lint, unit tests); never slow end-to-end, deploy or release steps |
The project's own git hooks (husky, lefthook, pre-commit, .git/hooks) keep running on every worker commit, in every worktree, since workers commit with plain git; wt.toml hooks are separate from them.
The first time a machine runs one of these commands, wt asks for approval; non-interactively it fails instead. An unapproved pre-start hook stops a task from starting — wt switch --create fails and the supervisor reports the task as not started — and an unapproved pre-merge hook fails the merge, which finish-task.py reports as needing a person. A person approves once, in the main checkout:
wt config approvals add| Variable | Set by | Read by | Meaning |
|---|---|---|---|
DISPATCH_TASK |
start-worker.sh (via env) |
hooks/session-start.sh, hooks/worker-guard.sh, hooks/worker-stop.sh |
the task id a worker session is running; its presence marks the session as a worker, gating the worker hooks |
SDLC_SUPERVISOR |
supervise.py, for its own bd calls |
the beads hooks /sdlc:init installs (.beads/hooks/on_*) |
when set, a beads hook's write to the wake pipe is skipped, so the supervisor's own writes don't wake itself again. start-worker.sh unsets it (env -u SDLC_SUPERVISOR) before running a worker or record-task.sh, so their writes do wake the supervisor |
SDLC_REVIEW_MODEL |
set by hand, in the environment of the machine that dispatches | finish-task.py |
the model an agent-level review runs on when no reviewer agent is installed (~/.claude/agents/reviewer.md or .claude/agents/reviewer.md); default sonnet |
See task fields for the dispatch_* metadata the scripts set on a task as it runs, and hooks for what the plugin's own hooks do.