Your best model is wasted writing code. Its edge is not typing speed — a cheaper model types just as fast. Its edge is judgment: reading a codebase, deciding what is actually worth changing, and writing a specification tight enough that a weaker model can execute it without you. shadcn's improve skill turns that observation into a workflow. The expensive model advises. A cheaper model executes. The plan is the product.

The skill is a small repo with a large idea: an Agent Skill that surveys any codebase as a senior advisor and writes prioritized, self-contained implementation plans for other models to run. It never implements anything itself. It audits across nine categories, vets its own findings before showing them to you, and writes plans with verification gates and stop conditions, so the executor never has to guess whether it succeeded. This tutorial installs it, runs the full loop on a demo repo with real planted issues, and shows you the plans that came out — every command below ran for real on November 11, 2026, including the ones that behaved unexpectedly.

What you will need#

  • Node.js with npx. The install runs through the Vercel skills CLI. Verified here on Node.js 24.22.1 and npm 10.9.4.
  • A coding agent that loads Agent Skills — Claude Code, Codex, OpenCode, Gemini CLI, Pi, or any agent that reads SKILL.md files. The installer links the skill into all of these when it finds them.
  • Git. The skill stamps every plan with the commit it was written against, and the execute flow dispatches the executor into an isolated git worktree. A repo without git can still be audited, but it cannot use the full loop.
  • No API key, no account, no payment. The skill itself is MIT-licensed and free. The audit costs whatever your agent session costs — the advisor run burns your best model's tokens, which is the entire point: you pay for judgment once, then hand the cheap work to a cheap model.

Step 1: Install the skill#

The README's install is one command:

npx skills add shadcn/improve

One honest note before you run it: in this sandbox the bare command stalled. It never completed and never installed anything — most likely waiting on an interactive confirmation prompt with no terminal attached. I killed it after four minutes. The fix is the -y flag, which skips the prompts:

npx skills add shadcn/improve -y

That run completed in about four seconds and printed a full report. It cloned https://github.com/shadcn/improve.git, found one skill, and installed it to .agents/skills/improve/ in the project — the universal location the CLI writes for Antigravity CLI, Codex, Gemini CLI, OpenCode, Pi, and sixteen more agents — plus a symlink for Claude Code. (OpenClaw was listed as skipped: no project directory for it was found.) It also wrote a skills-lock.json pinning the skill to its source and a content hash, so npx skills update can upgrade it later without re-asking where it came from:

{
  "version": 2,
  "skills": {
    "improve": {
      "source": "shadcn/improve",
      "sourceType": "github",
      "skillPath": "skills/improve/SKILL.md",
      "computedHash": "9e8fe9ea4f9a0e4155801d1624e38ca23798467bb88b447efaa5120f7b1fe802"
    }
  }
}

The installer also runs a security assessment on the skill before installing it — worth noting, since a skill is instructions injected into your agent's context. For improve it reported Safe, 0 Socket alerts, and Snyk Low Risk, with details at skills.sh/shadcn/improve. Confirm the install landed:

npx skills list
Project Skills

improve ~/…/demo/.agents/skills/improve
  Agents: Antigravity CLI, Claude Code, Codex, Gemini CLI, OpenCode +1 more  Source: shadcn/improve

What actually landed in .agents/skills/improve/ is small: SKILL.md (122 lines), three reference files — audit-playbook.md, plan-template.md, closing-the-loop.md — and nothing else. I diffed the installed SKILL.md against the repo's copy: byte-identical. There is no binary, no dependency, no server. If you would rather not install it at all, the CLI has a try-before-you-install path — npx skills use shadcn/improve@improve generates a prompt for using the skill once without installing it — and the repo also ships Claude Code plugin files (.claude-plugin/) if your agent loads skills that way.

Step 2: Run your first audit#

Open your agent in the repo you want audited and run the skill's slash command. Start cheap:

/improve quick

That runs the recon and audit at the lightest effort level: hotspots only, no subagents or one at most, and only the top six HIGH-confidence findings. The full run is the bare command:

/improve

