Badge above the prompt for each active session skill.

Skills and mods for Claude-Code.
curl -fsSL shalom2552.github.io/agent-skills/install | bash
Or clone and run ./install. See ./install --help for options.
| Skill | Description |
|---|---|
docs-sync | Find and fix drift between docs and code. |
dotconf | Answer, change, and remember dotfile and app configs. |
read-only | Lock the session to read-only; change nothing. |
setup-sh25-skills | Install, manage and wire up shalom2552's agent-skills assets. |
system-audit | Read-only health, security and cleanliness audit of this machine. |
system-fix | Diagnose, fix, and document a system or config fault on this machine. |
to-prompt | Write a handoff prompt for a fresh agent. |
visualize | Turn any subject into a visual HTML page. |
walk-with-me | Learn languages and idioms by coding with a coach. |
Claude Code plugins.
/plugin install <mod> --marketplace shalom2552/agent-skills
| Mod | Description |
|---|---|
spinner-words | Swap the spinner verbs for dev ones. |
tape | /tape pane of tool calls per turn. |
frame | Rounded frame around your prompts. |
beat | Turn time and usage as pills. |
statusline | Bottom status line for claude. |
badges | Badge above the prompt for active skill. |
tdiff | Live diff of session changes. |
Small JSON files that ./install merges into the scope's settings.json.
./install settings --scope global -y
| Setting | Description |
|---|---|
tmux-truecolor | Truecolor inside tmux, so mod hex colors render right. |
hooks/register.tsx 90 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { Active } from '../types'
5
6export const BADGES: Record<string, string> = {
7 dotconf: 'DOTCONF',
8 'system-fix': 'FIX',
9 'system-audit': 'AUDIT',
10}
11
12const SESSIONS = 'sessions'
13const MAX_SESSIONS = 20
14
15const active = atom({ plugin: 'badges', key: 'active' } as const, [] as Active)
16
17export const skillsOf = (raw: unknown): Active =>
18 Array.isArray(raw) ? raw.filter((s): s is string => typeof s === 'string' && BADGES[s] !== undefined) : []
19
20const savedOf = (raw: unknown): Record<string, unknown> =>
21 typeof raw === 'object' && raw !== null && !Array.isArray(raw) ? { ...(raw as Record<string, unknown>) } : {}
22
23const save = async ($: EngineInterface, list: Active) => {
24 const id = await $.session.id()
25 const saved = savedOf(await $.store.get(SESSIONS))
26 delete saved[id]
27 const kept = Object.entries(saved).slice(1 - MAX_SESSIONS)
28 await $.store.set(SESSIONS, Object.fromEntries(list.length === 0 ? kept : [...kept, [id, list]]))
29}
30
31const restore = async ($: EngineInterface) => {
32 const list = skillsOf(savedOf(await $.store.get(SESSIONS))[await $.session.id()])
33 if (list.length > 0) await update($, active, () => list)
34}
35
36const set = async ($: EngineInterface, next: (list: Active) => Active) => {
37 await update($, active, next)
38 await save($, await read($, active)).catch(() => undefined)
39}
40
41export const register: Register = on => {
42 on('session.start', async ($, e, next) => {
43 await restore($).catch(() => undefined)
44
45 return next(e)
46 })
47
48 on('session.end', async ($, e, next) => {
49 if (e.reason === 'clear' || e.reason === 'resume') await update($, active, () => [])
50
51 return next(e)
52 })
53
54 on('skill.prompt', { skill: Object.keys(BADGES) }, async ($, e, next) => {
55 await set($, list => (list.includes(e.skill) ? list : [...list, e.skill]))
56
57 return next(e)
58 })
59
60 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
61 const list = await read($, active)
62 if (list.length === 0 || e.props.hasSurvey) return next(e)
63
64 const { Box, Button, Text } = $.ui.resolve(e)
65 const rest = await next(e)
66
67 return (
68 <Box flexDirection="column">
69 <Box gap={1}>
70 {list.flatMap(skill => [
71 <Text bold inverse color="permission" key={`badge:${skill}`}>
72 {` ${BADGES[skill]} `}
73 </Text>,
74 ...(e.props.isWorking
75 ? []
76 : [
77 <Button
78 key={`clear:${skill}`}
79 label="x"
80 onPress={() => set($, l => l.filter(s => s !== skill))}
81 />,
82 ]),
83 ])}
84 </Box>
85 {rest}
86 </Box>
87 )
88 })
89}
90types/index.d.ts 8 lines1export type Active = string[]
2
3declare module 'claude-code' {
4 interface PluginState {
5 badges: { active: Active }
6 }
7}
8