- Início
- Plugins
- Integrações e acesso remoto
- dsh-agent-persona
dsh-agent-persona
awoodwhale/dsh-agent-persona
Delimita personas de prompt de sistema por caminho do workspace ou id de sessão (exato, prefixo, contém, regex), com uma persona padrão opcional para sessões que nada reivindicou, uma aba 人设 na conversa mostrando o prompt realmente enviado, importação e exportação da lista, e um interruptor que recusa gravações de ferramentas no armazenamento de personas.
Instalar
dsh plugin --profile web add github:awoodwhale/dsh-agent-personaREADME
dsh-agent-persona
给不同的工作区、不同的会话,用不同的 system prompt 人设。
它能做什么
一个 DSH 部署里常常同时跑着好几摊活:写前端、写文档、盯告警、做代码审查。它们需要不同的身份、口径和约束。 这个插件把人设按工作区或会话分发出去,每一份都是 system prompt 里的一段:
- 多个人设,各自声明适用范围:一条人设可以同时用于若干个工作区目录和若干个会话;匹配方式有 完全一致、开头是、包含、正则匹配四种。
- 越具体越优先:会话 ID 的规则优先于工作区,精确优先于前缀/正则;只有具体度相同时才按列表顺序决定。
- 显式默认人设:可以把某一条标成「默认人设」,它会收下所有没被位置命中的会话 —— 同一时刻只允许一条。 不标就没有兜底,那些会话继续用 DSH 自带的 system prompt。
- 一个位置只能属于一条人设:把某个工作区/会话配给新人设时,原来占着它的那条会自动失去它,并告诉你从谁那里转来的。
- 追加或替换:保留 DSH 自带的身份提示、把人设接在后面,或者去掉那句身份提示只用人设。
- 正文为空 = 这里不要人设:给某个位置加一行、正文留空,就显式地在那里关掉人设。
- 改完下一条消息生效,不用重启(正文按文件时间戳在每次组装时重读)。
- 工具改不动人设文件:人设会被注入 system prompt,所以宿主注册了一个全局
tools.guard,拒绝一切指向人设 存储的写入(write/edit各类文件工具,以及含写入特征的 shell 命令),只读命令照旧放行。 - 存储读不出来时不会悄悄丢:文件存在但读不出来(内容坏了、不是人设存储)时,页面会说明原因,并且在第一次
保存之前先把原文件复制成
personas.json.bak-<时间戳>;备份失败就不会写入。 - 导入 / 导出:导出为一份 JSON 文件(同时复制到剪贴板);导入可以选文件或粘贴,边输入边预览每条人设的 字数与规则数,再以「一律新建、一律停用」的方式写进去,默认人设不会被替换。
三处界面,各管一件事:
| 界面 | 位置 | 用途 |
|---|---|---|
| 设置页 | 设置 → Agent 人设 | 新建/编辑/删除/复制/排序人设;写正文、Markdown 预览、让 AI 改一版。标题旁另有 GitHub / npm 链接与当前安装的版本号(悬浮会说明这一份是 npm 装来的还是本地开发目录加载的) |
| 会话视图 | 对话页顶部的 人设 标签 | 看这条会话命中了哪条人设、实际发出去的 system prompt(渲染/源码两视图),以及就地管理全部人设 |
| 侧边栏卡片 | dsh-better-sidebar 的右侧栏 | 把上面那个「人设」页面挂进右侧栏(需要装了该插件) |
五个偏好开关(编辑后自动保存 / 在对话页显示「人设」标签 / 注册到 dsh-better-sidebar / 禁止模型改写人设文件 / 保存人设版本历史)
都在设置 → Agent 人设页里,并且这个页面不受这些开关影响 —— 关掉「对话页显示」或「注册到 dsh-better-sidebar」后,
回到这里就能重新打开。本插件不在设置 → 通用设置里添加任何条目;鼠标停在开关上会给出每个开关的完整说明。
为什么它压得住 AGENTS.md
DSH 会把工作区指令(AGENTS.md 之类)变成一条 user 角色的消息,那条消息自己的导语就写着
"They do not override system, developer, or direct user instructions." 而这个插件写的是
system prompt 的一个 section(section 名 agent-persona,order 1,紧跟在身份行之后)。
这个先后关系是框架定的,不是插件自己声明的 —— 也正因为如此,工作区里怎么改文件都动不了这层人设。
装
实测过的 DSH 版本:0.1.5-rc.1(作者的开发环境)、0.1.5-rc.2、0.2.0-rc.2 与最新版
0.2.1-rc.2。 package.json 的 dsh.compatibility 声明的就是这四项 —— 含义是"我们在这些版本上跑过",
不是对更早或更新版本做过兼容工作的承诺;其它版本请自行验证。
侧边栏卡片还需要 dsh-better-sidebar:没装它时,「注册到 dsh-better-sidebar」这个开关不会出现
(没有可注册的地方),插件其余功能照常。
dsh plugin --profile web add dsh-agent-persona
装完重启一次 dsh web:profile 的 bundles 只在启动时读取,插件行是从那里挂进去的。
重启后能看到:
- 设置左栏的 Agent 人设;
cat ~/.dsh/dsh-agent-persona/state.json—— 插件的加载心跳,写明了它加载了哪个文件、人设存哪、几条人设。
仓库里也有本地安装脚本:bash scripts/install.sh(Windows 是 scripts/install.ps1)。
升级与卸载(dsh plugin … 就是在 profile 目录里代跑包管理器):
dsh plugin --profile web update dsh-agent-persona # 升级(按依赖的版本范围取最新)
dsh plugin --profile web add dsh-agent-persona@latest # 想跨大版本升到最新
dsh plugin --profile web remove dsh-agent-persona # 卸载
升级或卸载后重启一次 dsh web。人设文件不会被删、也不会被覆盖:卸载是人设只留在文件里的操作。
用起来

