openclaw-lark-integration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenClaw 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 -vIf below required version, upgrade:
bash
npm install -g openclaw- Node.js v22或更高版本
- OpenClaw版本2026.2.26或更高版本
检查OpenClaw版本:
bash
openclaw -v若版本低于要求,执行升级:
bash
npm install -g openclawInstall Plugin
安装插件
bash
npm install -g @larksuite/openclaw-larkOr with pnpm:
bash
pnpm add -g @larksuite/openclaw-larkbash
npm install -g @larksuite/openclaw-lark或使用pnpm:
bash
pnpm add -g @larksuite/openclaw-larkConfiguration
配置说明
1. Create Lark/Feishu App
1. 创建Lark/飞书应用
- Go to Lark Open Platform or Feishu Open Platform
- Create a new custom app
- Configure bot capabilities and permissions
- Obtain App ID and App Secret
2. Required Permissions
2. 所需权限
The app needs these permission scopes:
Messaging:
- - Send messages
im:message - - Read messages as user
im:message:read_as_user - - Access chat information
im:chat
Documents:
- - Manage docs
docx:document - - Access drive files
drive:drive
Base:
- - Manage base apps
bitable:app - - Manage records
bitable:record
Sheets:
- - Manage spreadsheets
sheets:spreadsheet
Calendar:
- - Manage calendars
calendar:calendar - - Manage events
calendar:event
Tasks:
- - Manage tasks
task:task
应用需要以下权限范围:
消息类:
- - 发送消息
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 larkOr specify config file:
bash
openclaw start --config openclaw.config.tsbash
openclaw start --channel lark或指定配置文件:
bash
openclaw start --config openclaw.config.tsKey Commands
核心命令
OpenClaw CLI Commands
OpenClaw CLI命令
bash
undefinedbash
undefinedStart 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
undefinedopenclaw stop
undefinedManaging 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 => ).join('\n')}
- ${t.fields.Name}${tasks.items.map(t => ).join('\n')}
- ${t.fields.Name}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;
}
undefinedBatch 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:
- Verify OpenClaw is running:
openclaw status - Check credentials are set correctly
- Ensure bot has required permissions in Lark admin console
- Verify group is in allowlist if is true
allowGroupChat - Check logs:
openclaw logs --channel lark
问题:机器人不回复消息
解决方案:
- 验证OpenClaw是否运行:
openclaw status - 检查凭证设置是否正确
- 确保机器人在Lark管理控制台拥有所需权限
- 若启用,验证群组是否在白名单内
allowGroupChat - 查看日志:
openclaw logs --channel lark
Permission Errors
权限错误
Issue: "Permission denied" errors
Solutions:
- Review required scopes in Lark app settings
- Re-authorize the app after adding permissions
- Check if user has necessary workspace permissions
- Verify app is published (not in development mode)
问题:出现“Permission denied”错误
解决方案:
- 检查Lark应用设置中的权限范围
- 添加权限后重新授权应用
- 检查用户是否拥有工作区必要权限
- 验证应用已发布(非开发模式)
Message Not Sent
消息发送失败
Issue: Messages fail to send
Solutions:
- Check if chat ID is valid
- Verify bot is added to the group chat
- Ensure permission is granted
im:message - Check message format and size limits
问题:消息无法发送
解决方案:
- 检查聊天ID是否有效
- 验证机器人已加入群组
- 确保已授予权限
im:message - 检查消息格式与大小限制
Configuration Not Loading
配置未加载
Issue: Config changes not taking effect
Solutions:
- Restart OpenClaw after config changes
- Verify config file path:
openclaw start --config ./path/to/config.ts - Check for TypeScript/JSON syntax errors
- Ensure environment variables are exported
问题:配置更改未生效
解决方案:
- 修改配置后重启OpenClaw
- 验证配置文件路径:
openclaw start --config ./path/to/config.ts - 检查TypeScript/JSON语法错误
- 确保环境变量已正确导出
Streaming Not Working
流式响应不工作
Issue: Streaming responses not appearing
Solutions:
- Verify in config
enableStreamingResponse: true - Check Lark client version supports interactive cards
- Test with simple message first
- Review network/firewall settings
问题:流式响应未显示
解决方案:
- 验证配置中
enableStreamingResponse: true - 检查Lark客户端版本是否支持交互式卡片
- 先使用简单消息测试
- 检查网络/防火墙设置
Rate Limiting
速率限制
Issue: "Rate limit exceeded" errors
Solutions:
- Implement exponential backoff in custom skills
- Cache frequently accessed data
- Use batch operations where possible
- Monitor API quota in Lark admin console
问题:出现“Rate limit exceeded”错误
解决方案:
- 在自定义Skill中实现指数退避策略
- 缓存频繁访问的数据
- 尽可能使用批量操作
- 在Lark管理控制台监控API配额
Best Practices
最佳实践
- Security First: Never disable default security policies without understanding risks
- Use Private Chats: Recommended for personal assistants to avoid permission abuse
- Whitelist Groups: If using in groups, explicitly whitelist trusted chats only
- Environment Variables: Always use env vars for credentials, never hardcode
- Error Handling: Wrap API calls in try-catch blocks
- Confirmation Dialogs: Use interactive cards for destructive operations
- Rate Limiting: Respect API limits, implement backoff strategies
- Logging: Enable detailed logs during development for debugging
- Skill Restrictions: Limit available skills per group to reduce attack surface
- Regular Updates: Keep OpenClaw and plugin updated for security patches
- 安全优先:未理解风险前,不要禁用默认安全策略
- 优先使用私聊:个人助手推荐使用私聊,避免权限滥用
- 群组白名单:若在群组使用,仅将可信群组加入白名单
- 环境变量存储凭证:始终使用环境变量存储凭证,切勿硬编码
- 错误处理:将API调用包裹在try-catch块中
- 确认对话框:对破坏性操作使用交互式卡片确认
- 速率限制:遵守API限制,实现退避策略
- 日志记录:开发阶段启用详细日志用于调试
- Skill限制:按群组限制可用Skill,减少攻击面
- 定期更新:保持OpenClaw与插件更新,获取安全补丁