OpenClaw
OpenClaw is a local-first agent gateway — it runs on your own machine or server, connects a model to real tools, and holds the credentials for every provider and channel it talks to. Those credentials are what this integration is about.
openclaw plugins install npm:@seekrit/openclaw-plugin
openclaw plugins enable seekrit
seekrit openclaw init --write
After that, a credential in your gateway config is a reference rather than a value:
// before — a key at rest in openclaw.json, readable by anything that can read the file
{ models: { providers: { openai: { apiKey: "sk-proj-…" } } } }
// after — a name OpenClaw resolves at startup, from your seekrit environment
{ models: { providers: { openai: { apiKey: { source: "exec", provider: "seekrit", id: "OPENAI_API_KEY" } } } } }
How it works
OpenClaw supports four SecretRef sources — env, file, store, and exec.
exec runs a command, hands it the ids it needs on stdin, and reads the values
back on stdout. seekrit plugs in there, which means the decryption happens on
your side of the line: the resolver runs as a short-lived child process, uses
your service token, and exits when the batch is answered. The gateway never holds
a data key, and seekrit's API never sees a plaintext.
Which ids to use
Two shapes, mirroring 1Password's op://vault/item/field:
| id | Resolves against |
|---|---|
OPENAI_API_KEY | the environment your credential already points at |
billing-api/production/STRIPE_SECRET_KEY | that application and environment |
A bare name is the common case, and the only one a service token needs — a token is already bound to one environment, so there is nothing to disambiguate.
seekrit openclaw ref prints either shape, ready to paste:
seekrit openclaw ref OPENAI_API_KEY
seekrit openclaw ref STRIPE_SECRET_KEY --app billing-api --env production
The credential the resolver uses
An exec provider runs with only the environment its config allowlists, which is a feature — the resolver gets the credential it needs and not the rest of the gateway's environment. Any of these work:
| Credential | Set | Good for |
|---|---|---|
| Service token | SEEKRIT_TOKEN=skt_… | a gateway; scoped to one environment |
| Machine credentials | SEEKRIT_CLIENT_ID + SEEKRIT_CLIENT_SECRET | CI and containers; the CLI mints and caches a token |
| A login session | seekrit login | a workstation gateway you sit in front of |
Scope the token to exactly the environment the gateway needs — see service tokens. It is the ceiling on everything this integration can reach.
Without the plugin
The plugin is the better shape, because OpenClaw re-reads the resolver's location
from its manifest at every startup — so a plugin upgrade that moves a file keeps
working, where a path copied into your config is pinned forever. But it is not
required. --exec generates a provider that points straight at the CLI:
seekrit openclaw init --exec
The generated command is an absolute path to the Node binary, not seekrit.
OpenClaw refuses a symlinked command, and the seekrit on your PATH is a
package-manager shim that symlinks into node_modules — so pointing at it
produces a gateway that fails to start. seekrit openclaw init resolves the
real paths for you.
Skills and MCP tools
Separately from secrets, OpenClaw reads the Agent Plugins bundle format, which is what seekrit's agent plugin already ships. So the skills and both MCP servers install with no seekrit-specific wiring at all:
openclaw plugins install git:github.com/seekritdev/agent-plugin
That gives the agent the three seekrit skills — so it knows when to reach for a secret — plus the local crypto-plane server and the hosted metadata-plane server. See AI agents for what each server does.
Two things that will surprise you
Resolution is eager. OpenClaw reads every active ref once, at startup and at config reload, into one in-memory snapshot. It does not re-resolve per request. So after you rotate a secret:
openclaw secrets reload
Without that, the gateway keeps serving the old value until it restarts. If you rotate on a schedule, put the reload in the same automation — see rotation.
A linked plugin is inert. OpenClaw only honours a plugin's secret-provider
integration when the plugin's origin is bundled or global. A development copy
installed with --link shows up in openclaw plugins list and resolves nothing.
Install from npm.
Check your work
openclaw secrets audit --check --allow-exec
That reports unresolved refs and any plaintext left behind. Migrating a
credential to a SecretRef does not remove the copy already sitting in
openclaw.json, models.json, or the gateway's SQLite store — the audit is how
you find them.
What this does and does not protect
A SecretRef keeps plaintext out of your config files. It does not stop the agent from reading a value once resolved: OpenClaw is explicit that its own egress sentinels are not a process boundary, and the same is true here. The resolved key lives in the gateway's memory, and the gateway is what the model drives.
If the requirement is that the agent must never hold the key, that is a different mechanism:
| Requirement | Use |
|---|---|
| No plaintext in config or on disk | this page |
| The workload never holds the key at all | egress proxy — the agent gets a {{seekrit:NAME}} placeholder |
| Bound to specific hosts, paths, and methods | agent access policy |
The two compose: resolve the proxy's own credential through a SecretRef, and give the gateway placeholders for everything downstream.
Troubleshooting
| Symptom | Cause |
|---|---|
| Startup fails on an unresolved ref | The resolver could not authenticate. Check SEEKRIT_TOKEN is in the provider's passEnv and in the gateway's own environment. |
openclaw plugins list shows seekrit but refs fail | The plugin is installed but not enabled (openclaw plugins enable seekrit), or it was installed with --link. |
| A rotated secret still serves the old value | Eager resolution — run openclaw secrets reload. |
NOT_FOUND for an id | No secret by that name in the target environment. seekrit secrets list to check the spelling. |
| The provider seems to exist but is never called | command in the manifest must be exactly ${node}; OpenClaw silently declines any other value. |
Reference
seekrit openclaw init— generate the provider blockseekrit openclaw ref— print a SecretRefseekrit openclaw resolve— the exec protocol handler OpenClaw calls