Skip to content
Β 
Β 

Repository files navigation

@openclaw/lark

First-class OpenClaw channel plugin for Lark (Feishu) with guaranteed message delivery.

npm version License: MIT

Features

Telegram Feature Parity

Full feature parity with the OpenClaw Telegram channel:

  • βœ… New Session Messages β€” Shows "βœ… New session started Β· model: ..." on /new, /reset
  • πŸ’Έ Usage Footer β€” Session cost, today's cost, 30-day cost
  • 🧠 Reasoning Visibility β€” See AI thinking process when enabled
  • πŸ“‹ Verbose Output β€” Tool calls, exec commands visible when enabled
  • ⚑ Native Dispatch β€” Uses OpenClaw's internal dispatch system

Robustness

  • πŸ”’ Guaranteed Delivery β€” All messages persisted to SQLite; never lose a message
  • ♾️ 120 Retries β€” Exponential backoff, capped at 120 minutes
  • πŸ›‘οΈ No Message Loss β€” Failed messages kept in DB for manual review
  • πŸ“Š 30-Day Retention β€” All messages kept for audit trail

Messaging

  • πŸ’¬ Full Messaging Support β€” Text, rich text (post), images, interactive cards
  • 🎨 Smart Card Formatting β€” Automatic color detection based on content urgency
  • πŸ“· Image Upload/Download β€” Seamless image handling in both directions
  • πŸ‘₯ Group Chat Support β€” Configurable mention requirements and allowlists
  • 🌏 International & China β€” Works with both Lark (international) and Feishu (China)

Installation

npm install @openclaw/lark

Or add to your OpenClaw configuration:

# openclaw.json
{
  "plugins": {
    "entries": {
      "lark": { "enabled": true }
    }
  },
  "channels": {
    "lark": {
      "enabled": true,
      "appId": "cli_xxx",
      "appSecretFile": "~/.openclaw/secrets/lark_app_secret"
    }
  }
}

Configuration

Basic Setup

  1. Create a bot in Lark Open Platform (or Feishu Open Platform for China)

  2. Enable the following permissions:

    • im:message β€” Send and receive messages
    • im:message.group_at_msg β€” Receive @mentions in groups
    • im:resource β€” Upload and download images
  3. Configure webhook URL in your bot settings:

    https://your-server.com/webhook
    
  4. Add configuration to OpenClaw:

    {
      "channels": {
        "lark": {
          "enabled": true,
          "appId": "cli_your_app_id",
          "appSecretFile": "~/.openclaw/secrets/lark_app_secret",
          "webhookPort": 3000,
          "domain": "lark"
        }
      }
    }

Configuration Options

Option Type Default Description
enabled boolean true Enable/disable the channel
appId string β€” Lark application ID
appSecret string β€” Lark application secret
appSecretFile string β€” Path to file containing app secret (recommended)
encryptKey string β€” Encryption key for webhook events
webhookPort number 3000 Port for webhook HTTP server
domain string "lark" API domain: "lark" (international) or "feishu" (China)
dmPolicy string "pairing" DM security: "open", "pairing", or "allowlist"
allowFrom string[] [] Allowed user IDs (for allowlist policy)
groupPolicy string "allowlist" Group security: "open", "allowlist", or "deny"
groups object β€” Per-group configuration
queueDbPath string ~/.openclaw/lark-queue.db Path to SQLite queue database

Environment Variables

The following environment variables are also supported:

  • FEISHU_APP_ID β€” Application ID
  • FEISHU_APP_SECRET β€” Application secret
  • FEISHU_ENCRYPT_KEY β€” Webhook encryption key

Message Types

Outgoing Messages

The plugin automatically selects the appropriate message type:

Content Type
Short text (<100 chars, ≀2 lines) Plain text
Longer/formatted content Interactive card
Contains NO_REPLY or HEARTBEAT_OK Skipped

Interactive Cards

Cards are automatically formatted with:

  • Colored headers based on content:

    • πŸ”΄ Red β€” urgent, critical, error
    • 🟠 Orange β€” warning, caution
    • 🟒 Green β€” success, done, completed
    • πŸ”΅ Blue β€” Default
  • Markdown support β€” Bold, lists, code blocks

  • Footer β€” Timestamp and session key

  • Automatic truncation β€” Long messages are safely truncated

Images

Images are automatically handled:

// Incoming: Images are converted to base64 attachments
// Outgoing: Image URLs are uploaded and embedded in cards

Queue System

The queue system ensures no message loss:

