Shows the session id in the prompt footer; click to copy

Mods for Claude Code: small plugins that add to its screen and behavior. Each folder is one mod. Turn on the ones you want (see Setup) and change their settings in /config, under the mod's name.
Shows how full Claude's context window is, as a colored bar above the prompt.
/context-bar hides or shows it for this session.Shows how much of your 5-hour and weekly usage limits you've used, as two small meters under the context bar. They turn yellow at 70% and red at 90%, and you get a warning once a limit passes 90%.
Shows this session's ID in the bottom-right corner of the screen.
claude --resume <id> command.Adds a receipt to the line that closes each turn ("✻ Baked for 42s"): how many tools ran, which files were edited, the tokens used and what the turn cost.
Adds a one-sentence summary under Claude's longer replies, written by Claude Haiku.
/config sets how long a reply must be (600 characters by default).Lets you see images Claude reads, right in the conversation.
🖼 name.png · hover to preview. Point at it to show the picture, and move away to hide it.Gives Claude a voice, through murmur. It speaks only when you're away from the session (another app or tab in front), so it never talks over you while you're watching.
/read reads Claude's last reply aloud./tldr-aloud gives a spoken 2–3 sentence summary of the session so far./config./hush mutes this session; run it again to unmute./config under voice.Ties Claude into the Ghostty terminal. All its settings start with "Ghostty" in /config.
/title gets a new one right away. A resumed session gets its old title back./workspace saves and reopens whole windows of sessions: see Workspaces./goto (or ⌘⌃G) lists your open Claude sessions, the ones waiting on you first, and jumps to the one you pick. /goto next jumps straight to the one waiting longest; /goto <words> jumps to the one whose title matches./keybind add <keys> <text> makes a Ghostty key type something into Claude, like /keybind add super+ctrl+h /hush for ⌘⌃H. /keybind lists them, and /keybind remove <keys> removes one.A workspace is a Ghostty window of Claude sessions you can put away and bring back later. It remembers every tab and split: each Claude session with its conversation, and each shell with its folder. Reopening it brings back the whole window, with every conversation picking up where it left off.
| Command | What it does |
|---|---|
/workspace save [name] | Saves this window. With no name, it keeps the name the window already had, or Claude Haiku picks one from the tabs. |
/workspace close [name] | Saves this window, then exits every Claude session in it and closes their tabs. Your current tab stays open at the shell, and shell tabs stay open. |
/workspace list | Shows your saved workspaces, newest first. Press a number or Enter to reopen one, or Tab to ✕ delete to remove it. |
/workspace open <name> | Reopens a saved workspace in a new window. Part of the name is enough. |
claude --resume, so they continue their own conversation, with the tab title they had when you saved. A tab saved without a title gets a new one from its conversation. Shell tabs open at the prompt./workspace close. Pick it up tomorrow: /workspace list, then press its number.~/.claude/workspaces/, one JSON file per workspace.CLAUDE_CODE_PLUGIN_DIRS, separated by :, in the env block of ~/.claude/settings.json: "env": {
"CLAUDE_CODE_PLUGIN_DIRS": "/path/to/claude-mods/context-bar:/path/to/claude-mods/voice"
}
To try one mod for a single session: claude --plugin-dir /path/to/claude-mods/tldr.
CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 in the same env block, so Claude Code doesn't overwrite the tab title.The first time a mod controls Ghostty, macOS asks for permission. Allow it.
Editing a mod's files reloads it in running sessions.
claude plugin validate context-bar # check a mod the way Claude Code will load it
claude plugin test context-bar # run its tests
IDEAS.md has ideas for more mods.
hooks/register.tsx 46 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4// OSC 22 sets the mouse pointer's shape (Ghostty, Kitty, foot; other terminals ignore it).
5// A mod can't print to the screen, so write it straight to the tty of the nearest ancestor that has one.
6const SET_POINTER = `p=$$
7while [ "$p" -gt 1 ]; do
8 t=$(ps -o tty= -p "$p" | tr -d ' ')
9 case "$t" in ''|'?'|'??') p=$(ps -o ppid= -p "$p" | tr -d ' ') ;; *) printf '\\033]22;%s\\033\\\\' "$1" > "/dev/$t"; exit ;; esac
10done`
11
12const copied = atom({ plugin: 'session-id', key: 'copied' } as const, false)
13
14export const register: Register = on => {
15 // The footer's mode labels: no plugin-name prefix, always visible, and the id follows /clear.
16 on('ui.render', { component: 'SessionMode' }, async ($, e, next) => {
17 if (e.surface !== 'terminal' && e.surface !== 'desktop') return next(e) // no Client elsewhere
18 const { Box, Text, Client } = $.ui.resolve(e)
19 const id = await $.session.id()
20 const isCopied = await read($, copied)
21
22 return (
23 <Box>
24 {e.props.modes.length > 0 && <Text dimColor>{e.props.modes.join(' & ')} & </Text>}
25 <Client key="session-id" module="./sid.tsx" props={{ id, copied: isCopied }} />
26 </Box>
27 )
28 })
29
30 // sid.tsx posts hovers and clicks here, where $ can reach the tty and the clipboard.
31 on('ui.message', { element: 'session-id' }, async ($, e, next) => {
32 if (e.data === 'enter' || e.data === 'leave') {
33 await $.process.run(['sh', '-c', SET_POINTER, 'sh', e.data === 'enter' ? 'pointer' : 'default'])
34 return next(e)
35 }
36 const id = await $.session.id()
37 const text = e.data === 'copy-command' ? `claude --resume ${id}` : id
38 const { isCopied } = await $.ui.copy({ text, surface: e.surface })
39 if (isCopied) {
40 await update($, copied, () => true)
41 $.clock.after(1500, () => update($, copied, () => false))
42 }
43 return next(e)
44 })
45}
46hooks/sid.tsx 19 lines1import type { ClientModule } from 'claude-code'
2
3// Drawn by the surface itself, so it keeps its own colors and isn't inverted on hover like a Button.
4const SessionId: ClientModule<{ id: string; copied: boolean }, boolean> = ({ id, copied }, surface) => {
5 const { Text } = surface.elements
6 surface.onPointer(ev => {
7 if (ev.type === 'enter' || ev.type === 'leave') {
8 surface.setState(ev.type === 'enter')
9 surface.post(ev.type)
10 }
11 // Ctrl-click copies the whole resume command; macOS terminals may report it as a right click.
12 if (ev.type === 'up') surface.post(ev.ctrl || ev.button === 'right' ? 'copy-command' : 'copy')
13 })
14 return copied
15 ? <Text color="green">✓ Copied</Text>
16 : <Text>🏷️ <Text color={surface.state ? 'blue' : undefined} underline>{id}</Text></Text>
17}
18export default SessionId
19types/index.d.ts 8 lines1export type Copied = boolean
2
3declare module 'claude-code' {
4 interface PluginState {
5 'session-id': { copied: Copied }
6 }
7}
8