openclaw-lark-integration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenClaw Lark Integration

OpenClaw Lark 集成

Skill by ara.so — Hermes Skills collection.
Official Lark/Feishu plugin for OpenClaw that seamlessly connects AI agents to Lark workspaces. Enables reading and writing messages, managing docs, bases, sheets, calendars, and tasks with built-in security controls and interactive cards.
ara.so 开发的Skill — 属于Hermes Skills集合。
OpenClaw官方Lark/飞书插件,可无缝连接AI Agent与Lark工作区。支持读写消息、管理文档、多维表格、电子表格、日历和任务,内置安全控制与交互式卡片功能。

What It Does

功能介绍

The OpenClaw Lark plugin allows AI agents to:
  • Messaging: Read message history (groups/DMs/threads), send/reply to messages, search, download attachments
  • Documents: Create, update, and read Lark docs
  • Base: Full CRUD operations on bases, tables, fields, records with advanced filtering
  • Sheets: Create, edit, and view spreadsheets
  • Calendar: Manage calendars, events, attendees, and check free/busy status
  • Tasks: Create, query, update, complete tasks and manage subtasks/comments
  • Interactive Cards: Real-time status updates with streaming responses
  • Security: Built-in permission policies and per-group configuration
OpenClaw Lark插件允许AI Agent:
  • 消息功能:读取消息历史(群组/私聊/线程)、发送/回复消息、搜索、下载附件
  • 文档管理:创建、更新和读取Lark文档
  • 多维表格:对多维表格、数据表、字段、记录执行完整的CRUD操作,支持高级筛选
  • 电子表格:创建、编辑和查看电子表格
  • 日历管理:管理日历、事件、参会人员,查询空闲/忙碌状态
  • 任务管理:创建、查询、更新、完成任务,管理子任务与评论
  • 交互式卡片:通过流式响应实现实时状态更新
  • 安全控制:内置权限策略与群组级配置

Installation

安装步骤

Prerequisites

前置要求

  • Node.js v22 or higher
  • OpenClaw version 2026.2.26 or higher
Check OpenClaw version:
bash
openclaw -v
If below required version, upgrade:
bash
npm install -g openclaw
  • Node.js v22或更高版本
  • OpenClaw版本2026.2.26或更高版本
检查OpenClaw版本:
bash
openclaw -v
若版本低于要求,执行升级:
bash
npm install -g openclaw

Install Plugin

安装插件

bash
npm install -g @larksuite/openclaw-lark
Or with pnpm:
bash
pnpm add -g @larksuite/openclaw-lark
bash
npm install -g @larksuite/openclaw-lark
或使用pnpm:
bash
pnpm add -g @larksuite/openclaw-lark

Configuration

配置说明

1. Create Lark/Feishu App

1. 创建Lark/飞书应用

  1. Go to Lark Open Platform or Feishu Open Platform
  2. Create a new custom app
  3. Configure bot capabilities and permissions
  4. Obtain App ID and App Secret
  1. 访问 Lark开放平台飞书开放平台
  2. 创建新的自定义应用
  3. 配置机器人能力与权限
  4. 获取App ID和App Secret

2. Required Permissions

2. 所需权限

The app needs these permission scopes:
Messaging:
  • im:message
    - Send messages
  • im:message:read_as_user
    - Read messages as user
  • im:chat
    - Access chat information
Documents:
  • docx:document
    - Manage docs
  • drive:drive
    - Access drive files
Base:
  • bitable:app
    - Manage base apps
  • bitable:record
    - Manage records
Sheets:
  • sheets:spreadsheet
    - Manage spreadsheets
Calendar:
  • calendar:calendar
    - Manage calendars
  • calendar:event
    - Manage events
Tasks:
  • task:task
    - Manage tasks
应用需要以下权限范围:
消息类:
  • im:message
    - 发送消息
  • im:message:read_as_user
    - 以用户身份读取消息
  • im:chat
    - 访问聊天信息
文档类:
  • docx:document
    - 管理文档
  • drive:drive
    - 访问云盘文件
多维表格类:
  • bitable:app
    - 管理多维表格应用
  • bitable:record
    - 管理记录
电子表格类:
  • sheets:spreadsheet
    - 管理电子表格
