cwp config set
shipped 1.0.0cwp config set <key> <value> [flags]
Local only: it acts on no environment.
| Argument | What it is | Default |
|---|---|---|
<key> | dotted path, e.g. pull.uploads | |
<value> | new value; a comma-separated list for list keys |
| Flag | What it does | Default |
|---|---|---|
--because <text> | why this value, recorded beside the line | |
--until <condition> | when the reason is spent: cwp:B- | |
--with-agent | with —dry-run on a host with no shell: install and remove the PHP agent so the plan is real | off |
Plus the shared flags --json, -v, --verbose, -q, --quiet and --dry-run.
What it does
config set writes one key to whichever layer owns it: cwp.yml for project
keys, ~/.config/cwp/config.yml for machine keys.
Example
cwp config set pull.uploads sync
cwp config set defaults.uploads sync
cwp config set pull.keep_roles administrator,editor
cwp config set pull.uploads sync --dry-run
The reason goes beside the line
A value without its reason is a riddle in three months, and a reason that no
longer holds stays where you wrote it. --because records why, --until
records when it is spent, and cwp adds the date and its own name:
cwp config set pull.uploads sync --because "Bricks checks is_file(), B-147" --until cwp:B-147
# because: Bricks checks is_file(), B-147 | until: cwp:B-147 | since: 2026-09-05 | by: cwp config set
uploads: sync
The line above the key is a comment a person reads and cwp parses. A comment
you wrote yourself stays above it. Where a grammar line already stands, cwp
merges into it: --because alone renews a reason and keeps its until. The
command also records a reason on a value that already stands.
--until takes one of five forms:
| form | spent when |
|---|---|
cwp:B-147 | the running cwp lists the bug as fixed |
cwp>=2.1 | the running cwp is at least that version |
plugin:bricks>=2.5 | inventory.yml names the slug at least at that version |
stage:live | the environment reached that stage, or one past it |
2026-12-01 | the date has passed |
cwp refuses anything else and names the five forms.
cwp status and cwp doctor name every
reason that no longer holds:
! pull.uploads — the reason no longer holds: B-147 is fixed in 2.0.0. Change the value, or renew it: cwp config set pull.uploads <value> --because "…"
A reason belongs to the project file. A machine key takes none.
php lands in two files, because the container reads the other one
cwp.yml declares the PHP version, and .ddev/config.yaml is what the
container runs. cwp config set php 8.5 writes both and says that the
container needs a restart:
✓ php — 8.3 → 8.5 (project)
✓ php_version — 8.3 → 8.5 (.ddev/config.yaml) — run `ddev restart` to pick it up
.ddev/config.yaml keeps everything else it holds. cwp edits around the
services, hooks and settings a project adds to it, not through them.
No other key does this. cwp reads every other key from the file it writes it to.
What it does not do
It does not pin defaults into your file. It writes back your file with one key changed, never a serialised copy of the parsed config. Otherwise every schema default would freeze into the file the first time you set anything, and a default cwp later corrects would never reach you.
It changes no value but the one you named, and your comments survive. cwp edits the YAML document in place rather than re-serialising it. Every other key keeps its value, and every comment you wrote is still there afterwards.
Where a comment sits is not guaranteed. An inline comment can end up on its own line. The YAML library can normalise spacing you chose for alignment. So a write to one key sometimes shows up as a diff of a few lines rather than one. You lose nothing and no value moves. The YAML library tidies your formatting; cwp does not edit what you did not ask it to.
It deletes no keys, creates no environments and contacts nothing.