Runs detect prompts through the engine for scripts/bench/bench.ts

Know the question before it is asked, and what you can safely say.
A side panel for Claude Code. Before a pitch, a customer meeting or the daily stand-up, it reads your repository, your tickets and, with Wispr Flow, earlier meetings, and shows the questions most likely to come up, each with answers ranked by risk and the source they rest on. During the meeting it listens along and predicts live which questions come next, with their answers ready before anyone asks.
/plugin install great-question --marketplace jsc2304/great-question
Then, in the repository you work in:
/great-question-prep today's daily
The panel opens and the questions appear when the background agent is done. For a meeting, name it instead: /great-question-prep customer pitch Thursday. More under Installation and Usage.
Every answer carries its risk as a mark, a word and a colour, safest first:
| Mark | Meaning |
|---|---|
| ● SAY IT · sourced | well founded, with a source |
| ○ WEAK · vague | true and binds us to nothing, but shallow |
| ▲ ONLY IF COVERED · commitment | binds us (date, price, scope); say it only when the documents back it |
| ✖ DON'T SAY · risky | unsupported, attackable or contradicting the documents |
A pitch prepared: what you worked on last as safe to say, then questions grouped by how surely they can be answered, each with its risk marks. An opened question says who is likely to ask, why, who answers on our side, and offers answers by risk, with their sources:

Where the documents give no firm answer, the panel offers, safest first, what is harmless but shallow, what you may promise only if it is covered, and what to leave out:

Listening along: the question just asked appears with answers by risk, your recent work stays on show as safe to say, and the next likely questions appear below, each with its safest answer in one line:

While a question is open, new ones wait behind a button instead of moving the list:

