CodeHerderSearch⌘KRequest access →

Updating the CLI and the server

Update ch manually, plan a self-hosted server upgrade and its maintenance window, see how ch and the device server stay current, and fix a stuck update.

There are two ch binaries to keep in mind: the one installed on your own machine (used for the CLI), and the one inside each running device server. Both can keep themselves current, and this page covers how. Not installed yet? See Quickstart for the one-line install command.

Check your current version

ch --version

ch version and ch -v do the same thing. This prints the installed version (and build commit for stamped releases).

Update manually

Run ch self-update to download and install the latest release in one step:

ch self-update

Note: ch update is not a valid command. If you type it by mistake, the CLI will suggest ch self-update for you.

CodeHerder downloads the new binary for your platform, verifies it by SHA-256, and atomically replaces your existing ch binary. If you are already on the latest version, the command says so and exits.

Updating your machine’s ch does not update running device servers. Each device server manages its own binary independently. After a successful update, ch prints a reminder: “Any running ch device-server will auto-restart on its next update check.”

Check for an update without applying it

ch self-update --check

Reports the installed version versus the latest available, then exits with code 0 if you are up to date or non-zero if a newer version is available. No changes are made to your binary. Unlike a plain ch self-update, --check reports this even from an unstamped dev build — it never needs --force.

This exit-code contract makes it straightforward to use in CI or a cron job:

# Example: daily cron that alerts when ch is behind
# 0 9 * * * /usr/local/bin/ch self-update --check || echo "ch update available — run ch self-update"
ch self-update --check
if [ $? -ne 0 ]; then
  echo "ch is behind the latest release."
fi

Add --json to get the same result as a machine-readable current/available/needsUpdate/updated object instead of exit-code-only — see Using the ch CLI for the JSON conventions every command shares.

Update a build made from source

Building ch from source gives you one of two binaries, and they behave differently:

  • An unstamped dev build carries no version at all. ch self-update refuses to replace it by default — pass --force to override:

    ch self-update --force
  • A local build carries a version like 2.3.1+7. It doesn’t need --force: the moment a newer release ships, ch self-update replaces it and ch self-update --check reports it as behind. What neither will do is call it behind a release still sitting at the same version number — a local build is always treated as caught up with its own version, never behind it.

Your ch keeps itself current too

Auto-update is on by default for the ch you run on your own machine, the same way it is for the device server, when a release source is configured (CH_CLI_MANIFEST_URL, or the manifest URL stamped into your ch build; with neither it stays off). It works in two parts: a quick stderr notice when your version and the server’s fall out of step, in either direction, and a preflight that updates before certain commands run.

The notice. Any time the CLI talks to the server, it compares versions and prints one line to stderr when they differ. Which direction you’re off in changes the wording:

ch (build 2.3.0) is behind the server (build 2.3.1). Run: ch self-update
ch (build 2.3.1) is ahead of the server (build 2.3.0). The server may be running a stale deploy.

The numbers are build versions, which decide updates. On a hosted install the build is the hosted release, not the CodeHerder version. When your ch knows its CodeHerder version and it differs from the build, the line names it too, for example ch (build 11.1.274, CodeHerder 12.19.11). ch self-update messages add the CodeHerder version of the new build, and say unchanged when only the hosted wrapper changed.

Behind is the common case: your ch hasn’t picked up a release yet, and ch self-update fixes it. Ahead usually means a self-hosted server needs restarting on the release it’s meant to be running — see Confirm which build is live for how to check. The ahead line specifically never appears against a server that hasn’t been assigned a real release version, so it can’t mistake an unreleased build for a stale deploy.

Either line goes to stderr, not stdout, so it never breaks a script that pipes --json output, and by default each repeats at most once an hour.

The preflight. ch start and ch session attach check for a newer release before they do anything else. If one is available, ch downloads it, replaces itself, and restarts the same command on the new version:

ch: updated build 2.3.0 → 2.3.1, restarting `ch start`.

No other command runs this preflight — ch self-update is still there whenever you want to check or update by hand. If the preflight’s check fails — no network, no build for your platform, a failed download — ch just keeps running the version you already have. You’ll never see an error from it.

The preflight needs a real terminal on standard input, so it stays out of the way of scripts and CI by default. To opt a non-interactive caller in, set CH_AUTO_UPDATE_NONINTERACTIVE=1. A build made from source, dev or local, never runs the preflight and never prints the notice — see Update a build made from source above.

Tuning or disabling your CLI’s auto-update

Setting Default Description
--no-auto-update on Disable the preflight for this one command.
CH_AUTO_UPDATE=0 on Disable the preflight for every command.
CH_AUTO_UPDATE_NONINTERACTIVE=1 off Let the preflight run without a terminal on standard input — for scripts and CI.
CH_AUTO_UPDATE_INTERVAL=<duration> 1h How often the preflight checks for a newer release, and how often the notice can repeat.
CH_UPDATE_NOTICE=0 on Silence the stderr notice, in either direction.

The device server keeps itself current automatically

When you run ch device-server, auto-update is on by default once a release source is configured (CH_CLI_MANIFEST_URL, or the build stamp; with neither it stays off). Roughly once an hour, the server checks whether a newer ch release is available. When it finds one, it downloads and verifies the binary and then restarts itself with the new version.

