Adds a 'Discuss first' choice to every Q&A question: talk it through in chat, then Claude re-asks it with the agreed answer.

Claude Code mods (plugins), as one local marketplace: cc-mods.
| Mod | What it does |
|---|---|
discuss-first | Adds a "Discuss first" choice to every Q&A (AskUserQuestion) question. Pick it, talk the question through in chat, and Claude re-asks it with the agreed answer as option 1 "(Agreed)". With 4 options already, type discuss under Other. |
harness-coach | Teaches Claude Code while you work: one small toast every 3 turns (💡, 9 s) with a tip about keys, slash commands, skills or the harness, chosen by what the turn did (shell, edits, subagents, a long turn, a full context). First-time situations get a one-time nudge at once. Every tip is shown once before any repeats, across sessions. /coach = a tip now · list · off / on · reset · every <n> · find <word>. |
checklist | A checklist band above the prompt for what waits on you: decisions, approvals, answers, steps. Claude adds items with its add tool whenever a reply hands you something, grouped ("Change requests waiting for your approval"), each with an Open button to the sub-session where you work on it; it ticks them when you answer. Click an item to tick it. /checklist = full list · add <text> · clear. One list per session, kept across restarts. |
git clone https://github.com/pnshad/claude-code-mods.git ~/claude-code-mods
claude plugin marketplace add ~/claude-code-mods
claude plugin install discuss-first@cc-mods --scope user
claude plugin install harness-coach@cc-mods --scope user
claude plugin install checklist@cc-mods --scope user
The plugin is read from this folder: after editing, run /reload-plugins in a session.
claude plugin test discuss-first
claude plugin test harness-coach
claude plugin test checklisthooks/register.ts 53 lines1import type { Register } from 'claude-code'
2
3export const DISCUSS = 'Discuss first'
4const DISCUSS_OPTION = {
5 label: DISCUSS,
6 description: 'Talk it through in chat; Claude re-asks this one with the agreed answer.',
7}
8
9// "Discuss first" picked, or "discuss ..." typed under Other (for questions that already had 4 options).
10export const wantsDiscussion = (answer: unknown): string | undefined => {
11 if (typeof answer !== 'string') return undefined
12 const a = answer.trim()
13 if (a.split(',').map(s => s.trim()).includes(DISCUSS)) return ''
14 const m = /^discuss\b[:\s-]*(.*)$/is.exec(a)
15 return m ? m[1].trim() : undefined
16}
17
18export const register: Register = on => {
19 on('tool.call', { tool: 'AskUserQuestion' }, async ($, e, next) => {
20 const questions = e.questions.map(q =>
21 q.options.length < 4 && !q.options.some(o => o.label === DISCUSS)
22 ? { ...q, options: [...q.options, DISCUSS_OPTION] }
23 : q,
24 )
25 const ran = await next({ ...e, questions })
26 if (ran.deny !== undefined || ran.isError) return ran
27
28 const answers = (ran.result as { answers?: Record<string, unknown> }).answers ?? {}
29 const discuss = questions.flatMap(q => {
30 const note = wantsDiscussion(answers[q.question])
31 return note === undefined ? [] : [{ q, note }]
32 })
33 if (discuss.length === 0) return ran
34
35 const list = discuss
36 .map(({ q, note }, i) => `${i + 1}. "${q.question}"${note ? ` — his first thought: ${note}` : ''}`)
37 .join('\n')
38 return {
39 ...ran,
40 context: [
41 ...(ran.context ?? []),
42 `discuss-first: the user chose "Discuss first" on ${discuss.length} question(s):\n${list}\n\n` +
43 'Every other answer in this result stands; record it, but do not act yet on anything that depends on a discussed question. ' +
44 'Take the discussed questions one at a time, in order. For each: give the background he needs (assume he remembers nothing), ' +
45 'the options and trade-offs, and your recommendation with why; then talk it through in normal chat, with no AskUserQuestion, until he reaches an answer. ' +
46 'When he has one, call AskUserQuestion with only that question, the agreed answer as option 1 labelled "<answer> (Agreed)", ' +
47 'its description summing up what was decided, so he confirms it with one pick. Then move to the next discussed question, ' +
48 'and when all are settled, continue the work.',
49 ],
50 }
51 }).catch(($, e, next) => next(e)) // never break the Q&A: on a failure, plain answers go through
52}
53