点 新建人设 → 在「适用范围」里加行,选工作区或会话 → 写正文 → 打开启用开关 → 保存。
- 新建出来的人设默认停用,所以多一条人设不会影响任何现有会话,配好了再开。
- 适用范围是一行一行加的。每行先选类型(工作区目录 或 某个会话),再从下拉框里挑具体是谁。 两种类型互斥:把一行从「工作区」切成「某个会话」,这一行原来选的值会被清掉,重新选。
- 下拉框里的工作区来自 DSH 的工作区列表(带会话数),会话来自 DSH 的全部会话,按时间倒序, 带标题、工作目录和「几分钟前」—— 不记得 session id 是什么没关系,认标题就行。
- 想用前缀、正则这类高级匹配,选 自己输入… 就会变成输入框。
- 折叠状态下,卡片第二行分开列出这条人设用在了哪些工作区、哪些会话;一个位置都没加时写着 「未设置位置:不生效,该会话仍用 DSH 自带的 prompt」——那是停在草稿状态的人设,不是兜底。
- 想让它兜底,就打开卡片里的 默认人设 开关;列表行上会出现绿色的「默认」标记。
展开一张卡是这样:

版本历史(可选)
打开设置页的 保存人设版本历史,之后每次保存都会把这次的正文改动记成一条 diff(写在
personas.history.json)。编辑器底部的 版本历史 按钮打开对比窗口:

- 只记正文:名称、启用状态、适用范围不参与版本,改这些不会产生一条记录。
- 每条都是 diff:相等行只记行数,只有真正改动的行才存原文,所以一百条版本也远小于一百份正文。
- 恢复:选中任意一条点「恢复到此版本」写回正文;恢复动作本身也记一条,恢复错了还能再回滚。
- 删除:选中任意一条点「删除此版本」(连点两次确认)就把这条记录删掉;它后面的版本会重新计算 diff,仍然可以逐条打开,链不会断。
- 同一份正文只存一条:每条版本带正文的 sha256 前 16 位,保存时若和已有版本的内容哈希相同,就不 再新增记录(撤销、恢复后再保存、导入同样的正文都属于这种情况),列表和对比窗口里都能看到哈希。
- 链式重放:第一条版本作为基准快照,之后逐条重放;超过 200 条时把最旧的几条折进基准, 保留下来的版本仍可逐条打开。每条记录带内容摘要,历史文件被手改坏时重放会报错,不会给出别的正文。
- 关掉开关只是停止记录,已有历史仍可查看与恢复。
看这条会话聊了什么
下拉框旁边那个按钮会打开一个只读弹窗:左右气泡式对话(你的输入在右、Agent 的回复在左)。
- 只显示你真正敲进去的内容:工作区指令(
AGENTS.md)、运行时上下文快照、skill 目录说明这类 插件注入的"看起来像用户消息"的东西一律不展示,弹窗顶部只写「已隐藏 N 条插件注入内容」, 不占位置,也不会让你困惑"这条我没说过"。 - 消息过长会被截断,就地提供 展开全文(只重读这一条,换掉这一个气泡)与 收起全文。
- 跳到最新 只显示最后一个用户输入及之后的回复。
对话页的「人设」标签

