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:

  • name is not empty.
  • site is 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, protocol and port.
  • port on 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 list and wp theme list (name, title, status, version)
  • must-use plugins
  • wp core version
  • wp option get home
  • wp user list
  • wp 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.