Install
$ agentstack add skill-wangyendt-wayne-skills-lark-custom-bot ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Pywayne Lark Custom Bot - Webhook Message Sender
Overview
LarkCustomBot is a webhook-based Feishu (Lark) bot wrapper designed for one-way message pushing. It's ideal for scenarios where you only need to send messages to Feishu groups without listening for incoming messages or managing complex interactions.
Key Characteristics:
- Lightweight, simple webhook-based architecture
- No event subscription or listening capabilities
- Perfect for alerts, notifications, scheduled tasks
- Supports signature verification for security
When to Use LarkCustomBot:
- Push-only scenarios (notifications, alerts, reports)
- Simple scheduled tasks sending updates
- Quick setup without event subscription configuration
- Don't need message replies, reactions, or chat management
When to Use LarkBot Instead:
- Need to listen and reply to messages
- Require message lifecycle management (recall, edit, reactions)
- Need chat management (members, admins, announcements)
- Interactive features like button callbacks
Installation
pip install pywayne
Quick Start
from pywayne.lark_custom_bot import LarkCustomBot
# Initialize bot with webhook
bot = LarkCustomBot(
webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxx"
)
# Send simple text message
bot.send_text("Hello, Feishu!")
# Send text with @all mention
bot.send_text("Important announcement!", mention_all=True)
LarkCustomBot Class
Constructor
bot = LarkCustomBot(
webhook: str, # Required: Webhook URL from Feishu group bot settings
secret: str = '', # Optional: Signing secret for request verification
bot_app_id: str = '', # Optional: App ID for image upload authentication
bot_secret: str = '' # Optional: App secret for image upload authentication
)
Parameters:
webhook: Webhook URL obtained from Feishu group custom bot settingssecret: Signing secret for signature verification (enhances security)bot_app_id: Required forupload_image()andupload_image_from_cv2()bot_secret: Required forupload_image()andupload_image_from_cv2()
Note: Image upload requires app credentials (bot_app_id and bot_secret) because it uses Feishu's OpenAPI authentication, not webhook.
Core Methods
send_text - Send Text Message
Send plain text message with optional @all mention.
bot.send_text(text: str, mention_all: bool = False) -> None
Parameters:
text: Message text contentmention_all: Whether to @all users in the group (defaultFalse)
Examples:
# Simple text
bot.send_text("Daily backup completed successfully")
# With @all mention
bot.send_text("System maintenance at 23:00 tonight", mention_all=True)
# Multi-line text
bot.send_text("""
Deployment completed:
- API: v1.2.3
- Frontend: v2.4.5
- Database migration: done
""")
# With HTML-like formatting (supported in text messages)
bot.send_text("Bold text and italic text")
send_post - Send Rich Text Post
Send rich text message with structured content including text, links, @mentions, and images.
bot.send_post(
content: List[List[Dict]], # 2D list of content elements
title: Optional[str] = None # Optional post title
) -> None
Parameters:
content: 2D list structure where:- Outer list = multiple lines
- Inner list = multiple elements in the same line
title: Post title displayed at the top
Content Structure:
content = [
[element1, element2], # Line 1 with 2 elements
[element3], # Line 2 with 1 element
[element4, element5], # Line 3 with 2 elements
]
Basic Example:
from pywayne.lark_custom_bot import (
LarkCustomBot,
create_text_content,
create_link_content,
create_at_content,
create_image_content
)
bot = LarkCustomBot(
webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
bot_app_id="cli_xxx",
bot_secret="sec_xxx"
)
# Upload image first
image_key = bot.upload_image("/tmp/report.png")
# Construct post content
content = [
# Line 1: Title text
[create_text_content("Daily Report", unescape=False)],
# Line 2: Link
[create_link_content(href="https://dashboard.example.com", text="View Dashboard")],
# Line 3: @mention
[create_at_content(user_id="all", user_name="Everyone")],
# Line 4: Image
[create_image_content(image_key=image_key, width=400, height=300)],
# Line 5: Multiple elements in one line
[
create_text_content("Status: "),
create_text_content("✅ Completed", unescape=True)
]
]
bot.send_post(content, title="Daily Operations Report")
send_image - Send Image Message
Send image message using image key.
bot.send_image(image_key: str) -> None
Note: Must upload image first using upload_image() or upload_image_from_cv2().
Example:
# Upload and send local image
image_key = bot.upload_image("/path/to/chart.png")
bot.send_image(image_key)
# Upload from OpenCV image
import cv2
import numpy as np
img = cv2.imread("/path/to/image.jpg")
# Process image...
image_key = bot.upload_image_from_cv2(img)
bot.send_image(image_key)
send_interactive - Send Interactive Card
Send interactive card message with buttons, forms, or other interactive elements.
bot.send_interactive(card: Dict) -> None
Parameters:
card: Interactive card JSON structure following Feishu card schema
Example: Simple Notification Card:
card = {
"config": {"wide_screen_mode": True},
"header": {
"title": {"tag": "plain_text", "content": "Approval Required"},
"template": "red"
},
"elements": [
{
"tag": "markdown",
"content": "**Ticket #1234** is waiting for approval"
},
{
"tag": "action",
"actions": [
{
"tag": "button",
"text": {"tag": "plain_text", "content": "View Details"},
"type": "primary",
"url": "https://example.com/ticket/1234"
}
]
}
]
}
bot.send_interactive(card)
Example: Status Card with Multiple Elements:
card = {
"header": {
"title": {"tag": "plain_text", "content": "Build Status"},
"template": "blue"
},
"elements": [
{
"tag": "div",
"text": {"tag": "lark_md", "content": "**Build #456** completed"}
},
{
"tag": "hr"
},
{
"tag": "div",
"fields": [
{"is_short": True, "text": {"tag": "lark_md", "content": "**Duration**\n3m 42s"}},
{"is_short": True, "text": {"tag": "lark_md", "content": "**Status**\n✅ Success"}}
]
}
]
}
bot.send_interactive(card)
sendsharechat - Share Chat
Share a chat group as a card.
bot.send_share_chat(share_chat_id: str) -> None
Example:
# Share a group chat
bot.send_share_chat("oc_a1b2c3d4e5f6g7h8")
Image Upload Methods
upload_image - Upload from File Path
Upload local image file to Feishu and get image key.
image_key = bot.upload_image(file_path: str) -> str
Parameters:
file_path: Local path to image file
Returns:
str: Image key if successful, empty string if failed
Example:
# Upload and send
image_key = bot.upload_image("/tmp/screenshot.png")
if image_key:
bot.send_image(image_key)
else:
print("Image upload failed")
Requirements:
- Must set
bot_app_idandbot_secretin constructor - File must exist and not be empty
- Supported formats: JPEG, PNG, GIF, etc.
uploadimagefrom_cv2 - Upload from OpenCV Image
Upload image directly from OpenCV/numpy array.
image_key = bot.upload_image_from_cv2(cv2_image: np.ndarray) -> str
Parameters:
cv2_image: OpenCV image array (np.ndarray)
Returns:
str: Image key if successful, empty string if failed
Example: Generate and Send Visualization:
import cv2
import numpy as np
# Create visualization
img = np.zeros((400, 600, 3), dtype=np.uint8)
cv2.putText(img, "TEST PASSED", (80, 220), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 5)
cv2.rectangle(img, (50, 50), (550, 350), (0, 255, 0), 3)
# Upload and send directly
image_key = bot.upload_image_from_cv2(img)
bot.send_image(image_key)
Example: Process and Send:
import cv2
# Read and process image
original = cv2.imread("/input/image.jpg")
gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)
edges_colored = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
# Upload processed result
image_key = bot.upload_image_from_cv2(edges_colored)
bot.send_image(image_key)
Use Cases:
- Algorithm result visualization
- Real-time monitoring screenshots
- Computer vision processing results
- Generated charts and plots
Content Builder Functions
These module-level functions help construct send_post() content elements.
createtextcontent
Create text content element.
create_text_content(text: str, unescape: bool = False) -> Dict
Parameters:
text: Text contentunescape: Whether to unescape HTML entities (defaultFalse)
Example:
text_elem = create_text_content("Normal text")
unescaped_elem = create_text_content("Bold", unescape=True)
createlinkcontent
Create hyperlink content element.
create_link_content(href: str, text: str) -> Dict
Parameters:
href: URL linktext: Display text for the link
Example:
link_elem = create_link_content("https://www.feishu.cn", "Visit Feishu")
createatcontent
Create @mention content element.
create_at_content(user_id: str, user_name: str) -> Dict
Parameters:
user_id: User ID or "all" for @everyoneuser_name: Display name for the mention
Examples:
# @specific user
at_user = create_at_content("ou_xxxxxxxxxxxx", "John Doe")
# @everyone
at_all = create_at_content("all", "Everyone")
createimagecontent
Create image content element.
create_image_content(
image_key: str,
width: Optional[int] = None,
height: Optional[int] = None
) -> Dict
Parameters:
image_key: Image key obtained from uploadwidth: Optional image display width in pixelsheight: Optional image display height in pixels
Example:
img_elem = create_image_content(
image_key="img_v3_xxxxxxxxxxxx",
width=500,
height=300
)
Common Usage Scenarios
Scenario 1: Simple Scheduled Notification
from pywayne.lark_custom_bot import LarkCustomBot
bot = LarkCustomBot(webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx")
# Daily morning notification
bot.send_text("Good morning! Daily inspection started at 09:00")
Scenario 2: Rich Announcement with Multiple Elements
from pywayne.lark_custom_bot import (
LarkCustomBot,
create_text_content,
create_link_content,
create_at_content
)
bot = LarkCustomBot(webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx")
content = [
[create_text_content("Release v1.2.0 Completed", unescape=False)],
[create_text_content("New Features:", unescape=False)],
[create_text_content(" • API optimization")],
[create_text_content(" • Bug fixes")],
[create_link_content("https://example.com/release-notes", "View Release Notes")],
[
create_at_content("all", "Everyone"),
create_text_content(" please review and confirm.")
]
]
bot.send_post(content, title="Release Announcement")
Scenario 3: Upload and Send Local Image
bot = LarkCustomBot(
webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
bot_app_id="cli_xxx",
bot_secret="sec_xxx"
)
# Upload image file
image_key = bot.upload_image("/tmp/performance_chart.png")
if image_key:
bot.send_image(image_key)
else:
bot.send_text("Failed to upload image")
Scenario 4: OpenCV Processing Pipeline
import cv2
import numpy as np
bot = LarkCustomBot(
webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
bot_app_id="cli_xxx",
bot_secret="sec_xxx"
)
# Generate test result visualization
img = np.zeros((400, 600, 3), dtype=np.uint8)
# Add test status
status = "PASS"
color = (0, 255, 0) # Green
cv2.putText(img, status, (120, 220), cv2.FONT_HERSHEY_SIMPLEX, 3, color, 6)
cv2.rectangle(img, (30, 30), (570, 370), color, 3)
# Upload OpenCV image directly
image_key = bot.upload_image_from_cv2(img)
bot.send_image(image_key)
Scenario 5: Combined Post with Text, Image, and Links
from pywayne.lark_custom_bot import (
LarkCustomBot,
create_text_content,
create_link_content,
create_image_content
)
bot = LarkCustomBot(
webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
bot_app_id="cli_xxx",
bot_secret="sec_xxx"
)
# Upload dashboard screenshot
image_key = bot.upload_image("/tmp/dashboard.png")
# Construct rich post
content = [
[create_text_content("Monitoring Snapshot:")],
[create_image_content(image_key, width=600, height=400)],
[create_link_content("https://grafana.example.com", "Open Full Dashboard")],
[create_text_content("Generated at: 2026-03-12 14:30:00")]
]
bot.send_post(content, title="Daily Monitoring Report")
Scenario 6: Interactive Approval Card
card = {
"config": {"wide_screen_mode": True},
"header": {
"title": {"tag": "plain_text", "content": "Approval Request"},
"template": "orange"
},
"elements": [
{
"tag": "markdown",
"content": "**Deployment Request #5678**\n\nEnvironment: Production\nRequested by: John Doe"
},
{
"tag": "hr"
},
{
"tag": "action",
"actions": [
{
"tag": "button",
"text": {"tag": "plain_text", "content": "Approve"},
"type": "primary",
"url": "https://example.com/approve/5678"
},
{
"tag": "button",
"text": {"tag": "plain_text", "content": "Reject"},
"type": "danger",
"url": "https://example.com/reject/5678"
}
]
}
]
}
bot.send_interactive(card)
Scenario 7: Secure Sending with Signature Verification
# Initialize with signature secret
bot = LarkCustomBot(
webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
secret="your_signing_secret"
)
# All messages will automatically include timestamp and signature
bot.send_text("This message is signed for security")
Scenario 8: Multi-Step Operations Report
from pywayne.lark_custom_bot import LarkCustomBot, create_text_content, create_link_content
bot = LarkCustomBot(
webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
)
# Step 1: Start notification
bot.send_text("🔄 Nightly inspection started...")
# Perform tasks...
# ... inspection logic ...
# Step 2: Send detailed report
content = [
[create_text_content("✅ Nightly Inspection Completed", unescape=True)],
[create_text_content("")],
[create_text_content("Results:")],
[create_text_content(" • Database backup: OK")],
[create_text_content(" • Log cleanup: OK")],
[create_text_content(" • Health check: OK")],
[create_text_content(" • Disk usage: 42%")],
[create_text_content("")],
[create_link_content("https://monitoring.example.com", "View Detailed Report")]
]
bot.send_post(content, title="Inspection Report - 2026-03-12")
Scenario 9
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: wangyendt
- Source: wangyendt/wayne-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.