Unofficial Python SDK for the Weixin ClawBot/iLink channel protocol.
Project description
weixin-channel-sdk
Unofficial Python SDK for the Weixin ClawBot/iLink channel protocol.
This project is community-maintained and is not affiliated with, endorsed by, or supported by Tencent or Weixin/WeChat. It is intended for developers who already have authorized ClawBot/iLink access and want to build custom Python integrations.
The current implementation covers the known protocol surface needed for custom developer integrations:
- QR-code login
- QR login progress events for custom UIs
- token/session persistence
- multi-account session index
getupdateslong pollingsendmessagetext replies- text chunking
- persistent message de-duplication
- cursor persistence
- typing indicator helpers
- typing ticket cache
- media upload via Weixin CDN
- optional thumbnail upload for images/videos
- inbound media download/decrypt
- optional voice conversion hook for downloaded voice media
- simple callback runner for custom tools or Claude/Codex bridges
- optional access policy for users/groups/rate limits
- bot runtime events for TUI/Web/trace integrations
- JSONL event writer and redaction helper
- Markdown-to-plain-text cleanup for model replies
- synchronous wrapper for simple scripts
- persisted session pause after token expiration
- configurable retry, media limits, auto-thumbnail, and concurrency modes
OpenClaw runtime adapters are intentionally not included. This package is a pure Weixin channel SDK for direct developer integration.
Install
pip install weixin-channel-sdk
For local development:
uv pip install -e forks/weixin-channel-sdk
Minimal Echo Bot
import asyncio
from weixin_channel import WeixinBot, WeixinClient
async def main() -> None:
client = WeixinClient.from_default_store()
if not client.session:
client = await WeixinClient.login()
bot = WeixinBot(client)
@bot.on_text
async def echo(msg):
return f"echo: {msg.text()}"
await bot.run_forever()
asyncio.run(main())
Access Policy
from weixin_channel import AccessPolicy, RateLimit, WeixinBot
policy = AccessPolicy(
allow_users={"your_user_id@im.wechat"},
group_enabled=True,
allow_groups={"group_id"},
group_trigger_prefixes=("/", "@bot"),
user_rate_limit=RateLimit(max_events=6, window_seconds=60),
)
bot = WeixinBot(client, policy=policy, typing=True, send_error_notice=True)
@bot.on_event
async def trace(event):
print(event.type, event.data)
Persist events as JSONL:
from weixin_channel import JsonlEventWriter
writer = JsonlEventWriter("./weixin-events.jsonl")
@bot.on_event
async def trace(event):
writer.write(event.type, message=event.message, **event.data)
Examples
python examples/echo_bot.py --login
python examples/echo_bot.py
python examples/claude_bridge.py
python examples/media_bot.py
python examples/sync_echo.py
CLI Login
After installation, use the CLI to save a Weixin session:
weixin-channel login
Useful options:
weixin-channel login --state-dir ~/.weixin-channel
weixin-channel login --no-qr
weixin-channel login --timeout 480 --max-refreshes 3
The command stores the session token in the SDK state directory and prints the account id, user id, and base URL after successful authorization.
Safety
This package assumes you are using a Weixin account and ClawBot/iLink access that you are authorized to use. Do not use it for unsolicited messaging, scraping, account abuse, bypassing client restrictions, or unsafe tool execution.
For any tool/agent bridge, configure an allowlist before enabling tools that can read files, run commands, mutate systems, or access private data.
Media
Send a local file:
await client.reply_media_file(msg, "/absolute/path/to/report.pdf", text="Report attached.")
await client.reply_media_file(msg, "/absolute/path/to/image.png", thumb_path="/absolute/path/to/thumb.jpg")
await client.reply_remote_media(msg, "https://example.com/image.png", text="Downloaded and sent.")
Download media from an inbound message:
downloads = await client.download_message_media(msg, dest_dir="./downloads")
for item in downloads:
print(item.path, item.mime_type)
Media support follows the original Weixin channel behavior:
- files are AES-128-ECB encrypted before CDN upload
getuploadurlis used to get the upload parameter- CDN response header
x-encrypted-paramis used as the downstream media reference - inbound media is downloaded from CDN and decrypted when an AES key is present
Voice conversion can be supplied as a hook:
async def silk_to_wav(raw: bytes) -> bytes:
...
downloads = await client.download_message_media(msg, dest_dir="./downloads", voice_converter=silk_to_wav)
Login Events
For a custom TUI/Web UI:
async for event in WeixinClient.login_events():
if event.type == "qrcode":
print(event.qrcode_url)
elif event.type == "connected":
print(event.session.account_id)
Sync Wrapper
from weixin_channel import SyncWeixinClient
with SyncWeixinClient.from_default_store() as wx:
for msg in wx.iter_messages():
wx.reply_text(msg, f"echo: {msg.text()}")
Configuration Objects
from weixin_channel import ConcurrencyConfig, MediaConfig, RetryConfig, SessionGuardConfig, WeixinClient
client = WeixinClient.from_default_store()
client.retry = RetryConfig(max_consecutive_failures=3)
client.session_guard = SessionGuardConfig(pause_on_expired=True, pause_seconds=3600)
client.media = MediaConfig(auto_thumbnail=True, thumbnail_size=(320, 320))
client.concurrency = ConcurrencyConfig(mode="per-conversation", max_concurrency=4)
Recommended runtime modes:
serial: safest; one message at a time.per-conversation: parallel across users/groups, ordered within each conversation.concurrent: fastest; no per-conversation ordering guarantee.
For long-running bridges, seen_flush_interval controls how often processed
message ids are flushed to disk. Larger values reduce I/O; smaller values reduce
duplicate risk after crashes.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file weixin_channel_sdk-0.1.0.tar.gz.
File metadata
- Download URL: weixin_channel_sdk-0.1.0.tar.gz
- Upload date:
- Size: 31.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6f61527f2dc2d46aeafee7d9a7c9347562d7b93779766a0a99ee4a4aa6dd3a5
|
|
| MD5 |
12c049b9e6c4a6ae3e914c35e7230711
|
|
| BLAKE2b-256 |
5fa6adee3fd481d53b63f311a80eb410c769827a05e805a693ad19a4e367bc92
|
File details
Details for the file weixin_channel_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: weixin_channel_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d26f9cffcac5e82dbcb032b9359725422df216de21ce210a3766c50afd0914cd
|
|
| MD5 |
565f5eec5612394a8b782555fd57d4e6
|
|
| BLAKE2b-256 |
02b6f374281e9840c5e1c06b2334fd97d9a2eccfd30ec34626ce4d4ab05bb8e9
|