بنقرة واحدة
deploy-hermes-multi-role
部署 Hermes Agent 多角色协作系统,包含 PM/SE/Assistant/Writer/Reviewer 五个专业角色
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
部署 Hermes Agent 多角色协作系统,包含 PM/SE/Assistant/Writer/Reviewer 五个专业角色
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
PM任务路由与分派技能。定义如何拆解用户需求、按角色分派任务、以及对外输出的审稿流水线。
Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions "deck," "slides," "presentation," or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.
Reviewer角色的PPT审稿工作流。使用pptx-generator技能按设计系统重构PPT, 保持内容和逻辑,优化结构、排版、配色、字体。输出修改清单。
| name | deploy-hermes-multi-role |
| category | software-development |
| description | 部署 Hermes Agent 多角色协作系统,包含 PM/SE/Assistant/Writer/Reviewer 五个专业角色 |
| tags | ["hermes","multi-role","ai","deployment","configuration"] |
这个技能用于部署基于 Hermes Agent 的多角色协作系统,支持四个专业角色的切换和协作。 包含两个方向:准备迁移(源机器→GitHub)和部署安装(GitHub→新机器)。
当本地 Hermes 已配置好 SOUL.md、skills、profiles 后,需要迁移到另一台机器时执行。
Hermes 初始化时会为每个 profile 铺一套默认技能(apple/creative/github/research 等约 45+ 个)。这些技能在新机器上运行 Hermes 就有,不需要入 Git。
# 在源机器上,只看自定义/修改过的技能
# 不同角色维护在不同路径下:
# PM → ~/.hermes/skills/
# writer/reviewer/se/assistant → ~/.hermes/profiles/<角色>/skills/
使用 hermes-skills-audit-and-dedup 技能系统梳理一遍,按职责归并后,只把自定义技能入 Git。
# config.yaml 含有 API Key,绝不能提交
# 创建脱敏模板:
cp ~/.hermes/config.yaml ./config.yaml.example
# 然后手动编辑替换 api_key 为 YOUR_API_KEY_HERE
写入 .gitignore:
config.yaml
.env
**/auth.json
**/gateway.pid
**/state.db*
入 Git 的(体积小,自定义配置):minimax-docx / minimax-xlsx / minimax-pdf / pptx-generator / ppt-review-workflow / powerpoint / nano-pdf
不入 Git 的(体积超大或平台默认):
ppt-master(~515MB,含大量 SVG 模板/图标库)→ 通过 setup.sh 脚本从 GitHub 仓库 cloneapple/ creative/ github/ research/ 等 → 新机器自动有# .gitignore 追加大文件排除规则
cat >> .gitignore << 'EOF'
skills/ppt-master/
skills/apple/
skills/creative/
skills/github/
EOF
setup.sh 负责在新机器上自动完成:
# 核心框架(伪代码):
for role in writer reviewer se assistant; do
mkdir -p ~/.hermes/profiles/$role
cp -r repo_dir/profiles/$role/* ~/.hermes/profiles/$role/
done
# PM 技能放根 skills/
cp -r repo_dir/skills/pptx-generator ~/.hermes/skills/
# Writer 技能放 writer/skills/
cp -r repo_dir/skills/minimax-docx ~/.hermes/profiles/writer/skills/
# Reviewr 技能放 reviewer/skills/productivity/
cp -r repo_dir/skills/powerpoint ~/.hermes/profiles/reviewer/skills/productivity/
git add -A
git commit -m "清理仓库:精简skills、更新setup.sh、添加config模板"
git push origin main
首次从本机推送到远程仓库需要 Personal Access Token:
# 配置 remote 使用 token(只有一次 push 用,用完即清理)
git remote set-url origin https://<用户名>:<PAT>@github.com/<用户名>/<仓库名>.git
git push origin main
# 推完后立即恢复公开 URL
git remote set-url origin https://github.com/<用户名>/<仓库名>.git
⚠️ 不要将 PAT 写入任何脚本或配置文件。用完立即从 git remote 中清除。
# 离开前删除临时工作目录
rm -rf /tmp/hermes-multi-role-profiles
git clone https://github.com/chenlin9194/hermes-multi-role-profiles.git
cp -r hermes-multi-role-profiles/* ~/.hermes/
由于原脚本可能存在问题,需要创建或修复 ~/.hermes/bin/hermes-profile:
#!/bin/bash
# Hermes 多角色切换脚本
# 用法: hermes-profile [角色名称]
PROFILE_DIR="$HOME/.hermes/profiles"
CURRENT_SOUL="$HOME/.hermes/SOUL.md"
# 检查参数
if [ $# -eq 0 ]; then
echo "可用角色:"
echo " pm - 项目经理 (默认)"
echo " se - 技术专家"
echo " assistant - 助理"
echo " writer - 写手"
echo " reviewer - 审稿专家"
echo ""
echo "当前角色: $(basename $(readlink -f $CURRENT_SOUL) 2>/dev/null || echo 'default')"
exit 0
fi
ROLE=$1
# 检查角色是否存在
if [ ! -d "$PROFILE_DIR/$ROLE" ]; then
echo "错误: 角色 '$ROLE' 不存在"
echo "可用角色: pm, se, assistant, writer, reviewer"
exit 1
fi
# 切换到指定角色
if [ "$ROLE" = "pm" ]; then
# PM 是默认角色,使用根目录的 SOUL.md
cp "$PROFILE_DIR/pm/SOUL.md" "$CURRENT_SOUL"
else
cp "$PROFILE_DIR/$ROLE/SOUL.md" "$CURRENT_SOUL"
fi
echo "✅ 已切换到 $ROLE 角色"
echo "📍 当前 SOUL.md: $CURRENT_SOUL"
chmod +x ~/.hermes/bin/hermes-profile
# 临时生效(当前会话)
export PATH="$HOME/.hermes/bin:$PATH"
# 永久生效(添加到 ~/.bashrc)
echo 'export PATH="$HOME/.hermes/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
| 角色 | 职责 | 适用场景 |
|---|---|---|
| PM (项目经理) | 目标拆解、任务路由、成果汇总 | 项目管理、任务分配、进度跟踪 |
| SE (技术专家) | 技术难题、代码分析、方案设计 | 技术攻关、代码审查、架构设计 |
| Assistant (助理) | 事务执行、信息检索、结构化输出 | 日常事务、信息整理、格式化输出 |
| Writer (写手) | 文档撰写、PPT生成、汇报材料 | 文档编写、报告制作、内容创作 |
| Reviewer (审稿专家) | 内容审查、视觉美学优化、PPT/文档审稿 | 文档审稿、PPT美化、质量把关 |
# 切换到技术专家
hermes-profile se
# 切换到项目经理
hermes-profile pm
# 切换到助理
hermes-profile assistant
# 切换到写手
hermes-profile writer
# 切换到审稿专家
hermes-profile reviewer
# 查看可用角色
hermes-profile
直接在对话中说明:
PM 角色可通过 delegate_task 将任务分发给其他角色。
~/.hermes/
├── SOUL.md # 当前激活的角色配置
├── config.yaml # 核心配置
├── profiles/ # 多角色配置目录
│ ├── pm/SOUL.md
│ ├── se/SOUL.md
│ ├── assistant/SOUL.md
│ ├── writer/SOUL.md
│ └── reviewer/SOUL.md
├── memories/ # 长期记忆(共享)
├── skills/ # 自定义技能(共享)
└── bin/ # 工具脚本
└── hermes-profile # 角色切换脚本
sessions/、memories/ 和 state.dbdelegate_task)SOUL.md 定义⚠️ 重要:当角色作为独立 Gateway 进程运行时(每个 profile 有自己的 gateway),
memories/和skills/是不共享的。每个 profile 的存储路径在profiles/<角色>/memories/和profiles/<角色>/skills/,与主实例的~/.hermes/memories/完全隔离。这是后续所有协作模式设计的根本约束。
用户先与助理对话,助理整理了会议纪要和待办事项,存入了 D:\Work\YYYY-MM-DD\ 共享目录。随后用户向 PM 要求输出日报,PM 完全不知道助理存了什么——因为两个角色的 sessions/ 和 memories/ 是彻底隔离的。
助理(独立Gateway):收到信息 → 整理 → 写入 D:\Work\ ✅
PM (另一独立Gateway):收到\"出日报\" → 不知道数据在哪 → 输出空 ❌
| 问题 | 本质 | 解决方案 |
|---|---|---|
| 任务路由(谁做什么) | 控制流问题 | delegate_task 程序化分派 |
| 数据共享(结果放哪) | 数据流问题 | 共享文件系统总线 |
两者必须同时解决,缺一不可。
PM 用 delegate_task 内部拆分子任务,子任务结果自动回流:
用户需求 → PM拆解
│
┌─────────┼─────────┐
▼ ▼ ▼
delegate delegate delegate
(SE) (助理) (写手)
│ │ │
└─────────┼─────────┘
▼
PM汇总验收 → 交付
每个 delegate 通过 context 字段注入 SOUL.md 内容,让子 Agent 以指定角色身份执行。
优势:
所有角色的持久化数据写入约定好的共享目录,作为数据交换的"共享硬盘":
约定的共享路径:/mnt/d/Work/YYYY-MM-DD/(或相应平台路径)
│
┌─────────┴─────────┐
│ │
助理写入整理数据 PM读取生成日报
写手读取素材 SE写入分析报告
审稿读取审稿结果 ...
│ │
└─────────┬─────────┘
▼
所有角色可见
数据契约规范:
# 目录结构(标准化版本)
D:\Work\YYYY-MM-DD\ ← 当日工作目录
├── shared\ ← 公共区:所有人可读可写
│ ├── tasks.md ← 今日待办(助理维护)
│ ├── risks.md ← 风险登记(SE/全员可登记)
│ └── decisions.md ← 关键决议(全员可登记)
├── assistant\ ← 助理工作区(会议纪要、日常整理)
├── se\ ← 技术专家工作区(技术分析报告)
├── writer\ ← 写手工作区(文档/PPT产出)
└── reviewer\ ← 审稿工作区(审稿意见)
每个角色的写入和读取权限:
| 角色 | 写入目录 | 可读目录 |
|---|---|---|
| PM | -(不直接写) | 所有目录 |
| 助理 | assistant/ + shared/tasks.md + shared/risks.md | 所有目录 |
| SE | se/ + shared/risks.md | shared/, assistant/ |
| 写手 | writer/ | shared/, assistant/, se/ |
| 审稿 | reviewer/ | writer/, shared/ |
文件命名规范:{类型}-{项目名}-{主题}.{扩展名}(如 会议纪要-Infiniti项目-STR4预评审.md)
创建好共享目录后,必须将数据共享规则写入每个角色的 SOUL.md,否则各独立 Gateway 进程不知道共享目录的存在。在 SOUL.md 末尾追加一个 ## 团队数据共享契约 章节:
## 团队数据共享契约
本团队使用共享数据仓库进行跨角色数据同步。详见 `D:\Work\数据共享契约.md`。
### 你的职责
- 📝 **写入目录**:`D:\Work\YYYY-MM-DD\<角色目录>\`
- 📖 **可读目录**:`shared/`、`assistant/`、`se/` 等
- 📋 **公共区**:同步写入 `shared/tasks.md`、`shared/risks.md` 等
### 文件规范
- 文件名格式:`{类型}-{项目名}-{主题}.{扩展名}`
- 文件头标注日期和来源角色
- 使用 Markdown 格式,表格用 Pipe 格式
同时创建一份 数据契约文档 D:\Work\数据共享契约.md 供各角色查阅
首次建立共享数据总线时,执行以下步骤:
# 1. 创建分角色目录
TODAY=$(date +%F)
WORK_DIR="/mnt/d/Work/$TODAY"
mkdir -p "$WORK_DIR"/{shared,assistant,se,writer,reviewer}
# 2. 创建 shared 公共文件
cat > "$WORK_DIR/shared/tasks.md" << 'EOF'
# ... 待办表格 ...
EOF
cat > "$WORK_DIR/shared/risks.md" << 'EOF'
# ... 风险表格 ...
EOF
cat > "$WORK_DIR/shared/decisions.md" << 'EOF'
# ... 决议表格 ...
EOF
# 3. 写入数据契约文档
# 见 D:\Work\数据共享契约.md
assistant/,同步待办到 shared/tasks.mdse/,同步风险到 shared/risks.mdshared/ + assistant/ + se/ 读取素材,产出文档到 writer/writer/ 读取待审文档,写入审稿意见到 reviewer/| 场景 | 推荐通道 | 原因 |
|---|---|---|
| 技术分析、数据处理 | delegate_task | 结果直接回流,无需持久化 |
| 日报/周报生成 | 文件总线 | 需阅读历史数据,多人衔接 |
| 批量并行任务 | delegate_task | 并发能力强 |
| 文件/PPT 产出 | 文件总线 | 文件格式需持久化到磁盘 |
| 信息整理归档 | 文件总线 | 长期保存,后续检索 |
| 临时计算、一次查询 | delegate_task | 用完即弃,不污染文件系统 |
1. PM接收用户需求
2. PM拆解为子任务
├─ 技术类 → delegate(SE)
├─ 整理类 → delegate(助理)
└─ 输出类 → delegate(写手) → 写入共享文件
3. SE/助理/写手执行任务
├─ 中间结果:用 delegate 回流给 PM
└─ 持久化结果:写入 D:\Work\ 共享目录
4. PM汇总所有结果,验收
5. PM输出最终交付
所有对外交付的文档/PPT,必须经过以下强制流水线,由 PM 路由逻辑保证:
写手产出 → 写入 writer/目录
↓
PM 自动触发 Reviewer
↓
Reviewer 审稿 → 写入 reviewer/审稿意见.md
↓
┌── 通过?→ PM 交付给用户
└── 有问题?→ 退回 Writer 修改 → 再次送审
判定条件(PM 检查):
reviewer/ 目录下缺少对应审稿意见文件 → 拒绝交付,强行触发 Reviewer事后审稿流程(初次建立共享总线时,对已交付内容补审):
python -m markitdown file.pptx 或 python-pptx)reviewer/审稿意见-{目标文件名}.md审稿意见格式:
## 审稿意见 - {PPT/文档名称}
**审稿日期:** YYYY-MM-DD
**审稿人:** Reviewer
### 第N页({页面标题})
| 类型 | 问题描述 | 建议修改 | 优先级 |
|------|---------|---------|-------|
| 文字 | ... | ... | P0 |
| 排版 | ... | ... | P1 |
| 视觉 | ... | ... | P2 |
优先级定义:
- P0:必须改(内容/数据错误)
- P1:建议改(措辞/排版/布局优化)
- P2:锦上添花(视觉细节/模板规范)
很多用户期望在飞书上可以直接 @写手 或 @SE 单独对话,但这是不工作的。原因如下:
用户 ──▶ 飞书 ──▶ Hermes 网关(1个实例)
│
├── 加载 SOUL.md → 当前角色
│
└── profiles/ ── 其他角色的"说明书"文件
├── writer/SOUL.md ← 只是定义,不是进程
├── se/SOUL.md ← 只是定义,不是进程
└── assistant/SOUL.md ← 只是定义,不是进程
~/.hermes/SOUL.md 决定通过 PM 路由,不要直接找子角色对话:
| ❌ 错误用法 | ✅ 正确用法 |
|---|---|
| 飞书对写手说:"写一份周报" | 飞书对 PM 说:"让写手帮我写一份周报" |
| 飞书对SE说:"分析这个bug" | 飞书对 PM 说:"让SE分析这个bug" |
| @写手Bot 发消息(没有独立Bot) | PM 接收后用 delegate_task() 派发给子角色 |
PM 收到用户请求后,用 delegate_task() 创建子 Agent:
详见下一节「独立 Bot 方案」
如果需要让每个角色成为独立的飞书机器人(用户可直接 @对应Bot 对话),需要:
Bot 配置完成后,如果 FEISHU_ALLOW_ALL_USERS=false(默认),用户发消息会显示:
Unauthorized user: ou_f8c6407751e804379c95a25b8bda784b (None) on feishu
解决方案(二选一):
# 方式 A:开放给所有用户(开发/测试用,推荐)
sed -i 's/FEISHU_ALLOW_ALL_USERS=false/FEISHU_ALLOW_ALL_USERS=true/' ~/.hermes/profiles/<角色>/.env
# 方式 B:仅限特定用户(生产用)
echo 'FEISHU_ALLOW_ALL_USERS=false' >> ~/.hermes/profiles/<角色>/.env
echo 'FEISHU_ALLOWED_USERS=ou_xxx1,ou_xxx2' >> ~/.hermes/profiles/<角色>/.env
⚠️ 修改后必须重启网关才生效! 见下方「WSL 环境中的网关管理」
如果使用 hermes profile create 创建的独立 profile(每个 profile 有独立的 .env 和 config.yaml):
.env 填入对应的 FEISHU_APP_ID 和 FEISHU_APP_SECRET:
# ~/.hermes/profiles/<角色>/.env
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=xxx
FEISHU_DOMAIN=feishu
FEISHU_CONNECTION_MODE=websocket
Unauthorized user:
# 方式 A:开放给所有用户(测试用)
echo 'FEISHU_ALLOW_ALL_USERS=true' >> ~/.hermes/profiles/<角色>/.env
# 方式 B:仅限特定用户(生产用)
echo 'FEISHU_ALLOW_ALL_USERS=false' >> ~/.hermes/profiles/<角色>/.env
echo 'FEISHU_ALLOWED_USERS=ou_xxx1,ou_xxx2' >> ~/.hermes/profiles/<角色>/.env
hermes --profile <角色> gateway run --replace
# 一键给所有 profile 启用全部开放
for p in se reviewer assistant writer; do
sed -i 's/FEISHU_ALLOW_ALL_USERS=false/FEISHU_ALLOW_ALL_USERS=true/' ~/.hermes/profiles/$p/.env
done
# 批量重启
for p in se reviewer assistant writer; do
kill $(cat ~/.hermes/profiles/$p/gateway.pid 2>/dev/null) 2>/dev/null
hermes --profile $p gateway run --replace
done
# 方法 A:查看 profile 列表状态
hermes profile list
# 方法 B:查看进程
ps aux | grep "gateway run" | grep -v grep
# 方法 C:查看飞书 WebSocket 连接日志(WSL 可用)
journalctl --user -u hermes-gateway* --no-pager | grep "connected to wss"
# 方法 D:通过飞书 API 验证 Bot 身份
curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
-H "Content-Type: application/json" \
-d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}' | jq -r '.tenant_access_token' | \
xargs -I {} curl -s -H "Authorization: Bearer {}" "https://open.feishu.cn/open-apis/bot/v3/info"
每个飞书应用的用户 open_id 是应用级隔离的:
ou_cfb089cf77...ou_9637675e8...open_id cross app 错误)测试各 Bot 收发消息时,需要在对应 Bot 的飞书对话框内直接发送。
WSL 没有 systemd 用户会话,hermes gateway restart 会报错:
✗ User systemd not reachable:
User D-Bus socket is missing even though linger is enabled.
# 查看所有 profile 网关进程
ps aux | grep "gateway run" | grep -v grep
# 输出示例:
# ... --profile writer gateway run --replace
# ... --profile se gateway run --replace
# ... --profile reviewer gateway run --replace
# 方式 A:通过 PID 文件(推荐)
kill $(cat ~/.hermes/profiles/<角色>/gateway.pid 2>/dev/null)
# 方式 B:强力终止已知 PID
kill -9 <PID>
# 清理 stale PID 文件
rm -f ~/.hermes/profiles/<角色>/gateway.pid
# 单 profile 启动
hermes --profile <角色> gateway run --replace
--replace 是关键标志:它会检查是否有同 profile 旧进程并替换之,然后自动 daemonize 到后台。
⚠️ 不能使用 & background 启动(Hermes 会拒绝)。直接用
gateway run --replace,命令会自动 daemonize。
# 一键重启所有非 default profile 的网关
for p in se reviewer assistant writer; do
kill $(cat ~/.hermes/profiles/$p/gateway.pid 2>/dev/null) 2>/dev/null
rm -f ~/.hermes/profiles/$p/gateway.pid
hermes --profile $p gateway run --replace
done
# 等待连接
sleep 5
# 验证
ps aux | grep "gateway run" | grep -v grep
journalctl --user -u hermes-gateway* --no-pager | grep "connected to wss"
| 症状 | 原因 | 解决 |
|---|---|---|
Unauthorized user: ou_xxx | ALLOW_ALL_USERS=false 且用户未批准 | 设为 true 或添加 ALLOWED_USERS;或写入 pairing store |
Code 'xxx' not found or expired | 配对码发到了错的 Hermes 实例 | 去生成该配对码的 profile 进程里执行 approve |
| Bot 收不到消息但进程在跑 | 权限配置变更后未重启 | 重启网关进程 |
FEISHU_ALLOW_ALL_USERS 修改后不生效 | 进程仍在用旧环境变量 | Kill 旧进程 → 重新 --replace |
open_id cross app | 用 A App 的 open_id 通过 B App 发消息 | 每个 Bot 用各自 App 内的 open_id |
| Bot 显示在线(ps 有进程)但长时间不回复 | --replace 残留僵尸 + WebSocket 断连后进程静默退出 | 对比 gateway_state.json.pid 与真实进程;检查 agent.log 最近日志时间戳;强杀后重启 |
Agent 崩溃: ImportError: cannot import name 'cfg_get' from 'hermes_cli.config' | __pycache__ 字节码缓存与源码不一致 | 清所有 __pycache__ + *.pyc,重启 gateway |
Agent 崩溃: ImportError: cannot import name 'atomic_replace' from 'utils' | 同上 — 批量缓存损坏 | 同上 |
当某个角色的 Bot 在飞书群里不响应时,不要零散排查。按以下顺序系统排查:
# 步骤 1:确认进程存活
ps aux | grep "gateway run --profile <角色>" | grep -v grep
# → 没进程:`hermes --profile <角色> gateway run --replace`
# 步骤 2:确认 Feishu 连接状态
cat ~/.hermes/profiles/<角色>/gateway_state.json | python3 -m json.tool
# → 检查 platforms.feishu.state 是否为 "connected"
# 步骤 3:检查 gateway.log 看错误类型
tail -50 ~/.hermes/profiles/<角色>/logs/gateway.log
# → 找新消息到达后的关键日志:Received → Flushing → next action
日志流模式判断:
日志流 A: Received → Flushing → "inbound message" → "response ready" → "Sending"
结论:正常。Bot 已响应。
日志流 B: Received → Flushing → "Unauthorized user: ou_xxx"
结论:用户未授权。修复见下方「配对存储」节。
日志流 C: Received → Flushing → "Agent error" + ImportError traceback
结论:Agent 启动失败。修复:
1. 清理字节码缓存:
find /home/linchen/.hermes/hermes-agent -name "__pycache__" -type d -exec rm -rf {} +
find /home/linchen/.hermes/hermes-agent -name "*.pyc" -delete
2. 重启:
kill $(cat ~/.hermes/profiles/<角色>/gateway.pid)
hermes --profile <角色> gateway run --replace
日志流 D: Flushing 后的行完全不出现(空档)
结论:Agent 启动失败但日志被截断,或模型 API 超时。检查 agent.log + errors.log。
日志流 E: 日志在 30 分钟前完全停止,但 ps 显示进程仍在
结论:***关键陷阱*** — 进程是 `--replace` 后的残留僵尸,真正的网关进程已因 WebSocket 断连(1011 keepalive ping timeout)静默退出。
修复:强杀残留 `kill -9 $(cat .../gateway.pid)` → `hermes --profile <角色> gateway run --replace`
详见 [debug-stale-zombie-websocket-disconnect.md](references/debug-stale-zombie-websocket-disconnect.md)
用户消息从飞书到达后,需通过 两层检查:
飞书消息 → ① Feishu Adapter 层级 → ② Gateway 层级 → Agent
│ │
检查 FEISHU_GROUP_POLICY 检查 FEISHU_ALLOW_ALL_USERS
和 allowed_group_users 和 FEISHU_ALLOWED_USERS
和 pairing_store.is_approved()
即使 Adapter 层放行(GROUP_POLICY=open),Gateway 层仍可能拒绝(Unauthorized user)。
每个 profile 的批准用户存储在:
~/.hermes/profiles/<角色>/platforms/pairing/
├── feishu-approved.json ← 已批准用户列表
├── feishu-pending.json ← 待批准配对码
└── _rate_limits.json ← 速率限
已批准 示例(与其他角色格式一致):
{
"ou_f8c6407751e804379c95a25b8bda784b": {
"user_name": "",
"approved_at": 1777270241.9251142
}
}
每个 Feishu bot 有自己的 App ID 和 Feishu 租户。 同一个人在不同的 Bot 中有不同的 open_id。所以:
ou_7f2628d10c645ad3f993ba64bcec1328ou_f8c6407751e804379c95a25b8bda784bou_9637675e8e736e6ba40778bc4da18c0eou_1fa9c918711c9a34af8f29e567986bba误判案例: 其他角色都工作,唯独 Writer 不响应。原因不是 Writer 配置不同,而是其他角色在部署时已完成配对(feishu-approved.json 存在),Writer 从未配过。
# 方式 A:创建批准文件(推荐)
# 1. 从 "Unauthorized user" 日志中获取用户 open_id
# 2. 创建配对批准
cat > ~/.hermes/profiles/<角色>/platforms/pairing/feishu-approved.json << 'EOF'
{
"ou_<用户open_id>": {
"user_name": "",
"approved_at": $(date +%s)
}
}
EOF
# 方式 B:使用配对码
# 1. 在飞书向该 Bot 发私信 → Bot 返回配对码
# 2. 在 Bot 所在 profile 下执行配对批准
hermes pairing approve feishu <配对码>
# 方式 C:开放所有人
# 适合测试/开发环境,不推荐生产
sed -i 's/FEISHU_ALLOW_ALL_USERS=false/FEISHU_ALLOW_ALL_USERS=true/' ~/.hermes/profiles/<角色>/.env
# ⚠️ 修改后必须重启 gateway
⚠️ 配对批准文件创建后立刻生效(PairingStore 每次调用都从磁盘读取),无需重启 gateway。但如果修改 .env 中的
FEISHU_ALLOW_ALL_USERS,则必须重启。
# 检查 PATH
echo $PATH | grep ~/.hermes/bin
# 如果没有输出,添加 PATH
export PATH="$HOME/.hermes/bin:$PATH"
# 检查脚本权限
ls -la ~/.hermes/bin/hermes-profile
# 检查角色目录
ls -la ~/.hermes/profiles/
# 检查 SOUL.md 文件
ls -la ~/.hermes/SOUL.md
# 测试角色切换
hermes-profile se
hermes-profile pm
hermes-profile assistant
hermes-profile writer
# 查看当前角色配置
head -10 ~/.hermes/SOUL.md
| File | Description |
|---|---|
| debug-nonresponsive-bot-session.md | Real-world case study: debugging a non-responsive Feishu Bot (pycache corruption + pairing/approval missing) |
| debug-stale-zombie-websocket-disconnect.md | Real-world case study: stale --replace zombie process + WebSocket 1011 ping timeout → silent exit |
| deploy-github-skill-to-profile.md | Deploying a GitHub repo as a Hermes profile skill (cross-filesystem rsync, symlinks, .venv setup) |
| sync-config-to-github.md | Syncing local ~/.hermes config to GitHub reference repo: diff methodology, security rules, watchdog v2 upgrade, push auth |