Operate

Backup & updates

Keeping a copy of your Omnesis data, getting it back, and moving every machine to a new release: omnesis backup, restore and export, omnesis update on one machine or the whole fleet, Docker and source installs, and how the gateway judges which device versions it still supports. Commands run on the gateway machine unless a section says otherwise.

Backup

omnesis backup takes a snapshot while the gateway keeps running, into ~/.config/omnesis/backups/<timestamp>/ on the gateway machine. It holds the databases (documents, index, analytics), omnesis.json, OMNESIS.md, tokens, config secrets, TLS certificates and a manifest. --note labels a backup, omnesis backup list shows the ones you have, and --no-index leaves out index.db, the largest file, which the gateway can rebuild from the documents.

❯ omnesis backup --note before-cleanup

Backup started…
✔ Backup complete: 8 files, 812.4 MB
    omnesis.db.enc                 611.3 MB
    index.db.enc                   182.0 MB
    analytics.db.enc                18.4 MB
    …
  Saved on the gateway host at ~/.config/omnesis/backups/2026-03-14T09-12-05

A backup leaves out four things:

omnesis update takes no backup by default. Add --backup to request a pre-update backup on the gateway host. After each successful backup, Omnesis keeps the newest two such pre-update backups and deletes older ones; backups you took yourself are never deleted. Set backupRetention.preUpdateCount to keep a different number, or 0 to keep them all.

Restore and export

omnesis restore <backup-dir> puts a backup back into a configuration directory, ~/.config/omnesis/ or the one --target names. It replaces what a backup holds: the databases, omnesis.json, OMNESIS.md, tokens, config secrets, pasted API keys, sweeps, TLS certificates and the recovery envelope. An item of that kind the backup does not hold is removed, so an index the backup was taken without does not survive beside the restored documents; the gateway rebuilds it, and the search graph, at its next start. Everything else in the directory stays as it was: other backups, models, exports, logs, the keyring passphrase file and the keyring's own entries, and a Docker install's Compose file. In .env, the image tag, the keyring settings and the gateway port stay this machine's.

Restoring over an existing corpus needs --force. The restore unpacks the backup inside the directory first and moves it into place only once every file is there, so a failed restore leaves the directory as it was. It refuses to start while a gateway holds the directory.

An encrypted backup needs its root key. On the same machine, restore uses the key already in the keyring. On a new machine, pass the recovery code with --code (or on standard input) and restore rebuilds the key from it. The databases come back plaintext and the gateway encrypts them again at its next start.

On a source or package install, stop the services around the restore:

❯ omnesis backup --list

❯ omnesis service stop

❯ omnesis restore <backup-dir> --force

❯ omnesis service start

On a Docker install

On a Docker install, run the same command on the host. The omnesis command there stops the containers, runs the restore in a one-off container of the gateway's image with the gateway's mounts and environment, starts the containers again and waits for the gateway to report healthy. A restore that fails leaves the directory as it was, and the containers are started again all the same.

❯ omnesis backup --list

❯ omnesis restore <backup-dir>

At a terminal it lists what it will do and asks before replacing a corpus. Without one, as under a script or an agent, it asks nothing and refuses unless --force is given; its progress goes to standard error, so --json leaves standard output with the restore's result alone. It exits non-zero if the gateway does not report healthy within ten minutes; OMNESIS_RESTORE_HEALTH_TIMEOUT sets another limit in seconds. A backup outside the configuration directory is mounted read-only for the restore. --target does not apply: a Docker install restores into its own directory. A host that only collects has no corpus to restore.

omnesis service start, stop, restart, status and logs run their docker compose equivalents on a Docker install. The omnesis command from an older release sends restore and service into the container instead, which refuses them and names the host command; omnesis update replaces it.

On a new machine

Install Omnesis on the new machine the way the old one was installed, with encryption at rest if the backup is encrypted, and keep the configuration directory at the same path. Copy the backup directory into ~/.config/omnesis/backups/, then restore it with the recovery code. On a Docker install, the omnesis command on the host stops and starts the containers itself; on another install, stop the services first and start them after, as above.