What happens next follows the workflow in SKILL.md, and it is worth knowing the shape of it before you hand your codebase over. Phase 1, recon: the advisor reads your README, CLAUDE.md/AGENTS.md, package manifest, CI config, and directory structure, and records the exact build, test, lint, and typecheck commands — those become the verification gates in every plan. It also ingests intent docs where they exist (ADRs, PRDs, CONTEXT.md, DESIGN.md, PRODUCT.md), so a tradeoff your team already decided is not re-reported as a bug. Phase 2, audit: it works through nine categories — correctness, security, performance, test coverage, tech debt, dependencies, DX, docs, and direction — fanning out to parallel subagents on a repo of any real size. Phase 3, vet and prioritize: it re-reads every cited location itself before showing you anything, because subagents over-report. Findings that are by-design behavior, wrongly attributed, or duplicated get dropped or corrected, and the rejections are recorded so the next run does not re-audit them. What you get is a findings table ordered by leverage — impact divided by effort, weighted by confidence — and then you pick which findings become plans. Non-interactive runs default to the top three to five.

One thing to be straight about: the audit itself runs inside your coding agent, and this sandbox has no Claude Code session to run it in. What I verified directly is everything around that step — the install, the skill files, the demo repo below, the measurements, and the plan output, which I produced by executing the skill's workflow by hand on the demo repo, following SKILL.md phase by phase. The findings table and plans in Step 4 are the real output of that run, with real file and line evidence. The command variants below are quoted from the README and SKILL.md themselves, which I read in full.

InvocationWhat it does
/improveFull audit, then plans for the findings you pick
/improve quickCheap pass: hotspots, top findings only
/improve deepExhaustive: every package, every category
/improve securityFocused audit — also perf, tests, bugs, and the rest
/improve branchAudit only what the current branch changes, tagged introduced vs pre-existing
/improve nextDirection only: grounded feature suggestions for the roadmap
/improve plan <description>Skip the audit, specify one thing
/improve review-plan <file>Critique and tighten an existing plan
/improve execute <plan>Dispatch a cheaper executor in an isolated worktree, then review its diff
/improve reconcileRefresh the backlog: verify, unblock, retire
… --issuesAlso publish each plan as a GitHub issue

Step 3: What a good plan looks like#

Before running the loop on your own code, read one plan the skill has already produced. The repo ships a real example: a plan /improve wrote against shadcn/ui itself at commit 1994caba0 (June 10, 2026), extracting a duplicated shadow-config resolution shared by the search and view commands. The example is worth reading because it shows the three properties every plan must have. First, self-contained context: the plan inlines the current code excerpts, the exact file paths, the repo's conventions, and the commands — a model that has never seen the advisor session can execute it from the file alone. Second, verification gates: every step ends with a command and its expected result (pnpm shadcn:test passes, grep returns no matches), so the executor never judges whether it succeeded. Third, hard boundaries and escape hatches: an explicit in-scope file list, an explicit out-of-scope list, and STOP conditions — if the code has drifted since the plan was written, if a step's verification fails twice, if the fix needs an out-of-scope file, stop and report instead of improvising.

A circular diagram showing the improve workflow: audit with a magnifying glass, write plans as documents, then a robot executes them
Illustration generated for this article. The loop is audit, plan, execute — and then reconcile, so the backlog stays true.

Two details in that example plan carry the whole design. Every plan stamps the git commit it was written against, and opens with a drift check — git diff --stat <planned-at SHA>..HEAD -- <in-scope paths> — because a plan written against last week's code is a liability, not an asset. And every plan is written for the weakest plausible executor: a model that has never seen the repo and may be much smaller than the advisor. That is why the plan inlines excerpts instead of referencing the audit, and why its done criteria are machine-checkable commands rather than prose like "works correctly."

Step 4: The full loop on a demo repo#

To show the loop end to end, I built a small demo repo — tiny-shop, a Node CLI that lists orders with customer names — with three issues planted in it deliberately, then ran the skill's workflow on it. The planted issues are labeled as planted; the findings, measurements, and plans below are the real output of auditing that code. Recreate it to follow along. The whole repo is dependency-free: plain Node, node --test for tests.

package.json — the verification baseline the recon phase records first:

{
  "name": "tiny-shop",
  "version": "1.0.0",
  "type": "commonjs",
  "main": "src/index.js",
  "scripts": { "start": "node src/index.js", "test": "node --test" }
}

src/db.js — an in-memory store where every method call counts as one query, so the N+1 is measurable:

const customers = [
  { id: "c1", name: "Amina" },
  { id: "c2", name: "Bruno" },
  { id: "c3", name: "Chloe" },
];
const orders = [
  { id: "o1", customerId: "c1", total: 42.5 },
  { id: "o2", customerId: "c2", total: 18.0 },
  { id: "o3", customerId: "c1", total: 99.99 },
  { id: "o4", customerId: "c3", total: 7.25 },
];
let queryCount = 0;
function getCustomerById(id) { queryCount += 1; return customers.find((c) => c.id === id) || null; }
function getAllCustomers() { queryCount += 1; return customers.slice(); }
function getAllOrders() { queryCount += 1; return orders.slice(); }
function resetQueryCount() { queryCount = 0; }
module.exports = { getCustomerById, getAllCustomers, getAllOrders, resetQueryCount, get queryCount() { return queryCount; } };

src/orders.js — planted issues one and two: an N+1 lookup inside the loop, and an error handler that swallows every failure and returns an empty list:

const db = require("./db");
function loadOrders() {
  try {
    return db.getAllOrders();
  } catch {
    return [];
  }
}
function listOrdersWithCustomers() {
  const orders = loadOrders();
  return orders.map((o) => {
    const customer = db.getCustomerById(o.customerId);
    return { id: o.id, customer: customer ? customer.name : "unknown", total: o.total };
  });
}
module.exports = { listOrdersWithCustomers, loadOrders };

src/commands/search.js and src/commands/view.js — planted issue three: the same shadow-config resolution hand-rolled in both commands, with a TODO admitting it, and the two copies already drifted — search seeds its defaults with {style: "compact"}, view starts from bare defaults. (src/config.js holds the shared configWithDefaults helper both should be using.) A smoke test covers the happy path, and the CLI itself works — node src/index.js search ami prints the two Amina orders, node src/index.js view o2 prints the Bruno order. Commit it, so the plans can stamp a real SHA:

git init && git add -A && git commit -m "demo: tiny-shop CLI with planted issues"
git rev-parse --short HEAD   # 7ec02de in my run
npm test                     # 3 pass, 0 fail

Recon first: one language (JavaScript, CommonJS), no dependencies, verification command npm test, no lint or typecheck configured. Then the audit. The findings table below is what the workflow produced, in leverage order — each finding vetted against the code it cites, with the measurement included where one exists:

#FindingCategoryImpactEffortRiskEvidence
1Duplicated shadow-config resolution, already driftedtech-debtConfig changes must be made twice; copies diverged on seedingMMEDsrc/commands/search.js:9-35, src/commands/view.js:9-28
2N+1 customer lookups in order listingperf5 queries for 4 orders; grows linearlySLOWsrc/orders.js:15-20, src/commands/search.js:39-43; measured query count 5
3loadOrders swallows all errors, returns []bugFailed reads look like an empty store; silent failureSLOWsrc/orders.js:7-13
4No failure-path or query-count teststestsRegressions in 2 and 3 have no netSLOWtest/smoke.test.js covers happy path only

The N+1 number is measured, not estimated. Before the fix, listing 4 orders issues 5 queries — one getAllOrders() plus one getCustomerById() per row — and searching for "ami" issues 5 queries for 2 results. The plans that came out of the table follow the skill's template exactly. Plan 001 extracts the shared shadow-config resolution into src/config.js as resolveShadowConfig(cwd, seed), with four new tests and a drift check against commit 7ec02de. Plan 002 batches the customer lookup — one getAllCustomers() call plus a Map — with a regression test asserting the query count drops from 5 to 2. Plan 003 removes the silent catch in loadOrders and adds a failure-path test. A plans/README.md index records the execution order (001, then 002, then 003 — 002 and 003 both touch src/orders.js, so they land sequentially), the dependency notes, and the findings considered and rejected (none — the audit was scoped to the demo's issues). The whole output is 458 lines across four files, all in plans/, and the source code is untouched: the drift check on every plan returns zero lines, and npm test still passes 3 for 3. That is the contract working as designed — the advisor's only writes are the plans.