选中一条会话后,对话页顶部有 人设 / 提示词 / 管理 三个面板:
- 人设:这条会话命中了哪条人设、依据是哪几条规则(命中依据)、正文(Markdown 渲染), 以及它自己的状态标记(在用 / 已停用、是否默认人设、注入方式);下面是一个就地编辑器 (名称、默认人设开关、注入方式、正文),改动后卡片头会出现「未保存 · 点击保存」。
- 提示词:这条会话实际发出去的 system prompt,可以切换「渲染 / 源码」、复制、刷新。 没有命中任何人设时,这里显示的就是 DSH 原生注入的 prompt —— 不做任何特殊处理。
- 管理:与设置页同一套卡片(新建、启用/停用、编辑、排序、复制、删除),就地管理。
五个偏好
| 开关 | 默认 | 含义 | 生效时机 |
|---|---|---|---|
| 编辑后自动保存 | 关 | 停手约 1 秒自动保存编辑区内容 | 立即;切换到人设规则行(工作区/会话)时不自动保存,避免存下半截选择 |
| 在对话页显示「人设」标签 | 开 | 是否注册对话页那个视图 | 立即(运行时注册/注销) |
| 注册到 dsh-better-sidebar | 开 | 是否把「人设」页面注册进 dsh-better-sidebar 的右侧栏 | 立即;没装该插件时这个开关不显示 |
| 禁止模型改写人设文件 | 开 | 按能力判定:任何会写入/删除人设存储(含它的历史文件与备份副本)的工具调用都拒绝,读取、grep、把路径写进笔记都不受影响;关掉后不拦 | 立即;对下一次工具调用生效 |
| 保存人设版本历史 | 关 | 每次保存记一条可重放的 diff(最多 200 条,可查看/对比/恢复) | 立即;关掉后不再记新版本,已有历史仍可查看 |
偏好存在人设文件的 prefs 字段里(不是浏览器),所以它和数据的可见范围一致;浏览器里只留一份镜像,
供"加载时决定要不要注册视图"用。
注入方式:追加还是替换
| 方式 | 效果 |
|---|---|
| 追加(默认) | 保留 DSH 自带的那句身份提示,这条人设接在它后面 |
| 替换 | 去掉 DSH 自带的身份句(以及部署自己写的 persona 段),只用这条人设 |
「替换」只动部署自己写的那句 persona;如果某个 Agent 预设在自己作用域里写了 persona(把这一段遮蔽了), 插件不会去覆盖它 —— 别人的身份提示优先。
匹配是怎么算的
宿主在每次组装 system prompt 时按这个顺序过一遍:
- 人设停用了 → 跳过;
- 一条人设的任意一行匹配上,它就是候选,按"具体度"比较(会话 ID 3 分 > 工作区 1 分;精确 > 前缀/包含/正则);
- 具体度相同 → 取列表里靠上的那条(顺序在卡片的
⋯菜单里调); - 一个位置都没加的人设不参与匹配(草稿态),除非它被标成「默认人设」;
- 谁都没命中 → 看有没有「默认人设」,有就用它,没有就不注入;
- 赢家的正文是空的 → 不注入任何人设(这是"这里明确不要人设"的表达方式)。
四种匹配方式里只有 完全一致 会把路径归一化(/a/project/ 和 /a/project 算同一个);
开头是、包含、正则匹配 都是拿你写的字符串直接比。值空着、正则写错、或者会话没有那个字段,
都算「不匹配」,不会报错。
文件与配置
~/.dsh/dsh-agent-persona/
├── personas.json # 人设数据 + 偏好,权限 600,原子写入
├── personas.history.json # 版本历史(开关打开后才出现)
└── state.json # 加载心跳,每次加载时重写
正文里可以写 {{model}} 和 {{cwd}},渲染时替换成当前的值;其他 {{...}} 会被去掉(未注册的变量会让
整个组装抛错,所以这里做了保护)。
配置项(Schemastery schema,加载时校验,写错类型会加载失败而不是被忽略):
| 配置 | 默认 | 说明 |
|---|---|---|
storePath | '' | 人设文件位置;留空即 $DSH_HOME/dsh-agent-persona/personas.json |
tuneProvider | '' | AI 调优用哪个 provider;留空即 DSH 当前设置的模型 |
tuneModel | '' | 同上,模型 id |
多个 profile 各用自己的人设文件(可选)
人设数据默认是全局一份($DSH_HOME/dsh-agent-persona/personas.json,与其它插件的状态目录同一约定),
所以同一台机器上的多个 profile 共用同一份人设。要让某个 profile 独立,在该 profile 的
cordis.patch.yml 里覆盖它自己的路径(是覆盖字段,不要再 insert 一行):
# ~/.dsh/profiles/<该 profile>/cordis.patch.yml
- id: agent-persona
config:
storePath: /Users/you/.dsh/profiles/<该 profile>/personas.json
也可以用 DSH_HOME 环境变量把整个 ~/.dsh 指向别的目录(那样连会话记录、其它插件状态一起隔离)。
当前生效的文件路径始终显示在「Agent 人设」页面的 meta 行上(保存在 …),不会出现"改了半天不知道改的是哪一份"。
AI 改一版用哪个模型
默认用 DSH 当前设置的模型,设置页里的下拉框会把它预选好;想固定别的模型就用上面的 tuneProvider/tuneModel。
AI 只产出建议稿,点「采用」或「追加」才会进编辑框,再点保存才落盘。
几句实话
- 人设是行为约束,不是安全边界。它约束模型怎么说,不阻止模型用工具。
- 人设文件的防篡改是能力层面的判定:插件注册了全局
tools.guard,它不看工具叫什么名字,而是看这次调用会不会写到 受保护的文件 —— 参数里的路径(解析~与相对路径)、shell 命令里的重定向目标、写入型命令(删、移、原地改、解释器-c),以及补丁正文里的*** Update File:目标。受保护的是主文件personas.json、它的历史文件和它们的备份/临时副本。 - 它仍然只是行为约束,绕过面写在明处:本机
danger-full-access下改插件代码、改 profile 补丁文件都能绕过;脚本里 运行时拼出来的路径静态看不出;$VAR展开看不出;别名/函数包装也看不出。要更结实得在本机层面做:chflags uchg <人设文件>(自己改之前先chflags nouchg),或者把 DSH 跑在受限沙箱里、让人设文件属于别的用户。 - 判定按单次工具调用生效:同一条命令里既读又写,写的那部分照样被拒,只读的部分不会被连坐。
- 多处同时匹配时只取第一条,不拼接;规则是线性扫的,几十条没问题,几百条就该重新设计了。
- 一个 profile 里只装一次。同一个进程挂两个同 id 的行会让组合起不来。
- 测试的边界:仓库里的测试是单元测试 + 源码审计(236 条宿主断言 + 187 条客户端断言 + 生成产物漂移校验; 这个数字由测试自己统计,不会随文件改动而失真),它们保证逻辑与代码形状,不驱动浏览器 —— 界面行为 (视图渲染、开关、侧边栏卡片)目前靠人工核对。
开发
源码是 TypeScript,lib/ 是构建产物(不进 git,npm publish 前由 prepare 构建):
src/index.ts host 半边:存储、匹配、system-prompt section、远程服务
src/client.ts client 半边:设置页 + 会话视图 + 侧边栏卡片(打包成单文件 lib/client.js)
src/endpoints.ts 远程方法的单一来源(生成 src/remote.ts 与 src/typert.ts)
scripts/ 生成器 + 安装脚本
test/ 单元测试与源码审计
docs/ 架构、开发笔记、设计决策
npm install
npm run build # generate:remote → tsc → esbuild(产出 lib/)
npm run typecheck # 两个 tsconfig 都不报错
npm test # 236 + 187 条断言 + 生成产物漂移校验
dsh --profile web --dump-config | grep -c 'id: agent-persona' # 组合自检,应输出 1
改代码之后怎么生效:
src/**改完必须npm run build(lib/是产物)。- 客户端产物(
lib/client.js)改内容:客户端会按内容重算,刷新页面即可;别改文件名。 - 宿主产物(
lib/index.js)改内容:ESM 按 URL 缓存模块,不会自动重载 —— 重启dsh web。 package.json的dsh.bundle.patch或 profile 的bundles有改动:必须重启。- 生成产物(
src/remote.ts、src/typert.ts)不要手改:改src/endpoints.ts后跑npm run generate:remote,npm test会校验它们是否与来源一致。
细节在 docs/development.md,内部结构在 docs/architecture.md。
许可
Apache-2.0,见 LICENSE。
Plugins relacionados
dsh-web (dsh-ssh)
zhu1090093659/dsh-web
dsh-web (dsh-remote-web-ui)
zhu1090093659/dsh-web
dsh-web-ui (dsh-ssh)
zhu1090093659/dsh-web-ui
dsh-web-ui (dsh-remote-web-ui)
zhu1090093659/dsh-web-ui