日历类:
  • calendar:calendar
    - 管理日历
  • calendar:event
    - 管理事件
任务类:
  • task:task
    - 管理任务

3. Configure Environment Variables

3. 配置环境变量

Create or update your OpenClaw config file with Lark credentials:
typescript
// openclaw.config.ts
export default {
  channels: {
    lark: {
      appId: process.env.LARK_APP_ID,
      appSecret: process.env.LARK_APP_SECRET,
      verificationToken: process.env.LARK_VERIFICATION_TOKEN,
      encryptKey: process.env.LARK_ENCRYPT_KEY,
      
      // Optional: Security policies
      policies: {
        allowPrivateChat: true,
        allowGroupChat: false, // Disable by default for security
        groupAllowlist: [], // Whitelist specific groups
      },
      
      // Optional: Default settings
      enableInteractiveCards: true,
      enableStreamingResponse: true,
    }
  }
}
Set environment variables:
bash
export LARK_APP_ID="your_app_id"
export LARK_APP_SECRET="your_app_secret"
export LARK_VERIFICATION_TOKEN="your_verification_token"
export LARK_ENCRYPT_KEY="your_encrypt_key"
在OpenClaw配置文件中添加Lark凭证:
typescript
// openclaw.config.ts
export default {
  channels: {
    lark: {
      appId: process.env.LARK_APP_ID,
      appSecret: process.env.LARK_APP_SECRET,
      verificationToken: process.env.LARK_VERIFICATION_TOKEN,
      encryptKey: process.env.LARK_ENCRYPT_KEY,
      
      // 可选:安全策略
      policies: {
        allowPrivateChat: true,
        allowGroupChat: false, // 默认禁用以保障安全
        groupAllowlist: [], // 白名单指定群组
      },
      
      // 可选:默认设置
      enableInteractiveCards: true,
      enableStreamingResponse: true,
    }
  }
}
设置环境变量:
bash
export LARK_APP_ID="your_app_id"
export LARK_APP_SECRET="your_app_secret"
export LARK_VERIFICATION_TOKEN="your_verification_token"
export LARK_ENCRYPT_KEY="your_encrypt_key"

4. Start OpenClaw with Lark Channel

4. 启动带Lark通道的OpenClaw

bash
openclaw start --channel lark
Or specify config file:
bash
openclaw start --config openclaw.config.ts
bash
openclaw start --channel lark
或指定配置文件:
bash
openclaw start --config openclaw.config.ts

Key Commands

核心命令

OpenClaw CLI Commands

OpenClaw CLI命令

bash
undefined
bash
undefined

Start with Lark channel

启动Lark通道

openclaw start --channel lark
openclaw start --channel lark

Check version

检查版本

openclaw -v
openclaw -v

View help

查看帮助

openclaw --help
openclaw --help

Stop OpenClaw

停止OpenClaw

openclaw stop
undefined
openclaw stop
undefined

Managing the Bot

机器人管理

Once running, interact with your bot in Lark/Feishu by:
  • Sending direct messages
  • @mentioning in allowed groups
  • Using configured skills and prompts
运行后,可通过以下方式在Lark/飞书中与机器人交互:
  • 发送私聊消息
  • 在允许的群组中@提及机器人
  • 使用已配置的Skill与提示词

API Usage Patterns

API使用示例

Sending Messages

发送消息

The plugin automatically handles message sending through OpenClaw's unified interface:
typescript
// Example skill that sends a Lark message
import { SkillContext } from 'openclaw';

export async function sendLarkMessage(context: SkillContext, message: string) {
  // OpenClaw automatically routes to Lark channel
  await context.channel.sendMessage({
    text: message,
    chatId: context.chatId
  });
}
插件自动通过OpenClaw统一接口处理消息发送:
typescript
// 发送Lark消息的示例Skill
import { SkillContext } from 'openclaw';

export async function sendLarkMessage(context: SkillContext, message: string) {
  // OpenClaw自动路由至Lark通道
  await context.channel.sendMessage({
    text: message,
    chatId: context.chatId
  });
}

Reading Messages

读取消息