❯ omnesis restore ~/.config/omnesis/backups/2026-03-14T09-12-05 --force --code <recovery code>

The new machine keeps its own keyring passphrase and seals the restored root key with it; the recovery code keeps working. Devices and tokens come back with the backup, so collectors and phones reconnect once the gateway's address reaches the new machine. The backup's certificates come back too: a certificate that names the old machine does not cover a new name, and a device that reaches the gateway by a new name pairs again.

Export

omnesis export writes your documents to ~/.config/omnesis/exports/<timestamp>/, as JSON lines by default or as CSV, which leaves out the full text and adds one file per analytics table. It is for taking your data elsewhere, not for restoring. On an encrypted install the export is encrypted too; decrypt it with omnesis keyring decrypt-artifact <export-dir> on a machine with the same root key before using it outside Omnesis.

Updating

Source updates check the target checkout's Node requirement before changing the checkout or stopping services. If the installed Node version is unsupported, upgrade Node, ensure node and npm select it on PATH, then rerun omnesis update. Package installations need only Node 24 or newer.

omnesis update moves a machine to the newest stable release and restarts what runs there. It works the same for a source or Docker install, and Omnesis never starts it on its own. Run it on the gateway machine first, then on each other machine, or add --fleet to have the gateway ask the other machines to run it (see Updating every machine).

❯ omnesis update

# or, for an unattended rollout

❯ omnesis update --yes

On a machine that runs the gateway, it does the following, in order:

  1. Installbuild the release, or pull the images
  2. Restart the gatewayits data migrations run; they only go forward
  3. Wait for health/health must report the new version
  4. Restart the collectoronly now, so it never meets a half-migrated gateway
  5. Refresh agent harnessupdate the plugin; ask before restarting it

If it fails before health

  1. Automaticthe previous release is put back and restarted

Code returns; migrations that already ran do not.

Restoring an existing backup

  1. Stopcollector, then gateway
  2. Restorea backup you previously created
  3. Startgateway, then collector

By hand, with the commands under Restore.

An update installs and restarts the gateway before anything that depends on it. A failure before the gateway is healthy puts the previous release back. Backups are optional: --backup adds one before any irreversible changes, as described under How the updater works.

A machine that only collects has nothing to back up: its collector simply restarts on the new release. A machine with a connected agent harness (OpenClaw or Hermes) refreshes the installed plugin, then asks before restarting the harness, since that interrupts whatever the agent is doing; --yes answers that prompt too. If the harness's authorization has lapsed, the update prints the command to renew it and leaves the harness alone. omnesis devices list, omnesis doctor and the portal's Devices page show any plugin refresh or restart still owed, with the command that finishes it.

If it fails

A build that does not compile, or a gateway that does not come back healthy, returns the machine to the release it was running and restarts it there. Ctrl+C during the install or the health wait does the same once the running step has stopped. Once the gateway serves the new release nothing is undone; a collector the update did not reach is reported with the command to restart it.

The health wait lasts up to ten minutes, so a long migration can finish. A gateway whose process has exited does not use that time: when the service manager (systemd or launchd) has relaunched it twice during the wait, or has held no gateway process for 15 seconds, the update rolls back at once. A gateway that is still running keeps the whole wait.

Rolling back the code does not roll back the data. If the new gateway got far enough to run its migrations, the previous release keeps running on the migrated database. Sources keep their sync positions and continue where they left off, unless the newer version changed how the gateway reads them; only those sources sync again from the start. An existing backup can restore the data state it captured; see Restore.

An older release does not know the settings a newer one added, and drops them from omnesis.json the next time it changes the configuration, for example when you add a source or assign a model. So before a rollback or a move to an older release, the update saves the configuration beside it as omnesis.json.newer-settings. When a release that knows those settings next starts its gateway, it puts back each one the configuration lacks, logs which, and removes the saved copy. A setting you changed on the older release keeps your change. A setting the older release knew and you removed there is also put back, because the gateway cannot tell it from one that release dropped.

If the update was cut short by a power loss or a forced kill, run omnesis update again: it notices the unfinished run, says what it will do, and completes or repeats it.

