Keeps the savvy-progress bar on for every task: the todo list, tasks and every agent the main thread starts become rows, counted done as they finish, unless a…

New Ward skills: agent skills and slash commands for Claude Code that I use on every project.
Most are my own. Some started as other people's skills and now carry my changes, mostly an unlazy completion gate and plain-writing rules wired in. Each one is marked in the tables below.
claude plugin marketplace add michaelezehi/nw-skills
claude plugin install nw-skills@nw-skills
Plugin skills and commands are namespaced, so /research becomes /nw-skills:research.
npx skills@latest add michaelezehi/nw-skills
This copies editable skill folders into your project or ~/.claude/skills.
Copy any folder under skills/<category>/ into ~/.claude/skills/, and any file under commands/ into ~/.claude/commands/.
Several skills point at ~/.claude/skills/unlazy/scripts/gate-check.mjs and ~/.claude/skills/unslop/SKILL.md. Install unlazy and unslop first if you take only a few.
| Skill | What it does | Origin |
|---|---|---|
app-user-journey | Scan a codebase for every user role and map each one's real journey, registration, onboarding, the day-one surface, and a proposed leaner path, then ship it as an... | Original |
build-speed | Audit and fix any project's build + deploy pipeline for speed, kill cache-busting, move builds off the deploy box into CI, wire registry pull mode, and prove every... | Original |
convex-backup-cron | Install a 4x-daily production backup cron for Convex + DigitalOcean Spaces projects. | Original |
og | Install a dynamic Open Graph / Twitter social card route into a Next.js project. | Original |
own-goal | Run a goal or a whole PRD to completion: a verifiable completion condition worked in a loop until met, with an accountability record and a /reviewer gate. | Original |
project-optimisation | Find and fix why a JS/TS monorepo is slow, from dev server memory to first-load JS per route: measure, fan out by cause, fix in parallel, re-measure, ship through staging. | Original |
qa-cases | Generate a shareable QA test case .md document for the current project. | Original |
terminal-upgrade | Turn pnpm dev / npm run dev / yarn dev / bun dev in every repo on the machine into Devdeck, a calm live terminal dashboard. | Original |
ts-upgrade | Move a repo's type checking to TypeScript 7, the native compiler, without breaking ESLint, tsup, Next, Expo, Remotion, Convex, CI or Docker builds, and measure before and after. | Original |
unlazy | Anti-laziness execution discipline, required on every task sized L or XL (the /prd-ch scale) and run on request for anything smaller. | Modified from Leonxlnx/unlazy |
vercel-react-best-practices | React and Next.js performance optimization guidelines from Vercel Engineering. | Modified from vercel-labs/agent-skills |
walkthrough | Add a guided walkthrough to any web app, one story per user role: a story bar with arrow keys, a journey reader with "show me how to get there", split prompt cards, and an optional demo tier... | Original |
| Skill | What it does | Origin |
|---|---|---|
apple-design | Apple's approach to interface design and fluid, physical motion, translated for the web. | Modified from emilkowalski/skill |
brandkit | Premium brand-kit image generation skill for creating high-end brand-guidelines boards, logo systems, identity decks, and visual-world presentations. | Modified from Leonxlnx/taste-skill |
click-burst | Adds a performant click-triggered full-viewport color burst transition (scale + opacity only, no animated blur). | Original |
design-taste-frontend | Anti-slop frontend rules for LANDING PAGES, PORTFOLIOS, and MARKETING REDESIGNS: reads the brief, infers direction, ships interfaces that do not look templated, with... | Modified from Leonxlnx/taste-skill |
emil-design-eng | Emil Kowalski's design-engineering philosophy, animation decisions, springs, gestures, component feel, and the invisible details that make software feel great. | Modified from emilkowalski/skill |
fed | Alias for frontend-design. | Original |
find-animation-opportunities | Search a codebase or UI for places that don't animate but should, and reject everything that shouldn't. | Modified from emilkowalski/skill |
frontend-design | The main frontend skill. Distinctive, production-grade UI with high craft in typography, layout, colour and motion. | Original |
iconize | Extract individual icons from sprite sheets into named, square PNG files organized by category. | Original |
image-to-code | Alias for imagegen-frontend-web (image-first web flow: generate section images, then code them). | Modified from Leonxlnx/taste-skill |
imagegen-frontend-mobile | Premium mobile app screen concept images, iOS, Android, and cross-platform screens and multi-screen flows (onboarding, auth, home, profile, settings, chat, commerce,... | Modified from Leonxlnx/taste-skill |
imagegen-frontend-web | The image-first WEB flow, generate one premium horizontal reference image per section (hero, landing page, marketing site, product page, portfolio), deeply analyze... | Modified from Leonxlnx/taste-skill |
impeccable | Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise... | Modified from pbakaus/impeccable |
improve-animations | Survey a codebase's animation and motion code as a senior motion advisor, then produce a prioritized audit and self-contained implementation plans for other agents... | Modified from emilkowalski/skill |
industrial-brutalist-ui | OPT-IN STYLE PRESET, use ONLY when the user explicitly asks for brutalist / industrial / Swiss-print / terminal aesthetics, or names this skill. | Modified from Leonxlnx/taste-skill |
minimalist-ui | OPT-IN STYLE PRESET, use ONLY when the user explicitly asks for a minimalist / Notion-like / warm-monochrome editorial look, or names this skill. | Modified from Leonxlnx/taste-skill |
pick-ui-library | Pick the right library for a given frontend task from a curated, opinionated list, numbers, OTP inputs, charts, command menus, virtualization, drag and drop, toasts,... | Modified from emilkowalski/skill |
prototype | Build multiple genuinely different versions of a UI piece you describe, rendered behind a visual picker so you can flip through them live and promote the one that... | Modified from emilkowalski/skill |
redesign-existing-projects | Upgrades existing websites and apps to premium quality. | Modified from Leonxlnx/taste-skill |
review-animations | Reviews animation and motion code against a high craft bar derived from Emil Kowalski's design engineering philosophy. | Modified from emilkowalski/skill |
sketches | Hand-drawn SVG sketch/doodle system with a growing, brand-themeable repertoire. | Original |
stitch-design-taste | Semantic Design System Skill for Google Stitch. | Modified from Leonxlnx/taste-skill |
the-broadside | Install the broadside editorial slide-deck design system into the current React/Next.js project. | Original |
the-stripe-modal | Install the editorial-press design system (surface card + slide-in modal flow + hero empty state) into the current React/Next.js project. | Original |
ui-ux-pro-max | UI/UX design intelligence for web and mobile. | Modified from nextlevelbuilder/ui-ux-pro-max-skill |
| Skill | What it does | Origin |
|---|---|---|
humanizer | Rewrite AI-sounding text so it reads like the writer without changing what it says. | Modified from blader/humanizer |
rnd | Create a shareable internal R&D page from a team brief, a votable consensus spec with a participant intro gate (--consensus), a screen-by-screen product build deck... | Original |
unslop | Cut AI tells from any writing. | Original |
writing-clearly-and-concisely | Strunk companion for prose humans will read. | Modified from softaworks/agent-toolkit |
| Command | What it does |
|---|---|
/cf | Force-continue a context-exhausted session. |
/ch | Handoff continuity mode: numbered task list, accountability record with every question and decision, optional HTML summary. |
/fd-ch | Frontend design run with reconnaissance, a quality gate and an accountability record, built on the frontend-design skill. |
/pr | Read every PR review comment, fix what is actionable, and reply to each one. |
/prd-ch | Create a PRD fast and well. |
/research | Deep research on any topic. |
/reviewer | Full audit and fix pass on the current task's changes, using any review skills installed on your machine (never Greptile or CodeRabbit). |
Claude Code mods (plugins with function hooks) in mods/. Each one installs on its own from this marketplace:
claude plugin marketplace add michaelezehi/nw-skills
claude plugin install savvy-progress@nw-skills
| Mod | What it does | Origin |
|---|---|---|
savvy-progress | Progress bar above the prompt and an agents panel (/agents-info) with each subagent's model, context, cost and time. Draws in 24-bit colour in any truecolor terminal (Warp, iTerm2, Ghostty, WezTerm, kitty) as well as on the desktop. | Modified from johnnyvizz/claude-kit |
agent-bar | Turns the savvy-progress bar on for every task: todos, tasks and subagent launches become its rows. Steps aside when a skill reports its own plan. Needs savvy-progress. | Original |
guard-rails | Denies git commands that sweep other agents' work (git add -A, commit -a, stash, reset, clean, restore, checkout) and dashes in commit or PR text. | Original |
session-pane | /session-pane opens a pane with the files changed this session as a tree and the latest 50 tool calls. | Original |
turn-chime | A toast and a chime when a turn that ran a minute or longer finishes. | Original |
The skills and commands report to the progress panel by the rules in references/progress-panel.md. Copy it to ~/.claude/references/. Without savvy-progress installed they skip it.
/ch, /fd-ch and /prd-ch hand work over to a fresh session when context runs low. That needs three hooks in hooks/:
context-monitor.sh warns at about 70 and 90 percent context use.precompact.sh writes .claude/handoffs/current.md (todos and modified files) before compaction.session-start.sh feeds that handoff back in when the next session starts.They are not switched on by installing the plugin. To use them, copy the scripts to ~/.claude/hooks/ and add this to ~/.claude/settings.json:
{
"hooks": {
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/context-monitor.sh" }] }],
"PreCompact": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/precompact.sh" }] }],
"SessionStart": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/session-start.sh" }] }]
}
}
Without them the commands still run; you just lose the automatic handoff.
My own skills and commands are MIT, see LICENSE. Modified skills keep their upstream licence and credit; see NOTICE.md.
hooks/register.tsx 157 lines1import type { EngineInterface, Register } from 'claude-code'
2
3const PROGRESS = 'mcp__savvy-progress__progress'
4const FLOW = { plugin: 'savvy-progress', key: 'flow' } as const
5
6type Row = { title: string; tier: string; isDone: boolean }
7
8// The module's own memory of this session's rows; a reload starts it over.
9const s = {
10 lastPrompt: '',
11 title: '',
12 todos: [] as Row[],
13 tasks: new Map<string, Row>(),
14 agents: [] as Row[],
15 agentRow: new Map<string, Row>(),
16}
17
18// savvy-progress only knows its own tiers; map ours onto them.
19function tierOf(type: string, model: string | undefined): string {
20 const bare = type.replace(/^[^:]*:/, '')
21 if (bare.startsWith('savvy-')) return bare.slice('savvy-'.length)
22 if (model === 'fable') return 'fable'
23 if (model === 'sonnet' || model === 'haiku') return 'light'
24 if (bare === 'Explore') return 'medium'
25 return 'careful'
26}
27
28// "/plan Unframed ATS, HR, ..." -> "Unframed ATS, HR"
29function titleOf(prompt: string): string {
30 const words = prompt.replace(/^\/\S+\s*/, '').trim().split(/\s+/).slice(0, 5)
31 return words.join(' ').replace(/[,.;:!?]+$/, '') || 'Working'
32}
33
34function rows(): Row[] {
35 const seen = new Set<string>()
36 return [...s.todos, ...s.tasks.values(), ...s.agents].filter(row => !seen.has(row.title) && seen.add(row.title))
37}
38
39function reset(): void {
40 s.title = ''
41 s.todos = []
42 s.tasks = new Map()
43 s.agents = []
44 s.agentRow.clear()
45}
46
47// A skill that reports its own plan owns the bar: a running flow under
48// another title is theirs, so this mod stays out of it.
49async function isOwnedElsewhere($: EngineInterface): Promise<boolean> {
50 const { value } = await $.state.get(FLOW)
51 return Boolean(value && !value.isFinished && value.title !== s.title)
52}
53
54async function report($: EngineInterface): Promise<void> {
55 const list = rows()
56 if (list.length === 0) return
57 if (s.title === '') s.title = titleOf(s.lastPrompt)
58 if (await isOwnedElsewhere($)) return reset()
59
60 const done = list.filter(row => row.isDone).length
61 const isFinished = done === list.length
62 const isDelegating = s.agents.some(row => !row.isDone)
63
64 try {
65 await $.tool.call({
66 tool: PROGRESS,
67 title: s.title,
68 total: list.length,
69 done,
70 phase: isFinished ? 'close' : isDelegating ? 'delegate' : 'plan',
71 tasks: list.map(row => ({ title: row.title, tier: row.tier })),
72 ...(isFinished ? { finished: true } : {}),
73 } as never)
74 } catch {
75 return
76 }
77
78 if (isFinished) reset()
79}
80
81export const register: Register = on => {
82 on('prompt.submit', ($, e, next) => {
83 if (!e.text.trim().startsWith('/agents-info')) s.lastPrompt = e.text
84
85 return next(e)
86 })
87
88 on('tool.call', { tool: 'TodoWrite' }, async ($, e, next) => {
89 const ran = await next(e)
90
91 if (!e.agentId && ran.deny === undefined) {
92 s.todos = e.todos.map(todo => ({ title: todo.content, tier: 'careful', isDone: todo.status === 'completed' }))
93 await report($)
94 }
95
96 return ran
97 }).catch(($, e, next) => next(e))
98
99 on('tool.call', { tool: 'TaskCreate' }, async ($, e, next) => {
100 const ran = await next(e)
101 const id = /#?(\d+)/.exec(ran.text ?? '')?.[1]
102
103 if (!e.agentId && ran.deny === undefined && id) {
104 s.tasks.set(id, { title: e.subject, tier: 'careful', isDone: false })
105 await report($)
106 }
107
108 return ran
109 }).catch(($, e, next) => next(e))
110
111 on('tool.call', { tool: 'TaskUpdate' }, async ($, e, next) => {
112 const ran = await next(e)
113 const row = s.tasks.get(e.taskId)
114
115 if (!e.agentId && ran.deny === undefined && row && e.status) {
116 if (e.status === 'deleted') s.tasks.delete(e.taskId)
117 else s.tasks.set(e.taskId, { ...row, isDone: e.status === 'completed' })
118 await report($)
119 }
120
121 return ran
122 }).catch(($, e, next) => next(e))
123
124 on('tool.call', { tool: 'Agent' }, async ($, e, next) => {
125 if (!e.agentId && !s.agents.some(row => row.title === e.description)) {
126 const tier = tierOf(e.subagent_type ?? 'general-purpose', e.model)
127 s.agents = [...s.agents, { title: e.description, tier, isDone: false }]
128 await report($)
129 }
130
131 return next(e)
132 }).catch(($, e, next) => next(e))
133
134 on('agent.spawn', async ($, e, next) => {
135 const started = await next(e)
136 const row = s.agents.find(one => one.title === e.description)
137
138 if (started.deny === undefined && started.agentId && row) s.agentRow.set(started.agentId, row)
139
140 return started
141 })
142
143 on('turn.complete', async ($, e, next) => {
144 const result = await next(e)
145 const agentId = e.agentId
146 const row = agentId ? s.agentRow.get(agentId) : undefined
147
148 if (agentId && row) {
149 s.agents = s.agents.map(one => (one.title === row.title ? { ...one, isDone: true } : one))
150 s.agentRow.delete(agentId)
151 await report($)
152 }
153
154 return result
155 })
156}
157