Install
openclaw skills install claw-lark-patchesRe-apply custom patches to claw-lark plugin dist files after updates. Use when claw-lark plugin is updated/reinstalled and custom behaviors (requireMention filtering, reply_in_thread, thread-based replies) stop working. Also use when debugging Lark message routing issues.
openclaw skills install claw-lark-patchesclaw-lark is a compiled plugin — we patch dist files directly. Every plugin update wipes these patches. This skill documents exactly what to change and provides an auto-apply script.
bash scripts/apply-patches.sh
Then restart gateway: openclaw gateway restart
Four files are patched:
Problem 1: message(send, lark, "oc_xxx") returns "Unknown target" because claw-lark has no messaging.targetResolver.looksLikeId. The core doesn't recognize oc_/ou_/on_ as valid IDs and falls through to directory lookup which fails.
Fix: Add messaging property to larkPlugin export:
looksLikeLarkId, normalizeLarkTarget from ./utils.jsmessaging.targetResolver.looksLikeId using existing looksLikeLarkId()messaging.normalizeTarget using existing normalizeLarkTarget()Problem 2: outbound.sendText gets { cfg, to, accountId } from core but expects { account, recipientId }. The account object is undefined → "Cannot read properties of undefined (reading 'appId')".
Fix: All 5 outbound methods (sendText, sendMedia, downloadMedia, addReaction, removeReaction) add:
const account = args.account ?? resolveAccount(args.cfg, args.accountId ?? "default");
const recipientId = args.recipientId ?? args.to;
Location: routeMessage() function, after parseMessage(event) and the log line.
What: In group chats, skip messages that don't @mention our bot.
Key facts:
event.message is the correct path (NOT event.event.message)message.mentions contains mention data with id.open_idBOT_OPEN_ID env var when running apply-patches.shuser_id (empty string) — cannot use !user_id to detect "is it me"@_user_N text placeholders appear for ALL @'d bots, not just ours — don't use regex matchparsed.text.includes("@" + BOT_NAME) (set via BOT_NAME env var)Location: Inside dispatchReplyWithBufferedBlockDispatcher deliver callback.
What:
replyToId = payload.replyToId || parsed.threadId || parsed.messageId (always have a value)client.im.message.reply() with reply_in_thread: true instead of client.im.message.create() with root_idKey facts:
root_id on create only associates with existing thread, does NOT create new threadreply_in_thread: true on reply API creates a new threadLocation: sendTextMessage() function.
What: When threadId is provided, use client.im.message.reply() instead of client.im.message.create().
Location: sendMessageLark() and sendCardLark() reply branches.
What: Add reply_in_thread: true to data object in client.im.message.reply() calls.
After applying patches and restarting gateway:
references/patch-details.md — Full code diffs for each patch