A findings table with severity dots beside lines of code, a magnifying glass over one highlighted row, and a checkmark badge
Illustration generated for this article. Every finding carries file and line evidence — a finding without evidence is not a finding.

Step 5: Close the loop — execute, reconcile, publish#

Plans are not the end of the workflow; they are the handoff. Three follow-through flows close it. /improve execute 001 dispatches a cheaper executor — a separate subagent, default model sonnet in Claude Code's naming, or whichever model you name — into an isolated git worktree, with the full plan text inlined in its prompt. The advisor then reviews the diff like a tech lead: it re-runs every done criterion in the worktree, checks scope compliance against the plan's in-scope list, reads the full diff, and audits the new tests (a test that asserts nothing passes and proves nothing). The verdict is APPROVE, REVISE (at most two rounds, then BLOCK), or BLOCK. Merging is always your decision — the advisor never merges, pushes, or commits to your branch. /improve reconcile keeps plans/ alive between sessions: DONE plans get spot-checked, BLOCKED ones get investigated and rewritten or rejected, TODO plans get their drift check re-run and their excerpts refreshed. And /improve --issues publishes each plan as a GitHub issue via gh, with one guard that matters: on a public repo the skill warns you that issues are publicly visible and asks for explicit confirmation before publishing any plan that describes a security vulnerability or a credential location.

When to use this vs alternatives#

Use improve when the work is bigger than one fix and you want a second, cheaper pair of hands to do it — a codebase you are about to hand to a junior model, a backlog of tech debt you keep deferring, a repo you inherited and have not mapped yet. The plan is the durable artifact: it survives the session, it can be reviewed, and it can be executed next week by a different model. Do not use it when the fix is obvious and small — if you already know the change, telling the agent to make it directly is faster than writing a plan about making it. And do not use it as a security scanner: a dedicated audit skill (Cloudflare's security-audit-skill, for example) goes deeper on security specifically, with independently verified findings; improve covers security as one of nine categories, not as its specialty. Against spec-driven planning tools like GitHub's Spec Kit, the difference is direction: Spec Kit starts from a feature you describe and writes the spec forward; improve starts from the code you have and writes the plan backward from what is wrong with it. Against a one-shot review ("review this PR"), the difference is durability: a review comment evaporates; a plan in plans/ with verification gates and a drift check can be executed, re-run, and reconciled.

Troubleshooting: what to do when it misbehaves#

  • The installer hangs. The bare npx skills add shadcn/improve waits on an interactive prompt; with no terminal attached it never returns. Add -y. If your agent is not among the detected ones, pass it explicitly with -a (see npx skills --help).
  • The skill does not trigger. Check that .agents/skills/improve/SKILL.md exists in the project and that your agent loads project skills — some agents need a restart or a session reload after a new skill lands. npx skills list shows what is installed and where.
  • plans/ already exists for something else. The skill detects the collision and writes to advisor-plans/ instead, and says so. If plans/ holds a previous improve run, it reconciles instead of duplicating: numbering stays monotonic and already-planned findings are skipped.
  • execute refuses to dispatch. It needs a git repository (worktree isolation) and the plan's dependencies marked DONE in the index. It also runs the plan's drift check first — a stale plan gets reconciled, not executed.
  • A plan reads like it was written for a different codebase. That is what the drift check is for. Run it; if the in-scope files changed since the plan's commit, refresh the excerpts and the SHA, or mark the finding rejected if it was fixed in passing.

The takeaway#

The interesting thing about improve is not that it finds bugs — any strong model reading your code finds bugs. It is that it refuses to fix them. That refusal is the design: the expensive model's job ends at a plan good enough for a cheap model to execute blind, with verification gates that make success checkable and stop conditions that make failure visible. On the demo repo that produced three real plans, a measured N+1, and a findings table with evidence on every row — and not one changed line of source. Install it, run /improve quick on a repo you know well, and read the findings table before you trust it on one you do not. If the findings are honest and the evidence checks out, you have just bought yourself a senior advisor that charges by the plan instead of by the hour.

Sources