🧰 Tooling Guide

OpenClaw Plugins Guide: Install, Allowlist, Pin, and Audit What Loaded

•7 min read

A plugin runs inside your gateway process, with the same environment variables your provider keys live in. The official docs put it in six words: "Treat plugin installs like running code."

Most of the guides that rank for this cover the install command and its source prefixes, then plugins list, then a troubleshooting section for the plugin that installed but never loaded. That material is fine and I repeat the useful parts below. What none of them do is tell you what your gateway is loading right now, which is a different question from what you remember installing. Plugins get discovered from folders as well as installed on purpose. The section on auditing is the reason this page exists.

Installing From Each Source

One command, several sources, picked by prefix:

openclaw plugins install clawhub:<package>
openclaw plugins install npm:<package>
openclaw plugins install git:github.com/<owner>/<repo>@<ref>
openclaw plugins install npm-pack:./my-plugin-0.3.1.tgz
openclaw plugins install ./my-plugin
openclaw plugins install -l ~/Projects/my-plugin

A bare spec with no prefix resolves in a fixed order: a bundled plugin with that id first, then the official external catalog, then the npm registry as the fallback. That order is convenient when you type @openclaw/something and get the bundled copy. It is less convenient when a package name you meant for npm happens to match something else. I always type the prefix. Four characters for npm:, and you never wonder.

The -l (--link) form points the gateway at a working directory instead of copying files, which is what you want while developing your own plugin. One catch the docs mention almost in passing: local paths and linked installs do not get hook-agent trust. If your plugin dispatches agent turns from a hook, it will work from npm or ClawHub and refuse from your laptop folder. The hooks guide covers what those hooks do.

Then enable it, if install did not already, and restart:

openclaw plugins enable <plugin-id>
openclaw gateway restart
openclaw plugins list --enabled --verbose

The restart is not optional. Installing, updating or uninstalling plugin code requires a gateway restart. Ordinary edits under plugins.entries.<id>.config apply on their own in the default hybrid reload mode, and openclaw plugins reload <id> handles source or manifest edits for a plugin you are working on.

Write plugins.allow Before You Need It

Here is the config block I put on every gateway, including ones with a single plugin:

{
  plugins: {
    allow: ["memory-core", "nylas"],
    deny: [],
    entries: {
      nylas: { enabled: true, config: {} }
    }
  }
}

allow is an exclusive list. Once it exists, a plugin whose id is not on it does not load. deny beats allow and beats per-plugin enabled: true. The part people miss is how this interacts with the per-agent tool lists from the tool allow and deny guide: plugin-owned tools outside plugins.allow stay unavailable even when an agent's tools.allow includes "*". A wildcard on an agent cannot resurrect a plugin you blocked.

You do not have to maintain the list by hand for normal installs. openclaw plugins install adds the new id to an existing plugins.allow and removes it from plugins.deny, on the theory that an explicit install is an explicit decision. That theory is right. It only works if the list already exists, though, and with no list at all the gateway takes whatever it discovers.

Audit What Actually Loaded

With plugins.allow unset, OpenClaw auto-discovers non-bundled plugins from the workspace and global plugin roots and from any directory in plugins.load.paths. It does tell you. Every startup logs this line:

plugins.allow is empty; discovered non-bundled plugins may auto-load: ...

That warning is the cheapest audit you will ever get, and it scrolls past in the first two seconds of every restart, buried under channel connects, so nobody reads it. Grep for it. If the ids after the colon include anything you cannot name the purpose of, you have found your first job for the afternoon. A folder you cloned into ~/Projects/plugins to read the source, eight months ago, and then added to load.paths to try once, is exactly the kind of thing that turns up.

The second check asks each plugin what it registered, as opposed to what its manifest claims:

openclaw plugins inspect --all --runtime --json > plugins-runtime.json
openclaw plugins doctor

