Claude Lark Plugin

Chat with Claude Code in real time through Feishu (Lark). Local-file memory, scheduled jobs, rich media support.
How It Works
Feishu User ──> Feishu Open Platform ──WebSocket──> claude-lark-plugin (MCP Server) ──> Claude Code
<── reply / edit / react ──<
The plugin connects to Feishu via the Lark SDK WebSocket client, receives messages in real time, enriches them with memory context, and forwards them to Claude Code as an MCP channel. Claude's responses are sent back through the Feishu IM API.
Features
Messaging
- Direct messages (P2P) and group chats (responds to @bot mentions)
- Rich message types: text, post (rich text), image, file, audio, video, interactive cards
- Image auto-download: images are downloaded to a local inbox so Claude can see them directly
- Quoted reply support with automatic parent message fetching
- Attachment extraction (image, file, audio, video) with type-aware download
- Reaction events: user emoji reactions on bot messages are forwarded to Claude
Responding
- Text replies with automatic chunking for long messages (configurable limit)
- Card rendering: long or markdown-rich replies (headings, code blocks, tables, lists, bold, or > 500 chars) auto-render as Feishu cards. Pass
format='card' to force card, format='text' to force plain. Optional footer footnote supported
- Ack reaction: bot automatically reacts with an emoji (default: MeMeMe) on receive, removes it after replying
- Image and file uploads (images up to 10 MB, files up to 30 MB)
- Message editing (plain text and card markdown)
- Emoji reactions on any message
- Auto-chunking splits at paragraph, line, or word boundaries
Memory
- Three-layer architecture: Buffer, Episodic, and Semantic memory
- Auto-flush distillation from conversation buffer to episodic memory
- Local markdown-file storage under
~/.claude/channels/lark/memories/
- User profiles (tiered public/private since v0.10.0), chat episodes, thread episodes, and global skills
- Memory-enriched context injection on every incoming message, filtered by caller identity
Privacy & Security (v0.9.0+)
- Server-derived caller identity: sensitive tools (
save_memory, create_job, list_jobs, update_job, delete_job, what_do_you_know, forget_memory) resolve the calling user from the authenticated Feishu event stream, not from tool arguments — socially-engineered prompts cannot act on behalf of another user
- Memory transparency (v0.11.0+):
what_do_you_know lists what the bot has stored about the caller (filtered by current-chat visibility); forget_memory removes a specific line by hash. Optional promote_to_rule feeds corrections into privacy-rules.md — a self-learning loop that makes future misclassifications less likely
- Append-only audit log (v0.11.0+):
~/.claude/channels/lark/audit.log records every sensitive-tool invocation (timestamp / tool / caller / outcome / redacted args) so the operator can retrospectively inspect what was accessed on their machine
- Terminal skills default to redacted output (v0.11.0+):
/lark:jobs hides prompt bodies by default; verbose opt-in is required. Destructive operations require interactive confirmation
- Tiered profile memory (v0.10.0+): each user's profile is split into
public.md (visible to anyone who @mentions the user) and private.md (owner-only). Private-chat preferences no longer leak into groups via @mention injection
- L1/L2/L3 classification (v0.10.0+): hardcoded regex + keyword rules catch phones / credentials / sensitive Chinese keywords. Email is intentionally NOT in L1 — the plugin targets work-chat use cases where emails are commonly shared via signatures/directories; personal deployments can add their own "Always private" email rule to
privacy-rules.md. User-editable privacy-rules.md covers personal/org-specific cases; LLM handles the nuance. parseTieredProfile applies an L1 safety net over LLM output so misclassified credentials get forced to private
- Legacy-profile migration respects L2 rules (v0.11.1+): if the operator authors
privacy-rules.md before (or during) the upgrade, ## Always private phrases are applied as case-insensitive substring matches during migration — org-specific codenames, client names, and people mentions get routed to private.md even though L1 alone wouldn't flag them