Claude Mod Hider: one tiny button that hides or shows every Claude Code mod above the prompt, remembered across sessions.

Part of Claude Mod Pack.
One tiny button that hides every Claude Code mod above your prompt, and brings them all back.
Running a few Claude Code mods (status bands, agent trackers, idle games) is great until you shrink the window and they push your prompt halfway up the screen. Claude Mod Hider puts a single arrow in the top-right corner of the band above the prompt, beside your mods, so it never adds a line. Click it and every mod there folds away; click again and they are back. It remembers your choice across sessions.

Click the arrow and the whole band folds down to a single ▸ mods button.
/plugin marketplace add finalpantasy/claude-mod-pack
/plugin install claude-mod-hider@claude-mod-pack
Restart Claude Code. Click the small ▾ in the top-right corner of the band above the prompt, or type /hide-mods. Click ▸ mods, or type /hide-mods again, to bring them back.
While hidden, Claude Mod Hider draws only its arrow and does not hand the band on, so every mod drawn beneath it disappears. Claude Code does not document the order mods draw in, so a mod drawn above it can still show. Mod authors can make their mod hide reliably with two lines:
const modsHidden = atom({ plugin: 'claude-mod-hider', key: 'hidden' } as const, false)
on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
if (e.props.hasSurvey || (await read($, modsHidden))) return next(e)
// ...draw as usual
})
and in your mod's type contract, inside interface PluginState:
'claude-mod-hider': { hidden: boolean }
A survey always gets the band, hidden or not.
With Claude Status Band installed, the band draws the arrow in its own top-right corner, so it sits in the same place whichever order Claude Code draws the mods in.
MIT
hooks/register.tsx 60 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4// One button above the prompt that hides or shows every mod drawn there, and stays itself.
5// Hidden, this hook draws only the button and does not hand the band on, so mods beneath it never draw;
6// mods above it in the chain read the same switch and pass. The choice is kept across sessions.
7
8const hidden = atom({ plugin: 'claude-mod-hider', key: 'hidden' } as const, false)
9// Mods draw in an order nobody sets: while Claude Status Band's band shows, it draws this arrow in its own corner.
10const bandArrow = atom({ plugin: 'status-band', key: 'hiderArrow' } as const, false)
11const bandHidden = atom({ plugin: 'status-band', key: 'isHidden' } as const, false)
12
13/** Whether Mod Hider draws its own arrow beside the mods: always while hidden, and while shown unless the band draws it. */
14export const drawsOwnArrow = (isHidden: boolean, bandDrawsArrow: boolean, isBandHidden: boolean) => isHidden || !bandDrawsArrow || isBandHidden
15
16async function toggle($: EngineInterface) {
17 const next = !(await read($, hidden))
18 await update($, hidden, () => next)
19 await $.store.set('hidden', next)
20 return next
21}
22
23export const register: Register = on => {
24 on('session.start', async ($, e, next) => {
25 const started = await next(e)
26 await $.command.register({ name: 'hide-mods', description: 'Hide or show everything mods draw above the prompt' })
27 const saved = await $.store.get('hidden').catch(() => undefined)
28 if (typeof saved === 'boolean') await update($, hidden, () => saved)
29 return started
30 })
31
32 on('command.run', { command: 'hide-mods' }, async $ => {
33 const isHidden = await toggle($)
34 return { text: isHidden ? 'Mods above the prompt hidden. /hide-mods or the button brings them back.' : 'Mods above the prompt shown.' }
35 })
36
37 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
38 // A survey always gets the band.
39 if (e.props.hasSurvey) return next(e)
40 const ui = $.ui.resolve(e)
41 const { Box, Text } = ui
42 const Button = 'Button' in ui ? ui.Button : null
43 const isHidden = await read($, hidden)
44 const control = Button
45 ? <Button key="hide-mods" label={isHidden ? '▸ mods' : '▾'} plain onPress={() => void toggle($)} />
46 : <Text key="hide-mods" dimColor>{isHidden ? '▸ mods (/hide-mods)' : '▾'}</Text>
47 if (isHidden) return <Box flexDirection="row">{control}</Box>
48 if (!drawsOwnArrow(isHidden, await read($, bandArrow), await read($, bandHidden))) return next(e)
49 // Shown, the arrow takes a narrow column beside the other mods, in the top-right corner, not a row of its own:
50 // the band is no taller than the mods make it.
51 const below = await next(e).catch(() => null)
52 return (
53 <Box flexDirection="row">
54 <Box flexDirection="column" flexGrow={1} flexShrink={1}>{below}</Box>
55 <Box flexShrink={0} marginLeft={1} alignSelf="flex-start">{control}</Box>
56 </Box>
57 )
58 })
59}
60types/index.d.ts 18 lines1// Claude Mod Hider's type contract: the one switch other mods read.
2
3/** True while mods above the prompt are hidden; any mod drawing there reads it and passes. */
4export type Hidden = boolean
5
6declare module 'claude-code' {
7 interface PluginState {
8 'claude-mod-hider': {
9 hidden: Hidden
10 }
11 /** Read only: Claude Status Band draws this arrow in its own corner while its band shows, so Mod Hider draws none then. */
12 'status-band': {
13 hiderArrow: boolean
14 isHidden: boolean
15 }
16 }
17}
18