cwp status
shipped 1.0.0cwp status [env] [flags]
Acts on the environment the project makes obvious: the only one it defines, or the one called dev. Name another to act there. A project with several and no dev has to name one.
| Argument | What it is | Default |
|---|---|---|
[env] | environment for the remote column |
| Flag | What it does | Default |
|---|---|---|
--drift | compare the local site against the committed tree | off |
--remote | compare an environment as well (implies —drift) | off |
--fail-on-drift | exit 1 when anything differs (implies —drift) | off |
--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
The “where am I in this project” screen. It saves you ddev describe,
cat cwp.yml and cwp db list run one after another.
$ cwp status
✓ cwp — 1.0.0 (32598ac-dirty, built 2026-08-29 09:01)
✓ project — example.com — ~/Code/example/example.com
✓ docroot — public
✓ php — 8.3
✓ environment local — https://example.com.ddev.site — this working copy — not adopted
✓ environment dev — https://example.com — app example.com — managed — not adopted
– ddev — unhealthy — https://example.com.ddev.site
– last pull with a snapshot (local) — unknown — no pre-pull snapshot on disk. A `cwp db pull --no-snapshot`, or a `cwp media pull`, leaves none, and `cwp db rm` removes the record with the restore point
– last pull with a snapshot (dev) — unknown — no pre-pull snapshot on disk. A `cwp db pull --no-snapshot`, or a `cwp media pull`, leaves none, and `cwp db rm` removes the record with the restore point
– snapshots — none in ~/Code/example/example.com/.ddev/db_snapshots
artifact repo detail
! bricks ? not a git repository, or git did not answer
! content/ ? not a git repository, or git did not answer
– inventory.yml – no inventory.yml. Run `cwp pull --only inventory`
– settings/ – no `settings:` block. This project does not carry options
– roles.yml – no roles.yml. Run `cwp pull --only roles`
– widgets/ – no `widgets:` declaration. This project does not carry widget areas
only the repo column was read. Pass --drift to compare the local site, --remote to compare an environment as well
Captured from cwp 1.0.0. Not written by hand.
It makes no remote calls unless you ask for them. It reads the config, the
DDEV state, the snapshot directory and git status, and nothing else. It has to
be instant and has to work on a train, with Docker stopped and no login anywhere.
cwp doctor talks to the remote and takes as long as that costs.
The first line says which cwp answered
✓ cwp — 1.0.0 (49fa29e, built 2026-08-17 19:17)
Everything under it is that binary’s account of the project. The release number
alone cannot say which binary that was: it moves at a release and not once in
the commits between two, so two builds a fortnight apart report the same
1.0.0.
The line matters on a working copy installed with npm link, where the bundle
and the source beside it are different things. When the source is newer the line
warns and says so. -dirty means the build came from a tree with uncommitted
changes and matches no commit. A published install prints its version and
nothing more: there is no second identity there to be wrong about.
Drift: is what you have what you committed?
The last lines are one per tracked artifact. By default they answer one question: whether you committed that tree.
artifact repo detail
✓ bricks ✓
✓ content/ ✓
✓ inventory.yml ✓
only the repo column was read — pass --drift to compare the local site,
--remote to compare an environment as well
--drift adds the local column: whether the site on this machine holds what
the tree says. --remote adds a third for an environment, and implies the first.
artifact repo local prod detail
✓ bricks ✓ ✓ ✓
! content/ ✓ ✗ ✓ 2 of 8 page(s) differ on local
! inventory.yml ✓ ✓ ✗ 2 difference(s) on prod
Under the project lines, cwp names every line in cwp.yml whose reason no
longer holds, with the way to renew it
(the reason beside a line).
The environment lines carry the stage where
the project declares one. cwp names an environment without one once, with the
line that sets it.
Each column heading names the side it is about, and each side has its own
colour. The tree is cyan, the local site magenta, the environment blue. An
environment marked protected takes the warn colour instead, because a mistake
on that side is expensive. Every command that names a side uses the same
colours, so you can find the column you care about without reading the
headings. In a pipe, under NO_COLOR or on a monochrome terminal the headings
still say it: colour never carries the answer alone.
Both are flags because both cost something. The remote column needs the
network and the local column needs a running container. A bare cwp status
stays half a second.
A cell reads ✓ agree, ✗ differ, – this project has no such artifact, and
? asked and got no answer. The last one covers Docker stopped, a remote
that did not reply, a tree that would not read. ? never rounds to either
side, and a run with one of them says so rather than closing with “everything
agrees”.
cwp compares each artifact with the machinery that moves it: the same drift
calculation cwp content status reports per page, the same
diff cwp push --only inventory acts on, the same export
cwp pull --only bricks writes. cwp status has no second opinion
about what “differs” means.
The inventory row reads both directions, and reports them separately because they are different facts with different fixes:
! inventory.yml ✓ ✗ 2 difference(s) on local — `cwp push --only inventory` would act;
1 installed on local and not recorded
(bricks-navigator) — `cwp pull --only inventory`
The second half is how a project drifts in practice: somebody installs
something, nobody records it, and otherwise the row stays green.
cwp push --only inventory does nothing about it, because without --prune it
does not look at the installed side. So the line points the other way, at
reading the environment down.
The table covers the tree, and says what it does not
Five artifacts is not a site. Options, roles that no roles.yml records, widget
areas and every post type no content group declares stay outside the comparison.
So a run that found no drift closes with everything the tree describes agrees
with it, and names what it did not look at:
outside the tree entirely, and therefore not compared above:
post types (28), taxonomies (14), options (181), widget areas (1)
— `cwp coverage` says what
cwp measures that line rather than writing it: it comes from the same census
cwp coverage runs, so it shrinks by itself as a project starts
carrying more. It costs a read of the local site, so it appears only where a run
reads a side anyway. The bare command still compares nothing, says so, and needs
neither Docker nor a network.
Drift warns, never fails. It is a fact about a project rather than an error in it. A command that exited non-zero over an unpushed page would be unusable in the loop it exists to serve.
--fail-on-drift is the exception that says so
A pre-push hook needs one line that can abort, and the
default above cannot be it. --fail-on-drift prints what --drift prints,
implies it the way --remote does, and exits 1 when any row differs:
cwp status --fail-on-drift
A column it could not read fails too. The failure mode of a gate is passing
for the wrong reason: DDEV down, nothing compared, the deploy goes ahead. The ?
cells say which side gave no answer. The run says this was not a clean
comparison.
cwp init scaffolds the line commented out in
cwp/hooks/pre-push.sh. Uncomment it and the gate is on. It guards
the build loop.
The last pull is read off the snapshots
cwp keeps no state file for it, and so has nothing to write, gitignore and keep
consistent. Every pull leaves pre-pull-<env>-<timestamp>, so the restore point
already records when and from which environment. That reading has three
limits. The output says “last pull with a snapshot” because of the first:
- A pull with
--no-snapshot, or acwp media pullthat touches no database, leaves no snapshot and is invisible here. cwp db rmon apre-pull-*snapshot deletes the record along with the restore point. Reclaiming disk space quietly rewrites this history.- The snapshot is taken before the import, so it proves a pull got past the confirmation guard, not that it finished. A pull that died on the transfer leaves the same trace as one that succeeded.
So an environment with no pre-pull-* snapshot reads unknown with the reason.
It never reads “never pulled”, because cwp cannot know that.
What it does not do
It contacts no remote unless you pass --remote. It starts nothing. It writes
nothing to git: the repo column is a git status, and cwp never stages, commits
or branches on your behalf.
--dry-run means nothing here, and cwp ignores it, as
cwp doctor does.