Draws your own prompts in the scrollback inside a thick colored box, so they are easy to find when you scroll

Claude Code mods I use daily.
rewrite-prompt: press Ctrl+P and the draft in the prompt box is rewritten in place by a model (Sonnet, on your plan). Nothing is sent until you press Enter, and Ctrl+_ undoes it.write-for-me: press Ctrl+N and the next prompt is written for you from the last 12 messages of the conversation. If the box has text, it is used as a hint ("tests too") and expanded. Nothing is sent, and Ctrl+_ undoes it.prompt-box: the prompts you type are drawn in the scrollback inside a thick cyan box instead of one > text line. Task notifications and messages from other sessions keep their normal rows. No key binding needed.tool-oneline: each tool call is drawn as one line (⏺ Bash(echo hello) (ctrl+o to expand)) with no result block under it. Set detail to runs for one line per run of calls (⏺ Ran 3 tools: Bash ×2, Read). Ctrl+O still shows the full rows. A failed call keeps its error text.claude plugin marketplace add ekinertac/claude-code-mods
claude plugin install rewrite-prompt@ekinertac-mods
claude plugin install write-for-me@ekinertac-mods
claude plugin install prompt-box@ekinertac-mods
claude plugin install tool-oneline@ekinertac-mods
Then bind the keys. Add these to the Global block of ~/.claude/keybindings.json and start a new session:
"ctrl+p": "app:toggleDiffNoiseFilter",
"ctrl+n": "app:toggleDiffPreSession"
To use the runs level, add this to ~/.claude/settings.json:
"pluginConfigs": { "tool-oneline": { "options": { "detail": "runs" } } }
No keybinding action runs a mod command. The mod draws a zero-size button above the prompt whose action is app:toggleDiffNoiseFilter (inert outside the diff panel; write-for-me uses app:toggleDiffPreSession the same way, so the two never share an action), and the chord you bind to that action presses it. Nothing shows on screen.
claude plugin test <mod> (stubs the model, no network).hooks/register.tsx 45 lines1// prompt-box: draws the prompts you typed in a thick colored box in the scrollback.
2//
3// Why: the engine draws a typed prompt as one `> text` line, which is easy to lose when you scroll
4// back through long agent output. A full-width bordered box is visible at scroll speed.
5// How: a ui.render hook on the UserMessage row, matched on origin.kind 'composer', so task
6// notifications, peer messages and plugin prompts keep the engine's own rows.
7// The chevron sits in its own column, so wrapped and multi-line prompts line up under the first
8// character of the text instead of under the chevron.
9// The text is drawn as given and wraps; the stored message and what the model reads do not change.
10// Pasted text is stored wrapped in <pasted_content id="..."> tags for the model; they are noise to
11// a reader, so they are removed from the drawn text only.
12// Constraint: the box costs two extra rows per prompt (top and bottom border), and it also shows in
13// the ctrl+o transcript.
14
15import type { Register } from 'claude-code'
16
17const BORDER = 'bold' // thick lines
18const COLOR = 'cyan'
19const CHEVRON = '❯'
20
21const PASTE_TAG = /<\/?pasted_content[^>]*>/g
22
23// Tags out, then the blank lines they leave: trim the ends and keep at most one empty line between.
24function readable(text: string): string {
25 return text.replace(PASTE_TAG, '').trim().replace(/\n{3,}/g, '\n\n')
26}
27
28export const register: Register = on => {
29 on('ui.render', { component: 'UserMessage', props: { origin: { kind: 'composer' } } }, ($, e) => {
30 const { Box, Text } = $.ui.resolve(e)
31 return (
32 <Box borderStyle={BORDER} borderColor={COLOR} paddingX={1} width="100%">
33 <Box marginRight={1}>
34 <Text color={COLOR} bold>
35 {CHEVRON}
36 </Text>
37 </Box>
38 <Box flexGrow={1} flexShrink={1}>
39 <Text wrap="wrap">{readable(e.props.text)}</Text>
40 </Box>
41 </Box>
42 )
43 })
44}
45