On a machine with less than about 5 GB of memory in total (or a container limited to less), a source build (which needs at least 3 GB for itself and about 2 GB beside it) stops this account's collector and gateway while it builds. The gateway is down until the build is in place, and the update's own restart brings it up on the new release; the collector starts again afterwards. If the build is still killed, the update says the machine most likely ran out of memory and rolls back. Stop the collector and gateway (omnesis service stop collector, omnesis service stop gateway), add swap or free memory, and run omnesis update again.

On a source install, npm ci installs over the node_modules the running release left. If that install fails, the update removes node_modules and installs once more before it rolls back, and the rollback's own install is retried the same way. If dependency installation is interrupted, killed, or still fails after its retry, rollback removes the incomplete dependency tree before reinstalling the previous release. If removing that tree fails, recovery stops and reports the failed step.

On Intel macOS, dependency installation also verifies the native vector engine and builds it locally when the bundled binary is incompatible. This applies to fresh installations, updates and rollback reinstalls. Keep Xcode Command Line Tools installed; see Requirements.

Options

Flag Effect
--yes Answers every prompt, including harness restarts. Needed in scripts.
--dry-run Prints the plan without changing anything.
--target-version X.Y.Z Moves to one exact release instead of the newest.
--commit <full-sha> Source installs only: fetches that exact 40-character commit from the checkout's origin, for controlled testing between releases. With --fleet it is offered only to paired machines verified as source installs; Docker installs and phone apps are left alone. The portal's update action always targets releases.
--edge Follows the main branch instead of stable releases (source installs). A Docker install refuses it.
--no-restart Installs, then reports which daemons still run the previous release.
--backup Takes a pre-update backup on the gateway host. Off by default.
--no-backup Accepted for compatibility; has no effect.
--health-timeout <seconds> Allows a long migration more than the default ten minutes.
--wait-for-lock=<minutes> Waits for an update already running on this machine instead of refusing to start.
--allow-rewind Source installs only: allows a target that is not a newer release and does not contain the build installed now, such as going back from an exact-commit test build. The commits it drops are listed. With --fleet, it is passed to each machine commanded at that moment.
--force Allows moving to an older release, and implies --allow-rewind. There are no down-migrations. Sources keep their sync positions, except where the older release predates a change in how the gateway reads them; those sources sync again from the start. Settings it does not know are saved for the next upgrade, as described under If it fails. An OpenClaw or Hermes plugin that has followed a certificate renewal stops connecting when moved back to a release whose plugin pins the certificate; afterwards, run omnesis connect <harness> --refresh --trust-fingerprint sha256:<served> on its machine, with the fingerprint omnesis tls status shows on the gateway machine.
--fleet Afterwards, asks the gateway to update the other machines.

Unless you pass --edge, the update installs only stable release tags. It refuses a source checkout it did not install or adopt, a checkout with local changes, and a tag whose contents do not match its name.

A source install that was moved to an exact commit, for example an unmerged test build, updates to the next release normally: a newer release is a forward update even when it was cut without that commit, and the update lists the commits it leaves behind. A target at the same or an older version that does not contain the installed build is refused unless you pass --allow-rewind.

The same rule covers a repository whose history was replaced, so that the target shares no commits with the installed build: a newer version is a forward update, and the update says the history was replaced instead of listing commits. This holds for stable and edge installs alike. When the installer itself moves an existing checkout, as it does with --reconfigure, it applies the same rules, with --force in place of --allow-rewind.

Running the install command again on a machine it already set up is an update: the installer finds the checkout the earlier install recorded, makes sure it can fetch from its origin, and runs omnesis update on the machine, so the update backs up, rebuilds, refreshes the service definitions, restarts and rolls back exactly as described above. The certificate, keyring, embedding model and pairing stay as they are, so a collector does not pair again. A plain re-run updates any machine that runs a gateway or a collector; to turn a collector machine into a gateway, pass --reconfigure. The full install also runs for --collector or --client-only on a machine with another role, for a first install that never registered its services, and for a flag that sets one of the kept choices, such as --code, --mkcert or --embedder.

Several collectors, one source

