* fix(plugins): allow reloads to wait for long-running work * test(plugins): await reload drain readiness without polling * test(sessions): await resource retirement before reopening cleanup fixtures
17 KiB
summary, title, read_when
| summary | title | read_when | |||
|---|---|---|---|---|---|
| What `plugins uninstall` removes, how `plugins update` resolves sources, channels, pins, and integrity drift, and reloading edited plugins | Uninstall and update plugins |
|
This page covers removing and updating installed plugins, and reloading edited plugin code without restarting the Gateway.
With a running Gateway, ordinary uninstall waits for the package runtime owners to stop before removing files, and update refreshes the Gateway after the local package operation finishes. Without a running Gateway, these commands save changes for its next startup. See Install plugins for installation sources and Gateway-host path requirements.
If the Gateway rejects a lifecycle request because another operation is still running, the CLI honors its retry delay within the existing request timeout. Connection failures and failures after a mutation starts still stop the command.
Uninstall
openclaw plugins uninstall <ids...>
openclaw plugins uninstall <ids...> --dry-run
openclaw plugins uninstall <ids...> --keep-files
openclaw plugins uninstall <ids...> --force
uninstall removes plugin settings from plugins.entries, the persisted plugin index, plugin allow/deny list entries, and any plugins.load.paths entry that exactly resolves to the recorded install path. It leaves only an exact enabled: false entry for each removed plugin id. This marker records the explicit uninstall choice so remaining model, provider, or channel selections do not automatically reinstall the package during startup repair. Reinstalling does not silently re-enable it; enabling the plugin again replaces the marker. For a package with multiple child entries, any child id resolves to the package owner; uninstall removes every sibling's policy and slot/channel references, the one package install record, and the managed directory once. Linked path installs also remove an exact entry for their recorded source path. Parent directories, child paths, prefix matches, and unrelated load paths are preserved. Unless --keep-files is set, uninstall also removes the tracked managed install directory, but only when it resolves inside OpenClaw's plugin extensions root. If the plugin currently owns the memory or contextEngine slot, that slot resets to its default (memory-core for memory, legacy for context engine).
Matching load-path references are removed before package files so symlink aliases cannot leave invalid config. With a running Gateway, runtime drain also precedes removal of the install record, including with --keep-files or a linked install. If runtime drain or file removal fails, the plugin stays disabled and tracked so you can retry uninstall.
uninstall prints a preview of what will be removed. Multi-entry packages name the package owner and every affected child before prompting. Pass --force to skip the confirmation prompt (useful for scripts and non-interactive runs); without it, uninstall requires an interactive TTY. --dry-run prints the same preview and exits without prompting or changing anything.
When several IDs are supplied, uninstall resolves the whole selection before removing anything. Repeated IDs and children of the same package select that package once. Packages are processed in first-requested order, with a separate preview and confirmation for each. Cancellation or failure stops the remaining removals; earlier successful removals stay committed. An invalid target rejects the selection before any package is removed.
If a tracked package has no discovered plugin entries, uninstall can remove its exact install record and same-owner policy, including owner-keyed channel config that no other discovered plugin claims. This recovery is allowed only when no other install record shares its package path and no discovered plugin matches its id or recorded paths. Unrelated policy remains unchanged. Registry refresh rebuilds discovery metadata; it does not remove these orphan install records.
Discovered packages with missing, ambiguous, or conflicting ownership still fail closed without changing package files, config, or the installed index. Run openclaw plugins registry --refresh, inspect openclaw plugins doctor, and use openclaw doctor --fix for repairable legacy index state. If ownership is still ambiguous, reinstall the package before retrying update or uninstall.
Update
openclaw plugins update <ids-or-npm-specs...>
openclaw plugins update --all
openclaw plugins update <ids-or-npm-specs...> --dry-run
openclaw plugins update @openclaw/voice-call
openclaw plugins update @acme/demo
openclaw plugins update openclaw-codex-app-server --acknowledge-install-policy-warning
Updates apply to tracked plugin installs in the managed plugin index and tracked hook-pack installs in shared SQLite state. They reuse the source that the user already chose when installing the plugin, so they do not require a second source acknowledgement.
Supply multiple IDs or npm specs to update a selection, or use --all without
IDs. Repeated targets and sibling plugin IDs update their package once. An
explicit npm spec overrides an ID-only selection of the same package; two
different explicit specs for one package are rejected. Unknown targets and
conflicting selections fail before updates start, including with --dry-run.
The existing bulk updater processes plugin packages and then hook packs, retains
successful updates when another package fails, and applies saved changes to the
running Gateway with one final refresh.
If update finalization fails, the error reports the original cause first and retains any rollback failures as additional diagnostic context. A failed rollback remains retryable; a successfully committed or rolled-back install is not applied again during cleanup.
On source installations, a selected plugin built with the host stays in use. Named updates, --all, and stable/beta core updates report why the registry copy was not admitted and leave its dormant install record unchanged. Package ownership checks still apply to plugins being updated; explicit plugin paths retain their selection priority.
During openclaw update, a locally linked plugin with an explicit load path keeps its selection even when OpenClaw bundles the same plugin ID. The update reports the retained plugin and path as a warning; update that plugin at its source. Linked path records are excluded from package-update ownership reconciliation, so stale package metadata does not turn link retention into an update failure.
update --all reports and skips orphaned path-source install records so remaining plugins can update. Remove an orphan record with openclaw plugins uninstall <id> when its files are no longer needed.
The narrow exception is a trusted official package completing a catalog-declared plugin id replacement. That update starts from the catalog package selector so the renamed manifest can replace the legacy id.
Verified OpenClaw-owned npm and official ClawHub plugins resume automatic updates when their recorded exact OpenClaw release is no newer than core and their catalog source follows the default release line. The update uses the existing channel and compatibility rules, retains the recorded registry, and saves the default selector only after a successful install or an unchanged-artifact verification. For npm installs, recovery can save the default selector without downloading or reinstalling when the existing version and recorded artifact identity already match the target.
An explicit npm version or tag supplied in the current command remains authoritative. Newer release pins, independently versioned packages, third-party packages, local, Git, marketplace, and custom ClawHub sources keep their existing selectors. An npm registry mirror stays in use while eligible official npm packages receive recovery. If a retained pin has a newer available release, OpenClaw prints an explicit replacement command. ClawHub selector replacement uses `plugins install clawhub:<package> --force` because `plugins update` accepts explicit selector overrides only for npm records.
Older official-plugin syncs could save an exact version without a user request. Those records do not distinguish automatic pins from manual ones, so qualifying older OpenClaw release pins resume automatic updates in both cases. The same recovery applies to targeted updates, `--all`, `openclaw update`, and `openclaw update repair`. A failed replacement keeps the previous install record for retry.
For npm installs, you can also pass an explicit npm package spec with a dist-tag or exact version. OpenClaw resolves that package name back to the tracked plugin record, updates that installed plugin, and records the new npm spec for future id-based updates.
Passing the npm package name without a version or tag also resolves back to the tracked plugin record. Use this when a plugin was pinned to an exact version and you want to move it back to the registry's default release line.
`openclaw update` resolves plugin targets from the newly installed core. npm updates on the beta channel select the newer of the package's `beta` and `latest` releases; ClawHub default-line updates try `@beta` and can fall back to the recorded default/latest selector when that release is unavailable. Integrity, compatibility, trust, install-policy, and capability-consent failures do not trigger source fallback. An unavailable plugin update leaves a notice without failing an otherwise successful core update. Explicit selectors retain their meaning, with the managed OpenClaw release-pin recovery described above.
When a stored integrity hash exists and the fetched artifact hash changes, OpenClaw treats that as npm artifact drift. The interactive `openclaw plugins update` command prints the expected and actual hashes and asks for confirmation before proceeding. Non-interactive update helpers fail closed unless the caller supplies an explicit continuation policy.
Reload
openclaw plugins reload <ids...>
openclaw plugins reload <ids...> --json
openclaw plugins reload <ids...> --wait
Reload discovered plugins after editing their TypeScript source, imported helpers,
or manifest, including plugins selected through plugins.load.paths. The command
requires a running Gateway and waits for the replacement to finish without
restarting it. Configured enablement is preserved, and unchanged
plugins keep their runtime instances. JSON output includes pluginIds,
restartRequired, and the applied runtime receipt with its generation
and source digests when available. The receipt's selectedEntries names the files
the loader selected. CLI and tool output remind you to rebuild compiled output
after editing its source; reload does not run the build. Multiple IDs use one Gateway reload request
and one applied runtime generation. Repeated IDs are collapsed, and the Gateway
resolves package siblings together. The request supports up to 64 distinct IDs.
Busy plugins admit replacement and fence new retained work on the old instance.
Existing agent runs keep their original callbacks while new runs wait for the
replacement. Before stopping services or channels, replacement waits up to
60 seconds for retained work and in-flight calls to finish. Detailed readiness
and Gateway logs show the queued work count and deadline; the command waits for
the final applied receipt. Successful publication emits plugins.changed and
logs the applied replacement. If work exceeds the budget, the reload fails once
and the previous generation resumes serving; unfinished runs are not forcibly
disposed. Retry openclaw plugins reload <id> after that work finishes, or use
openclaw plugins reload <id> --wait to wait without a deadline for admitted work.
--wait keeps new runs behind the same replacement gate. Press Ctrl+C to cancel
the wait; disconnecting its Gateway request also cancels it. Before publication,
cancellation restores the previous generation when recovery succeeds, without
cancelling admitted runs. Once publication commits, cancellation does not undo it.
Service shutdown, resource cleanup, and recovery keep their existing deadlines.
Detailed readiness exposes the pending reload; an explicit wait has no drain
deadline. Incoming messages retain their channel's existing queue and replay
contract; this option does not add durable ingress to channels that lack it.
Run this maintenance command outside a turn that itself holds the target plugin:
waiting for that turn while it waits for reload cannot make progress.
Replacement requires the previous registration's resource cleanup to finish before its successor acquires those resources. Failed cleanup can prevent replacement and automatic recovery; inspect the reported failure before retrying. The receipt can also include cleanup warnings. Modules and native libraries may remain loaded after their registrations are removed.
Bundled plugins can reload while preserving their enabled or disabled policy.
Compiled bundled plugins reuse their process-loaded code when their registrations
reload. If the plugin's files changed while its original module remains loaded,
the result reports restartRequired: true with a warning, and CLI and tool
output explain that a Gateway restart is needed to load edited code. Reload does
not rebuild compiled bundled code; source installations also need a build.
External captured sources return restartRequired: false after replacement.
Reloading unchanged bundled files also returns restartRequired: false; channel
and service registrations can be replaced without restarting the Gateway.
Reloading a discovered source does not create an
install record or grant permission to install, replace, or remove its files.
Reload also works with externally managed config (OPENCLAW_CONFIG_READONLY=1)
and in Nix mode (OPENCLAW_NIX_MODE=1), including config composed with $include.
It preserves config and installation state. If changed capabilities need new
consent, record that acceptance through the deployment owner before reloading.
Changed declared capabilities may require another review. Interactive text output
prompts for consent; --json never prompts. Use --accept-capabilities only after
reviewing the change, including when combining it with --json. If preparation
fails, the error reports whether a replacement was published. A failure after
publication can leave the new generation active; inspect the reported state before
retrying.