P37 37_协作篇_Profile功能介绍和演示
P37 · 37_协作篇_Profile功能介绍和演示(6:03)
课时概要
协作篇 · Profile 功能介绍和演示。Profile 是 Hermes 的多实例隔离:每个 profile 就是一个独立的 Hermes home 目录(底层机制是 HERMES_HOME 环境变量),拥有自己的 config.yaml / .env / SOUL.md / memories / sessions / skills / cron jobs / state.db。本机实测:本地只剩 1 个 default(09-24 瘦身删掉 8 个之后),生产侧的 9 个 profile 全在腾讯云服务器上。
本分P 没有逐P 的官方简介(视频简介只有资源链接)。以下「本节要点 / 关键概念 / 代码实操」均改写自 Hermes 官方文档 Profiles 页 / Profile 命令参考 / Profile distributions / 多 Profile 网关 四页原文并标注来源;「我的收获」里标 本机实测 的是在本机实跑/实读得到的真实状态。
视频:37_协作篇_Profile功能介绍和演示 | 时长 6:03 | P37
本节要点
- profile 是什么(官方定义):一个独立的 Hermes home 目录 —— 每个 profile 有自己的
config.yaml、.env、SOUL.md、memories、sessions、skills、cron jobs 和 state database。目的是让你为不同用途跑各自独立的 agent(编码助手、私人 bot、研究 agent)而不混淆 Hermes 状态。 - ⚠️ 识别规则(很实用):
~/.hermes/profiles/下的目录只有带以下身份文件之一才被认作 profile ——config.yaml/.env/SOUL.md/profile.yaml/auth.json/state.db;裸目录(日志或 cron 留下的)会被profile list、网关和-p忽略。 - ⚠️ 官方加粗的一条:给每个 agent 自己的 profile ——「永远不要两个 agent 进程指向同一个 profile(同一个 Hermes home)」。理由:两边都会自动写记忆,且各自在会话开始时会把对方的写入加载进 system prompt → 两个写者会把状态叠成「不再是你配置的任何东西」。profile 存在的意义正是防这个;需要共享记忆的 agent 应当改用外置记忆 provider。
- ⭐ 建 profile 就等于得到一个命令:建一个叫
coder的 profile,你立刻有了coder chat、coder setup、coder gateway start等 —— 官方原话「it automatically becomes its own command」。 - 五个术语的区分(官方专门澄清,很容易混):
· Profile = 助手配置与数据的持久 home(跨对话、跨重启保持同一状态)
· Agent = 使用那份配置与状态的运行中的助手(产品名也叫 Hermes Agent)
· Bot(Bot Mode) = 在桌面 Bot Mode 名单里被呈现的 profile(带头像 + 持久 Bot Chat);每个 Bot 都是 profile,但不是每个 profile 都是 Bot —— 只有当 Bot Mode 把它的名单呈现信息(标题/头像/分区/隐藏状态)写进 profile metadata 时才变成 Bot
· Messaging bot = 平台上某个账号(Telegram/Discord/Slack…),靠 bot token 标识,通过 gateway 接入
· Subagent =
delegate_task为某任务派生的子助手(全新对话)—— ⭐ 官方点明:「单独的对话」不等于「单独的 profile」 - 创建方式五种:空白(
hermes profile create mybot,会 seed bundled skills,然后mybot setup)|--clone(只克隆配置)|--clone-from <source>(指定源)|--clone-all(克隆一切)|--clone-channels(opt-in 保留消息渠道)。官方 tip:最快的完整设置是在新 profile 里跑hermes setup --portal一次把模型与工具都接好。 --description "<role>":如果你打算把这个 profile 当 kanban worker(或想让 kanban 编排器把活路由给它),创建时就给一句角色描述,例如hermes profile create researcher --description "Reads source code and external docs, writes findings.";也可以事后用hermes profile describe设置或自动生成。--clone到底克隆什么:当前 profile 的config.yaml、.env、SOUL.md、skills,以及策展记忆文件memories/MEMORY.md与memories/USER.md—— 官方定位很明确:记忆被当作 agent 身份的一部分,和SOUL.md一样。如果config.yaml选了外置记忆 provider,该 provider 自己的配置也一起走(其<provider>/目录或<provider>.json,如hindsight/config.json)→ 这样 clone 的记忆是真的可用而不是静默关闭。sessions、state.db、cron jobs 以及其余一切从空开始。要连记忆也空白就别用--clone,或事后删掉那两个文件 —— agent 永远不会回落到别的 profile 的记忆。--sync-imports(把 clone 的「导入的 agent 设置」保持同步):如果源 profile 跑过hermes import-agent,它的import-sync.json记录了从哪些外部 Claude Code / Codex 树导入过;--clone默认把这份清单留在原地,所以 clone 只拿到一次性副本然后就不动了。加--sync-imports才会带上清单,之后hermes -p work import-agent --sync可从同一~/.claude/~/.codex拉更新。它是显式、opt-in、单向的,只把 clone 链到外部 agent 树、永不链回源 profile —— 两个 profile 始终是互相独立的孤岛(改源的 config/SOUL/skills 永远传不到 clone)。--clone-all到底克隆什么:config、API keys、人格(personality)、全部记忆、skills、plugins —— 一个完整可用的快照。排除三类: · per-profile 历史:session 历史、state.db、backups/、state-snapshots/、checkpoints/(属于源 profile,可能几十 GB) · 从 default 克隆时的本地模型运行时树(models/、runtimes/、node/—— 下载的权重与托管二进制,按需重新取) · ⚠️ cron 任务也不克隆:官方理由很清楚 —— 它们是绑在源 profile 与其投递渠道上的计划工作,继承它们的 clone 会把每个任务跑两遍(两个网关、同样的 job id)→ 新 profile 从空cron/开始。要含历史与 cron 的完整备份,用hermes profile export或hermes backup。- ⚠️ OAuth 登录是「共享」不是「复制」(官方专门加框警告):Anthropic(Claude Pro/Max)、OpenAI Codex、xAI 的 OAuth 用一次性 refresh token —— 一份副本不是第二个凭证,而是同一个凭证有两个拥有者,先刷新的那个会把其他所有副本的 token 作废。所以
--clone-all(以及仪表盘的凭证镜像)会把这些 OAuth 行从 clone 里丢掉;新 profile 继续从根~/.hermes/auth.json读登录,任何 profile 里做的 token 刷新都写回根 → 所有 profile 保持登录。静态 API key 照常复制。要让某 profile 有自己独立的 OAuth 登录,就在它里面跑hermes -p <name> auth add <provider>。 - ⭐ 消息渠道永远不被克隆(除非显式
--clone-channels):每一种克隆方式(--clone、--clone-from、--clone-all,以及仪表盘/Desktop/TUI 的 "clone from profile")都不带源的消息渠道 —— 具体是 bot token 与 allowlist(TELEGRAM_BOT_TOKEN、DISCORD_ALLOWED_USERS、WHATSAPP_ENABLED、API_SERVER_KEY、WEBHOOK_SECRET…)、config.yaml里的platforms:/telegram:/discord:段、gateway.multiplex_profiles/profile_routes,以及(--clone-all时)pairing store、WhatsApp session 等 per-bot 状态。provider 与工具的 API key、model 块、记忆设置、skills、SOUL.md照常复制,命令会打印留下了哪些平台。 · 理由(一句话):一个 bot 只能属于一个 profile —— 两个独立网关持同一 token 会抢同一个长轮询,多路复用网关会把重复适配器停放(hermes gateway migrate --multiplex也会以「一个平台一个重复凭证 blocker」拒绝)。 ·--clone-channels在已有运行中的 multiplexed 网关服务着源 profile 时会被拒绝(复制品会立刻被停放);否则打印一条警告点名现在与源共享的平台;没有 clone 标志时它是个错误。⭐hermes profile list也会对任何 bot 凭证与 default 逐字节相同的既有 profile 打同样的警告 —— 好让老 clone 在咬人之前浮出来。 · 什么算「渠道设置」(官方给的是基于归属的清单,在源 profile 的插件作用域里判定,含它私有的plugins/适配器):适配器声明的每个键(token / app·client id / allowlist / allow-all 开关 / home channel)与<PLATFORM>_前缀下的每个键(含历史别名WECOM_*/SMS_*/TWILIO_*/QQ_*/HASS_*/EMAIL_*)|网关级渠道策略GATEWAY_ALLOW_ALL_USERS/GATEWAY_ALLOWED_USERS与 relay 身份GATEWAY_RELAY_ID/_SECRET/_DELIVERY_KEY|(--clone-all)per-bot 状态文件与目录(platforms/、pairing ledgers、google_chat_user_tokens/、<platform>_*)。 · ⚠️ 一个精细的例外:与「非渠道能力」共享的凭证(HASS_TOKEN/HASS_URL同时是 Home Assistant 工具、TWILIO_*同时是电话技能、EMAIL_*同时是发信脚本)只有在源的网关会跑那个适配器时才被剥掉(平台在它 config.yaml 里启用,或凭证集完整且没被显式禁用)。源里platforms.homeassistant.enabled: false时HASS_TOKEN是当工具 key 用的 → clone 保留它;但这些前缀下的 allowlist 与端口永远是渠道专属、永远剥掉。 · clone 是在profiles/旁一个隐藏暂存目录里构建、剥完再一次性 rename 发布的 → 正在跑的多路复用器(它会在 create 时重扫profiles/)永远不可能在半拷贝的树上启动适配器;符号链接的源.env/config.yaml会被先物化成私有副本 —— clone 永远不会写穿到源。 - Honcho 记忆 + profile:启用 Honcho 时,克隆操作会自动为新 profile 创建一个专属 AI peer,同时共享同一个 user workspace —— 每个 profile 构建自己的观察与身份。
- 命令别名:每个 profile 自动在
~/.local/bin/<name>得到一个命令别名(coder chat/coder setup/coder gateway start/coder doctor/coder skills list/coder config set …);别名对每一个 hermes 子命令都有效 —— 它本质就是hermes -p <name>。 -p标志:hermes -p coder chat|hermes --profile=coder doctor| ⭐hermes chat -p coder -q "hello"(放在任何位置都行)。- 粘性默认(
hermes profile use coder):设完之后裸hermes命令都指向那个 profile(hermes profile use default切回)。官方比喻:像kubectl config use-context。 - 知道自己在哪里:CLI 始终显示当前 profile —— prompt 变成
coder ❯而不是❯| 启动 banner 显示Profile: coder|hermes profile显示当前名字、路径、模型、网关状态。 - ⚠️⚠️ profiles vs workspaces vs sandboxing(官方专门澄清,三者完全不同):profile 给 Hermes 自己的状态目录(config/.env/SOUL/sessions/memory/logs/cron/gateway state)| workspace / 工作目录是终端命令的起点,由
terminal.cwd单独控制 | sandbox 才是限制文件系统访问的东西 —— ⭐ 「Profiles do not sandbox the agent」。 - ⚠️ 在默认的
local终端后端上,agent 仍拥有与你用户账号相同的文件系统访问权 —— profile 并不能阻止它访问 profile 目录之外的文件夹。想让某 profile 默认在特定项目工作,就在它config.yaml里设绝对terminal.cwd;⚠️ local 后端上写cwd: "."意思是「Hermes 被启动时所在的目录」,不是「profile 目录」。 - ⚠️ 三条隔离上的现实提醒(官方原文):
SOUL.md能引导模型,但它不强制工作区边界 | SOUL 的改动在新会话上干净生效(既有会话可能还在用旧 prompt 状态)| ⭐ 问模型「你在哪个目录」不是可靠的隔离测试 —— 要可预测的起始目录就显式设terminal.cwd。 - 每个 profile 跑自己的网关(独立进程 + 自己
.env里的 bot token):coder gateway start/assistant gateway start;各自设 token 就编辑各 profile 的.env。 - ⚠️⚠️ 安全:token 锁(P37 最该记的安全机制) —— 如果两个 profile 意外用了同一个 bot token,第二个网关会被拦住,并给出一条点名冲突 profile 的清晰错误(支持 Telegram / Discord / Slack / WhatsApp / Signal)。
- 持久服务:
coder gateway install→ 创建hermes-gateway-coder的 systemd/launchd 服务;每个 profile 有自己的服务名,各自独立运行。官方 Docker 镜像里:per-profile 网关由 s6-overlay(容器里的 PID 1) 监管,hermes profile create <name>会自动在/run/service/gateway-<name>/注册 s6 服务槽;hermes -p <name> gateway start/stop/restart会分派给s6-svc而不是 spawn 裸进程 → 崩溃自动重启,且docker restart保留之前在跑的那组网关。 - 每个 profile 自己配什么:
config.yaml(model / provider / toolsets / 所有设置)|.env(API keys、bot tokens)|SOUL.md(人格与指令)。例:coder config set model.default anthropic/claude-sonnet-4与echo "You are a focused coding assistant." > ~/.hermes/profiles/coder/SOUL.md。 - 仪表盘是机器级界面:能通过侧栏的 profile 切换器管理任何 profile 的 config / API keys / skills / MCPs / model,不需要每 profile 一个仪表盘;
coder dashboard会路由到机器仪表盘并预选 coder;仪表盘的 Chat 标签也跟随切换器(在所选 profile 的 home 下开对话)。⚠️ 官方提醒:仪表盘 Profiles 页上的 「Set as active」是未来 CLI/网关运行的粘性默认(等同hermes profile use)—— 想在仪表盘里编辑某个 profile,要用切换器。 - ⭐
hermes update只拉一次代码(共享)并把新的 bundled skills 同步到所有 profile(输出形如Code updated (12 commits)→Skills synced: default (up to date), coder (+2 new), assistant (+2 new));⭐ 用户改过的 skills 永不被覆盖。 - 管理命令:
hermes profile list|show <name>|rename <old> <new>(会更新别名与服务)|migrate-identity(重试一次 rename 的身份迁移)|purge-identity(重试一次 delete 的身份清理)| ⭐export(打包成<name>.tar.gz,可分享,keys 被剥离) | ⭐import(把归档装成一个新 profile)。聊天里对应/export与/import,Desktop 里是 ⌘K → Export/Import profile…。 - default profile 不能被真正改名:它的内部 ID 永远是
default(因为~/.hermes就是安装根)→hermes profile rename default Harumesu只是设一个显示名(UI 上替代裸 ID 展示,支持 Unicode 如小助手)。⭐ 显示名纯粹是呈现层:-p default、服务名、cron 任务以及所有其他引用仍用规范 IDdefault;它存在~/.hermes/profile.yaml的display_name里,删掉那行即恢复。 - 删除 profile:
hermes profile delete coder→ 停网关、移除 systemd/launchd 服务、移除命令别名、删掉所有 profile 数据;会让你键入 profile 名确认(--yes跳过)。⚠️ 不能删 default profile(~/.hermes) —— 要全清用hermes uninstall。 - Tab 补全:
eval "$(hermes completion bash)"/zsh;能补全-p之后的 profile 名、profile 子命令与顶层命令。 - ⭐⭐ 底层机制就是
HERMES_HOME环境变量:跑coder chat时包装脚本先设HERMES_HOME=~/.hermes/profiles/coder再启动 hermes;因为代码库里有 119+ 个文件通过get_hermes_home()解析路径,Hermes 状态(config/sessions/memory/skills/state.db/gateway PID/logs/cron)就自动作用域到该 profile 目录。⚠️ 这与终端工作目录是两件事:工具执行从terminal.cwd起(或 local 后端下cwd: "."时的启动目录),不是自动从HERMES_HOME起。 - ⭐⭐
HERMES_HOME≠HOME(最容易混的一对,官方专门解释):HERMES_HOME是 profile 边界 —— 它管 Hermes 的 config /.env/ memory / sessions / skills / logs / cron jobs / gateway state |HOME是操作系统/用户 home,外部 CLI 期望的那个。host 安装默认保持真实用户 HOME,好让git/ssh/gh/az/npm/ Claude Code / Codex 找到和普通 shell 里一样的凭证。 · 代价:host profile 默认共享用户级 CLI 状态。 · 要每个 profile 独立的 CLI 身份 → 在该 profile 的config.yaml设terminal.home_mode: profile(Hermes 会用HOME={HERMES_HOME}/home启动工具子进程),然后你得在那个 profile home 里初始化或链接~/.ssh、~/.gitconfig、~/.config/gh、云 CLI 认证、Claude/Codex 认证、npm state 等。 · Hermes 还会把HERMES_REAL_HOME暴露给子进程,好让脚本在home_mode: profile下仍能找到真正的账号 home。 - 默认 profile 就是
~/.hermes本身 —— 无需迁移,既有安装行为完全一致。 - ⭐ 分享 profile 的两条路:① 传文件 ——
/export打成一个.tar.gz(skills / memory / persona / crons / plugins / settings,桌面版还含主题与布局),API keys 被剥离,对方/import② 发布 distribution —— 把 profile 打包成 git 仓库,别人一条命令安装、之后还能拉版本化更新;携带 SOUL / config / skills / cron jobs / MCP 连接;凭证、记忆与会话保持 per-machine。安装形如hermes profile install github.com/you/research-bot --alias。 - 多 profile 网关(两种形态):① 每 profile 一个网关进程(默认,
hermes-gateway-<name>服务)② 多路复用:一个网关进程服务机器上所有 profile(由哪个 profile 启动都行,它成为唯一入站进程)。官方给的适用场景:一个个人助理 bot + 一个编码 agent | 每个家庭成员一个 | 沙箱 + 生产同配置 | 研究 agent + 写作 agent + cron bot 各自记忆与技能隔离。multiplexing 下:默认 profile 的生命周期动词针对那个进程,而具名 profile 可以只停/重启自己的 bot 而不停 host(hermes -p <name> gateway run在 host 活着时是附着而不是起第二个进程 —— 它会打印 host 网关的 PID 与已服务集合然后退出 0)。
关键概念
- Profile:一个独立 Hermes home 目录(
HERMES_HOME),Hermes 状态的全部边界。 - 身份文件识别:
config.yaml/.env/SOUL.md/profile.yaml/auth.json/state.db之一存在才算 profile。 - Profile / Agent / Bot / Messaging bot / Subagent:五个易混术语(官方澄清)。
--clonevs--clone-allvs--clone-from:只克隆配置/身份 vs 完整快照 vs 指定源。- 渠道永不克隆(
--clone-channelsopt-in):一个 bot 只能属于一个 profile。 - token 锁:第二个用同一 bot token 的网关会被拦住并点名冲突 profile。
- 一次性 refresh token:OAuth 登录共享不复制(静态 API key 可复制)。
terminal.cwd:工作目录的单独控制(≠HERMES_HOME)。terminal.home_mode: profile:让工具子进程用HERMES_HOME/home当HOME,换取独立的 CLI 身份。- 粘性默认 / 命令别名 /
-p:三种指定 profile 的方式。 - multiplexing:一个网关进程服务所有 profile(vs 每 profile 一个进程)。
- export/import vs distribution:传文件(keys 剥离)vs git 仓库(版本化更新)。
代码 / 实操
bash
# 创建(五种形态)
hermes profile create coder # 空白 + seed bundled skills
hermes profile create researcher --description "Reads source code and docs, writes findings."
hermes profile create work --clone # 只克隆配置 + 身份(含 MEMORY/USER)
hermes profile create work --clone --sync-imports # 连 import-sync.json 一起带
hermes profile create backup --clone-all # 完整快照(不含历史/cron)
hermes profile create work --clone-from coder # 指定源
hermes profile create twin --clone --clone-channels # 保留源的消息渠道
# 使用
coder chat # 别名 = hermes -p coder
hermes -p coder chat
hermes chat -p coder -q "hello" # -p 可放任意位置
hermes profile use coder # 粘性默认(像 kubectl use-context)
hermes profile # 看当前 profile 名/路径/模型/网关状态
# 管理
hermes profile list | show coder | rename coder dev-bot
hermes profile export coder # → coder.tar.gz(keys 被剥离)
hermes profile import ./coder.tar.gz --name coder
hermes profile delete coder [--yes] # 停网关 + 卸服务 + 删别名 + 删数据
hermes profile install github.com/you/research-bot --alias # 装一个 distribution每 profile 独立配置:
bash
coder config set model.default anthropic/claude-sonnet-4
echo "You are a focused coding assistant." > ~/.hermes/profiles/coder/SOUL.md
nano ~/.hermes/profiles/coder/.env # 各自不同的 bot tokenyaml
# 想让 profile 默认在某项目目录工作 + 独立 CLI 身份
terminal:
backend: local
cwd: /absolute/path/to/project # 注意:cwd "." = Hermes 启动时的目录,不是 profile 目录
home_mode: profile # 工具子进程用 HOME={HERMES_HOME}/home本机实测(2026-09-25):
$ ls ~/.hermes/profiles/
.DS_Store ← 18 KB Finder 产物(官方说非身份文件会被忽略)
default/ ← 只剩这一个(09-24 瘦身删掉 8 个之后)
└─ agent-project/ skills/ ← 默认 profile 的 config/.env/SOUL 都在 ~/.hermes/ 根
$ hermes profile list
Profile Model Gateway Alias Distribution
◆default deepseek-v4-flash stopped — —
我的收获
用户此前已学过本模块;以下是本机实测状态(2026-09-25):
- 本机
~/.hermes/profiles/实测只剩default/—— 与 09-24 那次瘦身(删掉 8 个 profile、只留 default、生产全在服务器)的架构决策完全一致。 hermes profile list实测只有一行:◆default| modeldeepseek-v4-flash| Gateway stopped | Alias—| Distribution—。◆是当前 profile 标记;Gateway 为 stopped 与 P33/P34 查到的「网关启动失败(api_server的API_SERVER_KEY被拒)」是同一件事。- ⭐
~/.hermes/profiles/default/里只有agent-project+skills两个目录 —— 正好印证官方那句「默认 profile 就是~/.hermes本身」:它的config.yaml/.env/SOUL.md/memories/state.db全在~/.hermes/根,profiles/default/只承载少数 per-profile 产物(skills 覆盖层等)。 - ⚠️
~/.hermes/profiles/里还躺着一个.DS_Store(18 KB,8/29) —— 它正是官方「裸目录/非身份文件会被profile list、网关和-p忽略」这条规则的无害实例(Finder 产物不会造成幽灵 profile)。 - ⭐ 官方文档给了我 09-24 那场事故的机制注解:那晚「本地 Mac 抢答飞书销售群」的根因是同一飞书应用被两台机器同时连接;而官方 P37 写的是「一个 bot 只能属于一个 profile」+「两个 profile 意外用同一 token,第二个网关会被拦住并点名冲突 profile」。差别在于我们遇到的是跨机(本地 ↔ 腾讯云)而不是跨 profile —— 本地那套 token 锁不会拦住另一台机器。但底层原理是同一条:同一凭证不能有两个拥有者。这也是为什么当时的解法是「本地显式
platforms.feishu.enabled: false」——主动放弃一侧的所有权。 - ⭐
terminal.cwd那条正好解释我自己的处境:本机terminal.backend: local且我没设terminal.cwd→ 工具从启动目录跑(而不是 profile 目录)。这就是为什么我在~/Documents/Code/PersonalWebsite里跑命令时能直接看到仓库内容、而不是跑到~/.hermes里去。 - ⭐ OAuth「共享不复制」这条也值得记牢(呼应 09-24 的 DeepSeek→OpenCode Go 迁移):静态 API key 可以照常复制,但 Anthropic / Codex / xAI 的 OAuth 必须共享根
~/.hermes/auth.json—— 因为用一次性 refresh token,谁先刷新谁会把其他副本作废。本机那批 key 型 provider(OPENCODE_GO_API_KEY/DEEPSEEK_API_KEY等)属于「静态 key」,所以它们跨 profile 复制是安全的。 - 📌 按 MEMORY 记载的服务器侧(本轮未实测,只作对照):9 个 profile、7 个 gateway + 每 profile 独立飞书应用 + 独立 DeepSeek key + skills 软链到全局(省空间) —— 这正好是官方这套机制的组合用法:每 profile 独立进程与 token(= 官方默认形态)、
--clone不克隆渠道(所以每个 profile 得自己配飞书应用)、以及「skills 软链」这种官方没写但完全合理的手工优化。 - 💡 一条我现在才串起来的:09-24 删 profile 时踩的坑(不能在有 gateway 运行时删 —— 它持有
state.db句柄 → 报cannot read the main image header+ 网关自己重启 exit 78 + 空目录被重建),在官方文档里找到了对应依据:默认 profile 的网关会服务/触及所有 profile 的存储(多路复用形态下 一个 PID/锁/状态面),所以「先 bootout 停网关 → 再删目录 → 再 bootstrap」才是正确顺序。
(个人感想部分待补写。)
待深入
(待填:没听懂、想回头查的。)