Update the gateway first, then every collector. A collector newer than its gateway reports Gateway upgrade required and waits. If several collectors host the same source, update all of them: until they are all on the new release, the older ones may be unable to sync that source or change its settings, and the sync status of each collector that needs updating says so. Sources hosted only by older collectors keep working.

Release notices

The gateway checks for a newer stable release shortly after it starts and every 24 hours, asking the source checkout's origin or the container registry, according to how it was installed. Clients do not check. A newer release shows as a quiet line in the portal sidebar and in omnesis doctor; failures say nothing. The check never downloads or installs anything. What each release changes is in the release notes and the changelog.

It does tell that Git host or registry the gateway's network address. Omnesis adds no install identifier, corpus data or version information to the request. Turn it off with omnesis config set /releaseCheck false.

Daemons the update cannot restart

The update restarts only services that belong to the account running it. A daemon started by hand, a hardened gateway, or a named instance is reported as still running the previous release, with the command to restart it when the machine knows it. A collector is restarted only once its own gateway is serving the new release; if the gateway could not be restarted, the collector is reported instead. A hardened gateway is updated with its own root command, which omnesis update prints.

How the updater works

The update runs in two halves. The release already installed finds the target and puts it in place. Everything after that (an optional backup when it can wait, the restarts, the health wait, the harness refresh and any rollback) is run by the newly installed release, so a fix to those steps applies to the update that delivers it. Only one update runs on a machine at a time; a second is refused with the running process and its current step, or waits with --wait-for-lock. The lock of a killed update is recovered automatically after a short interval.

With --backup, a gateway that runs from the installation being updated is backed up before the install. A gateway in a container or on a hardened release keeps serving its current build during the install and is backed up after it, before anything restarts. A gateway that is not running is backed up by copying its closed databases into the same backups folder.

Before restarting a daemon, the update rewrites its launchd plist or systemd unit to what the new release's omnesis service install would write, keeping its executable, configuration directory, keyring wiring and environment. A unit it cannot rewrite without losing something (a systemd drop-in, EnvironmentFile=, a comment, or a setting service install does not write) is left alone and reported; a hardened gateway's unit and named instances are never rewritten.

A source install writes a completion record once its build succeeds, and a Docker install once the gateway answers with the new image; the next run uses it to decide whether an interrupted update must be repeated. A source build sizes its memory from the machine as the installer does, and never overrides a heap size you set in NODE_OPTIONS.

Updating every machine

omnesis update --fleet on the gateway machine updates that machine, waits up to 90 seconds for the collectors and agent harnesses that were connected to reconnect, and then asks each one to run omnesis update on itself. You confirm each machine after seeing its current and target version; --yes confirms them all. It then waits, up to 45 minutes, for each commanded machine to report: updated, restart still owed, or failed with its reason. The command exits with an error when any machine failed or never answered, so a machine that refused cannot pass for one that updated.

# on the gateway machine

❯ omnesis update --fleet

No code travels over the connection. A device receives only a version number, runs its own update against its own release source, and refuses a version that is not a real release there, so a tampered gateway cannot make a machine run code of someone else's choosing. A device is only ever sent the version the gateway is serving, so it can never be moved past its gateway; if the gateway could not be restarted, the fleet step stops and says so. A device that is offline keeps the request and runs it when it next connects.

A collector restarts on the new release when it finishes, through its service or, when it was started some other way, by exiting for its supervisor to restart. A machine with an agent harness installs the new plugin and restarts the harness. OpenClaw restarts at once, interrupting any agent run in progress. OpenClaw restarts even when its running gateway saved the new plugin but could not load it; the restart is what loads it. Hermes lets running work finish for up to its drain timeout (three minutes by default) first. When the harness cannot be restarted from there, its device row records the restart still owed and the command to run.

--dry-run cannot be combined with --fleet, because the fleet step depends on what the gateway serves after this machine moves; preview this machine with omnesis update --dry-run. --edge cannot be combined with it either, since a branch build has no release number to send.

The gateway will not command these devices, and says which ones to update yourself:

From the portal

The portal's Devices page offers the same actions: Update on one device and Update all for the fleet, with the same version comparison and confirmation. Each device's card shows where its update stands: waiting to be sent, running, failed, installed but still needing a restart, or to be updated on its own machine. A failure or restart notice stays until the device reconnects on the requested release or a newer one.

