refactor-plan
A realistic, step-by-step plan for refactoring one overgrown function. Every step is behavior-preserving and gated by a green test run.
$ npx -y skills add vanara-agents/skills --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
Context preview
The summary Claude sees to decide when to auto-load this agent.
A realistic, step-by-step plan for refactoring one overgrown function. Every step is behavior-preserving and gated by a green test run.
Agent definition
refactor-plan.mdWorked Refactor Plan — Untangling `processCheckout`
A realistic, step-by-step plan for refactoring one overgrown function. Every step is behavior-preserving and gated by a green test run.
Starting point
function processCheckout(cart, user, coupon) {
let total = 0;
for (const item of cart.items) {
total += item.price * item.qty;
}
if (coupon) {
if (coupon.type === "percent") {
total = total - (total * coupon.value) / 100;
} else if (coupon.type === "flat") {
total = total - coupon.value;
}
}
if (user.tier === "gold") {
total = total * 0.9;
}
if (total < 0) total = 0;
db.orders.insert({ userId: user.id, total });
email.send(user.email, "Order confirmed", `You paid ${total}`);
return total;
}Smells: long function mixing calculation + persistence + notification; nested coupon conditional; magic numbers (`0.9`); the pricing math is untested and hard to test because of side effects.
Step 0 — Safety net
The function has no unit tests, only a flaky end-to-end test. **Add characterization tests** for the pure pricing outcomes first:
test("subtotal with no coupon, standard tier", () => {
expect(priceOf(cart([{price:10,qty:2}]), user("standard"), null)).toBe(20);
});
test("percent coupon then gold discount", () => {
expect(priceOf(cart([{price:100,qty:1}]), user("gold"), {type:"percent",value:10})).toBe(81);
});
test("never goes negative", () => {
expect(priceOf(cart([{price:5,qty:1}]), user("standard"), {type:"flat",value:50})).toBe(0);
});These pin *current* behavior (including the `81` that results from applying percent then gold). Run → GREEN. (They reference a `priceOf` we will extract in Step 2; write them against the current function first, then point them at the extraction.)
Step 1 — Guard clause for the negative-total clamp
Pull the clamp to a named helper. Run tests → GREEN.
const clampNonNegative = (n) => (n < 0 ? 0 : n);
Step 2 — Extract the pure pricing function
Move all calculation into a side-effect-free `priceOf(cart, user, coupon)`; `processCheckout` calls it. Now the characterization tests target `priceOf` directly. Run tests → GREEN.
Step 3 — Replace nested coupon conditional with a lookup
const COUPON = {
percent: (t, c) => t - (t * c.value) / 100,
flat: (t, c) => t - c.value,
};
const applyCoupon = (t, c) => (c && COUPON[c.type] ? COUPON[c.type](t, c) : t);Run tests → GREEN.
Step 4 — Name the magic number
const GOLD_DISCOUNT = 0.9; // 10% off for gold tier
Run tests → GREEN.
Step 5 — Separate side effects
`processCheckout` keeps the `db.orders.insert` and `email.send`; the testable pricing now lives in `priceOf`. Persistence/notification stay as the orchestration shell. Run tests → GREEN.
Result
`priceOf` is pure and fully tested; the conditional is flat; the magic number is named; side effects are isolated. **No behavior changed** — every characterization test that was green at Step 0 is still green. Each step was a separate, revertible commit.
Read more
Worked Refactor Plan — Untangling `processCheckout`
A realistic, step-by-step plan for refactoring one overgrown function. Every step is behavior-preserving and gated by a green test run.
Starting point
function processCheckout(cart, user, coupon) {
let total = 0;
for (const item of cart.items) {
total += item.price * item.qty;
}
if (coupon) {
if (coupon.type === "percent") {
total = total - (total * coupon.value) / 100;
} else if (coupon.type === "flat") {
total = total - coupon.value;
}
}
if (user.tier === "gold") {
total = total * 0.9;
}
if (total < 0) total = 0;
db.orders.insert({ userId: user.id, total });
email.send(user.email, "Order confirmed", `You paid ${total}`);
return total;
}Smells: long function mixing calculation + persistence + notification; nested coupon conditional; magic numbers (`0.9`); the pricing math is untested and hard to test because of side effects.
Step 0 — Safety net
The function has no unit tests, only a flaky end-to-end test. **Add characterization tests** for the pure pricing outcomes first:
test("subtotal with no coupon, standard tier", () => {
expect(priceOf(cart([{price:10,qty:2}]), user("standard"), null)).toBe(20);
});
test("percent coupon then gold discount", () => {
expect(priceOf(cart([{price:100,qty:1}]), user("gold"), {type:"percent",value:10})).toBe(81);
});
test("never goes negative", () => {
expect(priceOf(cart([{price:5,qty:1}]), user("standard"), {type:"flat",value:50})).toBe(0);
});These pin *current* behavior (including the `81` that results from applying percent then gold). Run → GREEN. (They reference a `priceOf` we will extract in Step 2; write them against the current function first, then point them at the extraction.)
Step 1 — Guard clause for the negative-total clamp
Pull the clamp to a named helper. Run tests → GREEN.
const clampNonNegative = (n) => (n < 0 ? 0 : n);
Step 2 — Extract the pure pricing function
Move all calculation into a side-effect-free `priceOf(cart, user, coupon)`; `processCheckout` calls it. Now the characterization tests target `priceOf` directly. Run tests → GREEN.
Step 3 — Replace nested coupon conditional with a lookup
const COUPON = {
percent: (t, c) => t - (t * c.value) / 100,
flat: (t, c) => t - c.value,
};
const applyCoupon = (t, c) => (c && COUPON[c.type] ? COUPON[c.type](t, c) : t);Run tests → GREEN.
Step 4 — Name the magic number
const GOLD_DISCOUNT = 0.9; // 10% off for gold tier
Run tests → GREEN.
Step 5 — Separate side effects
`processCheckout` keeps the `db.orders.insert` and `email.send`; the testable pricing now lives in `priceOf`. Persistence/notification stay as the orchestration shell. Run tests → GREEN.
Result
`priceOf` is pure and fully tested; the conditional is flat; the magic number is named; side effects are isolated. **No behavior changed** — every characterization test that was green at Step 0 is still green. Each step was a separate, revertible commit.
🐒 Free agents, skills & packs for Claude Code One subscription. An army of Claude Code agents. 30 production-grade agents, skills, and packs for Claude Code — free, Apache-2.0, install with one command.
Repo: vanara-agents/skills
Other agents on vanara-agents-skills.
- AGENT
Use when designing a new HTTP/GraphQL API or changing an existing one — modeling resources, defining endpoint contracts, choosing status codes, pagination, filtering, error envelopes, versioning, and idempotency. Produces a reviewable API contract plus an OpenAPI snippet, not
Open agent - review-notes
This shows how the api-designer agent reviews a flawed draft. Findings are severity-ranked so the implementer fixes the contract-breakers first. Severity legend: **CRITICAL** (breaks clients / data risk), **HIGH** (real bug or inconsistency), **MEDIUM** (maintainability),
Open agent - contract-and-openapi
The contract is the deliverable. Express it as an **OpenAPI 3.1** document so it is human-readable *and* machine-checkable. This reference covers how to structure that document and what `scripts/lint-openapi.mjs` enforces.
Open agent - design-checklist
Run through this before declaring an API contract done. It is ordered the way you should *design*: resources first, cross-cutting rules last. Every box is a place real APIs go wrong in production.
Open agent - versioning-and-evolution
APIs are forever once published: a consumer you've never met may depend on any field you expose. Design so you can **add without breaking**, and version explicitly when you must break.
Open agent - pr-comment-template
Copy-paste templates for leaving review comments. Keep each comment to one finding: an anchor, the problem, and the fix.
Open agent

