Hermes 的 Milky QQ 平台适配器
让 Hermes 进入 QQ 私聊和群聊,成为一个会判断何时回应的 AI 参与者:
- 接收消息,并识别提及、引用、图片等上下文;
- 根据会话状态判断何时回应、何时保持沉默;
- 发送文本、@、引用、图片、语音、视频和文件;
- 提供群组、成员、文件和好友/入群请求等 QQ 能力。
Warning
当前仍有一类权限隔离尚未完成:
- ToolSpec: 25 个 QQ 工具没有独立的调用者和目标授权。模型、其他会话或 cron 可能查询无关群/好友,或执行禁言、踢人、撤回、退群、删好友、接受/拒绝请求等操作。
最低限度的安全配置:
MILKY_ALLOWED_CHATS只填写你能控制、成员可信且用途明确的会话;- 不要加入公开群、成员可随意加入的群或不受控私聊;
- 记住:该配置只限制入站会话,不等于 ToolSpec 或通用出站 sender 的授权;
- 留空表示允许所有会话进入。
示例:
MILKY_ALLOWED_CHATS=group:123456789,dm:987654321示例中的 ID 仅为占位值。
允许使用 dm:* 放行所有私聊,或使用 group:* 放行所有群聊;通配符只匹配对应的
dm:/group: 命名空间,也可以和具体 chat key 混用。
详细的模块职责、生命周期和行为契约见 ARCHITECTURE.md;主规范、未归档 change 和已归档 change 的测试证据见 openspec/。
插件适合希望把 Hermes 放进 QQ 私聊和群聊的场景:
- 自然参与: 根据提及、引用、关键词和会话状态,决定回应还是保持沉默;
- 多媒体消息: 接收图片等上下文,并发送文本、@、引用、图片、语音、视频和文件;
- QQ 信息能力: 查询群组、成员、文件和好友/入群请求,并提供部分 QQ 操作;
- 会话安全边界: 支持 chat 白名单、禁言状态同步、消息去重和有界历史缓冲。
运行环境:Python 3.13+、Hermes Gateway、Milky v1.3 服务和 httpx。Hermes 负责 Agent
队列及入站资源的下载、缓存和权限边界;本插件负责 Milky 适配和已声明的 QQ 能力。
hermes plugins install ByteColtX/hermes-plugin-milky --enable--enable 会在安装成功后直接启用插件并跳过确认提示。首次安装完成后,可以用下面的命令确认
插件状态:
hermes plugins list如果 hermes-plugin-milky 显示为 disabled,启用插件:
hermes plugins enable hermes-plugin-milky插件启用后,按配置完成 Milky 服务地址、access token 和可选白名单配置, 然后重启 Gateway:
hermes gateway restart已有安装需要拉取新版本时,执行:
hermes plugins update hermes-plugin-milky
hermes gateway restart更新插件代码或配置后都需要重启 Gateway,运行中的进程不会自动加载新的插件代码。
git clone https://github.com/ByteColtX/hermes-plugin-milky.git
cd hermes-plugin-milky
uv sync源码安装适合开发和调试。拉取新代码后重新同步环境,并重启 Gateway:
git pull
uv sync
hermes gateway restartImportant
启动前先完成下方的 Milky 配置,并确保启动 Hermes 的进程会加载 ~/.hermes/.env。
配置只在启动时读取;修改后需要重启 Gateway。
建议将环境变量集中保存到 ~/.hermes/.env:
MILKY_BASE_URL=http://127.0.0.1:3000
MILKY_ACCESS_TOKEN=<从安全凭证存储注入>
MILKY_ALLOWED_CHATS=group:123456789,dm:987654321
MILKY_SESSION_BUFFER_SIZE=20
MILKY_HOME_CHANNEL=group:123456789
# MILKY_MAX_LOCAL_MEDIA_BYTES=33554432
# MILKY_WILL_POLICY=<JSON 字符串,见下方 Will policy>上面的 QQ/群号仅为合成示例。.env 只应保存在本机或安全的部署环境中,不要提交到版本库。
| 变量 | 必需 | 作用 |
|---|---|---|
MILKY_BASE_URL |
是 | Milky 服务基址;Action 使用 <base>/api/{action},事件流使用 <base>/event。远程部署请使用 HTTPS。 |
MILKY_ACCESS_TOKEN |
是 | Milky access token,只用于 Bearer 认证。 |
MILKY_ALLOWED_CHATS |
否 | 入站 chat key 白名单,支持具体 group:<群号>/dm:<QQ号> 以及 group:*/dm:*;通配符只匹配对应命名空间,可混用;留空表示允许所有会话进入。 |
MILKY_WILL_POLICY |
否 | 决定消息等待(wait)或触发(trigger)的嵌套 JSON 配置。 |
MILKY_SESSION_BUFFER_SIZE |
否 | wait 历史消息上限,默认 20;设为 0 可关闭历史缓冲。 |
MILKY_HOME_CHANNEL |
否 | 系统消息和 cron 的默认目标;不参与入站白名单。 |
MILKY_MAX_LOCAL_MEDIA_BYTES |
否 | 出站本地资源原始字节数上限,默认 33554432(32 MiB),合法范围 8388608(8 MiB)至 33554432(32 MiB)。 |
消息 chat key 只接受 group:<十进制群号> 或 dm:<十进制 QQ 号>;白名单另支持完整的
group:* 和 dm:* 规则,temp 会话不会回退到其他目标。
下面的配置让群聊共享 session、在 Agent 忙碌时排队,并减少进度消息。请合并到
~/.hermes/config.yaml,保留已有的其他配置:
# 群友共享同一个 group:<群号> 会话
group_sessions_per_user: false
# 显式指定时区
timezone: Asia/Shanghai
# 长任务跟进
agent:
gateway_timeout: 1800
gateway_auto_continue_freshness: 3600
gateway_notify_interval: 180 # 每 3 分钟发一次“仍在处理”
session_stall_timeout: 300 # 排队且无进展 5 分钟时提醒
# 已确认主模型支持图片输入时,直接以内联图片交给主模型
image_input_mode: native
# 自定义 provider 的模型不会总能从模型目录自动识别视觉能力。
# 请在已有 model 配置中保留其他字段,并追加 supports_vision: true。
model:
supports_vision: true
# 群聊消息不要打断当前任务,排队处理
display:
busy_input_mode: queue
busy_ack_enabled: false
tool_progress_command: false
background_process_notifications: result
memory_notifications: off
platforms:
milky:
thinking_progress: off # 关闭“思考中”状态
tool_progress: off # 关闭工具进度
interim_assistant_messages: false
long_running_notifications: false # 可选:关闭“仍在处理”心跳
show_reasoning: false # 关闭最终回复中的思考摘要
streaming: false # 关闭本插件会话的流式输出
busy_ack_detail: false # 隐藏忙碌提示中的迭代/工具详情
busy_steer_ack_enabled: false
live_status: off # 关闭支持状态文本时的实时状态
# Slash Command 发送者门禁;命令名不带 /
platforms:
milky:
extra:
# 私聊管理员 QQ 号
allow_admin_from:
- "123456789"
# 私聊普通用户允许的只读命令
user_allowed_commands:
- "milky"
- "status"
- "context"
- "agents"
# 群聊管理员 QQ 号
group_allow_admin_from:
- "123456789"
# 群聊普通用户允许的只读命令
group_user_allowed_commands:
- "milky"
- "status"
- "context"
- "agents"
# 关闭后台自动复盘、自动写入记忆/Skill
auxiliary:
background_review:
enabled: true
memory:
memory_enabled: true
user_profile_enabled: true
nudge_interval: 20 # 每累计 20 个对话回合,触发一次自动记忆复盘,写入 MEMORY.md / USER.md
# 关闭自动建议创建 Skill
skills:
creation_nudge_interval: 0
# /goal 的最大自动续行轮数
goals:
max_turns: 20
# 推荐闲置 2 小时后重置,避免群聊上下文无限变旧
session_reset:
mode: idle
idle_minutes: 120
notify: false管理员可以执行所有已注册命令;普通用户默认可以执行 /help 和 /whoami,以及对应
user_allowed_commands 中列出的命令。私聊和群聊的管理员列表分别配置;某个作用域未配置
对应的 *_allow_admin_from 时,该作用域的 Slash Command 门禁不会启用。
建议只开放明确的只读命令。config、tools、model、sessions、cron、goal、
memory、suggestions 和 skills 等命令包含配置、会话、工具或任务状态变更,不建议加入普通用户白名单。
修改后需要重启 Gateway;配置只在启动时读取。
group_sessions_per_user: false 会让群友共享同一个 Hermes session;这适合群聊,但也意味着
群内消息会共同影响上下文。busy_input_mode: queue 让 Hermes 负责 queue、follow-up、
pending 和 interrupt/steer,插件不复制 Agent 执行队列。
Tip
平台显示设置必须放在 display.platforms.milky 下,不要放到全局 display 下。
如果不希望在 QQ 中看到自动压缩过程中的 413/compression 提示,可通过 CLI 关闭:
hermes config set compression.progress_notices false
hermes gateway restart该配置只隐藏常规压缩进度提示;压缩最终失败时的错误提示仍会保留。
image_input_mode: native 与 model.supports_vision: true 只应配置在已确认支持
OpenAI-compatible image_url 输入的主模型上。如果接口不支持原生图片输入,请移除这两项并
使用文本视觉路径。修改后重启 Gateway;日志应出现 Image routing: native。
建议使用 Hermes 的 holographic 记忆后端:
hermes config set memory.provider holographic它适合本地部署:数据保存在本地,不依赖付费云服务,并支持围绕实体召回长期上下文。修改后 重启 Gateway 使配置生效。
查看本地记忆库中的事实记录:
sqlite3 -header -column ~/.hermes/memory_store.db "SELECT fact_id, content, category, tags, trust_score, updated_at FROM facts ORDER BY fact_id;"Will 决定一条消息是先等待,还是交给 Hermes:
wait:放入当前 chat 的有界缓冲,暂不启动 Agent;trigger:先取出该 chat 的等待历史,再把当前消息交给 Hermes。
MILKY_WILL_POLICY.engine 只选择一套引擎。routing 和 willingness 共用消息特征、都输出
wait/trigger,但不会叠加运行。
| 引擎 | 决策方式 | 适合场景 |
|---|---|---|
routing(默认) |
当前消息命中规则就触发,结果确定 | 希望行为可预测、方便排查 |
willingness |
按 chat 维护分数,再按概率抽样 | 希望机器人偶尔参与、减少刷屏 |
routing 只看当前消息:不维护分数、不使用随机数。direct 等规则字段的值只能是 wait 或
trigger;keywords 不填写动作,命中时固定为 trigger。
| 字段 | 命中条件 | 默认行为 |
|---|---|---|
direct |
friend 私聊 | trigger |
mention |
直接 @Bot(只认 mention.user_id == self_id) |
trigger |
mentionAll |
@全体成员 | wait |
quote |
回复 Bot 的消息(只认 reply.data.sender_id == self_id) |
wait |
poke |
协议明确指向 Bot 的 poke | wait |
allMessage |
每条普通 friend/group 消息 | wait |
keywords |
正文包含任意一个非空关键词 | 空数组(不命中) |
一条消息可以同时命中多条规则;结果按 OR 合并,任一规则为 trigger 就触发,不会被其他
wait 抵消。图片没有独立 routing 规则,单独出现时仍由 allMessage 决定;
friend_nudge 和 group_nudge 在普通消息流程中保持 observe-only。
示例:只有私聊、@Bot 或包含“提醒”的消息进入 Hermes,其余消息等待:
{
"engine": "routing",
"routing": {
"allMessage": "wait",
"direct": "trigger",
"mention": "trigger",
"keywords": ["提醒"]
}
}willingness 不把每个信号直接设成 wait/trigger,而是为每个 chat 单独维护一个分数。
普通消息大致经过以下步骤:
- 先让分数按静默时间衰减;
- 根据文本、提及、reply、图片、私聊等特征增加分数;
- 命中
willingness.interestKeywords时提高本次增益倍率; - 命中
willingness.forceKeywords时直接得到trigger,否则在分数超过probabilityThreshold后换算成概率并抽样,得到wait或trigger。
因此,同一条消息可能因为当前分数或随机抽样不同而得到不同结果。willingness.interestKeywords
只控制加分倍率,不是确定性触发器;willingness.forceKeywords 才是包含即触发的
确定性规则。
directForce、mentionForce、quoteForce 可让对应信号跳过随机抽样,直接 trigger。
其中 mentionForce 只匹配直接提及当前 Bot(mention.user_id == self_id),quoteForce 只匹配
至少一个明确引用当前 Bot 的 reply(reply.data.sender_id == self_id);他人提及、mention_all、
here、他人引用和无法确认目标的引用都会继续走其他 force 条件或概率抽样。
forceKeywords 与这些 force 字段等价地跳过随机抽样,但不额外增加 score;两类关键词同时
命中时,interestKeywords 仍控制增益倍率,forceKeywords 决定最终触发。
mentionGain 只在直接提及当前 Bot 时加分;quoteGain 只在至少一个 reply 明确引用当前 Bot
时加分,has_reply 只保留 reply 存在性事实,不会单独产生 quoteGain;pokeGain 只在协议
确认 Bot 为接收者的 self-poke 时加分。非 Bot 或无法确认目标的 mention、reply、poke 均不产生
对应 gain。routing 的 quote 规则同样只认引用 Bot;friend_nudge 和 group_nudge 仍是
observe-only,不会直接创建 Agent turn。通过 Gate 且得到 trigger 后立即扣除一次
replyCost 参与成本,不等待 Hermes 接受、资源解析或最终发送;后续失败不回滚。等待、Gate
拒绝、命令、temp 和系统事件不会扣费。
示例:默认按概率参与,命中“提醒”时提高增益,命中“紧急”时直接触发:
{
"engine": "willingness",
"willingness": {
"interestKeywords": ["提醒"],
"forceKeywords": ["紧急"],
"keywordMultiplier": 1.2,
"directForce": false,
"mentionForce": false,
"quoteForce": false
}
}迁移时将旧的 willingness.keywords 改为 willingness.interestKeywords;旧字段不会被静默
兼容。需要包含即触发时再配置 willingness.forceKeywords,省略或配置为空数组表示关闭。
两者都只匹配规范化正文的直接子串,不支持正则、分词或隐式大小写转换。
- 不确定时使用默认的
routing;它最容易预测和调试; - 想切换到概率决策时,将
engine改为willingness,并配置willingness对象; - 完整配置可以同时保留两套参数,但运行时只使用
engine选中的一套; priority当前只保留在配置 schema 中,不参与 routing 优先级或 willingness 权重计算;- 旧的扁平字段、
routing.group、routing.image和routing.mentionHere不会被静默转换, 启动时会直接拒绝。
完整默认配置示例(包含两套引擎参数,默认折叠):
展开完整默认配置
{
"engine": "routing",
"routing": {
"direct": "trigger",
"mention": "trigger",
"mentionAll": "wait",
"quote": "wait",
"poke": "wait",
"allMessage": "wait",
"keywords": []
},
"willingness": {
"maxScore": 100,
"initialScore": 0,
"decayHalfLifeSeconds": 600,
"probabilityThreshold": 55,
"probabilityAmplifier": 0.04,
"replyCost": 35,
"textGain": 12,
"mentionGain": 100,
"quoteGain": 15,
"directGain": 40,
"imageGain": 8,
"pokeGain": 80,
"interestKeywords": [],
"forceKeywords": [],
"keywordMultiplier": 1.2,
"defaultMultiplier": 1,
"hotWindowSeconds": 15,
"warmWindowSeconds": 60,
"hotDecayWeight": 0.3,
"warmDecayWeight": 0.7,
"mentionForce": false,
"quoteForce": false,
"directForce": false
},
"priority": 1000
}未列出的字段使用插件默认值。配置写入 MILKY_WILL_POLICY 时必须是 JSON 字符串。
MILKY_HOME_CHANNEL 只影响 Hermes 系统消息和 cron 的默认出站目标,不参与入站 allowlist。
显式的 milky:group:<id> 或 milky:dm:<id> 目标优先。
未配置 home channel 时不会回退到 origin、默认频道、群聊或私聊,也不会猜测目标。standalone
cron 每次创建并关闭临时 Milky client,目前只支持无附件文本;媒体和文件输入返回
unsupported。
运行时日志使用 hermes_plugins.milky.* 标准 logger,并传播到 Hermes root。关键消息使用
event=milky.lifecycle、milky.action、milky.sse、milky.inbound、milky.resource、
milky.outbound、milky.mute 或 milky.tool 标签;插件不创建独立日志文件、handler、异步队列
或脱敏后端。
常用查看命令:
hermes logs -f
hermes logs --level DEBUG -f
hermes logs gateway -fAction、Tool 和出站日志保留结果分类、已知状态码和 duration_ms,不记录 token、Authorization、
完整 URL、请求/响应 body、消息正文、媒体引用、路径、文件内容、Tool 原始参数或结果。Tool 调用方
仍会收到既有 raw envelope。日志不可用或 handler 失败不改变连接、重连、Gate/Will、扣费、发送和
未知结果语义。
# 查看 Gateway 状态
hermes gateway status
# 重启 Gateway,使启动配置生效
hermes gateway restart
# 执行 Hermes 整体状态和深度健康检查
hermes status --deep
hermes doctor# 查看最近的 Gateway 日志和错误
hermes logs gateway -n 100
hermes logs errors --since 30m
# 临时提高日志级别并实时跟踪
hermes logs gateway --level DEBUG --since 15m -f
# 列出日志文件,以及检查配置文件位置和有效性
hermes logs list
hermes config path
hermes config env-path
hermes config check
hermes config get security.redact_secrets# 查看已安装插件及启用状态
hermes plugins list
# 在源码 checkout 中执行只读 Milky smoke
uv run scripts/milky_smoke.py
# 生成用于提交 issue 的脱敏诊断摘要
hermes dumpmilky_smoke.py 默认只执行登录、群列表、Bot 成员禁言同步和有界 SSE 连接。发送消息或上传文件
必须显式使用 --allow-write,并且目标还必须位于 MILKY_ALLOWED_CHATS 中;没有明确授权时不要
使用该选项。hermes dump 用于生成脱敏诊断摘要,不要把包含敏感配置的命令输出直接粘贴到公开 issue。
Hermes core 默认会对日志中的敏感字段进行脱敏。如果需要临时确认日志中的完整 chat_key,可用
Hermes CLI 关闭全局脱敏:
hermes config set security.redact_secrets false修改后必须重启 Gateway;该配置只在进程启动时读取。排查完成后立即恢复脱敏:
hermes config set security.redact_secrets true该开关影响 Hermes 全局的日志、工具输出和聊天响应,不只影响 Milky。关闭期间可能泄露 API key、 token 或密码,仅应在受控环境中短时使用。
普通入站只处理 message_receive:
- friend 和 group 消息进入普通 Agent 流程;
temp会话直接忽略;- Milky SSE
GET /event中的message_recall、request、notice、lifecycle 和未知事件默认只观察,少数系统事件可作为上下文; facesegment 的正文占位符对非emoji 表情pack 优先使用随插件发布的本地 catalog 名称;未命中、冲突或目录不可用时回退原face_id,缺失 ID 时使用NOT SUPPORTED;- 同一 chat 按顺序处理,
wait消息进入有界历史,trigger时再交给 Hermes。
message_recall 的上下文行为如下:
- 只有字段完整且
message_scene为friend或group时才登记;friend 写入dm:<peer_id>,group 写入group:<peer_id>,非法场景或 ID 只记录安全诊断; - 合法事件进入对应 chat 的有界 system context FIFO,在下一次同 chat
trigger的channel_context中按 ingress 顺序出现一次,格式为<event message_recall> ...; - 无
operator_id或operator_id == sender_id时显示uid <sender_id> 撤回了消息 msg_seq <message_seq>;群聊仅在operator_id != sender_id时显示管理员 uid <operator_id> 撤回了 uid <sender_id> 的消息 msg_seq <message_seq>,好友有不同操作人时不添加管理员角色; - 撤回事件不创建普通 Agent turn、不发送回复、不调用主动撤回工具,也不调用
get_message或下载资源;插件只展示撤回元数据,不承诺恢复被撤回消息正文; - 该路径仍是 observe-only,不经过普通消息的 Gate/Will,也不扣 reply cost。fixture 和 fake host 测试不代表真实 Milky 服务端能力已被集成验证。
Agent 发送本地媒体时,在回复中写入:
MEDIA:<local_path>
例如 MEDIA:~/path/to/clip.mp4。显式调用 Hermes send_message 时,把同一指令放在
message 参数中。图片、语音和视频使用 Milky native segment,文档使用独立 file upload。
如果无需回复,只返回 [SILENT],不附加其他内容;该标记由 Hermes core 抑制消息投递,Milky
plugin 不单独解析它。
需要模拟自然聊天节奏时,可把区分大小写且未转义的 [SPLIT] 单独放在一行,或直接放在普通
正文行中。独立行标记及其分隔边界会被删除,行中标记只删除自身;空段不发送,文本按原顺序
最多发送三条。超过三段时尾部合并到第三段,每个文本单元仍遵守既有长度边界,若实际文本消息
会超过三条,则在网络访问前整体拒绝。需要显示字面量 [SPLIT] 时使用 [[SPLIT]];语法完整的
CQ-compatible 或 unknown type CQ 候选中的标记不触发分段,malformed 或未闭合 CQ-like 内容中的标记
按普通文本规则处理。普通长文本没有有效 [SPLIT] 时继续使用原有长度分块。
回复同时包含文本分段和 MEDIA: 附件时,Hermes 先投递全部文本,再按提取顺序投递图片、语音、
视频和文档;当前不支持文本段与附件交错,[SPLIT] 不改变 MEDIA: 的独立交接。
Caution
MEDIA: 会读取本地文件并上传;默认只限制常规、非空且不超过 33554432 字节(32 MiB)
的文件,可用 MILKY_MAX_LOCAL_MEDIA_BYTES 在 8388608 至 33554432 字节之间调整,
没有固定的安全目录隔离。Base64 编码会带来约 4/3 的请求体放大;内网连接不代表
Milky、代理或下游平台没有更低的服务端限制。
CQ image 仅用于本地 file:// URI 的 sticker,例如:
[CQ:image,file=file:///path/to/sticker.ext,type=sticker]
普通图片请使用 MEDIA:<local_path>。sticker 会在发送前转换为 base64://。
本地路径、Path 和 file://localhost 只在 plugin 边界读取一次并受上述本地字节上限约束;
格式合法的 http(s):// 和显式 base64:// 会原样传递,plugin 不下载、读取或解码,也不应用
本地文件大小检查。
纯文本 /... 消息会在 canonical、去重和 Gate 之后分流,不进入 Will 历史或普通 Agent 正文。
合法命令交给 Hermes 既有命令分发;插件自身提供无参数 /milky,用于以可读摘要返回 Milky 实现信息。
插件固定提供 25 个 QQ ToolSpec,覆盖:
- 群组和成员查询;
- 文件、转发消息和私聊文件链接查询;
- 戳一戳、点赞、撤回、禁言、踢人、退群和删好友;
- 好友请求、入群请求和群邀请的接受/拒绝。
请求/邀请的接受和拒绝不会由通知、普通正文、关键词或 Will 自动触发,必须由 Agent 显式提供
完整参数。未知执行结果返回 transport_unknown,不自动重试或更新本地状态。
入站文件只显示为安全占位符,例如
[file:file_id=<file_id>,file_name=<file_name>,file_hash=<file_hash>];它不会被当作本地路径
或出站文件。
连接时依次完成登录信息、群列表和每个群的 Bot 成员状态同步,之后才启动事件流并开放普通 消息入口。断开时会取消 event、pipeline、TTL 任务,解除 sender/command 绑定,并关闭 HTTP/SSE 资源。
出站成功使用远端 data.message_seq 的稳定字符串作为 message_id;协议拒绝、传输未知、
malformed 和 unsupported 会保持明确失败分类。缺少消息序号时不会伪造稳定去重 ID。
插件不是以 Python package entry point 发布;Hermes 从根目录加载 plugin.yaml,再调用唯一
公开入口 __init__.py::register(ctx)。
| 对象 | 作用 |
|---|---|
__init__.py::register(ctx) |
解析启动配置,注册 platform、/milky、ToolSpec、standalone sender 和 QQ 指引 section。 |
__init__.py::register_tools(ctx) |
委托 outbound.tools 注册固定 ToolSpec;注册阶段不联网。 |
MilkyAdapter |
管理连接、停止、入站交接和出站委托。 |
MilkyOutboundSender |
校验 group:/dm: 目标,格式化消息并调用 Milky Action/upload。 |
SlashCommandService |
管理活动 Milky client,处理 /milky。 |
支持 register_system_prompt_section 的 Hermes 宿主会在 after_memory 登记
hermes-plugin-milky.qq-platform-guidance,并在连接完成后使用已确认的 QQ UID 和昵称渲染
媒体、CQ-compatible、无回复和 bundled skill 指引。旧宿主仍可完成平台注册,但只获得首句提示。
详细的稳定模块边界见 ARCHITECTURE.md;可观察行为和测试要求见 openspec/。新建的未归档 change 会放在 openspec/changes/。
欢迎通过 GitHub Issues 提问、报告 问题或提交 pull request。贡献前请阅读 CONTRIBUTING.md 和 ARCHITECTURE.md。
贡献要求:
- 行为变化先补充脱敏契约或 fixture,再实现并增加回归测试;
- 使用
uv管理 Python 环境和依赖,不使用pip、pipx或直接调用python/python3; - 遵循 Google Python Style Guide,并保持各模块依赖边界;
- 运行
uv run pytest -q、uv run ruff check .、uv run ruff format --check .、uv build和git diff --check; - 不提交 token、Authorization header、真实 QQ/群 ID、真实媒体 URL/路径、文件内容或敏感正文;
- 使用中文 Conventional Commits。
PR 应说明变更范围、实际执行的命令、测试结果和未解决风险。若行为契约发生变化,请同步 更新对应的 OpenSpec change;安全问题不要公开粘贴到 issue。
维护者:ByteColtX。问题、功能建议和安全联系入口见 CONTRIBUTING.md。
感谢 Hermes Gateway 的 platform adapter contract、Milky v1.3 协议生态,以及提供协议 fixture、测试和文档改进的贡献者。
本项目使用 MIT License,版权所有 © 2026 ByteColtX。完整条款见 LICENSE。