When the gateway's release notice reports a newer version, Update fleet updates the gateway itself first, then the devices. The confirmation names the gateway's version change and lists which devices will be updated and which you must handle separately. The portal may be unreachable briefly while the gateway restarts, and picks the progress up again when it is back; no device is sent anything until /health reports the confirmed version.

Update fleet works for source installs running as the standard user service. For named instances, hand-started or hardened gateways and Docker installs, the button explains why it is disabled; run omnesis update --fleet on the gateway machine instead.

External MCP clients keep their own sign-in, which an ordinary update does not affect. If a release's notes say otherwise, reconnect them after the update, and run omnesis connect openclaw --refresh or omnesis connect hermes --refresh for those harnesses.

Docker installs

A machine installed with install.sh --docker updates with the same omnesis update and the same steps. Installing means bumping the image tag recorded beside the Compose file and pulling the new images, the updater's included, quietly: one line for the pull, and Docker's own errors if it fails. With --backup, the backup runs after the pull, while the gateway still serves the previous image. Rolling back is quick: the previous tag is written back, and its image is still on the machine. Once the gateway answers on the new release and the collector has restarted onto it, the update removes the previous release's images of this install, about a gigabyte each; it never removes another image. One that a container still uses, such as the updater image the update itself started from, is kept and removed by the next update, or by the next run of the installer if that comes first. An image it cannot remove is reported with the docker image rm command that does, and never fails the update. Re-running the installer onto another release does the same once its gateway serves: the previous release's images of this install go, and one a container still uses stays. --target-version pins a release tag. A Docker install follows releases only, so it refuses --edge before anything changes.

To run an exact commit in Docker, a maintainer publishes its gateway, collector and updater images with the repository's docker-publish workflow, which tags them sha-<short-commit>; there is no combined image for a commit. Pin that tag on a host that runs the gateway and collector as separate containers, then pull and recreate them:

❯ sed -i.bak 's/^OMNESIS_IMAGE_TAG=.*/OMNESIS_IMAGE_TAG=sha-0123abc/' ~/.config/omnesis/.env

❯ docker compose -f ~/.config/omnesis/docker-compose.yml --profile update pull

❯ docker compose -f ~/.config/omnesis/docker-compose.yml up -d --force-recreate

A commit image can carry migrations no release has.

The update runs in a short-lived updater container that holds the Docker socket for that one run. The socket gives root-equivalent control of the host, which is why the long-running gateway and collector containers never hold it. If a run is interrupted, run omnesis update again; it checks what the gateway actually serves before trusting the recorded tag. A host that only collects has no gateway to ask, so there it checks the tag Docker started the collector container from.

The updater runs as your account and joins the group that owns the Docker socket as a container sees it. Where the daemon runs in a virtual machine, as on a Mac, or rootless, that group differs from the one the socket has on the host, so the installer asks a container which group it is. Before changing anything, the update checks that its container can reach the daemon. When it cannot, it stops, says nothing was changed, and writes the socket's group into the Compose file's updater; run omnesis update again. When it cannot correct the Compose file, it prints the installer line to run once, with the options the install was made with, before omnesis update.

The omnesis command on the machine is the one part of a Docker install that no image carries, so once the containers run the new release, the update also replaces that command with the new release's, through a one-shot container that mounts only its directory. It replaces only the file the installer wrote for this install. An install made before the location was recorded is found at ~/.local/bin/omnesis when its configuration directory is ~/.config/omnesis; otherwise the update says to run the installer again with the options you installed with.

Stable Docker updates select the newest release tag present in every image controlled by OMNESIS_IMAGE_TAG in the Compose file, including the updater. This lookup uses the container registry rather than npm, so a release does not need npm packages. Independently versioned sidecars do not participate in release discovery. The combined image is updated through its gateway service, preserving the mounted config directory and paired collector identity. An updater image from before registry discovery looks the release up on npm instead and stops with Could not resolve omnesis@latest; name the release once with omnesis update --target-version X.Y.Z, and later updates find it on their own.

