CLI Overview
What the CaptainCore CLI is, where it runs, how you address a site, and the global flags every command accepts.
The CaptainCore CLI is a single Go binary built with Cobra. It manages WordPress sites at scale by connecting to them over SSH and running WP-CLI and bash remote scripts, then posting the results back to a CaptainCore Manager WordPress site over HTTP.
Source lives at github.com/CaptainCore/captaincore. The repository is cloned to ~/.captaincore/ because the binary reads runtime files from there at execution time: bash scripts under app/, remote scripts under lib/remote-scripts/, exclusion lists under lib/, and configuration in config.json.
Where it runs
The CLI normally runs on a dedicated server that holds the SSH keys for the fleet. It has three modes of operation:
- Interactive, from a shell.
- As a long-running HTTP service, started with
captaincore server. The CaptainCore Manager plugin dispatches commands to it over REST and WebSocket. See providers and accounts. - From cron, for recurring fleet work. See cron and scheduling.
Rclone, Restic and Git are required for backup, quicksave and snapshot work.
Installing and connecting
curl -fsSL https://raw.githubusercontent.com/CaptainCore/captaincore/master/install.sh | bash
git clone https://github.com/CaptainCore/captaincore.git ~/.captaincore/
cp ~/.captaincore/config-sample.json ~/.captaincore/config.json
captaincore connect
captaincore connect authenticates against a CaptainCore Manager site using a WordPress application password, then pulls sites, environments, accounts, providers and domains into a local SQLite database. Running the bare captaincore command with an empty database prints a reminder to run connect first.
Global flags
These four flags are registered on the root command, so every subcommand accepts them.
| Flag | Description |
|---|---|
--captain-id string |
Captain ID, which selects the tenant block in config.json. Defaults to 1. |
--config string |
Path to the config file. Defaults to ~/.captaincore/config.json. |
--fleet |
Fleet mode. Runs the command once per captain ID found in the config. |
--label |
Print colored site name headers in bulk mode. |
In fleet mode the CLI reads every captain_id out of config.json and loops, setting CAPTAIN_ID for each pass. When captaincore_fleet is true in the system config, the site data path and the rclone backup remote are also suffixed with the captain ID so tenants stay separated.
Two commands, ssh and bulk, disable Cobra’s flag parsing and parse arguments themselves. That lets them forward unknown flags through to remote scripts and sub-commands. They still handle --captain-id, --config, --fleet, --label, --debug and --parallel locally.
Addressing a site
A site is addressed by its slug, which is the short single-token identifier stored in the site column, distinct from the domain stored in name. In practice the slug is the domain with the dots and the TLD removed, for example mysite.com becomes mysite. Slugs contain no hyphens, because the CLI treats the first hyphen as the environment separator.
The argument format is:
<slug>[-<environment>][@<provider>]
mysiteresolves to the production environment ofmysite.mysite-stagingresolves to the staging environment.mysite@kinstadisambiguates when two providers have a site of the same name.mysite-staging@kinstacombines both.
The environment defaults to production when no suffix is given. A numeric argument is treated as a site ID rather than a slug.
Target groups
Anything starting with @ is a target group, resolved against the local database rather than treated as a slug.
| Target | Meaning |
|---|---|
@all |
Every environment on every active site. |
@production |
Production environments only. |
@staging |
Staging environments only. |
Targets can be narrowed with a dot-separated suffix. The recognised suffixes are monitor-on, updates-on, updates-off, offload-on, offload-off, backup-local and backup-remote. For example @production.updates-off matches production environments that have updates disabled. Any other suffix is ignored.
Resolved targets are expanded to <slug>-<environment> names, deduplicated and sorted, then each one is run as a separate child process. See running commands for how concurrency works.
Passing a target, or passing more than one site, switches most commands into bulk mode automatically. A handful of commands are excluded from that automatic switch because they take multiple positional arguments of their own, including backup get, backup download, backup show, quicksave show-changes, quicksave rollback, update-log generate, capture generate and upload.
Two execution paths
Commands take one of two routes internally, and knowing which explains some of the behaviour you will see.
- Native Go. The command runs in-process against the local SQLite database and the provider or Manager APIs. It requires the database to exist and to hold site rows, otherwise it prints an error telling you to run
captaincore connectand exits 1. Most read commands and an increasing share of the write commands work this way, includingsite get,site list,drift,info,stats,sync-datafor a single site, and most of the Restic repository maintenance underbackupandquicksave. - Bash. The command path is converted into a script path, so
captaincore backup generatebecomes~/.captaincore/app/backup/generate, environment variables are set from the flags, and the CLI replaces its own process with that script usingsyscall.Exec. Backup generation, quicksave generation, uploads, updates and the snapshot pipeline still run this way.
The bash layer reads its settings back out of the Go layer by calling captaincore config fetch --captain-id=$captain_id, and parses its own flags with lib/arguments.
Output conventions
Output is plain text on stdout, with errors on stderr. Several commands accept --format=json or --json for machine-readable output, including site get, site list, backup list, backup snapshots, snapshot list, capture scan, drift, info, progress, sync-data, quicksave cache-check, quicksave malware-scan and performance-monitor fetch.
Commands that return a single value, such as stats, environment list and configuration get --field=, print the value with no trailing newline so it can be captured in a shell variable.
Colour is used for the help template (yellow section headers, green command names) and for the --label site headers in bulk mode.
Exit codes
The CLI does not define a custom exit-code scheme. In practice:
0on success.1on any handled failure. This covers argument validation errors from Cobra, a missing or unpopulated local database, configuration load failures, no sites matching a target, a recursive bulk invocation, and a bulk core-update run that finished with failures.
When a non-bulk command delegates to a bash script under app/, the CLI replaces its own process with syscall.Exec, so the exit code you see is the bash script’s.
Discovering commands
captaincore --help
captaincore backup --help
captaincore script list
captaincore version
captaincore info
captaincore completion bash|zsh|fish|powershell emits a shell completion script.