Back to skills
SKILL.md
Discuss
ASecurity讨论模式:把当前单人对话变成 Claude + codex + gemini 等 CLI agent 的回合制群聊,用户是讨论的参与方而不是审批人。 当用户在讨论一个需求/方案该怎么做、想听听别的模型怎么看、要在两个以上方案之间权衡,或点名某个 agent 时使用。 触发词——拟人说法:「叫上 codex」「问问 gemini 怎么看」「@codex」「@gemini」「大家怎么看」「让他们吵一架」 「听听别的模型的意见」「拉个人进来聊聊」; 技术说法:「讨论模式」「/trundle:discuss」「/discuss」「多模型讨论」「交叉验证这个设计」「让 codex 和 gemini 分头论证 A 和 B」 「这个方案有没有别的做法」。 即使用户只是说「这块我不太确定」「我们是不是想复杂了」而当前话题是设计取舍,也应触发——但只用来**提议**进入,不直接进。 不触发:事实查询、读代码就能确认的问题、已进入写代码/调试的执行阶段、 用户只想要一份规格文档或评审报告(本 skill 产出的是讨论过程,不是文档)。
- 2 stars
- 0 votes
- 0 copies
- 1 view
- Added September 5, 2026
Works with
Security analysis
100/100Pro scans all 17 files and shows the line behind each finding
npx -y skills add PouLJenny/trundle --skill discuss --agent claude-codeAre you the author of Discuss?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/pouljenny-discuss)---
name: discuss
description: >-
讨论模式:把当前单人对话变成 Claude + codex + gemini 等 CLI agent 的回合制群聊,用户是讨论的参与方而不是审批人。
当用户在讨论一个需求/方案该怎么做、想听听别的模型怎么看、要在两个以上方案之间权衡,或点名某个 agent 时使用。
触发词——拟人说法:「叫上 codex」「问问 gemini 怎么看」「@codex」「@gemini」「大家怎么看」「让他们吵一架」
「听听别的模型的意见」「拉个人进来聊聊」;
技术说法:「讨论模式」「/trundle:discuss」「/discuss」「多模型讨论」「交叉验证这个设计」「让 codex 和 gemini 分头论证 A 和 B」
「这个方案有没有别的做法」。
即使用户只是说「这块我不太确定」「我们是不是想复杂了」而当前话题是设计取舍,也应触发——但只用来**提议**进入,不直接进。
不触发:事实查询、读代码就能确认的问题、已进入写代码/调试的执行阶段、
用户只想要一份规格文档或评审报告(本 skill 产出的是讨论过程,不是文档)。
version: 1.1.0
license: Apache-2.0
---
# trundle discuss
把当前对话变成 host(正在读本文件的你)+ 其他 CLI agent 的回合制群聊。**用户是参与方,不是审批人。产出物是讨论过程本身,不是最后那份文档。**
本文件是**壳**:只管进入/退出、机械执行和渲染。每轮「谁发言、喂什么、怎么收尾」的裁量由 **moderator**(一个独立的 CLI agent,见 `protocol/moderator.md`)产出计划,我照计划执行。我自己的发言在计划的 `host_say` 划定的边界内展开——那是指引不是讲稿,话由我自己说:我是讨论的当事方,不是传声筒。
**路径约定**:下文 `<SKILL>` 指本文件所在目录(Claude Code 软链安装下是 `${CLAUDE_SKILL_DIR}`,plugin 安装下是 `${CLAUDE_PLUGIN_ROOT}/skills/discuss`;其他 host 没有这些变量,就是你读到本文件的实际目录),`<SCRIPTS>` 指 `<SKILL>/scripts`。**主 host 是 Claude Code(行为已验证);其他 host 先读 `references/hosts.md` 的机制映射与支持状态。**
## 铁律
1. **用户是参与方,不是审批人。** 不向用户「提交」结论等批准,而是向用户**提问**。
2. **默认一轮只有我说话。** 拉人是例外——这条裁量由 moderator 执行,但它同时是我在降级模式下的行为底线。
3. **辅助 agent 全程只读。** API 参与者天然满足(它够不到文件系统),其余四个 CLI: codex 走 `--sandbox read-only`,gemini 走 `--approval-mode plan`,claude 走工具白名单 `--allowedTools Read,Glob,Grep`,dsh 走 `DSH_PERMISSION_MODE=read-only`(它没有只读 flag,只读靠环境变量,而且它的默认值是**可写的**——脚本强制覆盖用户环境,不随环境变量放宽)。永不给写权限。moderator 自己也是子进程,同样只读。
4. **产出物是讨论过程。** 除非用户明确要,结尾不生成规格文档、不写"最终方案"。
5. **子进程无状态。** 每次调用把需要的上下文完整塞进 prompt——它不记得上一轮。moderator 也一样:它每轮从 transcript 重建判断。
## 一个回合(壳的机械循环)
用户发言后:
1. **组装本轮输入**,写进临时文件,五段(格式见 `protocol/moderator.md` 的「输入」):
【名册】本轮实际阵容(「这轮别带 X」在这里生效)/【共识状态头】/【讨论记录】/【主持人立场】我对议题当前的立场或内心状态,如实写,包括没把握的部分/【用户本轮消息】原话
2. **跑 moderator**:`python3 <SCRIPTS>/moderate.py --input <文件>`。**必须允许它跑满 600s**——它的总预算是 590s(含一次重试),要让它先于 host 的命令超时开枪(Claude Code:Bash 工具 `timeout` 显式设 `600000`,默认 120s 会误杀;其他 host 见 `references/hosts.md`)。
3. **照计划执行**:输出里 `===EXEC===` 给出的 invoke.sh 命令**原样执行**(同样 timeout 600000);「本轮无外部调用」则跳过。`===WARN===` 里的 soft 违规如实转告用户,不隐瞒。
4. **渲染**所有发言(见「渲染」),然后我在 `host_say` 的边界内发言。
5. **收尾**按 `closing`:`user_question` → 以那个问题结束回合;`fact_verdict` → **我当轮就去查/去跑**,结果以 `[事实裁定] <结论>(host 实测,第 N 轮)` 追加进 transcript 并告知用户——把事实问题推给用户是失职;`none` → 不追问。
6. **记账**:按 `transcript_delta.append` 追加 transcript(`direction_change` 非空则先插 `── 方向变更:X → Y(用户,第 N 轮)──`),打状态行。
回合内不中途问"要不要继续"。moderate.py 退出码非 0 → 走「降级模式」。
## 降级模式
moderator 缺席时(moderate.py 退出码非 0:没装任何可用 CLI、超预算、两次都产不出合法计划),**明说一行**,例如:`moderator 缺席(codex 未安装)· 本轮由我自行主持`,然后**我自己读 `<SKILL>/protocol/moderator.md`,按同一套裁量规则在脑内产出本轮计划,再照常走机械循环的 3-6 步**。
单一事实源:裁量规则只有协议那一份,壳里不复刻——否则协议改一处、壳漂一处。降级不静默、不中止讨论,只是裁量从子进程挪回我脑内,质量约束(不综合、伪共识警惕、@ 原话原样)一条不减。
## 进入与退出(两端都显式)
这个模式会改变我的行为(调外部 agent、拒绝直接下结论、把分歧端回去),所以不能隐式进出。
**进入**——三条路,都以用户点头收尾:`/trundle:discuss [话题]`(软链安装是 `/discuss`);口头声明(「叫上 codex」);或我识别到设计取舍时**提议**一句「要不要拉 codex 和 gemini 进来讨论?」等用户点头。**第三条是提议,不是自动挡。**
首次进入时若名册不存在(路径见「名册」的解析链),先组建阵容。进入后展示一次控制语法,之后每回合只有状态行:
```
─── 讨论模式 · codex + gemini · 第 4 轮 · 未决 2 ───
```
**退出**——用户明说(「退出讨论」「开始写吧」),或我在这三种信号下主动问一次(不反复骚扰):同一未决问题连续两轮无新论据 / 用户开始说执行性的话 / 未决问题清空。退出给两三行收尾:定了什么、还剩什么。**绝不因为退出就把 transcript 整理成规格文档。**
**未进入本模式时,以下规则全部不生效**——正常回答、正常写代码。
## 控制语法
进入时展示一次:
```
@codex <你的话> 只让 codex 回应,你的原话原样转达
@codex @gemini <你的话> 同时点名多个
@all <你的话> 全员回应
让 codex 和 gemini 分头论证 A 和 B 对赌,各给不同任务
把 cline 加进来 / 让 gemini 退出 中途加人 / 踢人
这轮别带 gemini 仅本轮跳过
/trundle:discuss agents 重新挑参与者
退出讨论 / 开始写吧 结束
```
这些控制语从我口中到 moderator 的输入原样传递:@ 的原话、点名、对赌任务分配都是【用户本轮消息】的一部分,moderator 按协议处理(@ 原话必须一字不差进被点名者的 prompt)。用户的话里若有事实错误,我在**自己那段**指出,转达的那份不动。
## 裁量规则在哪
「谁在什么时候说话」「不综合,把分歧端出来」「伪共识警告」——这三块是这个 skill 的价值核心,**正文在 `protocol/moderator.md`**,由 moderator 每轮执行、由我在降级模式下执行。要点仅提醒(执行以协议为准):
- 默认没人说话;拉人只有三个口子(用户点名 / 主动拉且每轮至多一次 / 显式对赌必须不同任务)。**每轮全员发言 = 这个 skill 已经坏了。**
- 分歧未解决时我不下「综合考虑建议 A」式结论——点破分歧、还原前提差异、把只有用户能答的问题交回去。
- 所有人一致时先怀疑答案是被喂进去的;向用户报告一致时必须带边界(「他们一致,但都没碰过 X」)。
## 名册与阵容
三层:**适配库**(`agents.yaml`,某个 CLI 怎么调)→ **名册**(用户选了谁 + 站位)→ **本轮阵容**(运行时,写进本轮输入的【名册】块)。
**名册路径是 host 无关的**,解析链(moderate.py 的 `resolve_roster()` 同一套,壳读写名册也照它走):`TRUNDLE_ROSTER` 环境变量 → `~/.config/trundle/roster.yaml`(XDG,新名册写这里)→ 旧路径 `~/.claude/trundle-discuss/roster.yaml`(存在则回退,老用户零迁移)。名册是用户的偏好,不是某个 host 的私产——换 host 接着用必须是同一份。
**站位只在名册里,适配库不预设任何站位。** 站位是「讨论里的位置」,不是 CLI 的属性——库作者既不知道用户装了哪些 agent,也不该替所有场次预定立场;何况适配库随 skill 更新被覆盖,而站位是用户偏好,写在一起必然漂。
- **首次**:跑 `<SCRIPTS>/discover.sh` 扫描 → 让用户勾选 → 问要不要分站位 → 写名册。适配库只收实测跑通的 CLI;**未登记的只列出、绝不调用**(猜错只读约束会给它写权限;moderate.py 对未登记名字有同样的闸)。
- **moderator 可配置**:名册顶部可写一行 `moderator: <名>`(可选)。缺省是 `codex`——spike 实测它三次全稳定、13-47s/轮;显式指定的 CLI 没装或没通过前置检查时,moderate.py 会**响亮**降级到回退链,不静默换人。首次组阵容时顺带问一句,不强制。
- **站位是可选的。** 写了 stance 的参与者:整场不变,且两人不能同站位(重复视角既是伪共识燃料,又白付一份延迟)。没写的:不预设视角,判伪共识时把观点重合概率算进去。默认 2 人,同时发言上限 3 人,超过要提示。
- **API 参与者**:名册条目带 `api:` 块的,是直连 LLM API 的参与者。它**没有工具**——看不到文件系统,只知道我写进 prompt 的字。字段:`base_url`(必填)/`model`(必填)/`api_key_env`(可选,只写**变量名**不写值)/`headers`(可选)/`max_tokens`(可选)。
```yaml
participants:
- agent: codex
- agent: deepseek
api:
base_url: https://api.deepseek.com/v1
model: deepseek-chat
api_key_env: DEEPSEEK_API_KEY
```
**每轮我要把本轮阵容里的 `api:` 块转写成一个 sidecar JSON**(`{名字: {字段…}}`,只含变量名不含凭证),写进本轮 outdir,然后用 `--api-config <该文件>` 传给 `moderate.py`;它会原样传给 `invoke.sh`。不传就等于本轮没有 API 参与者——**全 API 阵容时忘了传,moderator 会报「没有任何已登记的参与者」并退出**。
写进 moderator 输入的【名册】块时,API 参与者要带标记:`- deepseek [api · 无工具:看不到文件系统,只能看到你写进 prompt 的字]`。
它们的发言追加进 transcript 时,**署名带 `·api` 后缀**。
它们**不能当 moderator**(v1 明确不做),`moderator:` 字段只认已适配的 CLI。
- **中途加人**:发**入场简报**(共识状态头 + 最近两轮,**不是**全量 transcript——中途加人的价值就是没被前面锚定),末尾必须带「如果你觉得已确立的前提有问题,直接说」。
- **中途踢人**:「这轮别带 X」不写盘;「让 X 退出」写盘。**被踢者说过的话留在 transcript 里**,他提出的前提继续有效。
- **对赌进行中禁止加/踢**——换人毁掉对照。
## 状态:transcript + 共识头
transcript **只增不改**,署名原话是指向性反驳的唯一来源。静默 append,不向用户宣传、不做总结。落盘路径:新讨论写 `<项目>/.trundle/<date>-<slug>.md`;若项目里已有 `.claude/trundle-discuss/`(老项目)则**继续写那里**——transcript 是这个项目的记忆,与哪个 host 记的无关,同一项目的记录绝不因升级或换 host 劈成两份。
共识状态头(已确立前提 / 已废弃方向 / 未决问题)由我维护,每轮写进 moderator 的输入;`fact_verdict` 的裁定结果在下一轮进「已确立的前提」。用户改主意时**不作废**:插一行 `── 方向变更:X → Y(用户,第 N 轮)──`,把废弃前提移进「已废弃方向(不要再论证)」。少了这个,agent 会继续攻击一个已作废的方案。
## 调用与失败
参与者调用用 `===EXEC===` 给出的 `<SCRIPTS>/invoke.sh` 命令,原样执行。
**moderate.py 与 invoke.sh 都必须被允许跑满 600s**——两者内置看门狗(590s/540s),会自己收尾并给出失败分类;host 若先开枪,那一轮**连失败分类都拿不到,整段输出直接丢**。Claude Code 下这意味着 Bash 工具的 `timeout` 显式设 `600000`(默认 120s);其他 host 的对应事项见 `references/hosts.md`。
脚本的 stderr 里以 `···` 开头的行是**给用户看的实时进度**(逐字回显、状态行)。**解析时全部忽略,只认 `===AGENT` / `===PLAN` 分段。** 那些字用户在终端里已经看过了,不要当成 agent 的发言再渲染一遍。
超时是**按吐字间隔**判定的,不是墙钟:只要 agent 还在出事件就一直等,静默超限才算卡死(`DISCUSSION_IDLE`,codex 300s / gemini 与 claude 90s——codex 生成回答期间完全不发事件,不能按同一把尺子量);另有绝对上限防工具循环(`DISCUSSION_MAX_WALL`,默认 540s)。
**dsh 是例外:它没有事件流**,整轮 stdout 零输出,跑完才一次性给出全文。空闲超时对它不生效(脚本整体跳过),只受墙钟约束(540s,与全局相同)——无流意味着卡死没有任何征兆,墙钟是唯一的护栏,而 540 已是上限:Bash 工具自己在 600s 开枪,必须留余量让脚本先收尾。
`timeout` 状态有三种含义,脚本会在正文里说明是哪一种,并附上开枪那一刻它在干什么。**如果那里写着「发言中」,那多半不是它卡死,是被砍在正要说话那一刻**——告诉用户可以调大 `DISCUSSION_IDLE` 重试,不要直接当成它没话说。**如果写着「运行中(无进度事件)」,那是 dsh 这类没有事件流的 agent——它的静默是正常的,能调的只有 `DISCUSSION_MAX_WALL`**,别建议用户去拧另外两个。
**API 参与者的失败与 CLI 不同**:没有 exit code、没有 stderr、没有可给的 probe 命令,失败文案用的是 HTTP 状态码 / `finish_reason` / 已收事件数与字数。三种要认得出来——**「疑似上下文被截断」**表示模型只看到了 prompt 的一部分(被丢的通常是开头的共识状态头),这一轮宁可缺席也不能采信;**「生成未完成」**多半是撞上了 `max_tokens`;**「不是流式」**表示该端点或网关忽略了流式参数。它们**都不重试**,一次网络抖动就等于本轮缺席。
**gemini 必须在已 trust 的目录**——未 trust 时脚本返回 `untrusted` 并给补救指引,**绝不用 `GEMINI_CLI_TRUST_WORKSPACE=true` 绕过**(会把模型路由降级,延迟涨约 10 倍)。
失败**明说一行,不中止整轮**:`**gemini** · 调用失败(未认证)· 本轮缺席`。群聊里少一个人只是少一个人发言。**唯一例外**:对赌时一方缺席 → 对赌无效,问用户重试还是改单人回答。moderator 自己失败 → 降级模式,见上。
## 渲染
```
**codex** · 8.2s
先别争全量还是窗口,这可能解错了问题。你们两个方案都假设……
立场:先确认写放大来自哪一层,再选方案
不同意:Claude 说「窗口足够」—— 前提是写入均匀,日志类负载不是
如果我错了:写入其实是均匀的,那窗口确实够
```
## 参考
| 文件 | 何时读 |
|---|---|
| `protocol/moderator.md` | 每轮裁量的完整规则与 round plan schema;降级模式下我照它主持 |
| `references/hosts.md` | host 不是 Claude Code 时**必读**:机制映射与各 host 支持状态 |
| `references/invocation.md` | 要改调用方式、排查 CLI 失败、看实测数据 |
| `references/prompt-kit.md` | prompt 组装的展开说明(机器执行版以协议为准) |
| `references/adapting-new-cli.md` | 接纳一个未登记的 CLI |
| `references/adapting-api-model.md` | 接纳一个新的 API 端点(验证清单与 CLI 完全不同) |
Files in this skill
- SKILL.md
- agents.yaml
- protocol/moderator.md
- references/adapting-api-model.md
- references/adapting-new-cli.md
- references/hosts.md
- references/invocation.md
- references/prompt-kit.md
- scripts/discover.sh
- scripts/install.sh
- scripts/invoke.py
- scripts/invoke.sh
- scripts/moderate.py
- scripts/plan_check.py
- scripts/plan_fixtures.py
- scripts/selftest.py
- scripts/verify.sh
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.