The pictures show the 0.12 layout. Since 0.13 the question asked now is drawn as a large card at the top, and the sections below it are folded while listening.
Screenshots show a fictional pitch for a fictional company; no real meeting was recorded.
/great-question-prep finds the upcoming meeting with its attendees and earlier conversations with the other side.In a Claude Code session in the terminal, enter:
/plugin install great-question --marketplace jsc2304/great-question
Confirm the marketplace question with y and choose the scope User (Enter). The mod then applies to all projects, including sessions in the desktop app.
Without a running session, use the shell:
claude plugin marketplace add jsc2304/great-question
claude plugin install great-question@great-question --scope user
Sessions that were running before the installation only see the mod after a restart.
claude plugin update great-question@great-question
Then restart the session. The loaded version is shown top right in the panel (for example v0.9.0).
| Command | Effect |
|---|---|
/great-question | opens the panel without generating anything |
/great-question-prep [occasion] | finds likely questions with answers in the background, for example /great-question-prep steering committee Thursday |
The desktop app does not list these commands in its suggestions. Type them in full and press Enter.
With nothing prepared yet, the panel asks where to start: Likely questions about <folder>, Prepare my next meeting (the background agent finds it in your calendar) or Prepare today's daily. Or just Listen live: questions then come from the live transcript only, answers from the repository.
Sources and the sources of answers are links where they point somewhere: a URL, a GitHub issue or pull request (owner/repo#12, #12), or a repository file, which opens on GitHub at its line (docs/ops.md:12). A file path counts from the session's folder; it becomes a link only when the file exists there and its repository's default branch on GitHub has it, otherwise it stays plain text.
Buttons in the panel:
/great-question-prep without an occasion. A background agent reads the repository, connected sources and the newest 12,000 characters of this session's conversation (text only, no tool output) while your session stays free; the panel shows a turning ◐ with the time taken, and the questions appear when it is done.question-sets/YYYY-MM-DD-HHMM-<title>.md in the project folder.While listening, the panel follows the questions you have to answer:
While listening, answers come from the repository too:
git grep, exports left out). The answers are written from the lines found, the prepared questions, your recent work and the briefing (see Data and confidentiality). A SAY IT answer then names its file and line, for example docs/offer.md:42.While listening, the list only grows, it is never rebuilt:
What gets prepared depends on the project: with slides, a pitch preparation or a meeting at hand it prepares the meeting; otherwise the daily stand-up from commits, pull requests and open tickets.
~/projects/second-brain/projects/<repo>/<repo>.md, 8,000 characters, first; it wins on a ticket's state), the first 6,000 characters of memory/MEMORY.md, the two newest files in memory/daily-logs/ (3,000 characters each) and the last 15 commit subjects, at most 24,000 characters, re-read at most once a minute. A lookup for the question asked now runs as a read-only subagent with the same model in the session's folder. Speaker names from Wispr Flow are not sent; names mentioned in the conversation are in the text.~/.claude/great-question/labels/ exists, listening appends every step's decisions to <day>.jsonl in it: the two-minute transcript excerpt, your git user name, the questions listed at that moment and what the model decided (which questions were asked, whom they were for, what comes next). The rows are meant for training a local decision model and stay on the computer. Without the folder nothing is written; delete it to stop.question-sets/ to .gitignore or review it before committing.Check:
claude plugin validate .
claude plugin test .
A change reaches running sessions only with a release, since the mod installs from this repository on GitHub: raise version in .claude-plugin/plugin.json and add the CHANGELOG.md section in the same pull request, merge, tag vX.Y.Z, then run claude plugin marketplace update great-question and claude plugin update great-question@great-question and restart the session. The desktop app loads the mod from the plugin cache, not from the working folder, so unmerged work never reaches it; test it with claude plugin test ..
Measure the live step before and after a prompt or model change. The script runs detectTask from hooks/live.ts through the engine (claude -p with the small plugin in scripts/bench/plugin) on hand-checked transcript excerpts and reports how often the model names the right addressee, and how long a call takes. The excerpts are meeting content and stay outside the repository: label rows in ~/.claude/great-question/labels/backfill.jsonl, hand labels in ~/.claude/great-question/laya/eval.json ({"rows": [{"i": <row>, "a": "me"|"all"|"other"|"none"}]}).
node --no-warnings scripts/bench/bench.ts haiku,sonnet 3
Measure through the engine, not with claude -p --model: the CLI thinks differently and reported Haiku at 11 s per call where the engine took 7 s (23.10.2026).
| File | Contents |
|---|---|
hooks/register.tsx | commands, the question-set tool, panel, export |
hooks/live.ts | listening along: read the transcript, fold in the model's reply |
types/index.d.ts | data types and the panel's state |
tests/ | tests for panel, export and listening along |
scripts/bench/ | measures the live step on hand-checked excerpts |
Questions, ideas and meeting stories go to Discussions; bugs to Issues. If Great Question saved you in a meeting, a star helps others find it.
MIT, see LICENSE.
hooks/register.tsx 26 lines1import type { Register } from 'claude-code'
2
3type Item = { i: number; model: string; system: string; known: string; task: string }
4
5/** `/bench <dir>`: runs every item of `<dir>/in.json` through `$.model.complete` as listening does, 16 at a time, into `<dir>/out.json`. */
6export const register: Register = on => {
7 on('session.start', async ($, e, next) => {
8 await $.command.register({ name: 'bench', description: 'Great Question bench: detect calls through the engine' })
9 return next(e)
10 })
11 on('command.run', { command: 'bench' }, async ($, e) => {
12 const dir = e.args.trim()
13 const items = JSON.parse((await $.fs.read(`${dir}/in.json`)) as string) as Item[]
14 const run = async (it: Item) => {
15 const t0 = Date.now()
16 const r = await $.model.complete({ model: it.model, effort: 'low', system: it.system, prompt: [{ text: it.known, cache: true }, { text: it.task }], maxTokens: 1200, timeoutMs: 60_000 })
17 return { i: it.i, model: it.model, ms: Date.now() - t0, out: r.usage?.output_tokens ?? 0, text: r.isAnswered ? r.text : '' }
18 }
19 // Blocks, so one call's time is not the queue of all.
20 const out = []
21 for (let k = 0; k < items.length; k += 16) out.push(...(await Promise.all(items.slice(k, k + 16).map(run))))
22 await $.fs.write(`${dir}/out.json`, JSON.stringify(out))
23 return { text: `bench: ${out.length} calls` }
24 })
25}
26