Skip to content

ctx update

ctx update asks GitHub for the latest published ctx release and, unless you passed --check, downloads the archive for your OS and architecture, verifies its checksum, and swaps it in over the running executable.

Most people never type it: once a newer release exists, ctx prints a dim one-line “update available” nudge after every successful command on a terminal, and you run ctx update when you see it. Only the GitHub lookup behind that nudge is rate-limited — its answer is cached for 24 hours. Reach for it deliberately when you need a fix you just read about in a release, or when a teammate’s server-side feature isn’t showing up in your CLI.

It self-updates only when it can safely do so. A binary built with go build/go install has no version stamp, so there is nothing to compare and nothing to replace — it will tell you to reinstall instead. A binary living under a Homebrew or Scoop path is redirected to that package manager so its bookkeeping stays honest.

Terminal window
ctx update # check, download, verify, replace
ctx update --check # report only; install nothing
FlagTypeDefaultDescription
--checkboolfalseonly check for a newer version; don't install

--check still performs the network call and the version comparison; it stops before downloading. It’s the form to use in a health-check script — and note that, unlike the automatic nudge, it works even when the ambient checks are turned off by CONTEXO_NO_UPDATE_CHECK or CI.

FlagTypeDefaultDescription
--rootstringproject root directory (default: current directory)

Ask whether there’s anything newer:

Terminal window
ctx update --check
ctx update --check
Current version: 0.5.1
Checking for updates…
You're already on the latest version (0.5.1).

When a newer release does exist, the same command reports Latest is <version>., tells you to run ctx update to install it, and exits without touching the binary.

Install it:

Terminal window
ctx update

The install path prints the current version, Checking for updates…, Latest is <version>., Downloading…, Verified checksum. Installing…, and finally Updated ctx <old> → <new> 🎉.

  1. If the binary is a dev build (version.Version == "dev", i.e. no release ldflags), it prints the reinstall instructions — including go install github.com/sugihAF/contexo/cmd/ctx@latest — and returns without any network call.
  2. It classifies the install by inspecting the running executable’s own path: /cellar/, /homebrew/ or /linuxbrew/ means Homebrew, /scoop/ means Scoop. Those paths get a brew upgrade contexo / scoop update ctx message instead of a self-replace. Anything else is treated as a managed install (direct download or the install script) and is safe to swap.
  3. GET https://api.github.com/repos/sugihAF/Contexo/releases/latest, unauthenticated, under a 90-second deadline for the whole command. The response body is read with a 1 MiB cap.
  4. Versions are compared as major.minor.patch with any -pre/+build suffix dropped, and a leading v tolerated. Anything unparseable counts as “not newer”, so a malformed tag can never nag you into a downgrade.
  5. The asset is picked by exact name: ctx_<version>_<goos>_<goarch>.tar.gz, or .zip on Windows — the naming the release pipeline produces.
  6. Before anything is unpacked, checksums.txt is downloaded from the same release and the archive’s SHA-256 is compared against the entry for that asset name. A release with no checksums.txt is refused outright rather than installed unverified. The updater also supports a pinned minisign key over checksums.txt, which makes a valid checksums.txt.minisig mandatory; no key is pinned in the shipped binary today, so verification is checksum-only.
  7. The ctx (or ctx.exe) entry is extracted from the archive and written over the running executable atomically, with a rollback to the old binary if the swap fails. On Windows this uses the rename dance required to replace a running .exe.

Nothing in your project is touched: no .contexo/ file, no config, no server call.

The nudge that most often triggers an update runs as a post-run hook, and it’s worth knowing its rules:

  • It runs only after a successful command, only on a TTY, and never for mcp, capture, version or update — the first two emit machine-read output where a stray line would corrupt JSON-RPC or the capture buffer.
  • It is skipped entirely when CONTEXO_NO_UPDATE_CHECK or CI is set to any non-empty value, and on dev builds.
  • The GitHub result is cached for 24 hours in update-check.json under your OS cache directory (%LocalAppData%\contexo\ on Windows, ~/Library/Caches/contexo/ on macOS, ~/.cache/contexo/ on Linux). Within the TTL no request is made at all.
  • The live check gets 1.5 seconds; any failure — network, cache I/O, even a panic — is swallowed, and the notice goes to stderr so it never pollutes piped stdout.
  • check for updates: contact GitHub: … — no network, or a proxy in the way. --check fails the same way.
  • check for updates: GitHub returned 403 Forbidden — the unauthenticated GitHub API rate limit, usually on a shared IP. Wait, or download the release manually.
  • check for updates: no releases published yet — the API returned 404 for the releases endpoint.
  • download update: no release asset for <os>/<arch> (looked for "ctx_…") — that platform isn’t built in this release. Build from source, or use go install.
  • download update: release has no checksums.txt; refusing to install an unverified binary / checksum mismatch for … (got …, want …) — verification failed and nothing was installed. Treat a mismatch as suspicious rather than retrying blindly.
  • install update: … (permission denied, text file busy) — ctx lives somewhere your user can’t write, typically /usr/local/bin. Re-run with the privileges that installed it, or re-run the install script.