A note above the prompt that stays until you clear it.

A note that sits above the prompt until you clear it, so the one thing you must not forget stays in front of you while you work.
📌 call the printer before 5 [Done]
/note <text> sticks a note./note shows the note you have./note done, or the Done button, clears it. Your next message then carries one visible line saying which note you cleared and when, so Claude knows you are back.The note is kept across sessions on your own machine, in Claude Code's plugin store, until you clear it. It sends nothing anywhere. The band draws in the terminal and in the Code tab of the Claude desktop app.
Nothing goes to any service from the mod itself. Here is each thing, plainly.
What it sends, and where.
note.Which programs it runs, and why.
What it puts in the prompts it submits.
(📌 Sticky note cleared at <time>: "<note>").What each hook does.
session.start: adds the /note command and loads your note from the plugin store.command.run for note: sets, shows or clears the note.prompt.submit: adds the cleared-note line to your message. With no note cleared, it passes your message on unchanged.ui.render for AbovePrompt: draws the note, with a Done button, above the prompt.Tested with Claude Code 2.1.287.
See every Rostech mod, live, at rostech.app.
hooks/register.tsx 76 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4// The note on screen. $.store keeps it across sessions; this atom redraws the band.
5const note = atom({ plugin: 'sticky-note', key: 'note' } as const, '')
6// A note cleared since the last prompt. The next prompt carries one line saying so,
7// because pressing Done tells Claude you are back at the screen.
8const cleared = atom({ plugin: 'sticky-note', key: 'cleared' } as const, '')
9
10function stamp(): string {
11 return new Date().toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })
12}
13
14export const register: Register = on => {
15 on('session.start', async ($, e, next) => {
16 await $.command.register({ name: 'note', description: 'Stick a note above the prompt. /note <text> sets it, /note done clears it.' })
17 const kept = await $.store.get('note')
18 await update($, note, () => (typeof kept === 'string' ? kept : ''))
19 return next(e)
20 })
21
22 on('command.run', { command: 'note' }, async ($, e) => {
23 const text = e.args.trim()
24 if (text.toLowerCase() === 'done') {
25 const was = await read($, note)
26 await $.store.delete('note')
27 await update($, note, () => '')
28 if (was) await update($, cleared, () => `📌 Sticky note cleared at ${stamp()}: "${was}"`)
29 return { text: 'Note cleared.' }
30 }
31 if (!text) {
32 const now = await read($, note)
33 return { text: now ? `📌 ${now}` : 'No note. /note <text> sticks one above the prompt.' }
34 }
35 await $.store.set('note', text)
36 await update($, note, () => text)
37 return { text: `📌 ${text}` }
38 })
39
40 on('prompt.submit', async ($, e, next) => {
41 const line = await read($, cleared)
42 if (!line) return next(e)
43 await update($, cleared, () => '')
44 return next({ ...e, text: `${e.text}
45
46(${line})` })
47 })
48
49 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
50 const now = await read($, note)
51 if (e.props.hasSurvey || !now) return next(e)
52
53 const { Box, Button, Text } = $.ui.resolve(e)
54 // The note sits on its own line; every other band above the prompt draws beneath it.
55 const below = await next(e)
56 return (
57 <Box flexDirection="column">
58 <Box flexDirection="row">
59 <Text color="yellow" bold>📌 </Text>
60 <Text color="yellow">{now} </Text>
61 <Button
62 key="done"
63 label="Done"
64 onPress={async () => {
65 await $.store.delete('note')
66 await update($, note, () => '')
67 await update($, cleared, () => `📌 Sticky note cleared at ${stamp()}: "${now}"`)
68 }}
69 />
70 </Box>
71 {below}
72 </Box>
73 )
74 })
75}
76types/index.d.ts 6 lines1declare module 'claude-code' {
2 interface PluginState {
3 'sticky-note': { note: string; cleared: string }
4 }
5}
6