@carbonvoice/openclaw-extension
OpenClaw channel plugin for Carbon Voice: PAT websocket plus optional webhooks, with POST /v3/messages/recent catch-up after disconnects; text replies (voice/TTS stays on the Carbon Voice side).
npm package name (install spec): @carbonvoice/openclaw-extension. Plugin id in OpenClaw remains carbonvoice (openclaw.plugin.json / openclaw.channel.id).
Docs: https://docs.openclaw.ai/channels/carbonvoice
Plugin system: https://docs.openclaw.ai/plugin
Bundled vs installable
Carbon Voice ships bundled with the main openclaw npm package. Enable it with:
openclaw plugins enable carbonvoice
To try a different copy from disk (for example a patched checkout), install from a path or tarball; that copy shadows the bundled plugin when it uses the same id. See https://docs.openclaw.ai/plugin (discovery and precedence).
Install (local path)
From the OpenClaw repo root:
openclaw plugins install ./extensions/carbonvoice
Restart the Gateway after install.
Dev link (no copy)
openclaw plugins install --link ./extensions/carbonvoice
Tarball (npm / ClawHub)
Published plugins must ship compiled dist/*.js files. Plain npm pack inside extensions/carbonvoice only packs TypeScript sources and openclaw plugins install will reject the tarball.
From the OpenClaw repository root (after pnpm install):
node scripts/lib/plugin-npm-runtime-build.mjs extensions/carbonvoice
# --pack-destination must already exist (npm does not mkdir for you)
mkdir -p ./dist-pack
node scripts/lib/plugin-npm-package-manifest.mjs --run extensions/carbonvoice -- npm pack --pack-destination ./dist-pack
Example using /tmp only:
node scripts/lib/plugin-npm-package-manifest.mjs --run extensions/carbonvoice -- npm pack --pack-destination /tmp
That writes carbonvoice-openclaw-extension-<version>.tgz (npm’s filename for scoped packages) with dist/, openclaw.runtimeExtensions, and openclaw.runtimeSetupEntry set for the installer.
On the target host:
openclaw plugins install ./carbonvoice-openclaw-extension-<version>.tgz
# or
openclaw plugins install npm-pack:/tmp/carbonvoice-openclaw-extension-<version>.tgz
Publish to npm (@carbonvoice org)
This package is scoped to @carbonvoice on npm (publishConfig.access: "public"). It is not part of OpenClaw’s automated @openclaw/* plugin npm matrix (openclaw.release.publishToNpm is false here so repo release scripts keep enforcing the @openclaw publisher contract).
One-time npm setup
- Create the
carbonvoiceorganization on npmjs.com (if it does not exist) and invite maintainers. - Create a granular Automation or Publish token with permission to publish that org’s packages (or use
npm loginwith a user who is an org member).
Publish from the OpenClaw repo root (after pnpm install):
export NODE_AUTH_TOKEN="npm_..." # token with publish rights to @carbonvoice
# Local / non-GitHub-OIDC publishes cannot use npm provenance; disable for this shell:
export OPENCLAW_NPM_PUBLISH_PROVENANCE=0
bash scripts/plugin-npm-publish.sh --pack-dry-run extensions/carbonvoice
bash scripts/plugin-npm-publish.sh --publish extensions/carbonvoice
If you publish with trusted publishing (no NODE_AUTH_TOKEN / NPM_TOKEN) and the script refuses because beta dist-tag mirroring needs a token, either export a token as above or set OPENCLAW_NPM_SKIP_DIST_TAG_MIRROR=1 (the extensions/carbonvoice/publish.sh wrapper sets this by default).
The script runs the runtime build, applies the same package.json overlay as npm pack, then npm publish --access public. First publish of a scoped public package must stay public (already set in publishConfig).
Install for users (after publish):
openclaw plugins install npm:@carbonvoice/openclaw-extension
openclaw plugins install npm:@carbonvoice/openclaw-extension@2026.3.14
Publish to ClawHub
ClawHub is optional; use the ClawHub CLI (clawhub package publish …) with an owner whose scope matches @carbonvoice, or publish the tarball produced by clawhub package pack after the same dist/ build as above. See Publishing on ClawHub.
Install spec (after a ClawHub release exists):
openclaw plugins install clawhub:@carbonvoice/openclaw-extension
Peer dependency: openclaw must satisfy peerDependencies.openclaw in this package’s package.json.
Dependencies
The plugin install runs npm install --omit=dev in the extension directory. Ensure socket.io-client resolves (declared in dependencies).
Config
Channel config lives under channels.carbonvoice (multi-account under accounts.<accountId>).
Credential: set the AGENT_PAT environment variable to your Carbon Voice agent personal access token (cv_pat_...) for the default account, or set apiKey on the account in config (same value). On startup, OpenClaw calls GET /whoami, opens the realtime websocket, and runs recents catch-up on connect. If you set publicWebhookBaseUrl, it also subscribes webhooks and registers the HTTP route. Inbound filters exclude the PAT user’s own messages; optional creatorId limits inbound to that user only.
Typical fields per account:
creatorId(optional) — Carbon Voice user id; when set, only messages from this user are delivered (in addition to excluding the PAT user).baseUrl— API base (defaulthttps://api.carbonvoice.app).publicWebhookBaseUrl(optional) — public origin of your OpenClaw gateway for Carbon Voice webhooks. Omit for PAT-only websocket mode.webhookPath— path on the gateway when using webhooks (default/openclaw/carbonvoice/webhookwhenpublicWebhookBaseUrlis set).
Example (PAT-only via env):
export AGENT_PAT="cv_pat_..."
{
channels: {
carbonvoice: {
accounts: {
default: {
enabled: true,
// optional: "publicWebhookBaseUrl": "https://gateway.example.com",
// optional: "creatorId": "YOUR_USER_GUID",
},
},
},
},
}
Use openclaw onboard or channel setup for interactive configuration where available.