Connect your first site
Add a site in the dashboard, get it to the CLI, and run the first sync.
Add the site
Open /account, go to Sites, and click + New site. The dialog offers four paths, defined in templates/core/app.js as nsPaths:
| Path | What it does |
|---|---|
| New | Provisions a new site at Kinsta |
| Request | Sends a site request (the customer-facing path) |
| Import from provider | Imports existing sites from a connected provider |
| Connect manually | Registers a site you already have SSH access to |
Import and Connect manually are operator-only. POST /sites is gated by captaincore_admin_permission_check.
To connect a site you already host somewhere, choose Connect manually and fill in:
| Field | Notes |
|---|---|
| Site name | The domain. Stored as the site’s name |
| Server address | SSH or SFTP host |
| User | SSH or SFTP username |
| Password | Optional if you use keys |
| Port | Defaults to 2222, digits only |
| Protocol | sftp or ssh |
| Environments | Production, or Production + Staging |
| Accounts | Operators can assign shared accounts, and mark one as customer contact and one as billing contact |
The slug is derived from the name in the browser: lowercased, trailing TLD removed, everything that is not a letter or digit stripped. mysite.com becomes mysite.
What the Manager checks
The dialog sends POST /wp-json/captaincore/v1/sites with a site object, which lands in CaptainCore\Site::create(). It returns { "errors": [ ... ] } if any of these fail:
nameis not empty.siteis not empty, is all letters and digits (ctype_alnum), is at least 3 characters, and is not already in use.- The production environment has a non-empty
address,username,protocolandport. porton either environment is digits only.
A staging environment submitted with an empty address is dropped rather than rejected.
The all-alphanumeric rule matters downstream. The CLI parses a target like mysite-staging by splitting on the first -, so a slug containing a hyphen would be read as a site name plus an environment.
On success the Manager inserts the site row, inserts one environment row per environment, links any shared accounts, creates a customer account if none was given, and writes an activity log entry.
Get the site to the CLI
The CLI keeps its own copy of the fleet in ~/.captaincore/data/captaincore.db. A new site has to reach it before any command will resolve the slug.
The usual push is the site sync <site_id> command, which the Manager dispatches to POST {CAPTAINCORE_CLI_ADDRESS}/run. It fires when a site is updated, when an environment is added, and during Kinsta provisioning.
Site::create() itself does not dispatch a sync. After a manual connect, pull the fleet from the CLI side:
captaincore connect --sync
That re-reads everything from /wp-json/captaincore/v1/cli/connect and upserts sites, environments, accounts, providers and domains, removing rows the Manager no longer has.
Confirm the site landed:
captaincore site get mysite
captaincore site list @all
Run the first sync
captaincore sync-data mysite
A bare slug targets production. Append -staging for the staging environment:
captaincore sync-data mysite-staging
sync-data runs captaincore site get to resolve the site id, then runs captaincore ssh <site> --script=fetch-site-data over the stored connection. fetch-site-data returns key:value pairs, one per line, split on the first colon. It collects:
wp plugin listandwp theme list(name, title, status, version)- must-use plugins
wp core versionwp option get homewp user listwp core verify-checksums, parsed into modified, extra and missing files
The results are posted back to the Manager as a sync-data command on POST /wp-json/captaincore/v1/api.
If the connection’s home directory has no wp-config.php, the script returns WordPress not found, and sync-data records the environment with a token value of basic instead of a full payload.
You can also trigger a sync from the dashboard. GET /sites/{id}/{environment}/sync/data queues sync-data {slug}-{environment} as a task and returns a job token. That handler re-pushes site sync first if the environment was created in the last day, as a safety net for a push that never reached a wedged CLI server.
What you see afterwards
Once the sync completes, the site page shows the plugin and theme inventory with versions and statuses, the WordPress core version, core checksum results, the site’s users, and the home URL. From there, backups, quicksaves, captures and updates all work against the same environment record.