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

@nodeskai/feishu

v0.3.1

Published

Production-grade Feishu/Lark channel plugin for OpenClaw

Downloads

307

Readme

openclaw-plugin-feishu

Turn Feishu into your AI super-gateway. A production-grade Feishu/Lark channel plugin for OpenClaw — the brilliant AI agent framework.

Features

  • Human-like Message Processing — Bot reads all accumulated messages before responding, just like a human catching up on a conversation
  • Intelligent Batching — Groups messages by chat, flushes on trigger (like @mention) with full context
  • Mention Preservation — Non-bot @mentions are preserved as @[Name](open_id) so Agent can @ users back
  • Extensible Triggers@mention is just one trigger type; architecture supports keywords, schedules, etc.
  • History Messages API — Fetch chat history with pagination for context gathering
  • Flexible Access Control — DM policies (open/pairing/allowlist) and group policies (open/allowlist/disabled)
  • Dual Domain Support — Works with both Feishu (China) and Lark (International)
  • Interactive Card Tool — AI can send rich interactive cards with buttons, layouts, and formatted content
  • Multi-Account Support — Configure multiple Feishu apps in a single OpenClaw instance
  • Per-Sender Tool Policy — Fine-grained tool permissions based on message sender identity

Install

# npm
openclaw plugins install @xzq-xu/feishu

# GitHub (for testing)
openclaw plugins install github:xzq-xu/openclaw-plugin-feishu

Configure

Edit ~/.openclaw/openclaw.json:

{
  "channels": {
    "feishu": {
      "enabled": true,
      "appId": "cli_xxx",
      "appSecret": "xxx",
      "domain": "feishu",
      "dmPolicy": "pairing",
      "groupPolicy": "open"
    }
  }
}

Or use environment variables (takes precedence if config values are empty):

export FEISHU_APP_ID="cli_xxx"
export FEISHU_APP_SECRET="xxx"

Configuration Options

| Field | Type | Default | Description | | ---------------- | ----------------------------------------- | ------------- | ------------------------------------------------------ | | enabled | boolean | false | Enable/disable the channel | | appId | string | - | Feishu App ID | | appSecret | string | - | Feishu App Secret | | domain | "feishu" | "lark" | "feishu" | API domain (China / International) | | dmPolicy | "open" | "pairing" | "allowlist" | "pairing" | DM access policy | | allowFrom | string[] | [] | User IDs allowed for DM (when dmPolicy: "allowlist") | | groupPolicy | "open" | "allowlist" | "disabled" | "allowlist" | Group chat access policy | | groupAllowFrom | string[] | [] | Group IDs allowed (when groupPolicy: "allowlist") | | requireMention | boolean | true | Require @mention in groups |

Media Options

| Field | Type | Default | Description | | ---------- | ------ | ---------------------------- | ------------------------------------------ | | mediaDir | string | System temp dir (/tmp/...) | Directory to save downloaded media files | | mediaMaxMb | number | - | Maximum media file size in MB |

The plugin downloads images, files, and audio from Feishu messages. By default, files are saved to the system temp directory (e.g., /tmp/openclaw-feishu-media/). You can customize this:

{
  "channels": {
    "feishu": {
      "mediaDir": "~/.openclaw/media/feishu"
    }
  }
}

Supported media types:

  • Images: PNG, JPEG, GIF, WebP
  • Files: PDF, DOC, TXT, etc.
  • Audio: Opus/Ogg (Feishu voice messages)

Auto-Reply Options (Autonomous Mode)

Enable the bot to autonomously decide whether to respond in group chats, like a human observer.

| Field | Type | Default | Description | | ---------------------- | ------- | ------- | ----------------------------------------------------- | | autoReply.enabled | boolean | false | Enable autonomous reply mode | | autoReply.minMessages| number | 5 | Minimum messages before considering auto-reply | | autoReply.minTimeMs | number | 60000 | Minimum time window (ms) since first message | | autoReply.debounceMs | number | 3000 | Wait time (ms) for no new messages before evaluating | | autoReply.systemHint | string | - | Custom prompt for agent decision (optional) |

How it works:

                    消息进入
                        │
           ┌────────────┴────────────┐
           │                         │
      @bot / 触发?               否
           │                         │
           ▼                         ▼
    ┌──────────────┐         累积到缓冲区
    │ 立即触发      │         新消息重置防抖
    │ 必须回复      │               │
    └──────────────┘               ▼
                           防抖到期(3s无新消息)
                                   │
                                   ▼
                         双条件满足?
                         消息数 >= N 且 时间 >= T
                                   │
                              ┌────┴────┐
                            满足      不满足
                              │         │
                              ▼         ▼
                       交给 Agent    继续等待
                       让它决定
                       是否回复
  1. Trigger mode (default): Bot only responds when @mentioned - must reply
  2. Auto-reply mode: Bot observes group chat and decides whether to respond

Dual conditions (both must be met):

  • minMessages: Accumulated message count threshold
  • minTimeMs: Time elapsed since first message in buffer

Debounce: Every new message resets the debounce timer. Only when no new messages arrive for debounceMs, the conditions are checked.

Agent decision: If conditions are met, the agent receives all buffered messages with a system hint. The agent can:

  • Reply normally → message sent to group
  • Output [NO_RESPONSE] → silently dropped, no message sent
{
  "channels": {
    "feishu": {
      "autoReply": {
        "enabled": true,
        "minMessages": 5,
        "minTimeMs": 60000,
        "debounceMs": 3000
      }
    }
  }
}

Note: @mentions always trigger a response regardless of auto-reply settings.

Streaming Message Options

