/session-pane: files changed this session as a tree, plus the latest tool calls

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 106 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4import type { Call } from '../types'
5
6const PANE = 'session-pane'
7const files = atom({ plugin: 'session-pane', key: 'files' } as const, [])
8const calls = atom({ plugin: 'session-pane', key: 'calls' } as const, [])
9
10const WRITERS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit'])
11
12function labelOf(input: Record<string, unknown>): string {
13 const raw = input.file_path ?? input.notebook_path ?? input.command ?? input.pattern ?? input.description ?? ''
14 return String(raw).replace(/\s+/g, ' ').slice(0, 60)
15}
16
17function relative(path: string, cwd: string): string {
18 return path.startsWith(cwd + '/') ? path.slice(cwd.length + 1) : path
19}
20
21// Groups paths by folder so the pane reads as a tree, folders sorted.
22function treeRows(paths: string[]): Array<{ text: string; isFolder: boolean }> {
23 const byFolder = new Map<string, string[]>()
24
25 for (const path of paths) {
26 const cut = path.lastIndexOf('/')
27 const folder = cut === -1 ? '.' : path.slice(0, cut)
28 byFolder.set(folder, [...(byFolder.get(folder) ?? []), path.slice(cut + 1)])
29 }
30
31 return [...byFolder.keys()].sort().flatMap(folder => [
32 { text: `${folder}/`, isFolder: true },
33 ...byFolder.get(folder)!.sort().map(name => ({ text: ` ${name}`, isFolder: false })),
34 ])
35}
36
37export const register: Register = on => {
38 let cwd = ''
39
40 on('session.start', async ($, e, next) => {
41 cwd = e.cwd
42 await $.command.register({
43 name: 'session-pane',
44 description: 'Show files changed this session and the latest tool calls',
45 })
46
47 return next(e)
48 })
49
50 on('command.run', { command: 'session-pane' }, async $ => {
51 await $.ui.open({ id: PANE, title: 'Session' })
52
53 return { text: 'Session pane opened.' }
54 })
55
56 on('tool.call', async ($, e, next) => {
57 const input = e as unknown as Record<string, unknown>
58 const call: Call = { id: e.tool_use_id, tool: e.tool, label: labelOf(input), isDone: false, isError: false }
59 await update($, calls, list => [...list, call].slice(-50))
60
61 const ran = await next(e)
62 const isError = ran.deny !== undefined || ran.isError === true
63 await update($, calls, list =>
64 list.map(one => (one.id === call.id ? { ...one, isDone: true, isError } : one)),
65 )
66
67 const path = input.file_path ?? input.notebook_path
68
69 if (WRITERS.has(e.tool) && !isError && typeof path === 'string') {
70 const shown = relative(path, cwd)
71 await update($, files, list => (list.includes(shown) ? list : [...list, shown]))
72 }
73
74 return ran
75 }).catch(($, e, next) => next(e))
76
77 on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
78 const { Box, Text } = $.ui.resolve(e)
79 const changed = await read($, files)
80 const recent = await read($, calls)
81 const rows = Math.max(6, (e.viewport?.rows ?? 24) - 6)
82 const callRoom = Math.min(10, Math.floor(rows / 2))
83 const fileRows = treeRows(changed).slice(0, rows - callRoom)
84
85 return (
86 <Box flexDirection="column">
87 <Text bold>Changed ({changed.length})</Text>
88 {changed.length === 0 && <Text dimColor>No edits yet.</Text>}
89 {fileRows.map(row => (
90 <Text color={row.isFolder ? 'cyan' : undefined} dimColor={row.isFolder}>
91 {row.text}
92 </Text>
93 ))}
94 <Text> </Text>
95 <Text bold>Latest tool calls</Text>
96 {recent.length === 0 && <Text dimColor>None yet.</Text>}
97 {recent.slice(-callRoom).map(call => (
98 <Text color={call.isError ? 'red' : call.isDone ? undefined : 'yellow'} dimColor={call.isDone && !call.isError}>
99 {call.tool} {call.label}
100 </Text>
101 ))}
102 </Box>
103 )
104 })
105}
106types/index.d.ts 8 lines1export type Call = { id: string; tool: string; label: string; isDone: boolean; isError: boolean }
2
3declare module 'claude-code' {
4 interface PluginState {
5 'session-pane': { files: string[]; calls: Call[] }
6 }
7}
8