typescript
export async function getRecentMessages(context: SkillContext, limit: number = 10) {
  const messages = await context.channel.getMessages({
    chatId: context.chatId,
    limit: limit
  });
  
  return messages.map(msg => ({
    sender: msg.sender,
    content: msg.content,
    timestamp: msg.timestamp
  }));
}
typescript
export async function getRecentMessages(context: SkillContext, limit: number = 10) {
  const messages = await context.channel.getMessages({
    chatId: context.chatId,
    limit: limit
  });
  
  return messages.map(msg => ({
    sender: msg.sender,
    content: msg.content,
    timestamp: msg.timestamp
  }));
}

Working with Documents

文档操作

typescript
export async function createDocument(
  context: SkillContext, 
  title: string, 
  content: string
) {
  const doc = await context.channel.lark.createDoc({
    title: title,
    content: content,
    folderToken: context.workspace.defaultFolder
  });
  
  return {
    docId: doc.docToken,
    url: doc.url
  };
}
typescript
export async function createDocument(
  context: SkillContext, 
  title: string, 
  content: string
) {
  const doc = await context.channel.lark.createDoc({
    title: title,
    content: content,
    folderToken: context.workspace.defaultFolder
  });
  
  return {
    docId: doc.docToken,
    url: doc.url
  };
}

Managing Base Records

多维表格记录管理

typescript
export async function addBaseRecord(
  context: SkillContext,
  baseId: string,
  tableId: string,
  fields: Record<string, any>
) {
  const record = await context.channel.lark.base.createRecord({
    appToken: baseId,
    tableId: tableId,
    fields: fields
  });
  
  return record;
}

export async function queryBaseRecords(
  context: SkillContext,
  baseId: string,
  tableId: string,
  filter?: string
) {
  const records = await context.channel.lark.base.listRecords({
    appToken: baseId,
    tableId: tableId,
    filter: filter, // e.g., "AND(CurrentValue.[Status] = 'Active')"
    pageSize: 100
  });
  
  return records.items;
}
typescript
export async function addBaseRecord(
  context: SkillContext,
  baseId: string,
  tableId: string,
  fields: Record<string, any>
) {
  const record = await context.channel.lark.base.createRecord({
    appToken: baseId,
    tableId: tableId,
    fields: fields
  });
  
  return record;
}

export async function queryBaseRecords(
  context: SkillContext,
  baseId: string,
  tableId: string,
  filter?: string
) {
  const records = await context.channel.lark.base.listRecords({
    appToken: baseId,
    tableId: tableId,
    filter: filter, // 示例:"AND(CurrentValue.[Status] = 'Active')"
    pageSize: 100
  });
  
  return records.items;
}

Calendar Operations

日历操作

typescript
export async function createCalendarEvent(
  context: SkillContext,
  summary: string,
  startTime: string,
  endTime: string,
  attendees?: string[]
) {
  const event = await context.channel.lark.calendar.createEvent({
    summary: summary,
    startTime: { timestamp: startTime },
    endTime: { timestamp: endTime },
    attendees: attendees?.map(email => ({ email }))
  });
  
  return {
    eventId: event.eventId,
    htmlLink: event.htmlLink
  };
}
typescript
export async function createCalendarEvent(
  context: SkillContext,
  summary: string,
  startTime: string,
  endTime: string,
  attendees?: string[]
) {
  const event = await context.channel.lark.calendar.createEvent({
    summary: summary,
    startTime: { timestamp: startTime },
    endTime: { timestamp: endTime },
    attendees: attendees?.map(email => ({ email }))
  });
  
  return {
    eventId: event.eventId,
    htmlLink: event.htmlLink
  };
}

Task Management

任务管理

typescript
export async function createTask(
  context: SkillContext,
  summary: string,
  description: string,
  dueDate?: string
) {
  const task = await context.channel.lark.task.createTask({
    summary: summary,
    description: description,
    due: dueDate ? { date: dueDate } : undefined
  });
  
  return task;
}
typescript
export async function createTask(
  context: SkillContext,
  summary: string,
  description: string,
  dueDate?: string
) {
  const task = await context.channel.lark.task.createTask({
    summary: summary,
    description: description,
    due: dueDate ? { date: dueDate } : undefined
  });
  
  return task;
}

Security Configuration

安全配置

Permission Policies

权限策略

