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

@tuyenhx/openzalo

v2026.5.5

Published

OpenClaw OpenZalo channel plugin (personal account via openzca CLI)

Readme

@tuyenhx/openzalo

OpenClaw channel plugin for Zalo personal accounts via openzca CLI.

Warning: this is an unofficial personal-account automation integration. Use at your own risk.

AI Install Metadata

  • Plugin id: openzalo
  • Channel id: openzalo
  • Package name: @tuyenhx/openzalo
  • Required external binary: openzca
  • Optional external binary for /acp support: acpx

Bundled Skills

This plugin now bundles one optional skill (auto-discovered from ./skills):

  • openzca: advanced openzca CLI workflows, with DB-backed reads for summaries, history, and search.

Owner/Admin Usage Guidance for openzca Skill

openzca is installed at workspace/plugin level, not per-sender.
So "owner-only" should be enforced by runtime policy, not by skill installation.

Recommended setup:

  1. Keep general agents on tools.profile: "messaging" (no exec).
  2. Grant exec only to a dedicated admin agent.
  3. In OpenZalo group config, use allowFrom + skills filter to expose advanced skills only in admin-controlled groups.
  4. Use normal OpenZalo message actions for routine operations; use the bundled openzca skill when you want the full playbook or raw CLI workflows.

Prerequisites

  • OpenClaw Gateway is installed and running.
  • openzca is installed and available in PATH (or configure channels.openzalo.zcaBinary).
  • For local voice files that must play reliably on mobile clients, configure OPENZCA_VOICE_PUBLISH_CMD on the gateway host and make sure ffmpeg is installed there too.
  • If you want OpenZalo ACP-local sessions via /acp, install acpx too.
  • You can authenticate with your Zalo account on the gateway machine.

Example direct login with openzca:

openzca --profile default auth login

Example acpx install for /acp support:

npm i -g acpx

Verify:

which acpx
acpx --help

Install (npm)

Use this after @tuyenhx/openzalo is published:

openclaw plugins install @tuyenhx/openzalo

To force ClawHub as the source once the package is listed there:

openclaw plugins install clawhub:@tuyenhx/openzalo

Install (local checkout)

From the OpenClaw repo root:

openclaw plugins install ./extensions/openzalo

Or from this plugin directory:

openclaw plugins install .

Restart Gateway after installation.

Publishing Notes

  • OpenClaw plugin installs can resolve from ClawHub or npm.
  • Newer clawhub CLI builds can publish native plugin packages with clawhub package publish.
  • To distribute this plugin, publish the package itself; users can then install it with openclaw plugins install @tuyenhx/openzalo or openclaw plugins install clawhub:@tuyenhx/openzalo when available there.
  • The bundled skills/openzca skill can be published separately with the clawhub CLI if you want it discoverable as a standalone skill too.

Quick Start

  1. Login account for this channel:
openclaw channels login --channel openzalo
# optional multi-account
openclaw channels login --channel openzalo --account work
  1. Add channel config:
{
  channels: {
    openzalo: {
      enabled: true,
      profile: "default",
      dmPolicy: "pairing",
      groupPolicy: "allowlist",
      groupAllowFrom: ["<GROUP_ID>"],
    },
  },
}

Or via CLI:

openclaw channels add --channel openzalo --account default
  1. Send test message:
openclaw message send --channel openzalo --target <userId> --message "Hello from OpenClaw"
openclaw message send --channel openzalo --target group:<groupId> --message "Hello group"
openclaw message send --channel openzalo --target group:<groupId> --message "Hi @Alice Nguyen and @123456789"

For group sends, plain @Name and @userId are forwarded to openzca and become native Zalo mentions. For native mentions, do not guess. Only tag when you already have an exact unique member id or name from context or from the user.

ACPX (/acp) Support

This plugin can bind the current OpenZalo conversation to a local ACPX session without changing OpenClaw core.

Install acpx first:

npm i -g acpx

If the gateway service cannot see your shell PATH, set channels.openzalo.acpx.command to the absolute path from which acpx.

Example config:

{
  channels: {
    openzalo: {
      acpx: {
        enabled: true,
        command: "/full/path/to/acpx", // or "acpx" if PATH is correct
        agent: "claude", // e.g. claude | codex
        cwd: "/Users/<you>/.openclaw/workspace",
        permissionMode: "approve-all", // approve-all | approve-reads | deny-all
        nonInteractivePermissions: "fail", // fail | deny
      },
    },
  },
}

Notes:

  • agent is the ACPX agent id. For Claude Code, use claude. For Codex, use codex.
  • cwd is the working directory ACPX will use for that conversation.
  • command should be an absolute path if /acp on reports acpx command not found.

Supported OpenZalo ACP commands:

/acp status
/acp on
/acp on claude cwd=/Users/<you>/.openclaw/workspace
/acp reset
/acp off

Behavior:

  • /acp on binds the current conversation to a persistent ACPX session.
  • /acp status shows whether the conversation is bound and reports session status.
  • /acp reset recreates the ACPX session for the current conversation.
  • /acp off unbinds the conversation and closes the ACPX session.

Configuration

