Lark
Lark (international) communication channel for zylos.
Depends on: comm-bridge (C4 message routing).
Bundled Capability Modules (lark-cli)
This skill bundles 27 capability modules under references/, each operating against Lark via the lark-cli binary. They are not auto-loaded as top-level skills — Claude Code's skill discovery only scans top-level directories, and these sub-modules live inside this skill. The parent SKILL.md (this file) is the entry point.
How to use a module: when a user's request maps to one of the modules below, Read that module's SKILL.md first to learn its exact commands/flags, then invoke lark-cli <module> ....
Prerequisites (installed automatically by zylos add lark / zylos upgrade lark — see hooks/post-install-shared.js):
lark-clibinary on PATH (npm install -g @larksuite/cli).- 27 sub-skill folders under
references/lark-*/(npx xc-skills add larksuite/cli). - App credentials in lark-cli's keychain (
~/.lark-cli/config.json+ AES-256-GCM encrypted file under~/.local/share/lark-cli/); pushed from~/zylos/.envautomatically.
Identity (--as bot vs --as user):
⚠️ Prefer user identity for content operations. When querying or editing documents, wiki / knowledge bases, drive files, sheets, or Base via lark-cli, default to
--as user(OAuth-authorized; 7-day rolling refresh token). The bot identity is not a member of any knowledge space and lacks drive scopes, so bot-identity content queries silently find nothing. Bot identity is appropriate for IM messaging operations.
--as botworks out of the box for app/tenant-level operations (IM messaging, contacts, events). No extra login needed.--as useris the default for content operations (docs, wiki, drive, sheets, Base — see note above) and is required for surfaces tied to a real user's data (calendar, mail-write, tasks, attendance, OKR, minutes, VC-agent). The user runslark-cli auth login --domain <name>once. On auth failure lark-cli exits with a<domain>_user_login_requirederror envelope; the agent should detect this and notify the owner of the login command.
Module Index
Path prefix for all entries: references/
Messaging & people
| Module | Use when… |
|---|---|
lark-im/SKILL.md |
Send/search messages, manage groups and members, upload/download media (chunked for large files) |
lark-contact/SKILL.md |
Resolve names/emails ↔ open_ids; look up department / contact info |
Docs & drive
| Module | Use when… |
|---|---|
lark-doc/SKILL.md |
Lark Docs v2: create / fetch / update (DocxXML or Markdown); search Drive |
lark-sheets/SKILL.md |
Spreadsheets: create, read/write cells, append rows, find |
lark-slides/SKILL.md |
Presentations: create, read, page/element ops (XML protocol) |
lark-markdown/SKILL.md |
Markdown file create / read / upload / edit |
lark-drive/SKILL.md |
Drive files & folders: upload, download, copy, move, metadata |
lark-wiki/SKILL.md |
Wiki: spaces, members, node hierarchy |
lark-whiteboard/SKILL.md |
Whiteboards: query, export preview image, DSL edits |
Productivity
| Module | Use when… |
|---|---|
lark-base/SKILL.md |
Base (multi-dim tables): search base, tables, fields, records, views, dashboards, forms, roles |
lark-calendar/SKILL.md |
Calendar events: agenda, create, update, delete, attendees, reminders |
lark-task/SKILL.md |
Task lists, subtasks, collaborators, status |
lark-mail/SKILL.md |
Mail: draft / send / reply / forward / search; drafts, folders, labels, contacts, attachments, rules |
HR / workflow
| Module | Use when… |
|---|---|
lark-approval/SKILL.md |
Approval instances and tasks |
lark-attendance/SKILL.md |
Personal attendance / clock-in records |
lark-okr/SKILL.md |
OKR cycles, objectives, key results, alignment, metrics |
Meetings & A/V
| Module | Use when… |
|---|---|
lark-vc/SKILL.md |
Video conferencing history, meeting summaries (notes/todos/chapters/transcripts), participant snapshots |
lark-vc-agent/SKILL.md |
Have the bot join/leave a live meeting on the user's behalf; consume real-time events |
lark-minutes/SKILL.md |
Minutes: list, basic info, transcripts, AI summaries |
lark-note/SKILL.md |
Meeting notes (纪要): query note detail by note_id, get note_doc_token / verbatim_doc_token, read unified transcripts |
Apps & low-code
| Module | Use when… |
|---|---|
lark-apps/SKILL.md |
Miaoda/Spark apps: create, publish HTML sites, local full-stack dev, cloud-based generation, DB ops, release management |
Workflows & platform
| Module | Use when… |
|---|---|
lark-workflow-meeting-summary/SKILL.md |
Roll up meeting minutes over a time range |
lark-workflow-standup-report/SKILL.md |
Orchestrate calendar + task into a standup summary |
lark-event/SKILL.md |
Subscribe / consume real-time events as NDJSON streams |
lark-openapi-explorer/SKILL.md |
Discover native OpenAPI endpoints not yet wrapped by CLI shortcuts |
lark-skill-maker/SKILL.md |
Author new sub-skills wrapping lark-cli (atomic APIs or multi-step flows) |
lark-shared/SKILL.md |
Shared utilities / types referenced by other modules (rarely invoked directly) |
Loading Convention
Before running lark-cli <module> <subcmd>:
- Read
references/<module>/SKILL.mdto confirm exact subcommands, flags, and required vs. optional args. - If that module's
SKILL.mdreferences additional docs under its ownreferences/subdirectory, read those as well. - Run the command.
Skipping step 1 risks calling wrong subcommand names or missing required flags — lark-cli is feature-rich and each module covers dozens of subcommands.
Sending Messages
# Via C4 bridge (standard path — always use stdin form)
cat <<'EOF' | node ~/zylos/.claude/skills/comm-bridge/scripts/c4-send.js "lark" "<chat_id>"
Hello!
EOF
# Send image
cat <<'EOF' | node ~/zylos/.claude/skills/comm-bridge/scripts/c4-send.js "lark" "<chat_id>"
[MEDIA:image]/path/to/image.png
EOF
# Send file
cat <<'EOF' | node ~/zylos/.claude/skills/comm-bridge/scripts/c4-send.js "lark" "<chat_id>"
[MEDIA:file]/path/to/file.pdf
EOF
⚠️
[MEDIA:...]must be the only content in the message. Send text and media as separate calls.
Direct send (bypasses C4 logging, for testing only):
node ~/zylos/.claude/skills/lark/scripts/send.js <chat_id> "Hello!"
CLI Commands
# Test authentication
npm run cli test
# Send messages
npm run cli send-group oc_xxx "Hello"
# Documents
npm run cli doc <doc_id>
npm run cli sheet-read <token> <range>
# Calendar
npm run cli calendar --days 7
# Groups
npm run cli chats
Admin CLI
Manage bot configuration via admin.js:
ADM="node ~/zylos/.claude/skills/lark/src/admin.js"
# General
$ADM show # Show full config
$ADM show-owner # Show current owner
$ADM help # Show all commands
# DM Access Control
$ADM set-dm-policy <open|allowlist|owner> # Set DM policy
$ADM list-dm-allow # Show DM policy + allowFrom list
$ADM add-dm-allow <user_id_or_open_id> # Add user to dmAllowFrom
$ADM remove-dm-allow <user_id_or_open_id> # Remove user from dmAllowFrom
# Group Management
$ADM list-groups # List all configured groups
$ADM add-group <chat_id> <name> [mode] # Add group (mode: mention|smart)
$ADM remove-group <chat_id> # Remove a group
$ADM set-group-policy <disabled|allowlist|open> # Set group policy
$ADM set-group-allowfrom <chat_id> <id1,id2> # Set per-group allowed senders
$ADM set-group-history-limit <chat_id> <n> # Set per-group context message limit
$ADM migrate-groups # Migrate legacy group config to new format
# Legacy aliases (backward-compatible, map to commands above)
# list-allowed-groups, add-allowed-group, remove-allowed-group → list-groups, add-group, remove-group
# list-smart-groups, add-smart-group, remove-smart-group → list-groups, add-group, remove-group
# enable-group-whitelist, disable-group-whitelist → set-group-policy allowlist|open
# list-whitelist, add-whitelist, remove-whitelist → list-dm-allow, add-dm-allow, remove-dm-allow
# enable-whitelist, disable-whitelist → set-dm-policy allowlist|open
After changes, restart: pm2 restart zylos-lark
Downloading Media by Resource Key
In smart group mode, images and files sent without @mention are logged with
metadata only (image_key/file_key). Use download.js to fetch them on demand:
# Download image
node ~/zylos/.claude/skills/lark/scripts/download.js image <message_id> <image_key>
# Download file
node ~/zylos/.claude/skills/lark/scripts/download.js file <message_id> <file_key> [filename]
# Examples:
node ~/zylos/.claude/skills/lark/scripts/download.js image om_xxx img_v3_xxx
node ~/zylos/.claude/skills/lark/scripts/download.js file om_xxx file_v3_xxx report.pdf
The keys come from context messages like [image, image_key: xxx, msg_id: xxx]
or [file: name.pdf, file_key: xxx, msg_id: xxx].
Output: local file path on success, error message on failure.
Config Location
- Config:
~/zylos/components/lark/config.json - Logs:
~/zylos/components/lark/logs/ - Media:
~/zylos/components/lark/media/
Lark Setup
1. Credentials
Add to ~/zylos/.env:
LARK_APP_ID=your_app_id
LARK_APP_SECRET=your_app_secret
Get App ID and App Secret from your app's Credentials page: open.larksuite.com/app
2. Console Configuration
In the Lark developer console (open.larksuite.com/app):
- Enable Bot capability: Add capabilities → Bot (添加应用能力 → 机器人)
- Subscribe to events: Event subscriptions → Add
im.message.receive_v1 - Set Request URL: Event subscriptions → Request URL →
https://<your-domain>/lark/webhook(the path is defined byhttp_routesin SKILL.md)
3. Event Security
Lark provides two security mechanisms for webhook events.
Verification Token (REQUIRED) — validates that requests come from Lark. The service will refuse to start without it.
In the console: Event subscriptions → Verification Token. Add to config:
{
"bot": {
"verification_token": "your_verification_token_from_lark"
}
}
Encrypt Key — encrypts event payloads using AES-256-CBC:
In the console: Event subscriptions → Encrypt Key. Add to config:
{
"bot": {
"encrypt_key": "your_encrypt_key_from_lark"
}
}
Both can be set together:
{
"bot": {
"verification_token": "your_token",
"encrypt_key": "your_key"
}
}
Cloudflare Users
If your domain is behind Cloudflare proxy with Flexible SSL mode, Caddy's automatic HTTPS will cause a redirect loop. Options:
- Change Cloudflare SSL to Full: In Cloudflare dashboard → SSL/TLS → set mode to "Full" (recommended)
- Use HTTP mode: Run
zylos config set protocol http(automatically updates Caddyfile and reloads Caddy)
Owner
First user to send a private message becomes the owner (primary partner).
Owner bypasses DM policy and per-group/per-channel allowlist checks. However, groupPolicy: disabled blocks all group messages, including from the owner.
Owner info stored in config.json:
{
"owner": {
"bound": true,
"user_id": "xxx",
"open_id": "ou_xxx",
"name": "Howard"
}
}
Access Control
Permission Flow
DM and group access are controlled by independent top-level policies:
{
"dmPolicy": "owner", // "open" | "allowlist" | "owner"
"dmAllowFrom": ["ou_xxx"], // used when dmPolicy = "allowlist"
"groupPolicy": "allowlist", // "open" | "allowlist" | "disabled"
"groups": { ... } // per-group config (used when groupPolicy = "allowlist")
}
Private DM (dmPolicy):
- Owner? → always allowed
dmPolicy=open? → anyone can DMdmPolicy=owner? → only owner can DMdmPolicy=allowlist? → checkdmAllowFromlist; not in list → dropped
Group message (groupPolicy):
groupPolicy=disabled? → all group messages droppedgroupPolicy=open? → respond to @mentions from any groupgroupPolicy=allowlist? → only configured groups; unlisted groups → only owner passes, others dropped silently- Per-group
allowFromset? → only listed senders pass (owner always bypasses) - Smart group (mode:
smart)? → receive all messages, no @mention needed - Not smart? → only @mentions are processed, other messages are logged only
Key points:
- Owner bypasses allowlist checks only;
groupPolicy: disabledblocks all group messages, including from owner dmPolicyandgroupPolicyare fully independent — changing one never affects the other- Group access is controlled by
groupPolicy+groupsconfig + per-groupallowFrom - No user-level whitelist for groups; use per-group
allowFromif you need to restrict specific senders
Groups Config Format
Groups are stored in a map keyed by chat_id:
{
"groupPolicy": "allowlist",
"groups": {
"oc_xxx": {
"name": "研发群",
"mode": "mention",
"requireMention": true,
"allowFrom": [],
"historyLimit": 10,
"added_at": "2026-01-01T00:00:00Z"
},
"oc_zzz": {
"name": "核心群",
"mode": "smart",
"requireMention": false
}
}
}
mode:"mention"(respond to @mentions only) or"smart"(receive all messages)allowFrom: Optional list of user_id/open_id. Empty = all group members allowed."*"= wildcard.historyLimit: Optional per-group context message limit (overridesmessage.context_messages)
Markdown Card
Outgoing messages can be rendered as interactive cards with proper markdown formatting (code blocks, tables, headers, etc.):
{
"message": {
"useMarkdownCard": true
}
}
On by default. Note mobile display limitation: cards cannot be long-pressed to copy on mobile. Can be disabled via node admin.js set-markdown-card off. When enabled (cards cannot be long-pressed to copy on mobile). When enabled, messages containing markdown are auto-detected and sent as cards; plain text messages are sent normally. Falls back to plain text if card sending fails.
Group Context
When responding to @mentions in groups, the bot includes recent message context so Claude understands the conversation. Context is retrieved from logged messages since the last response.
Configuration in config.json:
{
"message": {
"context_messages": 10
}
}
Message logs are stored in ~/zylos/components/lark/logs/<chat_id>.log.
Service Management
pm2 status zylos-lark
pm2 logs zylos-lark
pm2 restart zylos-lark