On this page
On this page
Maintenance
Other update methods
Install-type switching, the source-server reference script, the installer, and manual package-manager updates. Part of the Updating guide.
Switch between npm and git installs
Installer-driven switches verify the replacement before the working owner is retired. Source wrappers are published atomically; same-path npm shim transitions use an identity-checked backup that is restored on failure, so a failed candidate leaves the previous command runnable. Before retiring an old source wrapper, the updater rechecks its identity and contents and confirms that it still owns the update. The openclaw update command prints its final success result only after post-core convergence and requested restart health checks succeed.
Candidate validation failures leave the old Gateway serving. After activation,
package recovery can restore the retained previous package only when the shared
and affected pre-existing per-agent database schema versions are unchanged and
configuration has not changed since the candidate’s activation Doctor pass. A database first created by the candidate is neutral only
at its supported schema version for that database kind. The restored
Gateway must pass the same runtime checks before recovery is reported as
complete. A schema migration prevents automatic package rollback; replacing
code cannot undo migrated state. Incomplete file rollback retains its backups
for inspection. See Automatic rollback.
If an older target does not support preserving the service definition, automatic
recovery stops and reports the error without retrying with weaker options. Repair
the reported failure, rerun openclaw update, and check openclaw gateway status --deep.
See Failed update recovery.
On macOS, if Doctor reports an installed but unloaded and disabled Gateway
LaunchAgent after an interrupted update, finish update verification or Doctor and
triage first. Then use the printed openclaw gateway start command, preserving
its profile and state/config or custom-label overrides. doctor --fix diagnoses
the disabled label but leaves an already-stopped Gateway stopped.
Use channels to change the install type. The updater keeps your state, config,
credentials, and workspace in ~/.openclaw; it only changes which OpenClaw
code install the CLI and gateway use.
Preview the install-mode switch first:
dev creates or reuses a git checkout, builds it, and installs the global CLI from that
checkout. The stable, extended-stable, and beta channels use package
installs. Extended-stable is rejected on a git checkout without mutating or
converting it. If the gateway is already installed, openclaw update refreshes
the service metadata and restarts it unless you pass --no-restart.
Automatic package-to-Git conversion currently requires an npm-owned package
symlink. A pnpm- or Bun-owned install rejects --channel dev before stopping
the Gateway; use the Git installer when changing that
installation's owner. Normal package-to-package updates keep using pnpm or Bun.
Git updates build the complete runtime, including plugins and the Control UI,
in a temporary candidate worktree. Dev updates preserve local commits by
rebasing the candidate before its build. The updater publishes that prepared
runtime during activation instead of repeating the build while stopped. It
preserves the build timestamps, so ordinary CLI commands keep using that
validated runtime without regenerating it after the move.
Candidate installs and nested build commands use a private pnpm virtual store,
so preparing an update cannot prune dependencies used by the serving Gateway.
The candidate's temporary workspace settings are restored before checking for
source changes; the live checkout's workspace settings are preserved.
Candidate commands keep the qualified Node first among Node providers on PATH,
while preserving launcher-only prefixes such as scoped pnpm shims ahead of it.
This also applies when the selected Node directory was already on PATH; its
package-manager executables do not displace those scoped launchers.
Before activating a package or Git update, the updater also checks discoverable
managed Gateways that share the physical installation. An observed live sibling
blocks the update before the selected Gateway is stopped; the updater checks again
at publication. Stop the sibling through its own service manager or exact Startup entry,
then retry. The updater does not stop or restart sibling services. Package
--no-restart still permits the selected service to keep running, but that
exception does not cover another service or Startup entry using the same files.
The Gateway's installation-change watcher can still restart it. If update Doctor
maintenance stops the selected service, finalization restores the matching service
and reports the maintenance restart, including with --no-restart. If its current
identity cannot be inspected, recovery remains pending.
This is a check of observed consumers, not a lock against new service starts;
unavailable inspection does not prove that the installation has no consumers.
Already-running older updaters retain their own activation and finalization behavior.
For package installs with an owned managed Bun Gateway at a different root,
openclaw update targets the Gateway's package root and leaves the invoking CLI
installation unchanged. It validates the service's actual Bun executable for
Bun 1.4.4+ and WAL-safe node:sqlite, and retains its recorded runtime pin through
service installation and restart. Bun's emulated Node version is never compared
to the target's engines.node requirement. When the updater runs on Node, its
Node must also pass the target's engine and SQLite checks before package
replacement, because finalization runs under the updater runtime.
Node services keep the existing routing: a writable owned definition normally
moves to the invoking CLI installation; Windows, overridden or nonwritable
definitions, and --no-restart retain the service-root route. The selected Node
must satisfy the target release's engines.node requirement. See
managed-service updates for
ownership checks and older-updater limitations.
Source-checkout servers (reference script)
Before manually rebuilding a source checkout, stop every Gateway serving its
dist files. Build entry points inspect discoverable managed Gateways, including
sibling profiles, and refuse when a live service shares that output. On systemd,
this includes processes remaining in the service cgroup after its main PID exits.
Use an external terminal, outside the running Gateway's agent session. Follow the
reported service/profile stop commands, rebuild, then start those same services.
For the default profile, run these commands from the source checkout:
Stop every listed sibling before building and start each one afterward. Preserve
its profile and custom service overrides, or use the matching native service
commands. For a listed launchd job, use its named domain, job, and loaded plist
to select those controls; the profile name alone can identify a different definition.
A Startup-only sibling must be stopped using the exact Startup-file
guidance and restarted through that same Startup entry; updating the selected
service cannot stop that sibling. Start services only after the build succeeds.
If this checkout's built runtime is missing and the CLI cannot run, use those
native controls before rebuilding.
By default, source-runner gateway stop and gateway restart use the existing
built CLI so recovery does not rebuild first. To apply source changes, use the
stop, build, and start sequence above.
openclaw update can apply an available update, but skipped / already-current
does not rebuild stale dist; use the external stop, rebuild, and start sequence
for that case.
A separate candidate checkout with independent output can build while the installed Gateway continues serving. This check observes current services; it does not prevent a service from starting during compilation, and unavailable inspection does not prove that no Gateway is running.
Discovery uses installed service definitions and the invoking service selector.
A bare systemd template is checked for the current OS account. Other active
template instances without an installed instance definition or an explicit
selector are not enumerated. Stop those instances with their native service
commands before building. Discovered macOS LaunchDaemons are inspected in the
system domain; global LaunchAgents remain in the invoking user’s GUI domain.
This observation does not grant the updater control of a system LaunchDaemon.
Teams running a gateway directly from a git checkout on a server can update it
with scripts/update-gateway.sh from inside that checkout. It is the reference
for a source-server update: it refuses tracked local changes, including build
outputs, and prepares the fetched target in a private checkout. It checks that
main can fast-forward, or rebases the local server branch with --rebase-merges.
Dependencies install with a frozen lockfile and the candidate builds before the
serving checkout changes. The built candidate checks the selected profile's
configuration and migration inputs through openclaw update admit before the
service stops. A refusal or unavailable admission leaves the existing service
running; resolve the reported conflict and retry. After preparation, the script stops its selected service and checks for
other observed managed consumers before publishing source, dependencies, and
generated output together. Stop any shared-install siblings through their own
service owners first; this script does not stop or restart them for you.
The consumer check precedes the first source change; it does not lock out new
service starts during source and runtime publication.
Like openclaw update, the script builds runtime JavaScript, plugin assets, and
the Control UI without generating TypeScript declarations by default. Set
OPENCLAW_RUN_NODE_SKIP_DTS_BUILD=0 when invoking the script if this checkout
also needs fresh declarations for plugin development.
This reference script requires Corepack and creates temporary shims without global activation before fetching. After fetching, it freezes the target commit and checks that its exact pnpm pin can run through those shims in a private check workspace. The check contains only package-manager metadata, not the target's dependencies, hooks, or configuration. Missing or invalid metadata, provisioning failure, or a version mismatch stops before checkout update or restart; repair the target pin or install a compatible Corepack, then retry.
The same fetched commit is used for fast-forward or rebase. The resulting
candidate's pnpm pin is checked separately, so local branch overrides remain in
effect. The same scoped shim directory leads nested commands' PATH, and each
operation uses its own workspace and lockfile roots. Accepted untracked build
inputs are copied into the candidate and checked again before publication.
References resolving inside the checkout follow the candidate's corresponding
files. Genuinely external links remain operator-owned references: their target
identity is checked, but external directory contents are not recursively frozen.
Retained runtime transaction directories remain recovery material and are excluded
from candidate build inputs on retry.
If publication fails after stopping the service, the script restores and verifies the previous Git revision and retained dependencies/output before restarting it. It preserves the original failure. Configuration and external operator data are outside this runtime transaction. Changed source or unverified child cleanup prevents destructive recovery; retained paths are reported for inspection. If restart of a verified new runtime fails, that runtime stays in place because a new process may already be using it, and previous artifacts remain available for operator recovery. Failed automatic invocations also retain their small scoped pnpm launcher directory; remove the reported directory only after all update children have stopped. The hosted installers also support npm-owned temporary provisioning when Corepack is unavailable; this server script deliberately requires Corepack.
Already-running source-server scripts that call the older three-argument build adapter still own their earlier Git and dependency changes. That compatibility path retains its output-only recovery; loading a newer adapter cannot move an old shell's completed install behind the stop boundary.
The published 2026.9.4 source-server script also builds before its final restart.
Candidate build entry points recognize its existing update marker only when the
selected, natively owned Gateway serves this checkout's physical dist. The
existing source-build transaction stops that Gateway before writing. On a settled
build failure, it restores the previous output and restarts the selected service
through its native owner, preserving its definition and rechecking its binding.
The original build failure remains visible; a custom shell restart command runs
only after a successful build in the old caller. A separate candidate checkout or
a sibling-only match never grants permission to stop another service.
If that native stop partially succeeds and then fails, the candidate revalidates
and restarts the original service through its native owner, without running a
custom shell command or starting the build. The original stop failure is still
reported, including any failure to complete recovery.
For that first hop, the old script still owns its one successful restart, including an authored custom restart command. Its empty or whitespace-only restart setting remains manual and does not trigger an automatic stop. The old script cannot receive the candidate process's recovery state: after a successful build, the candidate settles native autostart and retires its build backup before returning. A subsequent old-script restart failure therefore requires operator recovery; it does not gain the newer script's retained-backup guarantee. Unjoined build writers or failed output restoration leave the Gateway stopped and retain recovery material.
Generated output roots such as dist, dist-runtime, and package-local
dist directories must be real directories. Builds refuse symbolic-link roots
before reading or mutating their contents so cleanup cannot affect the link
target. Replace an output-root symlink with a real directory before updating or
building a source checkout.
The default stop command is openclaw gateway stop --force, so non-interactive
SSH updates can stop the service. Override both commands for custom service units:
Custom automatic commands must be provided together and must not be blank. An exactly empty restart command keeps the operator-owned manual lifecycle: stop the Gateway yourself before invoking the script, then restart it yourself after resolving any failure. Do not also set a stop override in this mode. The script performs no automatic stop, restart, or build-output rollback:
For a plain single-user source install, prefer openclaw update --channel dev
instead — it manages the checkout, build, and gateway restart for you.
Alternative: re-run the installer
Add --no-onboard to skip onboarding. To force a specific install type, pass
--install-method git --no-onboard or --install-method npm --no-onboard.
If openclaw triage cannot start after a failed npm package replacement, re-run
the installer. It runs the global package install directly and can recover a
partially updated npm install. Keep an unverified Gateway stopped while repairing it.
Pin the recovery to a specific version or dist-tag with --version:
Homebrew formula installs
For brew install openclaw-cli, update through Homebrew:
openclaw update leaves the formula unchanged and prints these commands. Existing
profiles retain that skipped outcome and guidance in openclaw update status --json
and the update report. Stop a running Gateway before a manual upgrade to avoid
loading files from a removed keg; back up first and run openclaw doctor --fix
before restarting.
New or refreshed service definitions use Homebrew's stable opt/openclaw-cli
path. To repair a service still pointing at a versioned Cellar path, run
openclaw gateway install --force from the upgraded CLI. Global npm packages
under the Homebrew prefix continue to use npm.
System-package and image-based installs
When your operating system owns the OpenClaw package, nothing OpenClaw-managed runs
Doctor. openclaw update skips only installs it verifies as owned by pacman or
FreeBSD pkg. It does not detect bootc or rpm-ostree images, so update those through
the image and do not run openclaw update on them. After the system replaces the
package, run openclaw doctor --fix. Before staging the new package or image,
create a verified backup.
An image-based system swaps the package and reboots, so the Gateway service starts
with the new release already in place; there is no window to stop it and run Doctor
first. If the release needs a state migration, the Gateway refuses to start and exits
with status 78. The generated systemd unit sets RestartPreventExitStatus=78, so
systemd does not retry: the unit stays failed and the Gateway stays down until you
run Doctor. The service log names the cause, for example:
After each image upgrade, check the unit and recover if it failed:
Doctor backs up the database beside it before migrating, then restarts the managed
Gateway. For a system service, run systemctl status with sudo on its unit, and run
Doctor as the service account with the service's profile and OPENCLAW_STATE_DIR or
OPENCLAW_CONFIG_PATH. From another account Doctor refuses the mismatched selection or
inspects unrelated state. If Doctor does not restart the unit, restart it with
sudo systemctl restart.
Rolling the image back (bootc rollback, rpm-ostree rollback) swaps the package but
not migrated state. After a migration, restore a verified backup with its matching
release; see Downgrade.
A failed unit is silent on a host nobody watches. To be notified, add an
operator-owned drop-in; openclaw gateway install --force never removes it:
Run systemctl --user daemon-reload after adding both files. systemd starts the
notifier when the Gateway unit enters failed, including after exit 78. For a system
service, use the matching /etc/systemd/system paths and drop --user.
Alternative: manual npm, pnpm, or bun
Prefer openclaw update for supervised installs: it can coordinate the package
swap with the running Gateway service. When a manual installation is required,
for example to bypass an older installed updater once, use this procedure for an
OpenClaw-managed Gateway service. Other pages link here instead of repeating it.
- Create a verified backup.
- Stop the Gateway. Package managers replace files in place, and a running Gateway can otherwise try to load core or plugin files mid-swap.
- Install the target with the package manager that owns the installation.
- Run
openclaw doctor --fixso the new build applies canonical config and migrated state before the Gateway starts. - Refresh the service definition with
openclaw gateway install --force. Installation starts the service. - Run
openclaw gateway startto confirm readiness, then verify withopenclaw gateway status --deep.
For an npm installation:
Run each command only after the previous one succeeds. The install command is
for npm 12 or npm 11.16+; on npm 11.15 and earlier, omit
--allow-scripts=openclaw. For pnpm or Bun, replace the install command with
the matching command below. Replace latest with an exact version or tag when
a refusal or recovery message names one. Keep the same service account, package
manager, installation prefix, profile, and state/config overrides throughout.
In a non-interactive shell, such as a script, openclaw gateway stop requires
--force. For a custom supervisor or foreground Gateway, stop and start it
through its owner instead of the openclaw gateway service commands.
Check openclaw update status for unfinished plugin upgrades and their repair
commands. Normal CLI commands and Gateway startup do not apply deferred plugin
migrations.
OpenClaw 2026.10.10 and 2026.11.1 can report spawnSync node ETIMEDOUT while
probing SQLite headers in a large state directory, because they check every path
in one child with a 10-second deadline. Candidate safety checks do not replace the
installed updater's backup implementation: its original-state capture and update
backup discovery still use the installed code, including its retained runtime.
Selecting a candidate with the batched probe does not repair that running updater.
A cold file cache makes this timeout much more likely. Read each file once, then run the update again straight away, adding any workspace directories outside the state directory:
This needs no file changes, but it only helps when the cached probe fits inside
10 seconds, which depends on the path count and the host. Regenerable directories
such as node_modules in a workspace count too, so removing them can also help.
If the update still times out, use the manual procedure above for the first hop. Its backup step can
use openclaw backup create --no-include-workspace --verify, which keeps database
coverage and skips workspace files; preserve your workspaces separately. If that
also times out, stop the Gateway and other state writers and take a verified
filesystem or volume snapshot covering the state, config, credentials, and
configured agent and workspace directories before replacing the package. Do not
copy only the main file of a live SQLite database or edit installed distribution
files to bypass the probe.
The batched probe first shipped in 2026.11.5-beta.1. A release without it, including 2026.11.1, can hit this timeout again on its own next update.
On any platform, the published OpenClaw 2026.9.3 and 2026.9.4 updaters can exhaust
their fixed 30-second baseline package-fingerprint budget before replacing any
files. They then report Installation recovery is unverified,
Package rollback verification timed out, or retained package tree changed
even when the installed tree is unchanged.
A newer candidate cannot repair the updater already running. Install the target
release once with the manual procedure above. Published OpenClaw 2026.9.5 and
later include the baseline-timeout fallback.
The published OpenClaw 2026.9.7 and 2026.9.8 updaters can fail at package-swap
with Package publication recovery permissions are unsafe once
.openclaw.package-activation-<key>.control exists beside the package. An earlier
update or failed attempt leaves that receipt, so each retry fails the same way.
These updaters hard-link its operation.sqlite journal into their retained runtime
during the update and remove the extra link when that runtime is cleaned up.
Afterward the journal shows owner-only permissions and one link, so tightening
permissions, openclaw doctor --fix, and openclaw update repair do not prevent
the next attempt from failing. A newer candidate cannot repair the updater already
running. Install the target release once with the manual
procedure above and keep the receipt; later updaters replace it themselves.
Published OpenClaw 2026.9.9 and later keep the receipt out of their retained runtime.
Gateways with installation-replacement detection also check the installed build
on their maintenance tick. If the running and installed builds differ, the
Gateway records the replacement, stops accepting new work, and gives active work
its existing bounded shutdown window before handing over to its service manager.
A foreground Gateway exits with instructions to run openclaw gateway run again.
Status and Doctor report the replacement while the Gateway drains. Afterward,
openclaw gateway status --deep, openclaw update status, and Doctor show the
recorded replacement as historical information until the next Gateway shutdown.
This record does not by itself confirm that the new Gateway is healthy.
If a reply's delivery module disappears before sending starts, the reply remains
eligible for recovery instead of being treated as an uncertain send.
This recovery cannot prevent every failure during a package manager's in-place
swap, and older running Gateways do not gain it from files installed underneath
them. openclaw update remains the supported path for coordinating replacement.
Release packages include generated compatibility files for lazy imports from updaters in the supported upgrade window, including the 2026.9.1 service restart path. These files let the old updater finish after its installation is replaced. They do not preserve a running Gateway's old module state, cover arbitrary plugin imports, or make rollback into an older published package safe without restarting.
For a root-owned Linux system-global install, if openclaw update fails with
EACCES, follow the manual procedure above with the system npm that owns the
root-owned global prefix as the install step. Use the same profile
flags/environment you normally use for that Gateway. Replace /usr/bin/npm with
that npm on your host; the same npm version rule applies to
--allow-scripts=openclaw:
For a deeper check after the Gateway starts:
When openclaw update manages a global npm install, it installs the target
into a temporary npm prefix first. The candidate package validates the host
Node version during preinstall; OpenClaw verifies the packaged dist inventory
before swapping the clean package tree into the real global prefix. Pending
lifecycle work is recorded in .openclaw-lifecycle-pending at the package root,
outside the dist inventory. postinstall removes that marker after completion.
If package scripts were skipped, the CLI completes the pending lifecycle before
running any command, including --version; failure stops the command with
reinstall guidance. The updater checks the owning npm before mutation. On npm
11.15 and earlier it omits the unsupported lifecycle-policy flag. On npm 12 and
npm 11.16+, it approves only the candidate OpenClaw lifecycle; transitive
dependency scripts remain unapproved.
This avoids npm overlaying a new package onto stale files from the old one. If
the install command fails, OpenClaw retries once with --omit=optional, which
helps hosts where native optional dependencies cannot compile.
The packaged lifecycle restores the matching precompiled fs-safe dependency
when that retry omitted it. It uses the version declared by the installed
fs-safe package and does not run dependency build scripts. Repair works on Node
and Bun and preserves any existing native package. A working native binding
needs no extra download. Unsupported hosts or failed downloads produce
a warning and allow installation to finish; explicitly disabling fs-safe native
support also skips this repair.
For local tarball targets on npm 12, the archive filename and every parent directory must be comma-free. See Installer path requirements.
OpenClaw-managed npm update and plugin-update commands also clear npm's
min-release-age supply-chain quarantine (or the older before config key)
for the child npm process. That policy exists for general protection, but an
explicit OpenClaw update means "install the selected release now."
If pnpm 11 installed OpenClaw 2026.7.1, run that manual command once. That release predates pnpm 11's isolated global-package layout, so its updater can mistake another npm installation for the running CLI. Later releases retain pnpm ownership and follow the replacement package root during updates. They also use the owning manager's reported global bin directory and stop before mutation when the available pnpm command reports another global root, or when the invoking package is orphaned or not the only active OpenClaw install there.
pnpm 12 retains the global/v11 layout; the layout number does not need to match
the pnpm CLI major version. New or repaired Gateway service definitions use the
active project hash link, so the saved command survives pnpm replacing its
versioned project directory. Ownership detection also recognizes commands that
already point inside a project's .pnpm directory.
Staged pnpm updates isolate both the global project and its launchers. OpenClaw
sets the staging bin through CLI configuration for pnpm 10/11 and child-process
environment configuration for pnpm 12, then verifies both destinations before
installation. A manager that still reports a live destination stops the update
before activation.
If OpenClaw shares a pnpm global install group with another package, the automatic updater stops before changing the group. Update the original comma-separated group manually so its sibling packages and build policy stay intact.
--trust allows OpenClaw's lifecycle scripts. The standard openclaw update
path applies the same OpenClaw-only Bun trust when it owns the install.
For Bun-owned updates, package-manager checks and installs use the verified
service Bun when updating a managed service root. Otherwise they use
process.execPath when the updater runs under Bun, with bare bun from PATH
only as the final fallback. A missing or different PATH Bun does not replace
an explicitly selected executable. Package-manager ownership detection is
unchanged; locating an installation under ~/.openclaw does not make it Bun-owned.
On Windows, the staged updater rejects Bun installs before stopping the Gateway
because it cannot relocate Bun's binary launchers. Follow the manual procedure
above with bun add -g --trust openclaw@<resolved-target-version> as the
install step; verify with openclaw update status.
Package lifecycle and operator state
Package lifecycle hooks validate the Node runtime and update only package-local
artifacts: the installed dist tree and lifecycle markers. Plugin-registry and
operator-state migration belong to Doctor, not package installation. Doctor also
removes genuinely dangling global plugin-runtime links, but preserves shared and
versioned runtime caches and valid links to them: other installs or profiles may
still use them. openclaw update still runs Doctor after installing the candidate;
after a manual package replacement, run openclaw doctor --fix before restarting
the Gateway.
During a marked Windows 2026.9.4 update, package lifecycle also asks Doctor's read-only schema preflight to reject an incompatible shared-state upgrade before activation. It does not migrate operator state. Independent package installation does not run this legacy-updater check.
The fresh post-core continuation runs repairing Doctor before plugin convergence,
including when an older updater already ran Doctor without --fix. This completes
pending legacy state even when the configuration itself needs no repair.
Doctor also brings drifted active official npm plugins to the installed OpenClaw
release, honoring recorded non-default tags and pins newer than its plugin cohort.
It uses the same plugin updater as openclaw update and leaves third-party plugins
unchanged. An unavailable plugin produces a warning with
the reason; it does not prevent the other repairs from completing. Restore
registry access or wait for the missing package, then rerun openclaw doctor --fix.
OPENCLAW_DISABLE_BUNDLED_PLUGIN_POSTINSTALL=1 skips package-local postinstall
cleanup, but still completes the lifecycle marker. Doctor migrations remain
enabled.
Stuck on 2026.9.3
The published 2026.9.3 updater has a fixed five-minute limit that can stop an upgrade before it finishes. A timeout fix in the target release cannot replace the updater already running. Bypass that older updater once with the manual procedure.
Automatic official-plugin drift repair was added after 2026.9.5. If the installed
release still prints Fix each drifted plugin after openclaw doctor --fix,
run its printed openclaw plugins update commands before refreshing and
starting the Gateway service. Once installed, a build
with automatic drift repair performs those official-plugin updates during
doctor --fix; any remaining readiness warning names the plugin that still
needs attention.
Advanced npm install topics
Read-only package tree
After package lifecycle completion, OpenClaw treats packaged global installs as read-only at runtime, even when the global package directory is writable by the current user. Plugin package installs live in OpenClaw-owned npm/git roots under the user config directory, and Gateway startup does not mutate the OpenClaw package tree.
Some Linux npm setups install global packages under root-owned directories such as /usr/lib/node_modules/openclaw. OpenClaw supports that layout because plugin install/update commands write outside that global package directory.
Hardened systemd units
Give OpenClaw write access to its config/state roots so explicit plugin installs, plugin updates, and doctor cleanup can persist their changes:
Disk-space preflight
Before package updates and explicit plugin installs, OpenClaw tries a best-effort disk-space check for the target volume. Low space produces a warning with the checked path, but does not block the update because filesystem quotas, snapshots, and network volumes can change after the check. The actual package-manager install and post-install verification remain authoritative.
For package updates, the check runs before registry lookups and database-schema validation. Managed update runs retain the warning in update history so it also appears in the Control UI.
Before staging a replacement, a read-only snapshot check measures the known SQLite database families, including WAL, SHM, and journal files. Its non-warning diagnostic entries in openclaw update status --json record each family's size, largest first. Current candidate copies need the total family bytes plus the largest family and 64 MiB for metadata. Separately, the activation backup and rollback check uses the same calculation as activation: twice the total family bytes plus three times the largest family and 64 MiB at the backup destination, with total family bytes plus the largest family and 64 MiB on each separate source volume. Plugin copies and registered external databases remain unknown until the complete check after staging.
Snapshot space is checked at the existing destinations: TMPDIR, the capture directory beside the state directory, and the system temporary directory. Git and package updates refuse before staging when every candidate destination has known free space below the snapshot requirement, or when the activation backup or a separate rollback volume has known insufficient space. Refusals report the required and free bytes and the database families that dominate the requirement. Free space on the reported backup or source volume; changing TMPDIR only helps a candidate-copy shortfall. Database sizes are inventory for the temporary snapshot, not database-health or growth warnings. A successful check needs no database cleanup. If measurement fails, the updater warns that it will check again after staging. A usable candidate alternative or unknown free-space reading does not itself stop the update. This is an early check of known database sizes, not a reservation: builds, retained runtimes, plugin copies, and concurrent disk use can consume space afterward, so activation still checks its complete inventory before migration. Package and Git targets that are already current need no candidate snapshot. The updater preserves a config copy, not a full-state backup.
For a direct CLI update, scratch variables set by the invoking operator (TMPDIR, TMP, and TEMP) take precedence over managed-service defaults. For example, TMPDIR="$HOME/.cache" openclaw update checks that directory first and labels it explicit-tmpdir in snapshot capacity reports. The service still owns installation, profile, state, and runtime-path selection. This precedence fix belongs to the installed updater and takes effect for updates it performs after installation; a newer candidate cannot change an older updater's environment merge.
TMPDIR is scratch placement, not a relocation of the installation or durable state. Large update writes have these owners:
| Data | Location |
|---|---|
| Retained updater runtime | Explicit TMPDIR, otherwise a sibling of the installation when possible so unchanged files can be hard-linked; system temp is the fallback. |
| Disposable candidate state and plugin rehearsal | A capacity-checked directory, preferring explicit TMPDIR. |
| Plugin source captures during update finalization | Explicit TMPDIR; ordinary Gateway captures remain under the state directory. |
| SQLite read-only inspection snapshots | Explicit XDG_CACHE_HOME, then TMPDIR during updates; ordinary inspection retains its platform cache default. |
| Original-state captures | <state-dir>.update-captures, retained there so later recovery and cleanup can discover them. These are durable recovery artifacts, not disposable temp files. Known payload space is checked before capture; an unavailable optional capture produces a warning. |
| Doctor migration backups | Beside the database being migrated, retained for recovery rather than moved with temporary scratch. |
| Package candidates and rollback images | Beside the package-manager installation, so activation and rollback can rename on the same filesystem. Database backup admission checks the backup and restore volumes before migration. |
| Installed plugin projects | The selected state directory's npm/git roots; these are the installed plugins. |
| npm cache | npm's configured cache, independently of TMPDIR. Set npm's existing npm_config_cache variable to move it. |
A large temp volume does not supply free space to these durable destinations. Preserve recovery artifacts when freeing space. After a failed update, retry the reported recovery command or openclaw update repair; do not delete journals or captures to clear a pending recovery hold.
This check runs in the installed updater; an already-installed 2026.9.3 updater retains its prior behavior for its own first upgrade hop.