Reskins how tool calls are drawn: an icon and a color per tool, in one of seven themes. Switch with /skin.

Nine mods for Claude Code (2.1.287 or newer), written from the walkthrough video. Each lives in mods/<name>.
Install one, or all, from a terminal session:
/plugin install <name> --marketplace KianaVega/KianaVega
| Mod | What it does | Extra model usage |
|---|---|---|
| savvy-progress | Progress bar above the prompt and a live list of subagents with model, tokens and rough cost | none |
| tool-skins | Icons and colors for tool calls in seven themes, switch with /skin <name> | none |
| you-should-know | A second, small model reads long answers and flags anything important you might miss | one small call per long answer |
| file-tree | Pane showing files Claude reads and edits, green once committed (/file-tree) | none |
| cache-tax | Holds a prompt that would reload a cold cache and shows an estimate. /keepwarm pings before the cache expires | none, except keep-warm pings |
| blast-radius | Stops recursive deletes, git clean, hard resets and shows the affected files before you press Proceed | none |
| reflect | Offers to save corrections as a rule in CLAUDE.md | one small call when you save |
| terminal-browser | /browse <url or file> opens a pane with a screenshot (kitty or Ghostty) and the page text | none |
| replay-theater | Replay button after a turn that steps through each edit as a diff (/replay) | none |
hooks/register.tsx. Edit and reload.hooks/register.tsx 92 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4type Palette = { read: string; edit: string; run: string; search: string; other: string; fail: string }
5
6// Add your own design system here: one palette per skin, any hex colors.
7const SKINS: Record<string, Palette> = {
8 nord: { read: '#88c0d0', edit: '#a3be8c', run: '#ebcb8b', search: '#81a1c1', other: '#b48ead', fail: '#bf616a' },
9 tokyo: { read: '#7dcfff', edit: '#9ece6a', run: '#e0af68', search: '#7aa2f7', other: '#bb9af7', fail: '#f7768e' },
10 dracula: { read: '#8be9fd', edit: '#50fa7b', run: '#f1fa8c', search: '#bd93f9', other: '#ff79c6', fail: '#ff5555' },
11 gruvbox: { read: '#83a598', edit: '#b8bb26', run: '#fabd2f', search: '#8ec07c', other: '#d3869b', fail: '#fb4934' },
12 solarized: { read: '#2aa198', edit: '#859900', run: '#b58900', search: '#268bd2', other: '#6c71c4', fail: '#dc322f' },
13 catppuccin: { read: '#89dceb', edit: '#a6e3a1', run: '#f9e2af', search: '#89b4fa', other: '#cba6f7', fail: '#f38ba8' },
14 mono: { read: 'white', edit: 'white', run: 'white', search: 'white', other: 'white', fail: 'red' },
15}
16const DEFAULT_SKIN = 'tokyo'
17
18const ICONS: Record<string, string> = {
19 Read: '[R]',
20 Edit: '[E]',
21 MultiEdit: '[E]',
22 Write: '[W]',
23 Bash: '[$]',
24 Grep: '[?]',
25 Glob: '[?]',
26 WebFetch: '[@]',
27 WebSearch: '[@]',
28 Agent: '[A]',
29}
30
31const skin = atom({ plugin: 'tool-skins', key: 'skin' } as const, DEFAULT_SKIN)
32
33const kindOf = (tool: string): keyof Palette => {
34 if (tool === 'Read') return 'read'
35 if (['Edit', 'MultiEdit', 'Write', 'NotebookEdit'].includes(tool)) return 'edit'
36 if (tool === 'Bash') return 'run'
37 if (['Grep', 'Glob', 'WebSearch', 'WebFetch'].includes(tool)) return 'search'
38 return 'other'
39}
40
41const summarize = (input: unknown): string => {
42 const i = (input ?? {}) as Record<string, unknown>
43 const pick = i.file_path ?? i.command ?? i.pattern ?? i.query ?? i.url ?? i.description ?? ''
44
45 return String(pick).split('\n')[0]!.slice(0, 80)
46}
47
48export const register: Register = on => {
49 on('session.start', async ($, e, next) => {
50 const saved = await $.store.get('skin')
51 if (typeof saved === 'string' && saved in SKINS) {
52 await update($, skin, () => saved)
53 }
54 await $.command.register({
55 name: 'skin',
56 description: `Pick a tool-call skin: ${Object.keys(SKINS).join(', ')}`,
57 argumentHint: '<name>',
58 })
59
60 return next(e)
61 })
62
63 on('command.run', { command: 'skin' }, async ($, e) => {
64 const name = e.args.trim()
65 if (!(name in SKINS)) {
66 return { text: `Skins: ${Object.keys(SKINS).join(', ')}. Current: ${await read($, skin)}.` }
67 }
68 await update($, skin, () => name)
69 await $.store.set('skin', name)
70
71 return { text: `Skin set to ${name}.` }
72 })
73
74 // Change: draw each tool row with its own icon and color. Display only.
75 on('ui.render', { component: 'ToolUse' }, async ($, e, next) => {
76 const { Box, Text } = $.ui.resolve(e)
77 const palette = SKINS[await read($, skin)] ?? SKINS[DEFAULT_SKIN]!
78 const tool = e.props.tool
79 const color = e.props.isErrored ? palette.fail : palette[kindOf(tool)]
80
81 return (
82 <Box>
83 <Text color={color} bold>
84 {ICONS[tool] ?? '[*]'} {tool}{' '}
85 </Text>
86 <Text dimColor={!e.props.isRunning}>{summarize(e.props.input)}</Text>
87 {e.props.isRunning && <Text color={color}> ...</Text>}
88 </Box>
89 )
90 })
91}
92types/index.d.ts 8 lines1export type SkinName = string
2
3declare module 'claude-code' {
4 interface PluginState {
5 'tool-skins': { skin: SkinName }
6 }
7}
8