Configure access control in your config file:
typescript
export default {
  channels: {
    lark: {
      // ... credentials
      
      policies: {
        // Allow private chats (default: true)
        allowPrivateChat: true,
        
        // Disable all group chats (recommended for security)
        allowGroupChat: false,
        
        // Or allow specific groups only
        allowGroupChat: true,
        groupAllowlist: [
          'oc_xxxxxxxxxxxxx', // Group chat ID
          'oc_yyyyyyyyyyyyy'
        ],
        
        // Require confirmation for sensitive operations
        requireConfirmation: {
          deleteDocument: true,
          deleteBaseRecord: true,
          sendMessageToGroup: true
        }
      }
    }
  }
}
在配置文件中配置访问控制:
typescript
export default {
  channels: {
    lark: {
      // ... 凭证信息
      
      policies: {
        // 允许私聊(默认:true)
        allowPrivateChat: true,
        
        // 禁用所有群组聊天(安全推荐)
        allowGroupChat: false,
        
        // 或仅允许指定群组
        allowGroupChat: true,
        groupAllowlist: [
          'oc_xxxxxxxxxxxxx', // 群组聊天ID
          'oc_yyyyyyyyyyyyy'
        ],
        
        // 敏感操作需确认
        requireConfirmation: {
          deleteDocument: true,
          deleteBaseRecord: true,
          sendMessageToGroup: true
        }
      }
    }
  }
}

Per-Group Configuration

群组级配置

typescript
export default {
  channels: {
    lark: {
      // ... credentials
      
      groupSettings: {
        'oc_xxxxxxxxxxxxx': {
          enabled: true,
          allowedSkills: ['search', 'summarize'], // Restrict skills
          customSystemPrompt: 'You are a helpful assistant for the engineering team.',
          maxTokens: 4000
        }
      }
    }
  }
}
typescript
export default {
  channels: {
    lark: {
      // ... 凭证信息
      
      groupSettings: {
        'oc_xxxxxxxxxxxxx': {
          enabled: true,
          allowedSkills: ['search', 'summarize'], // 限制可用Skill
          customSystemPrompt: '你是工程团队的得力助手。',
          maxTokens: 4000
        }
      }
    }
  }
}

Interactive Cards and Streaming

交互式卡片与流式响应

Enable Streaming Responses

启用流式响应

typescript
export default {
  channels: {
    lark: {
      // ... credentials
      enableStreamingResponse: true,
      enableInteractiveCards: true
    }
  }
}
Streaming automatically shows:
  • 🤔 Thinking indicator
  • 📝 Generating status with live text
  • ✅ Complete notification
typescript
export default {
  channels: {
    lark: {
      // ... 凭证信息
      enableStreamingResponse: true,
      enableInteractiveCards: true
    }
  }
}
流式响应自动展示:
  • 🤔 思考状态指示器
  • 📝 实时生成的文本状态
  • ✅ 完成通知

Custom Interactive Cards

自定义交互式卡片

typescript
export async function sendCardWithActions(context: SkillContext) {
  await context.channel.sendCard({
    header: {
      title: 'Confirm Action',
      template: 'blue'
    },
    elements: [
      {
        tag: 'div',
        text: {
          tag: 'plain_text',
          content: 'Do you want to proceed with this operation?'
        }
      },
      {
        tag: 'action',
        actions: [
          {
            tag: 'button',
            text: { tag: 'plain_text', content: 'Confirm' },
            type: 'primary',
            value: { action: 'confirm' }
          },
          {
            tag: 'button',
            text: { tag: 'plain_text', content: 'Cancel' },
            type: 'default',
            value: { action: 'cancel' }
          }
        ]
      }
    ]
  });
}
typescript
export async function sendCardWithActions(context: SkillContext) {
  await context.channel.sendCard({
    header: {
      title: '确认操作',
      template: 'blue'
    },
    elements: [
      {
        tag: 'div',
        text: {
          tag: 'plain_text',
          content: '是否要继续执行此操作?'
        }
      },
      {
        tag: 'action',
        actions: [
          {
            tag: 'button',
            text: { tag: 'plain_text', content: '确认' },
            type: 'primary',
            value: { action: 'confirm' }
          },
          {
            tag: 'button',
            text: { tag: 'plain_text', content: '取消' },
            type: 'default',
            value: { action: 'cancel' }
          }
        ]
      }
    ]
  });
}