| Field | Type | Default | Description | | -------------------------------- | ------- | ------- | ------------------------------------------------ | | blockStreamingCoalesce.enabled | boolean | false | Enable streaming message coalescing | | blockStreamingCoalesce.minDelayMs | number | - | Minimum delay before sending coalesced message | | blockStreamingCoalesce.maxDelayMs | number | - | Maximum delay before forcing message send | | streamingCard.enabled | boolean | false | Enable streaming card (shows "typing" indicator) | | streamingCard.title | string | - | Title shown on the streaming card | | textChunkLimit | number | 4000 | Max characters per message chunk |

Example with streaming enabled:

{
  "channels": {
    "feishu": {
      "enabled": true,
      "appId": "cli_xxx",
      "appSecret": "xxx",
      "blockStreamingCoalesce": {
        "enabled": true,
        "minDelayMs": 500,
        "maxDelayMs": 2000
      },
      "streamingCard": {
        "enabled": true,
        "title": "正在思考..."
      }
    }
  }
}

Multi-Account Support

Configure multiple Feishu apps in a single OpenClaw instance:

{
  "channels": {
    "feishu": {
      "enabled": true,
      "domain": "feishu",
      "dmPolicy": "pairing",
      "accounts": {
        "main": {
          "appId": "cli_main_xxx",
          "appSecret": "secret1",
          "botName": "Main Bot"
        },
        "support": {
          "appId": "cli_support_xxx",
          "appSecretFile": "~/.secrets/support-bot.txt",
          "botName": "Support Bot",
          "dmPolicy": "allowlist",
          "allowFrom": ["ou_admin1", "ou_admin2"]
        }
      }
    }
  }
}

Each account inherits from the base config and can override any setting. The appSecretFile option allows reading secrets from a file instead of storing them in config.

Per-Sender Tool Policy (toolsBySender)

Configure tool permissions based on message sender within groups:

{
  "channels": {
    "feishu": {
      "groups": {
        "oc_your_group_id": {
          "requireMention": false,
          "toolsBySender": {
            "张三": { "deny": ["shell", "write_file"] },
            "ou_admin_id": { "allow": ["*"] },
            "*": { "allow": ["web_search", "feishu_card"] }
          }
        }
      }
    }
  }
}

Resolution priority: toolsBySender[senderId] > toolsBySender[senderName] > tools > toolsBySender["*"]

Agent Tools

The plugin registers the following tools that AI agents can use:

feishu_card

Send rich interactive cards with structured content:

{
  "tool": "feishu_card",
  "args": {
    "title": "Status Report",
    "titleTemplate": "green",
    "elements": [
      { "tag": "markdown", "content": "**Task**: Completed\n**Duration**: 3.2s" },
      { "tag": "hr" },
      { "tag": "action", "actions": [
        { "tag": "button", "text": { "tag": "plain_text", "content": "View Details" }, "type": "primary", "url": "https://example.com" }
      ]}
    ]
  }
}

Supported elements:

  • div — Text block with plain_text or lark_md
  • hr — Horizontal divider
  • markdown — Markdown content block
  • note — Footnote with nested elements
  • action — Button row (supports url for links, type: default/primary/danger)
  • column_set — Multi-column layout
  • img — Image with img_key

Header colors: blue, wathet, turquoise, green, yellow, orange, red, carmine, violet, purple, indigo, grey

feishu_list_messages

Retrieve message history from a chat:

{
  "tool": "feishu_list_messages",
  "args": {
    "chatId": "oc_xxx",
    "pageSize": 20
  }
}

How It Works

Human-like Batch Processing

Unlike typical bots that respond to each message immediately, this plugin processes messages like a human would:

  1. Startup Window (10s): When the bot connects, it buffers all incoming messages
  2. Trigger Detection: @mention (or other triggers) signals the bot should respond
  3. Context Gathering: Bot reads ALL buffered messages, not just the trigger
  4. Single Response: Bot responds once with full conversation context
Example: Bot was offline, 5 messages arrive:

  User A: "Let's discuss the project timeline"
  User B: "@bot what do you think?"        ← trigger
  User A: "Budget is around $100k"
  User C: "@bot please summarize"          ← trigger
  User A: "Deadline is next Monday"

OLD behavior: Bot responds twice (to each @mention), missing context
NEW behavior: Bot sees all 5 messages, understands full context, responds ONCE

Mention Handling

Non-bot mentions are preserved with their open_id, enabling the Agent to @ users in responses:

Inbound message:  "Hi @张三 what do you think?"
Parsed content:   "Hi @[张三](ou_xxx) what do you think?"
ParsedMessage.mentions: [{ name: "张三", openId: "ou_xxx" }]

Agent response:   "I agree with @[张三](ou_xxx)'s point..."
Sent to Feishu:   "I agree with <at user_id="ou_xxx">张三</at>'s point..."

Bot mentions (@bot) are stripped completely to reduce noise.

Extensible Trigger System

The @mention is just the default trigger. The architecture supports:

  • Keyword triggers: Respond when specific words appear
  • Scheduled triggers: Periodic check-ins
  • Custom triggers: Implement the Trigger interface
// src/core/triggers/index.ts
export interface Trigger {
  name: string;
  check(ctx: TriggerContext): boolean;
}

Feishu App Setup

  1. Go to Feishu Open Platform
  2. Create a self-built app
  3. Enable permissions: im:message, im:chat, contact:user.base:readonly
  4. Events → Use Long Connection mode
  5. Subscribe to event: im.message.receive_v1
  6. Get App ID and App Secret from Credentials page
  7. Publish the app

Changelog

See CHANGELOG.md for version history.

License

MIT

Acknowledgments

Inspired by samzong/moltbot-channel-feishu.