cwp init
shipped 1.0.0cwp init [flags]
Acts on dev unless another environment is named.
| Flag | What it does | Default |
|---|---|---|
--name <name> | project name | |
--app <domain> | Cloudron app / domain for the environment | |
--provider <id> | host for the environment: cloudron | ssh | cloudron |
--ssh <host> | ssh host, e.g. deploy@example.com (with —provider ssh) | |
--path <path> | remote docroot (with —provider ssh) | |
--package <type> | Cloudron layout: managed | developer | managed |
--php <version> | PHP version for the local container | |
--plugin-slug <slug> | site-plugin directory name (default: | |
--keep-admin-email <email> | this user survives scrubbing (pull.keep_admin_email) | |
--env <env> | environment name to create | dev |
--non-interactive | do not prompt; use flags and defaults | off |
Plus the shared flags --json, --verbose and --dry-run.
What it does
Scaffolds a project. Interactive, and safe to re-run — re-running repairs the scaffold rather than overwriting your work.
It asks for the project name, the environment’s host and the site-plugin
directory, writes the scaffold — .cwp.yml, .ddev/, the site plugin, the
tracking files, CLAUDE.md, README.md, .gitignore — and registers the project
in the machine config.
It scaffolds either host. --provider ssh writes an ssh environment and the
matching DDEV provider config instead of a Cloudron one; --ssh and --path are
both required for it, because cwp cannot derive a docroot on a plain host and a
plausible guess would send every later transfer somewhere wrong.
--plugin-slug exists because the project name is usually the domain while the
plugin keeps a short slug. It defaults to <name>-site, is recorded as
plugin_slug in .cwp.yml, and is what tracked points at.
--keep-admin-email records pull.keep_admin_email — the account that survives
scrubbing. Together with pull.keep_roles it is what keeps you able to log in to
the local copy after a pull.
Nothing is probed before the scaffold. Earlier versions asked the remote for
its package layout and PHP version first; both are now written from what you said
or what the project already records, and cwp doctor checks them a
moment later with a fix hint naming the key to change. A probe that has to succeed
before a project can exist is a probe in the wrong place.
--dry-run names every file it would write, one per line, rather than
summarising. Nothing is created and no project is registered.
What “repairs” means for .cwp.yml
Every other scaffolded file is left alone if it exists. .cwp.yml is different:
it is the one file cwp itself has opinions about, so re-running init brings it
up to date in place. Each repair is reported as its own step, so nothing is
rewritten silently:
! repair .cwp.yml: pull.truncate_tables — removed snn_301_logs, snn_404_logs,
snn_search_logs — no such table has ever existed (B-001)
It only ever removes entries that cannot do anything, and adds keys that were absent. Your settings are never changed, and defaults you did not set are not written into the file — so your project keeps following future default corrections instead of pinning today’s values. A config that cannot be read or would not validate is left exactly as it is.
The DDEV provider it writes
.ddev/providers/<provider>.yaml lets ddev pull fetch the database and uploads
without cwp installed, so the project stays usable by someone who has only
DDEV. Every command in it runs on the host, because the host CLI lives there and
not in the web container.
ddev pullis notcwp pull. It brings production data down unscrubbed, installs no mail guard, and takes no snapshot of your local database first — so personal data lands on your machine and the site can mail real addresses. Prefercwp pull; if you do use the provider, runcwp scrubafterwards.
ddev push is refused. It has no confirmation, no backup, no
protected-environment check and no typed environment name, and a provider file
cannot add them. The refusal is deliberate rather than a missing stanza: DDEV’s
error for a missing stanza says nothing about why.
The uploads fallback it writes
.ddev/nginx/cwp-uploads-fallback.conf serves any file below
/wp-content/uploads/ from the remote when it is missing locally. It is
scaffolded here rather than at the first pull because it is nginx configuration
and takes effect on ddev start. If a re-run creates it in a project that is
already up, run ddev restart.
Example
What a dry run names, one file per line, before anything exists:
$ cwp init --non-interactive --name example.com --app example.com --plugin-slug example-site --php 8.3 --dry-run
✓ would create public/wp-content/plugins/example-site/inc/elements/.gitkeep
✓ would create public/wp-content/plugins/example-site/inc/hooks/.gitkeep
✓ would create public/wp-content/plugins/example-site/assets/.gitkeep
✓ would create public/wp-content/mu-plugins/.gitkeep
✓ would create bricks/.gitkeep
✓ would create .cwp/tmp/.gitkeep
✓ would create .cwp.yml
✓ would create .ddev/config.yaml
✓ would create .ddev/providers/cloudron.yaml
✓ would create .ddev/nginx/cwp-uploads-fallback.conf
✓ would create public/wp-content/plugins/example-site/example-site.php
✓ would create public/wp-content/plugins/example-site/README.md
✓ would create .gitignore
✓ would create CLAUDE.md
✓ would create README.md
✓ would create FEATURES.md
✓ would create BUGS.md
✓ would create CHANGELOG.md
✓ would create VERSION.txt
✓ would create .cwp/hooks/post-pull.sh
✓ would create .cwp/hooks/pre-push.sh
✓ would create .cwp/hooks/post-deploy.sh
Captured from cwp 1.0.0. Not written by hand.
cwp init --name example --app example.com --plugin-slug example-site
cwp init --provider ssh --ssh deploy@vps.example.com --path /var/www/example
cwp init --dry-run
What it does not do
It does not install WordPress core, start DDEV, or pull any data. Run ddev start
and cwp pull afterwards.
It does not probe the remote, and it does not overwrite a scaffolded file that
already exists — with the single, reported exception of .cwp.yml.