inspect without --runtime reads openclaw.plugin.json. With it, you get the capabilities the plugin loaded into the running gateway, mostly tools and hooks. Diff that JSON file week over week. A plugin that suddenly ships a new hook after an update is worth a minute of reading. Hooks deserve the attention because some of them can see conversations, and that access is gated per plugin by plugins.entries.<id>.hooks.allowConversationAccess. If a plugin has that flag set to true, you should know why.

OpenClaw does some of this for you at discovery. It blocks a candidate whose entry resolves outside its plugin root through a symlink, whose root or source path is world-writable, or whose ownership looks wrong for a non-bundled plugin. A chmod 777 on your extensions folder will quietly stop plugins from loading, which is a strange way to find out about a chmod.

Pin Versions, and Never Update Everything From Cron

An unpinned npm spec, or one ending in @latest, installs the newest stable version that advertises compatibility with your OpenClaw build. Exact versions stay pinned no matter what. So npm:some-plugin and npm:some-plugin@1.4.2 look nearly identical in your shell history and behave completely differently the next time anyone runs an update. Use --pin at install time.

My opinion, and I hold it firmly: openclaw plugins update --all belongs in your hands, not in a scheduled job. A plugin update is new in-process code, and the cron automation guide is full of jobs that are safe to run unattended. This is not one. Run it with --dry-run first, read the version changes, update the plugins you chose by id, restart, then rerun the runtime inspect and diff it against last week. Fold it into the routine from the upgrade guide, since a core upgrade changes which plugin versions count as compatible anyway.

If you want a gate that does not depend on remembering, security.installPolicy runs a local command of your choosing before any plugin install or update proceeds. It receives the plugin metadata and the staged source path. Non-interactive installs then need --acknowledge-install-policy-warning, which is a nice speed bump for scripts.

Slots Are Exclusive

plugins.slots.memory and plugins.slots.contextEngine each pick exactly one plugin. Installing a second memory plugin does not stack it on the first.

Removing a Plugin Cleanly

openclaw plugins uninstall <plugin-id> --dry-run
openclaw plugins uninstall <plugin-id>
openclaw gateway restart
openclaw doctor --fix

--keep-files leaves the code on disk if you might come back to it. The doctor step matters because stale ids in config can linger after removal; they stay inert, and doctor --fix cleans up stale plugin ids and allowlist mismatches by disabling the bad entries. The gateway doctor guide walks through reading its output. And if the plugin took an API key, rotate it. The secrets guide explains why a removed consumer does not make a key safe.

Common Failure Modes

Installed, listed, but its tools never appear

No restart since install, or the id is missing from plugins.allow because the list was edited by hand afterwards. Check plugins.deny too, since deny wins.

Hook works from npm, fails from a local folder

Linked and local installs carry no hook-agent trust. Reinstall from npm or ClawHub.

A plugin vanished after a permissions change

Discovery blocks world-writable plugin roots. Undo the chmod.

Behavior changed and nobody touched the config

An unpinned plugin moved to a newer compatible version during an update. Diff the runtime inspect output and pin.

Final Verdict

Write plugins.allow today, even with one entry, so discovery stops being a way in. Type the source prefix. Pin with --pin. Keep a weekly copy of plugins inspect --all --runtime --json and read the diff after every update, because the manifest is what a plugin promises and the runtime output is what it did.

⚡

Ready to build?

Get the OpenClaw Starter Kit — config templates, 5 production-ready skills, deployment checklist. Go from zero to running in under an hour.

$14 $6.99

Get the Starter Kit →

Also in the OpenClaw store

🗂️
Executive Assistant Config
Buy
Calendar, email, daily briefings on autopilot.
$6.99
🔍
Business Research Pack
Buy
Competitor tracking and market intelligence.
$5.99
⚡
Content Factory Workflow
Buy
Turn 1 post into 30 pieces of content.
$6.99
📬
Sales Outreach Skills
Buy
Automated lead research and personalized outreach.
$5.99

Get the free OpenClaw quickstart guide

Step-by-step setup. Plain English. No jargon.