Adds a button under each answer that collapses it, leaving only your question.

Three small tweaks that make long Claude Code sessions easier to live with.
After a few hours in Claude Code, the same small annoyances kept getting in my way: I'd lose track of what I'd asked, scroll past screens of output to find my last question, and hit my usage limit without seeing it coming. Each mod here fixes one of those. They're tiny, they don't change how Claude works, and you can turn any of them off by removing one line from your settings.
In a long conversation, your messages and Claude's answers are the same plain text, so scrolling back to find "what did I ask again?" means reading everything. This mod puts your messages on a colored band, so you can find them while you scroll.

Claude subscriptions have two usage limits, one per 5 hours and one per week, and Claude Code doesn't show you either until you're close. This mod keeps both in the status line, with when each one resets, so you can decide whether to start a big task now or save it for later.

Some answers run for screens: tool calls, file listings, long explanations. Once you've read one, it's just in the way. This mod adds a ▾ Collapse button at the end of each answer. Press it and the whole answer folds down to one line under your question, which also makes the conversation easy to skim later. Press ▸ Show answer to bring it back.

~/.claude/mods: git clone https://github.com/adriancoman/claude-code-mods.git ~/.claude/mods
If you already have a ~/.claude/mods folder, clone it somewhere else and use that path below.
~/.claude/settings.json and add the ones you want to the env block, separated by : (; on Windows): {
"env": {
"CLAUDE_CODE_PLUGIN_DIRS": "~/.claude/mods/prompt-highlight:~/.claude/mods/usage-status:~/.claude/mods/collapse-answers"
}
}
Want to try one first? This loads it for a single session only:
claude --plugin-dir ~/.claude/mods/collapse-answers
To update later, run git pull in ~/.claude/mods.
BACKGROUND at the top of prompt-highlight/hooks/index.tsx.Each mod is a folder with a short TypeScript file in hooks/. To check a mod after editing it, run claude plugin validate <mod folder>. Once Claude Code has loaded a mod, it adds type definitions to the folder, and tsc -p <mod folder> will type-check your changes.
MIT
hooks/index.tsx 89 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { CollapseAnswersTurns } from '../types'
5
6const EMPTY: CollapseAnswersTurns = { rowTurn: {}, first: {}, last: {} }
7
8const turns = atom({ plugin: 'collapse-answers', key: 'turns' } as const, EMPTY)
9const collapsed = atom({ plugin: 'collapse-answers', key: 'collapsed' } as const, [])
10
11function toggle($: EngineInterface, turn: string) {
12 return update($, collapsed, list => (list.includes(turn) ? list.filter(t => t !== turn) : [...list, turn]))
13}
14
15export const register: Register = on => {
16 // The prompt row that opened the turn the next answer rows belong to.
17 let current: string | null = null
18
19 on('session.append', async ($, e, next) => {
20 const stored = await next(e)
21
22 if (e.agentId !== undefined || e.message.isMeta) {
23 return stored
24 }
25
26 if (e.message.type === 'user' && e.origin.kind === 'composer') {
27 current = e.uuid
28 } else if (e.message.type === 'assistant' && current !== null) {
29 const turn = current
30 // A text block draws under the row's id, a tool call under its tool_use_id.
31 const drawn = e.message.content.flatMap<string>(block =>
32 block.type === 'text' ? [e.uuid] : block.type === 'tool_use' && typeof block.id === 'string' ? [block.id] : [],
33 )
34 const hasText = e.message.content.some(block => block.type === 'text')
35
36 const head = drawn[0]
37
38 if (head !== undefined) {
39 await update($, turns, t => ({
40 rowTurn: { ...t.rowTurn, ...Object.fromEntries(drawn.map(id => [id, turn])) },
41 first: t.first[turn] ? t.first : { ...t.first, [turn]: head },
42 last: hasText ? { ...t.last, [turn]: e.uuid } : t.last,
43 }))
44 }
45 }
46
47 return stored
48 })
49
50 on('ui.render', async ($, e, next) => {
51 if (!['AssistantMessage', 'ToolUse', 'ToolResult', 'ToolGroup'].includes(e.component)) {
52 return next(e)
53 }
54
55 const key = e.component === 'ToolGroup' ? (e.props.calls[0]?.tool_use_id ?? e.requestId) : e.requestId
56 const t = await read($, turns)
57 const turn = t.rowTurn[key]
58
59 if (turn === undefined) {
60 return next(e)
61 }
62
63 const { Box, Button } = $.ui.resolve(e)
64
65 if ((await read($, collapsed)).includes(turn)) {
66 return key === t.first[turn] && e.component !== 'ToolResult' ? (
67 <Box>
68 <Button key={`expand-${turn}`} label="▸ Show answer" onPress={() => toggle($, turn)} />
69 </Box>
70 ) : (
71 <Box />
72 )
73 }
74
75 if (e.component === 'AssistantMessage' && key === t.last[turn]) {
76 return (
77 <Box flexDirection="column">
78 {await next(e)}
79 <Box marginTop={1}>
80 <Button key={`collapse-${turn}`} label="▾ Collapse" onPress={() => toggle($, turn)} />
81 </Box>
82 </Box>
83 )
84 }
85
86 return next(e)
87 })
88}
89types/index.d.ts 12 lines1export type CollapseAnswersTurns = {
2 rowTurn: Record<string, string>
3 first: Record<string, string>
4 last: Record<string, string>
5}
6
7declare module 'claude-code' {
8 interface PluginState {
9 'collapse-answers': { turns: CollapseAnswersTurns; collapsed: string[] }
10 }
11}
12