折腾笔记[52]-使用kimi发送消息到matrix房间
摘要
在macOS上配置kimi-cli通过matrix-cli技能发送消息和文件到Matrix聊天房间.
声明
本文人类为第一作者, 龙虾为通讯作者.本文有AI生成内容.
matrix-cli技能
SKILL.md
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Matrix CLI Skill</title>
<style>
:root {
--bg: #f6f8fa;
--fg: #1f2328;
--border: #d1d9e0;
--code-bg: #f3f4f6;
--table-border: #d1d9e0;
--table-header-bg: #f6f8fa;
--table-row-alt: #ffffff;
--accent: #0969da;
--shadow: 0 1px 3px rgba(31,35,40,0.12), 0 8px 24px rgba(66,74,83,0.12);
}
* { box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
line-height: 1.6;
color: var(--fg);
background: #ffffff;
max-width: 900px;
margin: 0 auto;
padding: 40px 24px;
}
h1 { font-size: 2em; border-bottom: 1px solid var(--border); padding-bottom: .3em; margin-top: 0; }
h2 { font-size: 1.5em; border-bottom: 1px solid var(--border); padding-bottom: .3em; margin-top: 1.5em; }
h3 { font-size: 1.25em; margin-top: 1.5em; }
h4 { font-size: 1em; margin-top: 1.2em; }
code {
background: var(--code-bg);
padding: .2em .4em;
border-radius: 6px;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 85%;
}
pre {
background: var(--code-bg);
padding: 16px;
border-radius: 8px;
overflow-x: auto;
border: 1px solid var(--border);
}
pre code { background: none; padding: 0; font-size: 100%; }
table {
width: 100%;
border-collapse: collapse;
margin: 1em 0;
border: 1px solid var(--table-border);
border-radius: 8px;
overflow: hidden;
box-shadow: var(--shadow);
}
th, td {
padding: 10px 14px;
text-align: left;
border-bottom: 1px solid var(--table-border);
}
th { background: var(--table-header-bg); font-weight: 600; }
tr:nth-child(even) { background: var(--table-row-alt); }
ul, ol { padding-left: 1.5em; }
li { margin: .3em 0; }
strong { font-weight: 600; }
hr { border: 0; border-top: 1px solid var(--border); margin: 1.5em 0; }
.meta {
background: linear-gradient(135deg, #f0f4ff 0%, #f8faff 100%);
border: 1px solid #c8d6f5;
border-radius: 8px;
padding: 16px 20px;
margin-bottom: 24px;
box-shadow: var(--shadow);
}
.meta p { margin: 4px 0; color: #4a5568; font-size: .95em; }
.meta strong { color: #2b4c8c; }
</style>
<base target="_blank">
</head>
<body>
<div class="meta">
<p><strong>name:</strong> matrix-cli</p>
<p><strong>description:</strong> Send messages and files to Matrix chat rooms via CLI. Use when the user needs to (1) send text messages to Matrix rooms, (2) send images/files to Matrix rooms, (3) interact with Matrix servers from command line, or (4) automate Matrix messaging workflows.</p>
</div>
<h1>Matrix CLI Skill</h1>
<p>Send messages and files to Matrix chat rooms using a Python-based CLI tool.</p>
<h2>Quick Start</h2>
<p>Use the bundled script to send messages:</p>
<pre><code># Send text message
python scripts/matrix-cli.py \
-s http://xxx.qsbye.cn:xxx \
-u @username:xxx.qsbye.cn \
-t "ACCESS_TOKEN" \
-r "!ROOM_ID:xxx.qsbye.cn" \
-m "Hello World"
# Send file/image
python scripts/matrix-cli.py \
-s http://xxx.qsbye.cn:xxx \
-u @username:xxx.qsbye.cn \
-p "PASSWORD" \
-r "!ROOM_ID:xxx.qsbye.cn" \
-f /path/to/file.png</code></pre>
<h2>Authentication</h2>
<p>Two authentication methods supported:</p>
<p><strong>Default Account:</strong></p>
<ul><li>访问令牌: <code>你的令牌</code></li><li>用户名: <code>@ollama:xxx.qsbye.cn</code></li><li>密码: <code>你的密码</code></li><li>房间ID: <code>!你的id:xxx.qsbye.cn</code></li></ul>
<p><strong>Alternative Account:</strong></p>
<ul><li>访问令牌: <code>你的令牌</code></li><li>用户名: <code>@zeroclaw:xxx.qsbye.cn</code></li><li>密码: <code>你的密码</code></li></ul>
<ol><li><strong>Access Token</strong> (preferred for automation):</li></ol>
<p> ```bash</p>
<p> -t "YOUR_ACCESS_TOKEN"</p>
<p> ```</p>
<ol><li><strong>Password</strong> (generates new token):</li></ol>
<p> ```bash</p>
<p> -p "YOUR_PASSWORD"</p>
<p> ```</p>
<h2>Parameters</h2>
<table>
<tr><th>Flag</th><th>Description</th><th>Required</th></tr>
<tr><td><code>-s, --server</code></td><td>Matrix homeserver URL</td><td>Yes</td></tr>
<tr><td><code>-u, --user</code></td><td>User ID (@user:server)</td><td>Yes</td></tr>
<tr><td><code>-r, --room</code></td><td>Room ID (!room:server)</td><td>Yes</td></tr>
<tr><td><code>-t, --token</code></td><td>Access token</td><td>Token or password</td></tr>
<tr><td><code>-p, --password</code></td><td>Password</td><td>Token or password</td></tr>
<tr><td><code>-m, --message</code></td><td>Text message to send</td><td>Message, file, or --test</td></tr>
<tr><td><code>-f, --file</code></td><td>File path to send</td><td>Message, file, or --test</td></tr>
<tr><td><code>--test</code></td><td>Send "hello" test message</td><td>Optional</td></tr>
</table>
<h2>Common Patterns</h2>
<h3>Send Test Message</h3>
<pre><code>python scripts/matrix-cli.py -s SERVER -u USER -t TOKEN -r ROOM --test</code></pre>
<h3>Send Multiple Items</h3>
<p>Combine <code>-m</code> and <code>-f</code> to send both text and file in one command.</p>
<h3>Default Server Configuration</h3>
<p>For the server at <code>xx.qsbye.cn:xxx</code>:</p>
<ul><li>Server: <code>http://xxx.qsbye.cn:xxx </code></li><li>Test room: <code>!xxx:xxx.qsbye.cn</code></li></ul>
<h2>Dependencies</h2>
<p>Requires <code>matrix-nio</code> Python package:</p>
<pre><code>pip install matrix-nio</code></pre>
<h2>Script Location</h2>
<ul><li><strong>Script</strong>: <code>scripts/matrix-cli.py</code></li><li><strong>Shebang</strong>: <code>#!/home/qsbye/.venv/bin/python3</code></li></ul>
<p>Run directly: <code>./scripts/matrix-cli.py</code> (executable)</p>
<p>Or with Python: <code>python scripts/matrix-cli.py</code></p>
</body>
</html>
scripts/matrix-cli.py
#!/Users/workspace/Desktop/projects/ByeIO/software/exp323-kimi-skills/matrix-cli/.venv/bin/python3
"""Matrix CLI - Send messages and files to Matrix chat rooms."""
import argparse
import asyncio
import mimetypes
import os
import sys
from pathlib import Path
from nio import AsyncClient, UploadResponse
DEFAULT_SERVER = "http://xxx.qsbye.cn:xxx"
DEFAULT_USER = "@ollama:xxx.qsbye.cn"
DEFAULT_TOKEN = "你的令牌"
DEFAULT_ROOM = "!你的房间:xxx.qsbye.cn"
async def send_message(client, room_id, message):
"""Send a text message to a Matrix room."""
await client.room_send(
room_id=room_id,
message_type="m.room.message",
content={
"msgtype": "m.text",
"body": message,
},
)
print(f"Message sent to {room_id}")
async def send_file(client, room_id, file_path):
"""Send a file to a Matrix room."""
file_path = Path(file_path)
if not file_path.exists():
print(f"Error: File not found: {file_path}")
return False
mime_type, _ = mimetypes.guess_type(str(file_path))
if mime_type is None:
mime_type = "application/octet-stream"
with open(file_path, "rb") as f:
file_data = f.read()
upload_response, maybe_keys = await client.upload(
data_provider=lambda _429, _timeouts: file_data,
content_type=mime_type,
filesize=len(file_data),
filename=file_path.name,
)
if isinstance(upload_response, UploadResponse):
content = {
"msgtype": "m.file",
"body": file_path.name,
"url": upload_response.content_uri,
"info": {
"size": len(file_data),
"mimetype": mime_type,
},
}
# If image, use m.image type
if mime_type.startswith("image/"):
content["msgtype"] = "m.image"
await client.room_send(
room_id=room_id,
message_type="m.room.message",
content=content,
)
print(f"File sent: {file_path.name}")
return True
else:
print(f"Error uploading file: {upload_response}")
return False
async def main():
parser = argparse.ArgumentParser(description="Send messages/files to Matrix rooms")
parser.add_argument("-s", "--server", default=DEFAULT_SERVER, help="Matrix homeserver URL")
parser.add_argument("-u", "--user", default=DEFAULT_USER, help="User ID (@user:server)")
parser.add_argument("-r", "--room", default=DEFAULT_ROOM, help="Room ID (!room:server)")
parser.add_argument("-t", "--token", default=DEFAULT_TOKEN, help="Access token")
parser.add_argument("-p", "--password", help="Password (alternative to token)")
parser.add_argument("-m", "--message", help="Text message to send")
parser.add_argument("-f", "--file", help="File path to send")
parser.add_argument("--test", action="store_true", help="Send test message")
args = parser.parse_args()
if not args.message and not args.file and not args.test:
parser.print_help()
sys.exit(1)
client = AsyncClient(args.server, args.user)
try:
if args.token:
client.access_token = args.token
elif args.password:
response = await client.login(args.password)
if hasattr(response, "access_token"):
client.access_token = response.access_token
print(f"Logged in, token: {response.access_token}")
else:
print(f"Login failed: {response}")
return
else:
print("Error: Provide either --token or --password")
sys.exit(1)
if args.test:
await send_message(client, args.room, "Hello from matrix-cli! 👋")
if args.message:
await send_message(client, args.room, args.message)
if args.file:
await send_file(client, args.room, args.file)
finally:
await client.close()
if __name__ == "__main__":
asyncio.run(main())
运行效果
- 运行
python scripts/matrix-cli.py --test发送测试消息到默认房间 - 运行
python scripts/matrix-cli.py -m "自定义消息"发送文本消息 - 运行
python scripts/matrix-cli.py -f /path/to/file.png发送文件或图片

在macOS上配置kimi-cli通过matrix-cli技能发送消息和文件到Matrix聊天房间.
浙公网安备 33010602011771号