An 'ask me first' switch (/askfirst): while on, Claude asks its clarifying questions before starting any non-trivial task.

What it does: an "ask me first" switch. While it is on, Claude asks the clarifying questions it needs before it starts any non-trivial task, so you don't have to end every prompt with "ask me any questions to help you out".
Where you see it:
/askfirst flips the switch; /askfirst on and /askfirst off set it. It answers Ask-first is on. or Ask-first is off.How it decides: while the switch is on, every prompt Claude is sent carries one extra paragraph in its system prompt telling it to ask first. Claude itself judges what counts as trivial: a one-line fix, a quick lookup, a plain question, or a request that already says everything gets no questions; it just does the work. It asks once, up front, not again mid-task.
Data saved: just the switch, in the mod's own store (a small JSON file Claude Code keeps for it under your Claude folder). So it holds across chats and restarts. It starts off. A flip in one chat reaches your other open chats on their next prompt (their footer label catches up on its next redraw).
Cost: no extra model calls. While on, a few lines more of system prompt per request, and the questions Claude asks.
hooks/register.tsx 68 lines1import type { EngineInterface, Register } from 'claude-code'
2
3// An "ask me first" switch. While it is on, the system prompt carries one more
4// section telling Claude to ask its clarifying questions (with the
5// AskUserQuestion tool) before it starts any non-trivial task, so the person no
6// longer has to end every prompt with "ask me any questions to help you out".
7// /askfirst flips it (or /askfirst on, /askfirst off). The switch is kept in the
8// mod's own store, so it holds across chats and restarts; it starts off.
9
10const KEY = 'isOn'
11const LABEL = 'ask first'
12
13const SECTION = {
14 id: 'askfirst:ask-first',
15 scope: 'session',
16 text: [
17 '# Ask first',
18 'The user has switched on "ask me first". Before you start any non-trivial task, ask the clarifying questions you need using the AskUserQuestion tool, then begin once they have answered.',
19 '- Ask 2 to 4 questions, each about something that would change what you build or how: scope, behaviour, trade-offs, where things go.',
20 '- For each question put the option you recommend first and add " (Recommended)" to its label.',
21 '- Skip the questions for trivial requests (a one-line fix, a quick lookup, a plain question) and for requests that already spell out everything you need; then just do the work.',
22 '- Ask once, up front. Do not stop again mid-task with more questions unless something you could not have foreseen comes up.',
23 ].join('\n'),
24} as const
25
26// The store is the one place the switch lives: every chat reads it fresh, so a
27// flip in one chat reaches the others on their next prompt.
28const isOn = async ($: EngineInterface) => (await $.store.get(KEY)) === true
29
30const setOn = async ($: EngineInterface, value: boolean) => {
31 await $.store.set(KEY, value)
32 // The footer label follows the switch right away.
33 $.ui.invalidate('ui.render')
34}
35
36export const register: Register = on => {
37 on('session.start', async ($, e, next) => {
38 await $.command.register({ name: 'askfirst', description: 'Ask me first: Claude asks clarifying questions before non-trivial tasks (on, off, or bare to flip)' })
39 return next(e)
40 })
41
42 on('command.run', { command: 'askfirst' }, async ($, e) => {
43 const arg = e.args.trim().toLowerCase()
44 let value: boolean
45 if (arg === 'on') value = true
46 else if (arg === 'off') value = false
47 else if (arg === '') value = !(await isOn($))
48 else return { text: 'Usage: /askfirst [on|off] (bare flips it).' }
49 await setOn($, value)
50 return { text: `Ask-first is ${value ? 'on' : 'off'}.` }
51 })
52
53 // The instruction itself: one section after everything the engine composed,
54 // on the session side of the cache boundary, only while the switch is on.
55 on('prompt.compose', async ($, e, next) => {
56 const composed = await next(e)
57 if (!(await isOn($))) return composed
58 return { sections: [...composed.sections, SECTION] }
59 })
60
61 // A dim "ask first" among the engine's own mode labels while it is on. No
62 // button: the desktop footer is already crowded.
63 on('ui.render', { component: 'SessionMode' }, async ($, e, next) => {
64 if (!(await isOn($))) return next(e)
65 return next({ ...e, props: { ...e.props, modes: [...e.props.modes, LABEL] } })
66 })
67}
68