Common Patterns

常见使用场景

Message Handler Skill

消息处理Skill

typescript
import { Skill } from 'openclaw';

export const messageHandlerSkill: Skill = {
  name: 'lark-message-handler',
  description: 'Handle incoming Lark messages',
  
  async execute(context) {
    const { message, sender } = context;
    
    // Process message
    if (message.includes('help')) {
      return await context.reply('How can I assist you?');
    }
    
    // Search message history
    if (message.startsWith('search:')) {
      const query = message.substring(7);
      const results = await context.channel.searchMessages({ query });
      return results;
    }
    
    // Default response
    return await context.reply('Message received');
  }
};
typescript
import { Skill } from 'openclaw';

export const messageHandlerSkill: Skill = {
  name: 'lark-message-handler',
  description: '处理Lark incoming消息',
  
  async execute(context) {
    const { message, sender } = context;
    
    // 处理消息
    if (message.includes('help')) {
      return await context.reply('我能为你提供什么帮助?');
    }
    
    // 搜索消息历史
    if (message.startsWith('search:')) {
      const query = message.substring(7);
      const results = await context.channel.searchMessages({ query });
      return results;
    }
    
    // 默认响应
    return await context.reply('消息已收到');
  }
};

Document Automation

文档自动化

typescript
export async function createWeeklyReport(context: SkillContext) {
  const today = new Date();
  const title = `Weekly Report - ${today.toISOString().split('T')[0]}`;
  
  // Gather data from Base
  const tasks = await context.channel.lark.base.listRecords({
    appToken: process.env.LARK_TASK_BASE_ID!,
    tableId: 'tblxxxxxxxx',
    filter: "AND(CurrentValue.[CompletedAt] >= DATE_SUB(TODAY(), 7))"
  });
  
  // Create formatted document
  const content = `
typescript
export async function createWeeklyReport(context: SkillContext) {
  const today = new Date();
  const title = `周报 - ${today.toISOString().split('T')[0]}`;
  
  // 从多维表格获取数据
  const tasks = await context.channel.lark.base.listRecords({
    appToken: process.env.LARK_TASK_BASE_ID!,
    tableId: 'tblxxxxxxxx',
    filter: "AND(CurrentValue.[CompletedAt] >= DATE_SUB(TODAY(), 7))"
  });
  
  // 创建格式化文档
  const content = `

${title}

${title}

Completed Tasks

已完成任务

${tasks.items.map(t =>
- ${t.fields.Name}
).join('\n')}
${tasks.items.map(t =>
- ${t.fields.Name}
).join('\n')}

Summary

总结

Total tasks completed: ${tasks.items.length} `;
const doc = await context.channel.lark.createDoc({ title, content });
return doc.url; }
undefined
完成任务总数:${tasks.items.length} `;
const doc = await context.channel.lark.createDoc({ title, content });
return doc.url; }
undefined

Batch Operations

批量操作

typescript
export async function batchUpdateRecords(
  context: SkillContext,
  baseId: string,
  tableId: string,
  updates: Array<{ recordId: string; fields: Record<string, any> }>
) {
  // Lark API supports batch operations
  const result = await context.channel.lark.base.batchUpdateRecords({
    appToken: baseId,
    tableId: tableId,
    records: updates
  });
  
  return {
    updated: result.records.length,
    records: result.records
  };
}
typescript
export async function batchUpdateRecords(
  context: SkillContext,
  baseId: string,
  tableId: string,
  updates: Array<{ recordId: string; fields: Record<string, any> }>
) {
  // Lark API支持批量操作
  const result = await context.channel.lark.base.batchUpdateRecords({
    appToken: baseId,
    tableId: tableId,
    records: updates
  });
  
  return {
    updated: result.records.length,
    records: result.records
  };
}

Troubleshooting

故障排查

Bot Not Responding

机器人无响应

Issue: Bot doesn't reply to messages
Solutions:
  1. Verify OpenClaw is running:
    openclaw status
  2. Check credentials are set correctly
  3. Ensure bot has required permissions in Lark admin console
  4. Verify group is in allowlist if
    allowGroupChat
    is true
  5. Check logs:
    openclaw logs --channel lark
