Skip to content

Restarting Keryx

William Koch edited this page Sep 30, 2026 · 3 revisions

Changes to Python files don't take effect until Keryx restarts. Keryx may have made the change itself, so a restart reports its status and checks that Keryx came back.

uv run keryx restart --reason "picked up new code"
uv run keryx restart --status     # how the last one went

keryx restart asks the service manager to restart the installed unit. That's systemd on Linux and launchd on macOS; SERVICE_MANAGER overrides the choice. Once Keryx is up again, it phones you back by itself with a one-line status:

  • how long it was down;
  • the version before and after;
  • which channels are listening;
  • how many tasks the restart interrupted.

You can also ask on the phone: "restart yourself". A restart drops every call in progress, so a restart you ask for on a call waits until you've hung up.

Flags

Flag What it does
--reason "…" a few words, which you hear back on the call
--status print how the last restart went, and exit
--force restart even while a call is in progress
--no-callback restart quietly, with no call afterwards

Notifications during a call

If a restart finishes during a call that's yours, the assistant gives the confirmation in that call. A call is yours if you gave the PIN, or if Keryx placed it to your number.

Otherwise, Keryx waits for the line to be free before it calls. If the line stays busy, the call counts as failed. Keryx may be unable to place the call because Twilio is unavailable, PUBLIC_HOST isn't set, or the phone channel is down. In that case, if SMS_ENABLED=true, it texts you the summary. If texting is off or also fails, the result is still available from keryx restart --status.

When the restart itself doesn't go through

The restart command may fail, or nothing may happen within 20 seconds of it. Either way, the old process is still running, and it tells you:

  • If a call that's yours is in progress, it says so in that call.
  • Otherwise, if SMS_ENABLED=true, it texts you.
  • If texting is off or fails, and no call is in progress, it rings you with a plain spoken alert. The alert gives only the headline: the restart didn't go through, and the old version is still running. It never rings while a call is in progress.

keryx restart --status has the details.

If nothing supervises the process, a restart refuses, because stopping would leave nothing to start it again. That includes a keryx serve you started in a terminal on a machine where the service is installed too. If you say "restart yourself" on a call to that copy, it refuses rather than restart the installed one in its place. keryx doctor says which case you're in. Running as a Service explains how the unit is found, and Assumptions and Deployments explains what you give up without one.

How Keryx checks the new version

The confirmation reads the running version from STATE_DIR/running-version, which keryx serve writes when it starts. It doesn't ask git describe at the moment you request the restart. The checkout changes under a running process. In the usual order (edit, commit, then ask for the restart), the new commit is already on disk when you ask. A check at that moment would compare the new commit with itself, and report that nothing loaded. Only when the process starts are the checkout and the running code the same.

Keryx also checks that the service works, not just that it's running. Before the restart, it notes the current position in each service log. Afterwards, it reads the new entries, and reports any errors before the rest of the status.

Restart watchdog

If the service never starts again, it can't report the failure itself. This matters most after a code change that causes an import or startup error.

So just before a restart, Keryx starts a watchdog (keryx restart-watch) outside the service, where the restart can't stop it. On Linux, it runs in a separate systemd-run --user unit; on macOS, in a new session. The watchdog acts only if the restart is still pending when its time runs out.

It then rings you with a plain spoken alert. It never uses a media stream, because the process that serves media streams is the one that isn't running. If SMS_ENABLED=true, it texts you the details first. The call still works with texting off. When you ask for a restart, the assistant tells you which to expect: a text if texting is on, a call if it's off.

Beyond that, Restart=always (systemd) or KeepAlive (launchd) brings the service back. If the call never comes, look at systemctl --user status keryx and STATE_DIR/logs/keryx.log (~/.local/state/keryx/logs/ by default).

Exit code -15

An exit code of -15 can mean the restart worked. systemctl runs inside the service it restarts, so the restart stops it with that code.

Clone this wiki locally