Inbound Flow:
  Lark β†’ Webhook β†’ SQLite Queue β†’ Gateway β†’ Response β†’ SQLite Queue β†’ Lark

Outbound Flow:
  Gateway β†’ SQLite Queue β†’ Lark API

Features

  • WAL mode β€” Write-Ahead Logging for durability
  • Exponential backoff β€” 1s, 2s, 4s, ... up to 120 minutes max
  • 120 retry attempts β€” Never give up on message delivery
  • Deduplication β€” 10-minute window prevents double-sends
  • Automatic recovery β€” Stuck messages recovered on restart
  • 30-day retention β€” All messages kept for audit

Health Check

curl http://localhost:3000/health

Response:

{
  "status": "ok",
  "version": "1.0.0",
  "guaranteedDelivery": true,
  "unlimitedRetries": true,
  "queue": {
    "inbound": { "pending": 0, "processing": 0, "completed": 42, "failed": 0 },
    "outbound": { "pending": 0, "processing": 0, "completed": 128, "failed": 0 }
  }
}

Group Chats

Configuration

{
  "channels": {
    "lark": {
      "groupPolicy": "allowlist",
      "groups": {
        "oc_abc123": {
          "name": "Team Chat",
          "requireMention": true
        },
        "oc_def456": {
          "name": "Alerts",
          "requireMention": false
        }
      }
    }
  }
}

Behavior

  • requireMention: true β€” Bot only responds when @mentioned
  • requireMention: false β€” Bot responds to question-like messages

Security

DM Policies

  • "open" β€” Accept messages from anyone
  • "pairing" β€” Require pairing approval (default)
  • "allowlist" β€” Only accept from configured user IDs

Group Policies

  • "open" β€” Accept from any group
  • "allowlist" β€” Only configured groups (default)
  • "deny" β€” Ignore all group messages

Encryption

If your bot uses encrypted events:

{
  "channels": {
    "lark": {
      "encryptKey": "your-encrypt-key"
    }
  }
}

Development

Build

pnpm install
pnpm run build

Test

pnpm test

Local Development

# Start in development mode
pnpm run dev

# Run tests in watch mode
pnpm run test:watch

# Run coverage
pnpm run test:coverage

API Reference

LarkClient

import { LarkClient } from '@openclaw/lark';

const client = new LarkClient({
  appId: 'cli_xxx',
  appSecret: 'your-secret',
  domain: 'lark', // or 'feishu'
});

// Send text
await client.sendText('oc_chatid', 'Hello!');

// Send card
await client.sendCard('oc_chatid', {
  header: { title: { tag: 'plain_text', content: 'Title' }, template: 'blue' },
  elements: [{ tag: 'div', text: { tag: 'lark_md', content: '**Bold**' } }],
});

// Upload image
const { imageKey } = await client.uploadImageFromUrl('https://example.com/image.png');

MessageQueue

import { getQueue } from '@openclaw/lark';

const queue = getQueue();

// Enqueue outbound message
queue.enqueueOutbound('reply', {
  sessionKey: 'lark:oc_chatid',
  chatId: 'oc_chatid',
  content: 'Hello!',
});

// Get stats
const stats = queue.getStats();

Card Builder

import { buildCard, selectMessageType, detectColor } from '@openclaw/lark';

// Build a card
const card = buildCard({
  text: 'βœ… Task completed successfully!',
  sessionKey: 'lark:oc_chatid',
});
// β†’ Green header, formatted content, footer with timestamp

// Select message type
const type = selectMessageType('Short text'); // β†’ 'text'
const type2 = selectMessageType('Long formatted\ncontent\nhere'); // β†’ 'interactive'

// Detect color
const color = detectColor('🚨 URGENT: System down!'); // β†’ 'red'

Troubleshooting

Messages not arriving

  1. Check webhook is accessible:

    curl -X POST http://your-server:3000/webhook \
      -H "Content-Type: application/json" \
      -d '{"type":"url_verification","challenge":"test"}'
  2. Verify bot permissions in Lark Open Platform

  3. Check queue health:

    curl http://localhost:3000/health

Messages stuck in queue

Check for stuck messages:

sqlite3 ~/.openclaw/lark-queue.db "SELECT * FROM inbound_queue WHERE status='processing'"

The queue automatically recovers stuck messages (>5 min) on startup.

Card formatting issues

  • Markdown tables are not supported in Lark
  • Use fields array for side-by-side content
  • Maximum card length: 30,000 characters

License

MIT Β© Boyang Wang

Contributing

Contributions welcome! Please read our contributing guidelines first.

Related

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages