npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openclaw-plugin-onepassword

v0.1.1

Published

Native OpenClaw plugin that resolves 1Password secrets in-process (no exec sandbox), plus agent tools for vault/item CRUD.

Readme

openclaw-plugin-onepassword

CI npm license

A native OpenClaw plugin that resolves 1Password secrets in-process inside the Gateway — no op CLI, no child process, no exec sandbox — and writes them into OpenClaw's shared secret store. It also exposes optional 1Password vault/item agent tools.

Why this exists. OpenClaw v2026.8.1 introduced a security sandbox for exec secret providers that blocks filesystem writes and network access during provider execution. That breaks the common pattern of using op read as an exec provider (you'll see errors like sh: cannot open /tmp/op_out.txt and blocked network calls). This plugin runs inside the Gateway process, where the sandbox does not apply, and uses the official @1password/sdk over HTTPS.


Contents


How it works

This plugin can feed secrets to OpenClaw three ways. The in-process modes (store sync and file sync) run inside the Gateway and reliably bypass the exec sandbox; pick based on what the consuming channel/provider accepts.

| Mode | Runs where | Bypasses exec sandbox? | SecretRef you write | Vault/item paths live in | | ---------------------------- | ---------------------- | -------------------------------- | -------------------------------------- | ------------------------------ | | Store sync (default) | In-process (Gateway) | ✅ Yes | source: "store" | plugin config.secrets map | | File sync | In-process (Gateway) | ✅ Yes | source: "file" | plugin config.syncToFile map | | Exec resolver (advanced) | Sandboxed child node | ⚠️ Only with egress allowlisting | source: "exec" + pluginIntegration | the SecretRef.id (op://…) |

Which in-process mode? Prefer store sync (source: "store"). But some bundled channel plugins — notably Slack — reject source: "store" at config-validation time and accept only env, file, or exec. For those, use file sync (source: "file"). The two are independent and can run together (e.g. store sync for OpenAI, file sync for Slack).

Store sync, in one picture:

Gateway start / onepassword.sync
        │
        ▼
 read OP_SERVICE_ACCOUNT_TOKEN (env)
        │
        ▼
 @1password/sdk  ──HTTPS──▶  1Password API
        │
        ▼
 secrets.store.set { name, value }   (in-process Gateway RPC)
        │
        ▼
 OpenClaw shared store  ◀── resolved by SecretRefs with source:"store"

The plugin never writes secrets to openclaw.json, environment variables, or disk of its own. Values live only in OpenClaw's store (SQLite, 0600/0700 permissions, team scope).

Requirements

  • OpenClaw >= 2026.8.0 (Gateway runs on Node >= 22.22.3).
  • A 1Password service account token — see 1Password service accounts. The service account must have access to the vaults/items you reference.

Install

From npm (recommended):

openclaw plugins install openclaw-plugin-onepassword

Or from a local checkout:

openclaw plugins install ./openclaw-plugin-onepassword

Then provide the service account token to the Gateway process via the environment variable (default OP_SERVICE_ACCOUNT_TOKEN). Keep it out of openclaw.json, docker-compose files, and shell history — use your process manager's secret mechanism (systemd LoadCredential, Docker/Kubernetes secrets, etc.).

export OP_SERVICE_ACCOUNT_TOKEN="ops_..."

Quick start (store sync — recommended)

  1. Enable the plugin and map store keys to 1Password references in openclaw.json:
{
  "plugins": {
    "entries": {
      "onepassword": {
        "enabled": true,
        "config": {
          "serviceAccountTokenEnvVar": "OP_SERVICE_ACCOUNT_TOKEN",
          "secrets": {
            "SLACK_BOT_TOKEN": "op://MyVault/SlackBot/bot_token",
            "SLACK_APP_TOKEN": "op://MyVault/SlackBot/app_token",
            "OPENAI_API_KEY": "op://MyVault/OpenAI/credential"
          }
        }
      }
    }
  }
}

Store keys must match ^[A-Z][A-Z0-9_]{0,127}$ (OpenClaw store-id grammar). Values are standard 1Password secret references: op://Vault/Item[/Section]/Field.

  1. Reference those store keys anywhere OpenClaw accepts a SecretRef, using source: "store":
{
  "channels": {
    "slack": {
      "accounts": {
        "myworkspace": {
          "botToken": { "source": "store", "id": "SLACK_BOT_TOKEN" },
          "appToken": { "source": "store", "id": "SLACK_APP_TOKEN" }
        }
      }
    }
  },
  "agents": {
    "defaults": {
      "model": {
        "providers": {
          "openai": {
            "apiKey": { "source": "store", "id": "OPENAI_API_KEY" }
          }
        }
      }
    }
  }
}
  1. Start the Gateway. On startup the plugin fetches each reference from 1Password and writes it into the store; the referencing channels/providers then initialize with resolved credentials. Because store values persist, subsequent restarts are covered even before the first sync completes.

See examples/ for complete config files.

File sync mode (for channels that reject source: "store")

Some bundled channel plugins — Slack in particular — reject source: "store" SecretRefs at config-validation time and accept only env, file, or exec. Because this plugin runs in-process, it can resolve op:// references and write them to a JSON file that OpenClaw's built-in source: "file" provider reads — which those channels accept.

  1. Configure syncToFile in the plugin config (independent of secrets; both can be active):
{
  "plugins": {
    "entries": {
      "onepassword": {
        "enabled": true,
        "config": {
          "serviceAccountTokenEnvVar": "OP_SERVICE_ACCOUNT_TOKEN",
          "syncToFile": {
            "path": "/home/node/.openclaw/op-secrets.json",
            "mode": "json",
            "secrets": {
              "SLACK_BOT_TOKEN_A": "op://MyVault/SlackBot/bot_token",
              "SLACK_APP_TOKEN_A": "op://MyVault/SlackBot/app_token"
            }
          }
        }
      }
    }
  }
}
  1. Declare a file provider and reference the keys with source: "file" (the id is a JSON pointer, /KEY):
{
  "secrets": {
    "providers": {
      "op-file": {
        "source": "file",
        "path": "/home/node/.openclaw/op-secrets.json",
        "mode": "json"
      }
    }
  },
  "channels": {
    "slack": {
      "accounts": {
        "myworkspace": {
          "botToken": { "source": "file", "provider": "op-file", "id": "/SLACK_BOT_TOKEN_A" },
          "appToken": { "source": "file", "provider": "op-file", "id": "/SLACK_APP_TOKEN_A" }
        }
      }
    }
  }
}

The file is written atomically (temp file + rename) with 0600 permissions. Keys that fail to resolve keep their last-known-good value from the existing file, so a transient 1Password failure doesn't break a running channel. See examples/openclaw.file-mode.json.

⚠️ The sync file contains plaintext secret values. It lives in the OpenClaw data volume (same trust boundary as the SQLite store). Keep its path inside that volume and outside any path an agent can read — otherwise an agent with file tools could exfiltrate it. Add the file (or its directory) to your agent file-access denylist (e.g. tools.exec.denyPaths or the equivalent for your sandbox).

Configuration reference

All keys live under plugins.entries.onepassword.config.

| Key | Type | Default | Description | | --------------------------- | ------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | serviceAccountTokenEnvVar | string | "OP_SERVICE_ACCOUNT_TOKEN" | Name of the environment variable holding the service account token. | | secrets | object | {} | Map of store key → op://… reference (store sync). Keys must match ^[A-Z][A-Z0-9_]{0,127}$. | | syncToFile | object | – | File sync block: { path, mode: "json", secrets }. See File sync mode. | | syncOnStartup | boolean | true | Fetch configured secrets from 1Password and sync them (store + file) at Gateway startup. | | failFastOnStartup | boolean | false | If true, a startup sync failure (resolve, store write, or file write) throws and prevents startup. If false, log and fall back to last-known-good values. | | integrationName | string | "openclaw-plugin-onepassword" | Integration name reported to 1Password audit logs. | | requestTimeoutMs | number | 15000 | Per-operation timeout for 1Password SDK calls. | | tools.enabled | boolean | false | Register the read-only 1Password agent tools. | | tools.allowWrite | boolean | false | Also register create/update/delete tools. Requires tools.enabled. |

The plugin hardcodes no vault names, item paths, or field names. The only 1Password-specific configuration is the env var name and the secrets / syncToFile.secrets maps you provide.

Agent tools (optional)

Set tools.enabled: true to expose in-process tools to the agent. Read tools redact concealed field values by default.

| Tool | Requires allowWrite | Description | | ----------------------- | --------------------- | -------------------------------------------------------------------------- | | 1password_list_vaults | | List vaults accessible to the service account. | | 1password_list_items | | List item overviews in a vault. | | 1password_get_item | | Get a full item (concealed fields redacted unless includeSecrets: true). | | 1password_read_field | | Resolve a single op://… reference to its value. | | 1password_create_item | ✅ | Create a new item. | | 1password_update_item | ✅ | Update an existing item. | | 1password_delete_item | ✅ | Delete an item. |

{
  "plugins": {
    "entries": {
      "onepassword": {
        "enabled": true,
        "config": { "tools": { "enabled": true, "allowWrite": false } }
      }
    }
  }
}

Gateway methods

Both require the operator.admin scope.

  • onepassword.sync — re-fetch every configured secret from 1Password and write it to the store and/or the sync file. Returns { written, fileWritten, total, resolveErrors, storeErrors, fileErrors }.
  • onepassword.status — non-secret health/config summary: { version, serviceAccountTokenEnvVar, tokenPresent, syncOnStartup, managedStoreKeys, syncToFileEnabled, managedFileKeys, filePath, toolsEnabled, toolsWriteEnabled }.

Refreshing secrets at runtime

  • Rotate a value in 1Password, then call onepassword.sync (or restart the Gateway). The plugin re-fetches and writes fresh values; secrets.store.set triggers a live runtime refresh so dependent channels/providers pick up the new value without a full restart.
  • openclaw secrets reload re-reads the store; run onepassword.sync first if you need the store repopulated from 1Password.

Prefer native openclaw secrets reload to re-fetch directly from 1Password? Use the exec resolver mode, which OpenClaw re-invokes on reload — at the cost of requiring egress allowlisting.

Exec resolver mode (advanced)

The plugin also declares a secretProviderIntegrations entry so it can act as a plugin-managed exec secret provider using standard op:// ids:

{
  "secrets": {
    "providers": {
      "op": {
        "source": "exec",
        "pluginIntegration": { "pluginId": "onepassword", "integrationId": "op" }
      }
    }
  },
  "channels": {
    "slack": {
      "accounts": {
        "myworkspace": {
          "botToken": {
            "source": "exec",
            "provider": "op",
            "id": "op://MyVault/SlackBot/bot_token"
          }
        }
      }
    }
  }
}

Caveat: this runs OpenClaw's resolver as a sandboxed child node process (command: "${node}"). Under the v2026.8.1 sandbox its network is blocked, so it can only reach the 1Password API if you allowlist egress for secret resolution:

{
  "secrets": {
    "egressProxy": {
      "enabled": true,
      "allowedHosts": ["my.1password.com", "my.1password.eu", "my.1password.ca"]
    }
  }
}

Use the host that matches your 1Password account region. If your environment cannot allow this egress, use the store sync mode instead. The exec resolver reads the token from OP_SERVICE_ACCOUNT_TOKEN (override the env var name with OP_RESOLVER_TOKEN_ENV_VAR).

Security notes

  • The token is the crown jewel. Anyone with the service account token has the service account's access. Scope the service account to the minimum vaults required, and inject the token via your platform's secret mechanism — never commit it.
  • No plaintext secrets in config. The plugin only reads an env var name and op:// references; resolved values live only in OpenClaw's store (store sync) or the sync file (file sync).
  • The file sync output is plaintext. If you use syncToFile, keep its path inside the OpenClaw data volume and out of any agent-readable path; add it to your agent file-access denylist. See File sync mode.
  • Plugin code runs in your Gateway process with full Gateway privileges (this is true of every OpenClaw plugin). Review the source before installing.
  • Write tools are opt-in (tools.allowWrite) and concealed fields are redacted by read tools unless includeSecrets: true.
  • Report vulnerabilities per SECURITY.md.

Troubleshooting

| Symptom | Likely cause / fix | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | ... token not found at startup | The env var named by serviceAccountTokenEnvVar is unset on the Gateway process. | | SECRETS_PROVIDER_DEGRADED for a store ref | The store key hasn't been populated yet — run onepassword.sync, or check the startup logs for resolve errors. | | source: must be equal to constant (allowed: "env"/"file"/"exec") on a channel | That channel (e.g. Slack) rejects source: "store". Use File sync mode with source: "file". | | source: "file" ref resolves empty | The sync file wasn't written yet, or the id JSON pointer is wrong (must be /KEY). Check onepassword.statusfilePath and startup logs. | | Resolve error NOT_FOUND | The op:// reference is wrong or the service account can't access that vault/item/field. | | Exec resolver returns nothing | Sandbox is blocking network — add your 1Password host to secrets.egressProxy.allowedHosts, or switch to store sync. |

Development

npm install --ignore-scripts   # openclaw's preinstall gate is skipped here
npm run build                  # tsc -> dist/
npm run typecheck
npm run lint
npm test

--ignore-scripts is used because the openclaw dev dependency runs a Node-version preinstall check; the plugin itself only needs its type definitions to build and test.

Releasing

Releases are automated on push to main. The Release workflow publishes to npm (with provenance) and creates a GitHub release only when the version in package.json is not yet on npm — ordinary commits are a no-op.

To cut a release:

npm run release:prepare -- <x.y.z>   # bumps the 3 version files + rolls CHANGELOG
# edit CHANGELOG.md for the new section, then:
npm run verify
git commit -am "chore(release): v<x.y.z>" && git push origin main

The workflow publishes the package and tags v<x.y.z>. It requires an NPM_TOKEN repository secret (an npm automation token). See CONTRIBUTING.md → Releasing and AGENTS.md for details and the semver policy.

License

MIT