Docs CLI

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>]
  • mysite resolves to the production environment of mysite.
  • mysite-staging resolves to the staging environment.
  • mysite@kinsta disambiguates when two providers have a site of the same name.
  • mysite-staging@kinsta combines 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 connect and exits 1. Most read commands and an increasing share of the write commands work this way, including site get, site list, drift, info, stats, sync-data for a single site, and most of the Restic repository maintenance under backup and quicksave.
  • Bash. The command path is converted into a script path, so captaincore backup generate becomes ~/.captaincore/app/backup/generate, environment variables are set from the flags, and the CLI replaces its own process with that script using syscall.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:

  • 0 on success.
  • 1 on 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.