Registry tag discovery is anonymous. For a private registry, authenticate Docker on the host and rerun the installer with --docker --version X.Y.Z and the same topology flags, config directory and image repository. A one-shot updater cannot use the host's credential helper through the Docker socket alone. If you explicitly mount a self-contained Docker credential configuration into the updater, you can instead use omnesis update --target-version X.Y.Z; keep that credential mount out of the running daemons. For a registry addressed as localhost, use Linux host networking or an explicit target version; bridge-network registry discovery reaches the updater container’s loopback, rather than the host’s. Standalone Compose installations update with a pinned OMNESIS_IMAGE_TAG, docker compose pull, then docker compose up -d.

Adopting a hand-made source install

A source checkout that you cloned and built by hand has no marker saying the installer owns it, so omnesis update refuses to touch it. If that checkout is an installation rather than a development tree, adopt it from the repository root, then run the first update through npm run cli; after that, omnesis update works as usual.

❯ npm run cli -- update adopt-source

# then follow stable releases

❯ npm run cli -- update

# or follow the main branch instead

❯ npm run cli -- update --edge

Adoption requires a standalone clone of the official repository with a single official origin, a detached HEAD, the full history and tree, and no local changes. It then checks with the remote that HEAD is a stable release tag or part of main. A linked worktree, local branch, fork, shallow clone or checkout that changes during the check is refused with the reason. Adoption only records the marker; the first update then rebuilds the checkout.

To update a checkout by hand instead, fetch the exact release tag, detach at it, install, build, restart the gateway, confirm it reports the new version, and only then restart the collector:

❯ git fetch origin refs/tags/vX.Y.Z:refs/tags/vX.Y.Z

❯ git checkout --detach vX.Y.Z

❯ npm ci

❯ npm run build

❯ npm run cli -- service restart gateway

❯ npm run cli -- status

❯ npm run cli -- service restart collector

To follow main by hand, fetch it with git fetch origin refs/heads/main:refs/remotes/origin/main and detach at origin/main, then build and restart in the same order. If a fetch fails, stop: comparing against a stale origin/main can report nothing to update while the remote is unreachable.

Version compatibility

Every Omnesis release and app build shares one product version, and each device reports its own when it connects; the browser extension, which holds no connection open, reports it with its uploads and periodic checks. The gateway compares it with its own version and with the oldest build it still supports for that kind of device. omnesis devices list, the portal's Devices page and omnesis doctor all show the same verdict:

State Meaning What to do
current On the gateway's version or newer. Nothing.
behind Older than the gateway but still supported. Normal: a phone build or a collector on another machine often lags. Update when convenient; omnesis doctor does not fail.
unsupported Older than the oldest build the gateway supports, or speaking a connection protocol it no longer speaks. Update the device. The portal flags it and omnesis doctor fails.
unknown The device reported no version, or one that is not a version number. Nothing; the device keeps working. Update it by hand when you update.

A command-line token, such as the one the installer creates, reports a version only while it holds a connection open, as omnesis status --watch does. Until it has reported one it has no state: omnesis devices list shows —, and the device counts in omnesis status and omnesis doctor leave it out.

A fleet update leaves unknown and unsupported devices to you, because the gateway will not tell a build it cannot identify, or one below its floor, to replace itself. Reporting a version is optional, and a device is never refused for leaving it out.

What the gateway does refuse is a device speaking a different connection protocol: both sides exchange a protocol number when they connect. The browser extension checks the gateway's version before pairing and refuses only a gateway older than the oldest one its page capture works with; a newer extension on an older gateway keeps capturing pages and simply does not offer what that gateway lacks. Within a minor release, what the gateway accepts only grows, which is why the gateway is always updated first. A CLI that has not been updated yet keeps working against it: a model backend, certificate source or other value newer than the CLI is shown by its name instead of stopping the command.

GET /health needs no token and returns the gateway's version and a compat block with the connection and pairing protocol numbers and the database schema version, enough for a client to decide whether it can talk to this gateway. GET /admin/compat, with an admin token, returns the full picture: every store and how it is versioned, every protocol and the versions it accepts, and the oldest supported build per device kind.