{
  channels: {
    openzalo: {
      enabled: true,
      profile: "default", // default: account id
      zcaBinary: "openzca", // or full path
      acpx: {
        enabled: true,
        command: "/full/path/to/acpx", // or "acpx" if PATH is correct
        agent: "claude", // e.g. claude | codex
        cwd: "/Users/<you>/.openclaw/workspace",
        permissionMode: "approve-all", // approve-all | approve-reads | deny-all
        nonInteractivePermissions: "fail", // fail | deny
      },

      // DM access: pairing | allowlist | open | disabled
      dmPolicy: "pairing",
      allowFrom: ["<OWNER_USER_ID>"],

      // Group access: allowlist | open | disabled
      groupPolicy: "allowlist",
      groupAllowFrom: ["<GROUP_ID>"],

      // Optional per-group overrides
      groups: {
        "<GROUP_ID>": {
          enabled: true,
          requireMention: true, // default true
          allowFrom: ["<ALLOWED_SENDER_ID>"],
          tools: {
            allow: ["group:messaging"],
            deny: ["group:fs", "group:runtime"],
          },
          toolsBySender: {
            "<OWNER_USER_ID>": { allow: ["group:runtime", "group:fs"] },
          },
          skills: ["skill-id"],
          systemPrompt: "Custom prompt for this group.",
        },
      },

      historyLimit: 12,
      dmHistoryLimit: 12, // optional (schema-supported)
      textChunkLimit: 1800,
      chunkMode: "length", // length | newline
      blockStreaming: false,
      mediaMaxMb: 25, // optional (schema-supported)
      markdown: {}, // optional (schema-supported)

      mediaLocalRoots: [
        "/Users/<you>/.openclaw/workspace",
        "/Users/<you>/.openclaw/media",
      ],
      sendTypingIndicators: true,

      threadBindings: {
        enabled: true,
        spawnSubagentSessions: true,
        ttlHours: 24,
      },

      actions: {
        reactions: true,
        messages: true, // read/edit/unsend
        groups: true, // rename/add/remove/leave
        pins: true, // pin/unpin/list-pins
        memberInfo: true, // member-info
        groupMembers: true, // reserved
      },
    },
  },
}

Multi-Account

channels.openzalo.accounts.<accountId> overrides top-level fields:

channels:
  openzalo:
    enabled: true
    defaultAccount: default
    accounts:
      default:
        profile: default
        acpx:
          enabled: true
          command: /full/path/to/acpx
          agent: claude
          cwd: /Users/<you>/.openclaw/workspace
      work:
        profile: work
        enabled: true

Profile resolution is per account. If zcaBinary is not set, plugin uses:

  1. channels.openzalo[.accounts.<id>].zcaBinary
  2. OPENZCA_BINARY env var
  3. openzca

If acpx is not set, OpenZalo ACP-local uses:

  1. channels.openzalo[.accounts.<id>].acpx.command
  2. OPENZALO_ACPX_COMMAND env var
  3. acpx

Voice publishing is handled by openzca, not by OpenZalo directly. For local msg voice sends, openzca uses:

  1. OPENZCA_VOICE_PUBLISH_CMD env var
  2. legacy direct upload flow when that env var is unset or ffmpeg is unavailable

OPENZCA_VOICE_PUBLISH_CMD should point to a command available on the gateway host that accepts one local normalized audio file path and prints one final public http(s) URL to stdout.

Target Format

  • DM target: <userId>
  • Group target: group:<groupId>
  • Also accepted for groups: g-<groupId>, g:<groupId>
  • Also accepted for DM/user targets: user:<userId>, dm:<userId>, u:<userId>, u-<userId>
  • Channel prefixes like openzalo:<target> and ozl:<target> are normalized automatically.
  • Legacy zlu:<target> remains accepted for backward compatibility.

Use group: for explicit group sends.

Notes

  • Inbound listener uses openzca listen --raw --supervised so OpenZalo owns restart policy and receives lifecycle heartbeats.
  • Group messages require mention by default (requireMention: true) unless overridden.
  • Authorized slash/bang control commands can still be processed in groups when access policy allows.
  • Pairing mode sends approval code for unknown DM senders.
  • Subagent session binding controls use channels.openzalo.threadBindings.* (or per-account overrides).
  • Local media is restricted to allowed roots for safety.
  • OpenZalo checks mediaLocalRoots before calling openzca for local media. That still applies even when openzca later publishes local voice files through OPENZCA_VOICE_PUBLISH_CMD.
  • Public voice URLs are fine: if the upstream caller already provides a public audio URL, OpenZalo can pass it through to openzca msg voice --url ... without needing local media roots.

Default safe media roots (under OPENCLAW_STATE_DIR or CLAWDBOT_STATE_DIR, fallback ~/.openclaw):

  • workspace
  • media
  • agents
  • sandboxes
  • OpenClaw temp media under the preferred OpenClaw tmp root (typically /tmp/openclaw, with a secure host-specific fallback when needed)

Troubleshooting

  • openzca not found: install openzca or set channels.openzalo.zcaBinary.
  • acpx command not found: install acpx (for example npm i -g acpx) or set channels.openzalo.acpx.command to the absolute acpx path.
  • Auth check fails: run openclaw channels login --channel openzalo (or openzca --profile <id> auth login).
  • Group message dropped: verify groupPolicy, groupAllowFrom, and groups.<groupId> allowlist.
  • Group message dropped with allowlist configured: check requireMention and mention detection.
  • Local media blocked: add absolute paths to channels.openzalo.mediaLocalRoots.
  • Local voice sends work on web but fail on mobile: configure OPENZCA_VOICE_PUBLISH_CMD on the gateway host and ensure ffmpeg is installed for openzca.