open.larksuite.com, Feishu at open.feishu.cn. They share the same SDK, message types, and event protocol. A Custom App is registered with one of them; pick the region you need at setup time.
Craft Agent uses the official @larksuiteoapi/node-sdk’s long-connection (WebSocket) mode — no public webhook URL or reverse tunnel needed. Same lifecycle as the Telegram adapter, just talking to Lark instead.
Two ways to set up
Recommended: Built for agents quick-create
On the Open Platform’s app-creation page, look for the “Built for agents. Ready to connect” banner with a Create button. Clicking it produces an app with the right permissions and event settings pre-configured — you skip the scope toggles and event-subscription steps entirely.Then jump straight to Connect in the App below to paste your App ID and Secret into Craft Agent.
Manual setup
Create a Custom App and configure scopes + events yourself. Useful if the agent banner isn’t visible in your tenant’s UI yet, or if you want explicit control over which permissions you grant.Full walkthrough below.
You still copy App ID + Secret either way. Lark/Feishu issue per-tenant credentials regardless of which create flow you use — the agent quick-create path saves you the permissions and events configuration, not the credential paste.
Create an App
1
Open the Open Platform
- Lark: open.larksuite.com
- Feishu: open.feishu.cn
2
Create a Custom App
Developer Console → Create Custom App. Set a name and icon.
3
Copy App ID and App Secret
On the app’s home page, copy the App ID (starts with
cli_) and the App Secret (32-character string). Treat the secret like a password.4
Enable required scopes
Under Permissions & Scopes, enable:
im:message— read message eventsim:message.group_at_msg— receive @mentions in groupsim:message:send_as_bot— send messages as the bot
5
Subscribe to message events in long-connection mode
Under Events & Callbacks, set the delivery method to Long connection mode (NOT webhooks). Then add a subscription for:
im.message.receive_v1
6
Publish the app version
Lark/Feishu requires you to publish a version (or use the dev tenant) before the bot can receive messages. Submit for review or activate the dev mode.
Connect in the App
1
Open Settings → Messaging in Craft Agent
You’ll see a third tile alongside Telegram and WhatsApp: Lark / Feishu.
2
Click Connect
A dialog opens with a region selector and two secret fields.
3
Pick your region
Lark (international) uses
open.larksuite.com; Feishu (China) uses open.feishu.cn. A bot belongs to one or the other — they’re separate ecosystems.4
Paste App ID + App Secret, then Test
Craft Agent exchanges them for a
tenant_access_token. On success the button shows a green check; on failure you’ll see Lark’s error message verbatim.5
Click Save
Credentials are stored in your workspace keychain and the Lark adapter starts the long-connection socket.
First Conversation
1
Find your bot in Lark / Feishu
Search for the bot by name in your Lark/Feishu app. DM it.
2
Send /pair
The bot replies with a usage hint.
3
Generate a code in Craft Agent
Open any session’s menu → Pair with Messaging → Lark. Copy the 6-digit code.
4
Type the pair command in Lark
The bot confirms in chat and the binding is created.
5
Send any message
Craft Agent receives it. The assistant’s response streams back into the same chat.
Group chats
In groups, the bot only receives messages where it’s @mentioned — that’s Lark’s default scope behaviour forim:message.group_at_msg. Without an @mention, the event isn’t delivered server-side, so there’s nothing for the adapter to drop. Messages addressed to the bot work the same way as DMs.
Rich Text
The agent’s responses preserve common formatting when sent to Lark:- bold, italic,
strikethroughrender natively via Lark’spostmessage type [Links](https://example.com)are clickable- Fenced code blocks (
```python ... ```) render with their language tag - Paragraph breaks are preserved
- Headers (
#,##, …) — Larkposthas no header element - Bullet / numbered lists — bullets appear as plain
•or1.prefixes - Tables — rendered as space-padded plain text
- Inline
`code`— rendered as bold text (Larkposthas no inline-code element)
Rich Cards
When the agent needs your input mid-flow (e.g. plan approval), buttons render as a Lark interactive card with native action buttons. Tap a button — the agent receives the press and proceeds. The card auto-clears once the choice is processed. Phase-2 limits:- Up to 10 buttons per card
- Button labels truncated at 30 characters
Attachments
Both directions are supported in DMs and group @mentions:- Inbound: send images and files to the bot. They’re downloaded server-side and made available to the agent under the session’s working directory.
- Outbound: the agent can send images and documents back. Captions accompanying a file are sent as a follow-up text message (Lark API can’t combine caption + file in a single message).
- Max attachment size: 20 MB (matches the renderer’s read limit)
- Audio, video, and stickers are dropped with a polite “unsupported attachment” log line
Limitations
- Lark and Feishu are separate domains — a bot belongs to one or the other, not both
- Bot only sees @mentions in groups (Lark’s default
im:message.group_at_msgscope; cannot be widened without enterprise approvals) - Edits to messages older than 24 hours are silently dropped (Lark API limit)
- Markdown headers, lists, and tables are rendered as plain text within
post(Larkposthas no native equivalents)
Troubleshooting
- “Bot doesn’t receive messages” — verify
im:messageis enabled andim.message.receive_v1is subscribed under Events & Callbacks. Double-check the delivery mode is Long connection, not webhooks. - “Connection failed during Test” — if the App Secret was regenerated in the Open Platform, copy the new value. If you switched the app’s tenant, the old credentials are revoked.
- “Bot received my DM but ignores my group message” — bot needs the
im:message.group_at_msgscope, AND the message must @mention the bot. - “Cards arrive but button presses don’t reach the agent” — confirm the app is published (or the tenant is in dev-mode). Cards from a draft app can render but card-action callbacks won’t fire.
- “
lark_send_card_failedwithcode: 230099andunknown property, property: elements” — happens when something downstream emits a schema-1.0 card payload under aschema: '2.0'envelope. The fix is to wrap the card body underbody: { elements: [...] }(already in place; this note exists for anyone forking the adapter). - “Can’t send files larger than ~20 MB” — that’s the adapter’s hard cap. Compress or split before sending.
- Logs:
~/.craft-agent/logs/messaging-gateway.log— search forcomponent:"lark-adapter"orevent:"lark_*".