Skip to content

cwp init

shipped 1.0.0
cwp init [flags]

Acts on dev unless another environment is named.

FlagWhat it doesDefault
--name <name>project name
--app <domain>Cloudron app / domain for the environment
--provider <id>host for the environment: cloudron | sshcloudron
--ssh <host>ssh host, e.g. deploy@example.com (with —provider ssh)
--path <path>remote docroot (with —provider ssh)
--package <type>Cloudron layout: managed | developermanaged
--php <version>PHP version for the local container
--plugin-slug <slug>site-plugin directory name (default: -site)
--keep-admin-email <email>this user survives scrubbing (pull.keep_admin_email)
--env <env>environment name to createdev
--non-interactivedo not prompt; use flags and defaultsoff

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 pull is not cwp 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. Prefer cwp pull; if you do use the provider, run cwp scrub afterwards.

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.