Lines where Claude waits on you are drawn in colour and pinned in a band above the prompt

Personal Claude Code mods: plugins of function hooks that restyle the transcript, add rows around the prompt and react to tool calls. Built and used on Claude Code 2.1.287+, Linux.
| Mod | What it does | Commands | Needs | |||
|---|---|---|---|---|---|---|
| quiet-bash | One-line tool rows (✓ <description>, red ✗ exit N on failure, +N −M on edits, duration for calls ≥10 s). Hides every tool's result block (Bash output, Edit diffs, WebFetch, MCP and Agent results; interactive tools, SendUserFile and image Reads keep theirs), finished read-only rows (Read/Grep/Glob, and calls the engine ran read-only like ls or git status, and every Claude in Chrome step but navigate), collapsed tool groups unless one failed, and timed-out GitLab pipeline-wait notices. Inline PNG thumbnails under rows that read, sent or wrote a PNG (at most 3 written ones per call), relative paths included; a group holding a thumbnail stays open, even under /quiet | /quiet brings it all back; /thumb [big] <path> shows a PNG (relative to the session's directory) as thumb #N: <path> | ImageMagick (magick) for thumbnails; a terminal with kitty graphics (see herdr) | |||
| quiet-spinner | Plain spinner words (thinking, writing, running, waiting, preparing) and Took 1m 4s instead of the whimsical ones | – | – | |||
| usage-percent | Row under the prompt: `ctx ▰▱▱▱ 34% \ | 5h ▰▰▱▱ 41% \ | wk ▰▰▰▱ 86% \ | fable ▰▰▱▱ 28% (four-cell bars; the fourth is the plan's model-scoped week, from the usage endpoint with the session's login) and resets 1d5h a gap after them for the weekly reset, yellow from 80 %, red from 95 %. Memory (claude.slice usage as a ten-cell bar of its limit + app.slice pressure, yellow from 20 %, red from 50 %) is sampled every 10 s and drawn by TamaGoxtix's band. In Nx repos also, on the right, the session's own nx serve projects (▶ admin api; a bare nx serve or run-many -t serve shows ▶ serve) and the branch's pipeline (ci ⏳ test, ⏸` when it waits on a manual job or an approval; none for Azure remotes) | – | gh / glab logged in for the pipeline; systemd claude.slice for memory |
| reminder-log | Tallies the reminders Claude Code injects for the model, per session; drops the token counter and repeated commit attribution blocks (sent again after a compaction) | /reminders prints the tally of the last 30 days | – | |||
| mr-banner | Colored card with a link under each MR/PR created, merged, approved or reviewed | – | GitLab MCP server named gitlab, or glab / gh | |||
| coderabbit-band | Band above the prompt with the open CodeRabbit threads (by severity) and nitpicks of the current branch's GitLab MR, with a link. Shows only when something is open | /coderabbit hides it until the counts change | glab logged in; GitLab remote | |||
| redact | Secrets in prompts and tool output reach the model as ‹secret:…› tokens; only Write/Edit turn them back into the real value. See redact | – | betterleaks on PATH | |||
| mem-guard | Bash commands that run Node tools go into a memory-capped claude-cmd.slice scope. Refused, with the fix in the message: nx affected/run-many without --parallel=1, a pnpm script that has a :lite twin, jest without a worker cap (--maxWorkers=N, -w N or --runInBand; a percentage doesn't count), pkill -f/pgrep -f with an unbracketed pattern, ci:local, heavy runs and dev-server starts while the slice is above 75 % or under pressure, a third heavy command or a third dev server at once, and writes by a check-runner subagent. See mem-guard | – | Linux with systemd: a user claude-cmd.slice, ps; see mem-guard | |||
| handover | Skill plus mod: the handover skill writes a one-sentence handover for a cold session to ~/.claude/handover.md; the mod files it per session under ~/.claude/handovers/<session id>.md, so parallel sessions in one repo never overwrite each other. A band above the prompt shows it; after /clear that session's sentence waits in the prompt (Tab takes it) and the next prompt spends it. A new terminal suggests nothing but lists the open sentences of the repo it started in (newest first, 14 days); a sentence belongs to the repo of the file its session wrote last, else to the folder the session started in | /handover-copy copies it and hides the band; /handover lists, /handover N puts one in the prompt, /handover drop N removes it; a sentence pasted by hand leaves the list too | – | |||
| herdr-notify | GNOME popup when Claude waits for a permission, an answer or a new prompt (a Notification hook, not a plugin). Skipped while that pane is the focused one in herdr. Clicking it raises Ghostty and focuses that session's herdr pane. Hook: `"Notification": [{"matcher": "permission_prompt\ | idle_prompt\ | elicitation_dialog", "hooks": [{"type": "command", "command": "bash \"$HOME/.claude/skills/herdr-notify/notify.sh\""}]}]` | – | herdr, Ghostty, notify-send, jq | |
| stack-down | On /clear and exit (also logout, a finished -p run, SIGINT/SIGTERM/SIGHUP), stops what the session left running in its repo: the nx processes it started (with their workers), and the repo's Docker Compose projects (compose down, volumes kept) unless another Claude session works in the same repo. Only for a session at a repo's top level (git rev-parse --show-toplevel); one started above the repos, such as ~/Dev, stops nothing | – | docker compose, git | |||
| review-walk | Skill plus mod: /review-walk takes the findings of the reviews already run in the conversation (/code-review, a repo's own review skill, CodeRabbit threads, MR comments), merges and ranks them, and asks fix / issue / skip one finding at a time; fixes wait until every finding is decided. The mod puts Finding N/M, a progress bar and the decisions so far over each question, and a band above the prompt between them. Decisions you authorised up front ("apply every Fix") are recorded through its ReviewWalkDecide tool instead of a question. The walk starts only after the skill runs, so a review on its own draws no band | /review-walk | A review run first: it walks findings, it never reviews. Any review skill or source works | |||
| tamagoxtix | Third line beside the monster, idle and while Claude works: usage-percent's memory bar. A fork of fabandrade88/tamagoxtix (MIT): a pixel monster in place of the spinner that acts out what Claude does, a band above the prompt between turns, cheer scenes while you type, twelve palettes, an optional powerline status line. The fork drops the band's usage column and repo column (repo-line shows repo and branch), the spinner's token line (usage-percent has the limits), pads the effects column so the text beside the monster stays put, adds /tamagoxtix animate off for still scenes, and puts the other mods' bands under the monster's caption instead of replacing them. With quiet-spinner the monster's line shows the plain word when quiet-spinner sits outer in the chain, else the whimsical one. The herdr half is herdr-tamagoxtix (sidebar faces, a usage popup, a tab-bar status area) | /tamagoxtix help, `… pet on\ | off hides the band, … palette <name>, … statusline on\ | off (writes statusLine into settings.json, backup kept), … theme on\ | off, … reroll` | Node.js 18+, a Nerd Font (or /tamagoxtix icons plain); git for the status line |
| task-meter | Band above the prompt with one row per running task: background shells, foreground shells after 5 s, subagents (their shells as └ child rows, tool count ⚒ N), workflows, monitors. Per row a ten-cell bar (filled where the output shows [N/M], a percentage or an nx task count, else one cell walking), the process tree's memory (yellow from 2 GB, red from 4 GB) and the running time, in aligned columns. Rows end with the task | – | Linux: ps, /proc/<pid>/fd, tail | |||
| repo-line | A line right above the prompt: the repository's name as a badge on the repository's own colour (a golden-angle hue per new repository, kept in the store), the branch (@abc1234 when detached) and (wt: name) in a linked worktree, so a prompt does not go to the wrong session. `/repo-line color <hue | #rrggbb> overrides, color reset` drops it | /repo-line | git | ||
| needs-you | Asks that wait on you stand out. Adds a system-prompt section: yes/no approvals and choices go through AskUserQuestion; anything else Claude waits on you for goes on its own line ⏸ Needs you: …. Those lines are drawn bold in the theme's warning colour (as plain text: links and code spans inside them are not formatted), pinned in a band above the prompt until your next message (or Clear), and in herdr shown as a ⏸ in the session's sidebar row; a ? there while an AskUserQuestion picker is open. See herdr for the sidebar row | – | herdr ≥ 0.9.5 for the sidebar icons, with { token = "$ask" } and { token = "$pick" } in ui.sidebar.agents.rows | |||
| ask-guard | When a reply asks a yes/no question in prose (shall I…?, want me to…?, ok to push…?, should I…? and similar), a Stop hook sends Claude back to ask it with AskUserQuestion, once per reply. Skips code blocks, > quotes, quoted text and ⏸ Needs you lines; a hook that fails lets the reply through | – | – | |||
| pii-guard | Asks before a tool call would send your personal data off the machine: WebFetch, WebSearch, every MCP tool (Claude in Chrome form fills included) and network Bash commands (curl, wget, urllib, requests, gh, git push …) whose input holds one of your identifiers, plain or URL-encoded, case-insensitive. Calls only to localhost pass. Born from a session that put the user's email into a third-party API's User-Agent because the API's policy asked for contact details. Does not see inside script files a command runs | – | pluginConfigs.pii-guard.options.identifiers in ~/.claude/settings.json: comma-separated emails and names (empty = off) |
The model sees exactly what it would without them: the mods change what is drawn, except reminder-log, which drops two kinds of injected reminders, redact, which hides secrets, mem-guard, which runs Node commands inside a systemd scope and refuses some with a mem-guard: … error, and stack-down, which stops the session's own servers and, when no other session is in the repo, its Compose stacks when the session ends.
Four mods call out on their own:
get_merge_request on the gitlab MCP server for the link and title. gh/glab commands cost nothing extra.glab for GitLab origin remotes: a 60 s timer checks the branch, and a fetch (glab mr view plus all pages of the MR's discussions) runs every minute for 15 min after a git push, every 5 min while the band shows something, every 15 min otherwise, and once 5 s after a thread is resolved.node on its usage script at session start and after each turn, and contacts no host. The mod's own README lists every call.ps and pwdx for nx serve processes, and docker inspect once per container a server runs in, to read its compose project directory. The pipeline (gh run list / glab ci get) is fetched when HEAD moves, 15 s after a git push, every minute while it runs and every 5 min otherwise.From the marketplace (gets updates; herdr-notify and herdr-link-toast are not in it):
claude plugin marketplace add schreibse/claude-code-mods
claude plugin install quiet-bash@schreibse-mods # per mod
Then turn on updates: /plugin → Marketplaces → schreibse-mods → Enable auto-update. See Updates.
From a clone, to adapt a mod or work on it. Claude Code loads every plugin folder under ~/.claude/skills/ at session start. Don't install the same mod from the marketplace too: the installed copy silently replaces the folder.
~/.claude/skills: clone straight into it: ``sh git clone https://github.com/schreibse/claude-code-mods ~/.claude/skills ``sh git clone https://github.com/schreibse/claude-code-mods ~/src/claude-code-mods ln -s ~/src/claude-code-mods/quiet-bash ~/.claude/skills/quiet-bash # per mod ``New sessions pick them up; a running one needs /exit and claude --continue.
Leave a mod out: claude plugin uninstall <mod>@schreibse-mods, or delete or unlink its folder. Try one for a single session: claude --plugin-dir ~/src/claude-code-mods/<mod>.
Where they run. Built and used only in the terminal CLI on Fedora (Linux, systemd, cgroup v2). The engine also loads user-scope mods in the local session the desktop app starts for its Code tab, and draws them there (desktop surface); untested here. See Setting up for what each mod needs.
This repo is the skills folder itself, so .gitignore ignores everything and re-includes each mod: a new mod needs a !/<name>/ line or git won't see it. .claude-plugin/types/ is generated by the engine and stays untracked.
Each mod has its own version (plugin.json) and a CHANGELOG.md in its folder; each release is a git tag <mod>--v<version>.
Plugin updated: <mod> · Run /reload-plugins to apply. Without it nothing tells you; check by hand: ``sh claude plugin marketplace update schreibse-mods claude plugin update quiet-bash@schreibse-mods # per mod; "already at the latest version" if none ``CHANGELOG.md. Read every version you skipped: a major version means you have to act (a new hook in settings.json, a new dependency, a removed command).git -C ~/.claude/skills pull --ff-only, then read the changelogs of the mods whose version moved (git -C ~/.claude/skills diff ORIG_HEAD -- '*/.claude-plugin/plugin.json').betterleaks scans every prompt and tool result before it reaches the model. Each value it flags becomes ‹secret:xxxxxxxx› and stays hidden wherever it appears later, even where the scanner would not recognise it again.
| The model's call | What happens |
|---|---|
| Write, Edit, NotebookEdit with a token | the real value is written to the file |
| Write that would drop a secret the file holds | refused: use Edit |
| Agent, SendMessage, TodoWrite with a token | passed on as the token |
| Any other tool with a token (Bash, WebFetch, MCP …) | refused, so the value never leaves |
| A token the mod no longer knows (after a restart) | refused, never restored wrongly |
Cut-short output. Before Bash or any tool with a file_path/path (Read, Grep, Edit …) runs, every file the call names (Bash: the first 10 words that could be paths, files up to 1 MB) is scanned whole, so cut -c1-60 .env, cut -d= -f2 or a Read of a few lines from a PEM key still come back as tokens. Multi-line secrets are hidden line by line. Bash words resolve against the directory each segment runs in (cd sub && cut -c1-40 .env), and ~/, $HOME/ and ${HOME}/ expand to the home directory.
Rules. betterleaks' defaults plus redact/betterleaks.toml: Sentry DSN keys, and client secrets too short for the generic rules. A client secret containing dev, local, test, example, changeme or placeholder stays visible, so local dev clients keep working in commands.
Not covered:
git show HEAD:.env | cut …, printenv | cut …); the transcript file's structured tool records, which keep real values (the model does not read them).cut -c1-40 *.env), quoted paths with spaces and a cd inside a subshell ((cd sub && cut -c1-40 .env)).client-secret rule needs some entropy (≥ 3.0), so short, repetitive client secrets stay visible.base64, rev, xxd) or sent (curl -T file). redact keeps secrets out of the model's context by accident; it is not a sandbox against a model trying to get them.‹secret:…› token is refused like any other tool call carrying one.The vault lives in session memory: /exit forgets it.
The status line shows redacted N once a value is hidden: N counts vault entries, so a PEM key counts once per line. A toast per call names the rules that hid new values. Without betterleaks the status line says off (no betterleaks) and nothing is hidden. A betterleaks run that fails leaves that call unredacted (values already in the vault stay hidden): one toast per failure streak, the status says off (betterleaks), and the next call scans again.
Every Bash command that names a Node tool (node, npx, pnpm, npm, npm exec, yarn, nx, jest, vitest, playwright, tsc, ngc) runs as systemd-run --user --scope --slice=claude-cmd.slice -p MemoryMax=30% -p MemorySwapMax=4% -- bash -c '…', so an overrun dies with exit 137 instead of taking the desktop down. Leading cd … && stay outside the wrapper, so the shell's directory still moves.
The rules read what each part of a command runs (after &&, |, ;, &, $( ), inside bash -c '…', following cd), never words it only mentions, so a commit message saying pkill -f passes. Not looked into: xargs, make, eval, scripts.
At once, counted per scope or service anywhere in claude.slice from one ps scan (skipped when ps fails):
node script that imports Playwright, tsc, ngc, an nx task), a running dev server included; the nx daemon doesn't count;nx serve, nx run x:serve, a serve* script): the API and one app.A command counts as heavy for these checks when it runs one of those tools, docker compose up, or a test, build, lint, typecheck, e2e or serve* script.
check-runner subagents (an agent type of the owner's) only run checks: git commands that change the tree or history, sed -i, --write/--fix, starting or stopping servers or processes, and writes outside /tmp are refused with "Report the failure instead of fixing it".
Assumes this setup; the messages name it:
claude-cmd.slice user unit. Without it systemd makes the slice with no limit of its own: each command is still capped at 30 % of RAM, but the headroom check has nothing to measure and stays off: ``ini # ~/.config/systemd/user/claude-cmd.slice [Slice] MemoryMax=30% MemorySwapMax=4% ` A full slice can livelock without ever reaching the OOM killer, so let systemd-oomd kill a scope in it under sustained pressure: systemctl --user set-property claude-cmd.slice ManagedOOMMemoryPressure=kill ManagedOOMMemoryPressureLimit=50%. systemd turns a percentage into bytes of the machine's RAM (on 27 GiB: 8.2G and 1.1G), so the same unit fits any machine. Check what a machine gets: systemd-run --user --scope -q -p MemoryMax=30% -- sh -c 'cat /sys/fs/cgroup$(cut -d: -f3 /proc/self/cgroup)/memory.max'`fuser -k 4700/tcp.:lite twin (lint:affected:lite, typecheck:lite, test:affected:lite) and a slow ci:local script.git@work:org/repo) reads as ci no login (work) though you are logged in.Under herdr (here inside Ghostty), quiet-bash's thumbnails draw only their alt text, and links in mr-banner, coderabbit-band and Claude's own output aren't clickable.
Cause: Claude Code turns on kitty graphics only for terminals whose XTVERSION answer is kitty (≥ 0.28) or starts with ghostty, and hyperlinks only for terminals it recognises. herdr forwards both, but answers with its own name, so Claude Code turns both off.
Fix: force both on, inside herdr only, before Claude Code starts (it reads them at startup):
# ~/.bashrc.d/herdr-terminal.sh
if [ -n "$HERDR_ENV" ]; then
export CLAUDE_CODE_FORCE_TERMINAL_IMAGES=1
export FORCE_HYPERLINK=1
fi
The herdr client forks its server into the client's own cgroup, so a server started inside a Ghostty window dies with that window and takes every pane with it. A wrapper in ~/.bashrc.d starts the first server in its own scope under app.slice instead; every other call, herdr plugin … included, goes straight through:
# ~/.bashrc.d/herdr-scope.sh
herdr() {
if [ $# -eq 0 ] && [ -z "$HERDR_ENV" ] && ! command herdr status server 2>/dev/null | grep -q '^status: running'; then
systemd-run --user --scope -q --slice=app.slice --unit="herdr-$(date +%s)" "$HOME/.local/bin/herdr"
else
command herdr "$@"
fi
}
Also turn on herdr's kitty graphics passthrough (off by default) in ~/.config/herdr/config.toml:
[experimental]
kitty_graphics = true
Then herdr server reload-config, open a new herdr pane (old panes keep the old environment) and start Claude Code there. Check it: /thumb /path/to/some.png should draw the picture.
herdr opens a ctrl+clicked link in the background with no feedback, and ignores file:// links altogether. herdr-link-toast opens http(s) links with xdg-open and shows a toast. It also opens the path in quiet-bash's thumbnail captions, which link to http://localhost/open-file/<path> because file:// isn't clickable in herdr. Such a link opens only when the path ends in .png; any other gets a "Could not open link" toast. Needs python3 ≥ 3.9. Install:
herdr plugin link ~/.claude/skills/herdr-link-toast
needs-you reports two tokens on its own pane (herdr pane report-metadata): $ask (⏸) while a ⏸ Needs you line is open, $pick (?) while an AskUserQuestion picker is open. herdr draws them only where the agent row names them, in ~/.config/herdr/config.toml:
[ui.sidebar.agents]
rows = [["state_icon", { token = "$ask", fg = "#f5a623", bold = true }, { token = "$pick", fg = "#f5a623", bold = true }, "machine", "workspace", "tab"], ["agent"]]
fg takes hex only. The row layout is the client's: after editing, choose reload config in herdr's menu (herdr server reload-config does not reload it).
The herdr half of tamagoxtix, unchanged from upstream: the monster's face in the sidebar, a usage popup (herdr plugin action invoke tamagoxtix.stats) and, on request, a status area right of the tabs and herdr colors f
hooks/register.tsx 86 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4import { INSTRUCTION, MARKER, asksIn, segments } from './asks'
5import { ASK_ICON, PICK_ICON, setToken } from './herdr'
6
7const asks = atom({ plugin: 'needs-you', key: 'asks' } as const, [])
8
9export const register: Register = on => {
10 on('prompt.compose', async ($, e, next) => {
11 const result = await next(e)
12 return { sections: [...result.sections, { id: 'needs-you', text: INSTRUCTION, scope: 'session' }] }
13 })
14
15 on('turn.complete', async ($, e, next) => {
16 if (e.agentId === undefined) {
17 const found = asksIn(e.answer)
18 await update($, asks, () => found)
19 await setToken($, 'ask', found.length > 0 ? ASK_ICON : null)
20 }
21 return next(e)
22 })
23
24 on('prompt.submit', async ($, e, next) => {
25 if (e.origin.kind === 'composer' || e.origin.kind === 'bridge') {
26 await update($, asks, () => [])
27 await setToken($, 'ask', null)
28 }
29 return next(e)
30 })
31
32 on('tool.call', { tool: 'AskUserQuestion' }, async ($, e, next) => {
33 await setToken($, 'pick', PICK_ICON)
34 try {
35 return await next(e)
36 } finally {
37 await setToken($, 'pick', null)
38 }
39 })
40
41 on('ui.render', { component: 'AssistantMessage' }, ($, e, next) => {
42 if (e.props.isSummary || !e.props.text.includes('Needs you:')) {
43 return next(e)
44 }
45 const parts = segments(e.props.text)
46 if (!parts.some(p => p.kind === 'ask')) {
47 return next(e)
48 }
49 const { Box, Markdown, Text } = $.ui.resolve(e)
50 return (
51 <Box flexDirection="column">
52 {parts.map(p =>
53 p.kind === 'ask' ? (
54 <Text color="warning" bold>
55 {MARKER} {p.text}
56 </Text>
57 ) : (
58 <Markdown text={p.text} />
59 ),
60 )}
61 </Box>
62 )
63 })
64
65 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
66 const open = await read($, asks)
67 if (e.props.hasSurvey || open.length === 0) {
68 return next(e)
69 }
70 const { Box, Button, Text } = $.ui.resolve(e)
71 return (
72 <Box flexDirection="column">
73 {open.map(text => (
74 <Text color="warning" bold>
75 {MARKER} {text}
76 </Text>
77 ))}
78 <Button key="clear" label="Clear" onPress={async () => {
79 await update($, asks, () => [])
80 await setToken($, 'ask', null)
81 }} />
82 </Box>
83 )
84 })
85}
86hooks/asks.ts 45 lines1export const MARKER = '⏸ Needs you:'
2
3export type Segment = { kind: 'markdown' | 'ask'; text: string }
4
5const ASK_LINE = /^\s*(?:[-*]\s+)?⏸\s*Needs you:\s*(.*)$/
6const FENCE = /^\s*(```|~~~)/
7
8export function segments(text: string): Segment[] {
9 const out: Segment[] = []
10 let markdown: string[] = []
11 let isInFence = false
12 const flush = () => {
13 if (markdown.join('').trim() !== '') {
14 out.push({ kind: 'markdown', text: markdown.join('\n') })
15 }
16 markdown = []
17 }
18 for (const line of text.split('\n')) {
19 if (FENCE.test(line)) {
20 isInFence = !isInFence
21 }
22 const ask = isInFence ? null : ASK_LINE.exec(line)
23 if (ask) {
24 flush()
25 out.push({ kind: 'ask', text: (ask[1] ?? '').trim() })
26 } else {
27 markdown.push(line)
28 }
29 }
30 flush()
31 return out
32}
33
34export function asksIn(text: string): string[] {
35 return segments(text).filter(s => s.kind === 'ask').map(s => s.text)
36}
37
38export const INSTRUCTION = `# Asks that block on the user
39
40The user skims long replies, so an ask buried in prose gets missed.
41
42- A yes/no approval or a choice between options (an outward write such as a push, an issue, an MR comment; a destructive step) is asked with the AskUserQuestion tool, never as a sentence in the reply.
43- Anything else the reply waits on the user for (look at something, test visually, run a command in their terminal, supply a value) goes on its own line starting with \`${MARKER}\`, one line per ask, plain text without links or code spans.
44- Never use the marker for anything that does not block on the user.`
45hooks/herdr.ts 16 lines1import type { EngineInterface } from 'claude-code'
2
3export const ASK_ICON = '⏸'
4export const PICK_ICON = '?'
5
6// herdr draws the `$ask` / `$pick` tokens in ui.sidebar.agents.rows of ~/.config/herdr/config.toml.
7export async function setToken($: EngineInterface, name: 'ask' | 'pick', value: string | null): Promise<void> {
8 const pane = await $.env.get('HERDR_PANE_ID')
9 if (!pane) {
10 return
11 }
12 const herdr = `${(await $.env.get('HOME')) ?? ''}/.local/bin/herdr`
13 const change = value === null ? ['--clear-token', name] : ['--token', `${name}=${value}`]
14 await $.process.run([herdr, 'pane', 'report-metadata', pane, '--source', `needs-you-${name}`, ...change]).catch(() => null)
15}
16types/index.d.ts 8 lines1export type NeedsYouAsks = readonly string[]
2
3declare module 'claude-code' {
4 interface PluginState {
5 'needs-you': { asks: NeedsYouAsks }
6 }
7}
8