问题:机器人不回复消息
解决方案:
  1. 验证OpenClaw是否运行:
    openclaw status
  2. 检查凭证设置是否正确
  3. 确保机器人在Lark管理控制台拥有所需权限
  4. 若启用
    allowGroupChat
    ,验证群组是否在白名单内
  5. 查看日志:
    openclaw logs --channel lark

Permission Errors

权限错误

Issue: "Permission denied" errors
Solutions:
  1. Review required scopes in Lark app settings
  2. Re-authorize the app after adding permissions
  3. Check if user has necessary workspace permissions
  4. Verify app is published (not in development mode)
问题:出现“Permission denied”错误
解决方案:
  1. 检查Lark应用设置中的权限范围
  2. 添加权限后重新授权应用
  3. 检查用户是否拥有工作区必要权限
  4. 验证应用已发布(非开发模式)

Message Not Sent

消息发送失败

Issue: Messages fail to send
Solutions:
  1. Check if chat ID is valid
  2. Verify bot is added to the group chat
  3. Ensure
    im:message
    permission is granted
  4. Check message format and size limits
问题:消息无法发送
解决方案:
  1. 检查聊天ID是否有效
  2. 验证机器人已加入群组
  3. 确保已授予
    im:message
    权限
  4. 检查消息格式与大小限制

Configuration Not Loading

配置未加载

Issue: Config changes not taking effect
Solutions:
  1. Restart OpenClaw after config changes
  2. Verify config file path:
    openclaw start --config ./path/to/config.ts
  3. Check for TypeScript/JSON syntax errors
  4. Ensure environment variables are exported
问题:配置更改未生效
解决方案:
  1. 修改配置后重启OpenClaw
  2. 验证配置文件路径:
    openclaw start --config ./path/to/config.ts
  3. 检查TypeScript/JSON语法错误
  4. 确保环境变量已正确导出

Streaming Not Working

流式响应不工作

Issue: Streaming responses not appearing
Solutions:
  1. Verify
    enableStreamingResponse: true
    in config
  2. Check Lark client version supports interactive cards
  3. Test with simple message first
  4. Review network/firewall settings
问题:流式响应未显示
解决方案:
  1. 验证配置中
    enableStreamingResponse: true
  2. 检查Lark客户端版本是否支持交互式卡片
  3. 先使用简单消息测试
  4. 检查网络/防火墙设置

Rate Limiting

速率限制

Issue: "Rate limit exceeded" errors
Solutions:
  1. Implement exponential backoff in custom skills
  2. Cache frequently accessed data
  3. Use batch operations where possible
  4. Monitor API quota in Lark admin console
问题:出现“Rate limit exceeded”错误
解决方案:
  1. 在自定义Skill中实现指数退避策略
  2. 缓存频繁访问的数据
  3. 尽可能使用批量操作
  4. 在Lark管理控制台监控API配额

Best Practices

最佳实践

  1. Security First: Never disable default security policies without understanding risks
  2. Use Private Chats: Recommended for personal assistants to avoid permission abuse
  3. Whitelist Groups: If using in groups, explicitly whitelist trusted chats only
  4. Environment Variables: Always use env vars for credentials, never hardcode
  5. Error Handling: Wrap API calls in try-catch blocks
  6. Confirmation Dialogs: Use interactive cards for destructive operations
  7. Rate Limiting: Respect API limits, implement backoff strategies
  8. Logging: Enable detailed logs during development for debugging
  9. Skill Restrictions: Limit available skills per group to reduce attack surface
  10. Regular Updates: Keep OpenClaw and plugin updated for security patches
  1. 安全优先:未理解风险前,不要禁用默认安全策略
  2. 优先使用私聊:个人助手推荐使用私聊,避免权限滥用
  3. 群组白名单:若在群组使用,仅将可信群组加入白名单
  4. 环境变量存储凭证:始终使用环境变量存储凭证,切勿硬编码
  5. 错误处理:将API调用包裹在try-catch块中
  6. 确认对话框:对破坏性操作使用交互式卡片确认
  7. 速率限制:遵守API限制,实现退避策略
  8. 日志记录:开发阶段启用详细日志用于调试
  9. Skill限制:按群组限制可用Skill,减少攻击面
  10. 定期更新:保持OpenClaw与插件更新,获取安全补丁

Additional Resources

额外资源