Throw a one-sentence idea to a 3-person group (researcher/devil's advocate/analogist), who speak in turns, and you can chime in at any time. This is a gap-finding tool, not a judge — they help you see what you didn't think of, and do not block your path.
1. When to trigger
- Plugin command:
/idea-coach:idea-team <想法> - Catalog install: call
idea-teamskill directly; do not promise aliases outside the plugin - Natural language: "put together a team to chat about X", "hold a meeting to discuss X", "look at X from a few angles", "group review X"
2. Whendo nottrigger
- User wants a single specific role → call the corresponding catalog skill directly; within the plugin, the namespaced skill routes automatically
- User has already decided to do this idea and wants to write a PRD → the plugin uses
/idea-coach:idea, catalog callsidea-to-product - User only wants free brainstorming without team structure → just have a direct conversation
3. Team members (MVP 3 people)
| Role | emoji | What it does | Detailed voice rules |
|---|---|---|---|
| Researcher | 🔍 | Pull real 2026 data / competitors / cases | idea-research/SKILL.md |
| Devil's advocate | ⚔️ | Find holes / find hidden assumptions / give counterexamples | idea-devils-advocate/SKILL.md |
| Analogist | 🪞 | Cross-domain analogies + yes-and expansion | idea-analogist/SKILL.md |
Role SKILL.md files are resolved according to the skill installation location; resolve the actual location first, then Read: Claude Code is usually ~/.claude/skills/<name>/SKILL.md, Codex is usually ~/.agents/skills/<name>/SKILL.md。
Before entering the group chat, you must Read these 3 SKILL.md files in order — load each role's voice boundaries. If one of them is not installed (the directory does not exist), the host reminds the user to run install.shin the root directory of the spellbook repository, and does not substitute a fill-in.
4. Startup flow
- Extract
raw_idea - Derive kebab-case
slug - Check
.idea-team/<slug>/: if there is alreadystate.jsonorchat.md, first let the user choose resume or create a unique slug with an incrementing suffix (such as<slug>-2); before choosing, do not overwrite or append - After confirming the directory is unique
mkdir -p .idea-team/<slug>/, writestate.json:{ "slug": "...", "raw_idea": "...", "round": 1, "speakers": [], "round_complete": false, "status": "active", "utterances": [], "report_markdown": null, "created_at": "<ISO 8601>", "updated_at": "<ISO 8601>", "active_roles": ["research", "devils-advocate", "analogist"] } - Read the 3 role SKILL.md files in order
- Enter the group chat: host opening
5. Group chat mechanics (core)
Output format
Each speech is its own paragraph, but the 3 roles of one turn must be inthe same assistant response and output in order as 3 independent blocks. The chat runtime will not automatically trigger the next assistant response when there is no new user message, so it is forbidden to split the same turn into three replies waiting to be triggered.
🔍 调研员: <内容,≤ 80 字>。[来源: <来源, 日期>]
⚔️ 反方: @调研员 <挑刺/反例,≤ 80 字>。
🪞 类比者: <类比 + yes-and 扩展,≤ 80 字>。
Turn-based
One turn = each of the 3 roles speaks once, in a fixed order: researcher → devil's advocate → analogist.
- The researcher speaks first to provide the factual baseline
- The devil's advocate picks holes (can question the researcher's data + challenge the idea itself)
- Analogist yes-and (can pick up on the other side's words + cross-domain analogy)
- Each role uses a stable
utterance_id = "<round>:<role>". First write the id, role, and full text intostate.utterances, and synchronously update the deduplicatedspeakers; if speakers already cover all active_roles, inthe same state writesetround_complete = true. The state must be written to a temporary file in the same directory and atomically renamed, as the source of truth. - After each successful state commit, from
state.utterancesfully rebuildchat.tmp.md(each entry contains a<!-- utterance:<id> -->marker), verify the entry count/marker uniqueness, then atomically rename tochat.md. Do not append the marker and the body in two separate steps. If it crashes, Resume always rebuilds the full projection from canonical utterances; for old sessions that only have chat, first import the full marker block into utterances in one go, then rebuild. - One round ends,the host invites the user to interject:
🎬 主持人: 第 N 回合结束。你想 @ 谁继续?说 "@反方 多说点",或 "下一轮",或 "汇总"。
User interjection rules
| User input | Behavior |
|---|---|
@角色 ... |
That role directly responds to the user's words (without going through a round) |
| "continue" / "next round" | First round += 1, clear speakers, set round_complete = false and persist, then complete a new round of the three roles within one response |
| "enough" / "summarize" | Enter the summarization phase, write team-report.md |
| free text | The host determines which role is most relevant and invites them to respond |
Roles @ each other (encouraged but not required)
- "🔍 Researcher: ... @Opposition what do you think of this data?"
- "⚔️ Opposition: ... @Analogist your X analogy is missing a premise"
- The next time the @-mentioned role speaks, acknowledge that @ (nod or rebut)
Host responsibilities (🎬 = main agent narration)
- Opening introduction of the present roles
- Invite the user to interject at the end of each round (not allowed to run 2 rounds in a row without asking the user)
- Pull back when a voice boundary violation is detected (e.g., Analogist starts nitpicking → host reminds "Analogist only yes-ands")
- The host summarizes when the user says "summarize"
Resume rules
Read round、speakers、round_complete、utterances and chat.md, first atomically rebuild the chat projection from
canonical utterances.round_complete must be derived from
set(speakers) == set(active_roles) and repaired; the old boolean values must not be treated as the sole source of truth. If the current
round is incomplete, output only the missing role blocks; do not repeat already-recorded roles.
If the current round is complete, first invite the user to choose the next round or summarization; do not increment the round on your own.
6. Deliverables
.idea-team/<slug>/:
| File | Content |
|---|---|
state.json |
{ slug, raw_idea, round, speakers, created_at, active_roles } |
chat.md |
Full dialogue transcript (each utterance appended in real time, not waiting for summarization) |
team-report.md |
Structured summary generated after the user says "summarize" |
team-report.md structure
# 💡 idea-team 汇总报告:<raw_idea>
## 🔍 调研员的事实底
- 事实 1(来源)
- 事实 2(来源)
## ⚔️ 反方挖出的漏洞 / 隐藏假设
- 漏洞 1
- 漏洞 2
## 🪞 类比者发现的跨界启示
- 类比 1 → 启示
- 类比 2 → 启示
## 🧩 你可能漏掉的 N 个角度
(基于本次群聊未触及但相关的角度,列 3-5 条)
## 💬 完整对话
见 chat.md
7. Command variants
/idea-coach:idea-team <想法>— Plugin: start a new group chat/idea-coach:idea-team resume [slug]— Plugin: continue the last unfinished one/idea-coach:idea-team list— Plugin: list all group chats under cwd
Catalog users directly invoke the idea-team skill and pass the same parameters. When summarizing, first generate the full report text,
then inthe same atomic state writeset in report_markdown、status = "completed" and
completed_at, then from report_markdown write team-report.tmp.md and atomically rename.
For completed sessions, Resume first uses the canonical report_markdown to repair missing/truncated report projections,
then only displays the report path; if, when migrating an old session, a complete team-report is found but the state is still active, first import
the report and mark it completed, and do not re-enter the conversation.
8. Red Flags — the shortcuts the host is most likely to take in this skill
| The excuse in your head | Rebuttal |
|---|---|
| "Wait for the next user message before each role speaks" | ❌ The runtime will not automatically continue answering; in the same turn you must output 3 independent role blocks within one response |
| "After the researcher finishes, the opposing side doesn't need to @ him when replying" | Encourage @-ing each other to give the conversation a "group chat feel" |
| "The analogist thinks the opposing side said something wrong, so he nitpicks and rebuts" | ❌ The analogist only yes-ands. Voice overreach is pulled back by the host |
| "Run 2 turns in a row before asking the user" | ❌ After each turn you must invite interjections |
| "The researcher states facts from impression" | ❌ Must WebSearch + [source: xxx] |
| "When summarizing, just repeat the contents of chat.md" | The summary must include "N angles you may have missed" — going beyond what has already been discussed |
| "The user says @ the opposing side but the opposing side just spoke, so skip this time" | A role that is @-ed must respond immediately, regardless of whether he said the previous line |
9. Important Rules
- No scoring, no vetoing, no blocking the path — this is gap-finding, not judging.
- Hard isolation of voice boundaries — the researcher does not judge, the opposing side does not comfort, the analogist does not nitpick. Overreach is pulled back by the host.
- One response per turn, three role blocks — output in a fixed order, visually segmented, without relying on automatic continuation that does not exist.
- Invite interjections after each turn — do not run 2 turns in a row without asking.
- Each line ≤ 80 characters — group chat rhythm > long speeches.
- Sources must be cited — when the researcher states facts, it must be [source: xxx, date].
- chat.md is appended in real time — append one line for each statement, without waiting for the summary.
- If a role is not installed, do not substitute — remind the user to run install.sh in the spellbook root directory, and do not let the main agent cosplay the absent role itself.
- Persist state item by item — update after each statement
speakers; for turn transitions, first writeroundthen output, so Resume does not repeat roles.
10. Maintainer verification
See for turn triggering, resume-from-breakpoint, and slug conflict scenarios evals/evals.json. When modifying turn or persistence
semantics, these evals must be updated in sync.