How updates work
How the Manager updates itself, how you update the CLI, and how to check what version each is running.
Manager
The Manager updates through the normal WordPress plugin update path. includes/class-captaincore-manager-updater.php hooks plugins_api, site_transient_update_plugins and upgrader_pre_download and supplies the update itself.
The flow:
request()fetcheshttps://raw.githubusercontent.com/CaptainCore/captaincore-manager/master/manifest.jsonwith a 30 second timeout and caches the result in thecaptaincore_manager_updatertransient for one hour. If the fetch fails, the bundledmanifest.jsonshipped in the plugin is used and the failure is cached for five minutes.update()comparesCAPTAINCORE_VERSIONagainst the manifest’sversionwithversion_compare(). It refuses to offer the update at all unless the manifest’sdownload_urlpassesis_our_package_url()(https, host ingithub.com/objects.githubusercontent.com/codeload.github.com, path starting with/CaptainCore/captaincore-manager/) and the manifest publishes a non-emptysha256.verify_package()intercepts the download, fetches the zip withdownload_url( $package, 300 ), and compareshash_file( 'sha256', $file )to the manifest hash withhash_equals(). A mismatch deletes the file and returnscaptaincore_bad_package_hash. A manifest with no hash returnscaptaincore_missing_package_hash.purge()clears the transient after a successful plugin update.
Apply an update:
wp plugin update captaincore-manager
Force a fresh manifest read:
wp transient delete captaincore_manager_updater
The version lives in three places: the Version: plugin header, the CAPTAINCORE_VERSION constant in captaincore.php, and version in manifest.json. bin/build-zip.sh fails the build if they disagree, or if the manifest download_url does not point at the matching /v{version}/ release asset. A build whose header disagrees with its own manifest would either offer an update forever or never offer one.
Schema migrations ride along with the code. After an update, the next init or admin_init runs captaincore_maybe_upgrade_db(), which compares the captaincore_db_version site option against CaptainCore\DB::REQUIRED_VERSION and runs DB::upgrade() under a lock.
CLI
The CLI updates itself:
captaincore upgrade
It resolves the latest tag from the GitHub releases page, compares it with the running version, downloads captaincore_<Os>_<Arch>.tar.gz and checksums.txt for that release, verifies the sha256, extracts the binary next to the current one, runs its version command as a sanity check, then renames it over the running binary. If the directory is not writable it falls back to sudo mv. The new binary unpacks its embedded app/ and lib/ scripts on its first run, so scripts and binary always move together.
| Flag | Effect |
|---|---|
--check |
report the current and latest versions, exit 1 when behind, change nothing |
--yes |
skip the confirmation prompt |
--force |
reinstall even when already current |
--version=v1.2.0 |
install a specific release |
captaincore upgrade --check is safe to run from cron as a reminder.
A source checkout is different. When ~/.captaincore/.git exists the CLI was built in place, and upgrade refuses (without --force) and tells you to pull and rebuild instead:
cd ~/.captaincore
git pull
go build -o captaincore .
Restart captaincore server after either kind of update so the Manager talks to the new build. upgrade prints the restart hint when it sees a running server process.
Releases are cut with git tags and GoReleaser, which cross-compiles for Linux and macOS on x86_64, arm64 and armv7 and publishes the archives plus checksums.txt as release assets. install.sh and upgrade both read releases/latest/download/, so a tag without those assets is not an installable release.
Checking versions
For the CLI:
captaincore version
It prints the version, the Go version it was built with, and the platform:
captaincore 1.0.0
- go version: go1.25.0
- platform: linux/amd64
Release builds stamp the version at build time with -ldflags "-X github.com/CaptainCore/captaincore/version.Version=...". A source build reports the value in version/version.go, which is bumped in the same commit as each release, so both paths agree. Check git describe in ~/.captaincore if you need the exact source revision of a checkout.
For the Manager:
wp plugin list --name=captaincore-manager --fields=name,status,version
Or read the Version: header in wp-content/plugins/captaincore-manager/captaincore.php. The dashboard’s Settings section does not show a version number.