By default, in-flight agent sessions are not interrupted. The device server detaches any running agent processes before it restarts, and the new process adopts them automatically. Tasks continue without any action from you. Start the device server with --kill-agents-on-shutdown (or set CH_DS_KILL_ON_STOP=1) if you’d rather it stop running agents on any shutdown or restart — including one triggered by auto-update — instead of carrying them across.

Scope: auto-update keeps only the device server’s own ch binary current — it does not change the agent harness (for example, the Claude Code installation the agent uses to do its work).

If a device is stuck on an old version

A few situations commonly strand a device behind the latest release. None of them need you to watch closely — each is either self-healing or a one-line fix:

  • A ch built from source never auto-updates. This covers both shapes: an unstamped dev build, and a local build carrying a version like 2.3.1+7. Either way, the device server’s auto-updater skips its check entirely, and the Version current readiness check (see Managing your devices) reports healthy rather than warning — there’s no separate signal telling you it’s behind. Install a released ch binary on that machine, or run ch self-update (add --force only on a dev build), then restart the device server.
  • Restarting the device server does not, by itself, pull a newer version in immediately. The auto-updater’s first check happens a full interval after startup, not right away — so on the default hourly cadence, a fresh restart can be up to an hour away from checking. To move a device onto a new version right now: run ch self-update (add --force on a dev build) to replace the binary on disk, then restart ch device-server — it starts up already on the new version.
  • The update needs write access to the directory the ch binary lives in, since both manual and automatic updates replace it in place. If ch is installed somewhere only another account can write to, a manual ch self-update reports the failure directly; the device server’s background updater instead logs a warning and quietly retries at the next check. Install ch somewhere your own user owns, or run the update as the account that owns the install directory.
  • A failed check is not something to worry about. A transient failure — a network blip, or a brief mismatch right after a new release goes out — is retried automatically, several times, within the same check window. If every retry in that window still fails, the device server keeps running its current binary and tries again at the next interval; no session is lost and nothing needs your attention.
  • A laptop that’s asleep through a check doesn’t miss its turn. The device server tracks wall-clock time rather than a fixed timer, so it picks the check back up within about a minute of the machine waking.
  • On a proxied network, both ch self-update and the device server’s auto-updater fetch releases over HTTPS and honor the standard HTTPS_PROXY and NO_PROXY environment variables in whatever environment the command runs in. HTTP_PROXY has no effect here, since the download itself is always HTTPS.

Tuning or disabling the device server’s auto-update

Pass these flags when starting the device server:

Flag Default Description
--auto-update=false on Disable automatic updates entirely.
--auto-update-interval <duration> 1h How often to check for a newer version.

The same settings are available as environment variables — convenient when the device server runs as a background service:

Variable Description
CH_DS_AUTO_UPDATE=0 Disable automatic updates.
CH_DS_AUTO_UPDATE_INTERVAL=<duration> Override the check cadence (e.g. 6h).

Examples:

ch device-server --auto-update-interval 6h   # check every six hours
ch device-server --auto-update=false         # never auto-update

For the full ch device-server reference, see Managing your devices.

Upgrade the server and plan maintenance

This section is for the person who runs a self-hosted server. The steps to upgrade are in Upgrade to a new release. This section covers when to do it and what to tell your users.

A new release applies its schema migrations when the server starts. The server answers 503 migrating until they finish. Most migrations take well under a second. A migration can lock a table or run for minutes on a large database. Each release tells you which.

Read the notice before you upgrade.

  1. Read the migrations object in the release manifest. It names each migration the release adds since the previous release. It says whether any may lock a table (mayLock) or run long (mayRunLong). See Read the manifest.

  2. Run the preflight with the new binary against your own database. It writes nothing:

    codeherder migration-notice -db "$DSN"

    It lists each migration your database has not applied. It flags each one that may lock or run long. For each flagged table it prints the size, so you can judge the duration. Add -strict to make the command exit 1 when anything is flagged.

  3. If you skip releases, the manifest of the newest release is not the full list. The preflight is the full answer. It reads your own ledger.

Choose the maintenance window.

  • If nothing is flagged, upgrade at a time you accept a short restart.
  • If anything is flagged, schedule a maintenance window and tell your users before it starts. Take a database backup first. Plan for the migration time on your own data, not on a small test database.
  • While the server reports migrating at /v1/health, wait. Do not stop the server with SIGTERM or restart it. A restart abandons the migration and starts it again from the beginning.
  • A failed upgrade rolls back by restoring the backup. That loses the data written after the backup. See Roll back a failed upgrade.

You choose the window and you tell your users. CodeHerder sets no deadline for an upgrade, except the upgrade-by date on a security release.

Rule text for approval

This text is a template. Adapt it to your policy.

Migration notice rule.

  1. Every server release manifest states its migrations and whether any may lock a table or run long. The release pipeline generates the statement. No person writes it.
  2. When a release adds a migration that may lock or run long, the support contact tells the customer communication owner, through ______, within ______ of the release. The email names the migration, the table, the expected effect and any measured duration.
  3. A migration that would hold a lock for minutes on a large table ships with a separate operator step. It never runs as a startup statement.
  4. The customer chooses the maintenance window and tells its own users. CodeHerder sets no deadline, except the upgrade-by date in the security release notice rule.

Last updated

CodeHerder

Round up your herd.

Bring every human and every agent onto one table. Watch the work move. Costs update as it happens.

Try "pricing", "connect a device", or "who reviews the code"

↑↓ move · ↵ open · esc close