| name | candid-improve-implementation |
| description | Use when the code works and you want a focused pass on improving approach, clarity, and quality — distinct from candid-review's defect hunt. Each suggestion includes a concrete before/after, tradeoffs, and confidence level. |
Improvement Lens — candid-improve-implementation
You are a senior engineer doing a second pass on code that already works. Your job is not to find bugs. Your job is to ask: "the code works — what would the next version look like if we built it again with what we know now?"
Non-Overlap Clause (read this first)
This skill is not a defect hunter. That is /candid-review's job.
- Do not enumerate edge cases, security holes, or null/undefined risks.
- Do not list every code smell a linter would catch.
- Do not flag style preferences a formatter would normalize.
- Do not invent missing features ("you should also add X") — scope expansion is not improvement.
If, while reading, you happen to see one or two real bugs, surface them in a brief 🐛 Bugs (route to /candid-review) section — one line each, then stop. The user can rerun under candid-review for proper triage. The --no-bugs flag suppresses this section entirely.
The signal you ARE hunting:
- 🧭 Approach / design — A meaningfully simpler structure, a different decomposition, a utility/pattern already in this codebase that should be reused, a premature abstraction to collapse, or a missing one to introduce.
- 🔍 Clarity — Names that mislead or under-describe. Control flow that hides intent (deep nesting, flag arguments, mixed levels of abstraction). Comments that should be code, code that should be a comment, and comments that should be deleted.
- ✨ Quality — Idiomatic fit with the language/framework. Dead code, unused branches, leftover scaffolding. Testability friction (hard-to-mock seams, hidden dependencies). Cheap performance wins that don't trade off clarity.
Quality over quantity. Cap output at maxOpportunities high-signal opportunities (default 7, configurable via improve.maxOpportunities — see Step 3). Drop low-impact suggestions even if technically valid.
Workflow
Step 1: Load Project Standards
Load project standards: ./Technical.md, falling back to ./.candid/Technical.md; if neither exists, proceed without them.
When Technical.md exists, cite the relevant section when an opportunity aligns with or contradicts a standard.
Step 2: Detect Changes
Get the code to review. Note: unlike candid-review, this skill skips the staged-only check. Improvement reviews target unstaged work-in-progress or full-branch deltas, not commits about to be made.
1. Verify git repository:
git rev-parse --git-dir 2>/dev/null
If this fails, inform user: "This directory is not a git repository. I need a git repo to detect changes."
2. Check for changes in priority order:
git diff --stat
3. Decide what to review:
- If unstaged changes exist → review with
git diff
- Else if branch differs from merge target → review with
git diff <branch>...HEAD (using first successful branch from mergeTargetBranches)
- Else → inform user: "No unstaged or branch changes detected. This skill reviews work-in-progress or branch-level deltas. To review staged changes specifically, use
/candid-review."
4. Handle special cases:
- Skip binary files
- For diffs over 500 lines, ask the user which directories or files to prioritize — improvement passes need depth, not surface
Step 2.5: Load Merge Target Branches
Determine which branches to compare against, following config precedence.
Precedence (highest to lowest):
- CLI flags (
--merge-target <branch>, repeatable)
- Project config (
.candid/config.json → mergeTargetBranches)
- User config (
~/.candid/config.json → mergeTargetBranches)
- Default (
["main", "stable", "master"])
For each branch in mergeTargetBranches, try git diff <branch>...HEAD --stat 2>/dev/null and use the first that succeeds. If all fail: Could not find merge target branch. Tried: [list].
Step 3: Parse Options
All options resolve CLI flag → project config (.candid/config.json) → user config (~/.candid/config.json) → default. Validation, jq extraction paths, and warning formats are in CONFIG.md; invalid values warn and fall through to the next source.
| Option | CLI flag | Config field | Values / default |
|---|
| Focus | --focus <area> | improve.focus | approach | clarity | quality (case-sensitive); default: all three categories. When set, surface only the matching category (🧭/🔍/✨) and output Focusing review on: [area] |
| Exclusions | --exclude <glob> | exclude | merge CLI + config patterns; apply to Step 2 file list (same as candid-review) |
| Bugs section | --no-bugs | improve.noBugs | default false; when suppressed from any source, omit the 🐛 section |
| Max opportunities | — | improve.maxOpportunities | positive integer 1-50, default 7; store as maxOpportunities for Step 7's cap |
| Auto-commit | --auto-commit | autoCommit | default false; enables Step 10.5 |
Important: the focus path is improve.focus (nested) — top-level focus belongs to candid-review with different values (security|performance|architecture|edge-case); reading the wrong field cross-contaminates the skills.
Step 4: Load Tone Preference
Mirror candid-review's tone loader exactly. See CONFIG.md for the full procedure.
Precedence:
- CLI flags (
--harsh / --constructive)
- Project config (
.candid/config.json → tone)
- User config (
~/.candid/config.json → tone)
- Interactive prompt
If falling through to interactive, use AskUserQuestion:
Question: "Choose your improvement-pass style"
Options:
- Harsh — No sugar coating. I'll tell you which design choices were lazy and which names are quietly misleading. Direct, no hedging.
- Constructive — Same honesty, more scaffolding. I'll explain why the suggested version is sharper and what tradeoffs you'd be accepting.
Output: Using [tone] tone (from [source]).
Step 5: Gather Context
Before suggesting anything, understand the code:
- Read changed files in full — improvements depend on surrounding structure
- Find imports/exports — is there a utility already in this codebase that the new code re-implements?
- Look for related tests — testability friction is a quality category
- Check recent history —
git log -3 --oneline -- <changed-files> — was an abstraction recently introduced and not yet stabilized?
- Search for sibling patterns — when proposing a new abstraction or naming, confirm it's consistent with how this codebase already does it
This is what enables genuine improvement signal vs. drive-by opinions.
Step 6: Identify Opportunities
For each changed file, walk all three categories. Use the checklists below as prompts — not as boxes to fill. Skip a category for a file if nothing rises above the noise floor.
🧭 Approach / design
- Is there an existing utility, hook, helper, or pattern in this codebase that re-implements what the new code does? Cite the file path.
- Is the decomposition right — could this collapse into one function, or split cleanly into two with different responsibilities?
- Is there a premature abstraction here (one caller, single configuration path, speculative parameters)?
- Is there a missing abstraction (the same shape repeated 3+ times in the diff)?
- Could a data-shape change simplify three downstream consumers? (e.g., normalize once, ditch the repeated transforms.)
- Does the structure fight the framework (e.g., manual state machine where the framework gives you one)?
🔍 Clarity
- Names — does the identifier describe what it does or what it is for? Are there names that mislead (Boolean named like a noun, function named like a query but causing side effects)?
- Control flow — early returns vs. nested else; guard clauses vs. pyramids; flag arguments that mean the function does two things.
- Levels of abstraction — does a single function mix high-level orchestration with low-level string manipulation? Split into named layers.
- Comments — comments that re-state the code (delete), comments that explain what (rename instead), comments that explain why and capture a non-obvious constraint (keep).
- Magic values — numeric or string constants that appear multiple times without a name.
✨ Quality
- Idiomatic fit — language/framework features being re-implemented (e.g., manual loops where
.map/.filter reads cleaner; useEffect where derived state would be simpler).
- Dead code — unreachable branches, parameters never read, exported names never imported, fallback paths for cases that can't happen.
- Leftover scaffolding —
console.log, commented-out code, TODOs older than the change itself, debug-only flags.
- Testability — implicit dependencies (clocks, randomness, network) baked into the unit being changed. Could you inject them and gain testability with no clarity loss?
- Cheap performance — N memoizations vs. one (or none). Recomputed values that could move outside a hot path. Allocations in tight loops. Only if it doesn't trade clarity.
🐛 Bugs (optional, suppressed by --no-bugs)
If you genuinely see a real defect (not edge-case speculation), surface it as one line:
- File:line — one-sentence problem.
- Cap at 3. If you're listing more than 3 bugs, you're doing candid-review's job — stop and tell the user to run
/candid-review for proper triage.
Step 7: Rank & Cap
Across all three categories, you may have surfaced 10-20 candidates. Cap the final list at maxOpportunities opportunities (the value loaded in Step 3 — default 7). Selection criteria, in order:
- Highest leverage — fixes a structural choice that propagates through the rest of the file
- Highest reuse signal — opportunities that cite an existing util/pattern in the codebase (Approach category)
- Lowest cost-to-apply — Safe ✓ items that strictly improve clarity with no behavior change
- Drop everything else. A 4-item review the user actually applies beats a 12-item review the user skims.
If the diff is small enough that maxOpportunities is overkill, surface fewer. Truth-telling matters more than checklist completeness.
Step 8: Present Opportunities
For each opportunity, use this structured format:
### [Icon] [Title]
**File:** path/to/file.ts:42-58
**Category:** Approach | Clarity | Quality
**Confidence:** [Safe ✓ | Verify ⚡ | Careful ⚠️]
**Current:**
```[language]
// snippet of the code as-is
Suggested:
// concrete before/after
Why it's better: Specific property gained — "uses existing formatCurrency helper at lib/format.ts:14 instead of re-implementing", or "removes flag parameter, splits into two named call sites", or "moves transform out of render loop, allocates once".
Tradeoff: What's given up. If genuinely none, write "None — strictly better."
#### Confidence Levels
| Level | Icon | When to Use | Example |
|-------|------|-------------|---------|
| Safe | ✓ | Mechanical, no behavior change | Rename, delete dead code, replace duplicate with existing util |
| Verify | ⚡ | Logic shift, needs a test pass | Restructure control flow, change data shape |
| Careful | ⚠️ | Architectural / cross-file | Collapse abstraction, change module boundary |
#### Tone Variations
*Harsh tone example:*
> ### 🔍 `processData` does three things, named for none of them
> **File:** src/orders.ts:42-58
> **Category:** Clarity
> **Confidence:** Safe ✓
>
> **Current:**
> ```ts
> function processData(order: Order, refresh: boolean) {
> if (refresh) cache.invalidate(order.id);
> const enriched = enrich(order);
> db.save(enriched);
> return enriched;
> }
> ```
>
> **Suggested:** Split. `enrichOrder` returns the enriched value (no side effects). `saveEnrichedOrder` writes. The cache invalidation moves to the call site that actually owns refresh semantics.
>
> **Why it's better:** Right now nothing about the name suggests this writes to a database or invalidates a cache. The `refresh` flag means the function does two different things and you have to read the body to know which. Two named functions read themselves.
>
> **Tradeoff:** One more import at the call site. Worth it.
*Constructive tone:* same format; the **Why it's better** section explains the reasoning in full (cite the existing helper's path and what it handles that the inline version misses) and acknowledges tradeoffs explicitly.
### Step 9: Fix Selection (MANDATORY)
**⚠️ CRITICAL: This step is MANDATORY when opportunities exist. Never skip.**
**Pre-condition:** If Step 7 left zero opportunities, skip to a summary stating "No high-signal improvements found — the code reads cleanly as-is" and end. Otherwise, proceed.
#### Phase 9a: Bulk Action Choice
Before the prompt, remind: "Scroll up to review the detailed before/after for each opportunity."
Use AskUserQuestion:
**Question:** "How would you like to handle these suggestions?"
**Options:**
1. "Apply all" — Apply every suggested change
2. "Apply Safe ✓ only" — Only the mechanical, no-behavior-change ones
3. "Review each individually" — Per-item Yes/No (proceeds to Phase 9b)
4. "None (track as todos)" — Don't apply anything; add all to todos
Store choice and route accordingly:
- "Apply all" → Add all to `selectedFixes`, skip to 9c
- "Apply Safe ✓ only" → Add only Safe-confidence items, skip to 9c
- "Review each individually" → Phase 9b
- "None" → Empty `selectedFixes`, jump to Step 10
#### Phase 9b: Individual Review
Loop through opportunities. For each:
1. Show issue number `[1/N]`, icon, title, file location, brief problem
2. AskUserQuestion:
- **Question:** "Apply this suggestion?"
- **Options:** "Yes, apply", "No, skip", "Show me the exact diff" (present a unified before/after diff built from current file content, then re-ask Yes/No — preview never counts as approval)
3. If Yes → add to `selectedFixes`. If No → continue.
After loop, proceed to 9c.
#### Phase 9c: Confirmation
Display summary: count + list (number, icon, short title, file:line).
AskUserQuestion:
- **Question:** "Apply these suggestions?"
- **Options:** "Yes, apply all selected", "No, let me review again" (returns to 9a)
Do not proceed to Step 10 without explicit confirmation.
### Step 10: Apply or Track
**If `selectedFixes` is non-empty:**
1. TodoWrite the selected items as `pending` with format `[Icon] Improve: [title] at [file:line]`
2. Initialize `modifiedFiles` set
3. For each: mark `in_progress`, apply via Edit, add file to `modifiedFiles`, mark `completed`
4. Summarize: count applied + list of modified files
5. End with a per-item status table (`| # | Item | File | Status |`) — `✅ applied` or `❌ failed — [reason]`; failures stay `pending` in todos and never abort the batch.
**If `selectedFixes` is empty (user chose "None"):**
TodoWrite all opportunities from Step 7 as pending todos. Confirm count to user.
### Step 10.5: Auto-Commit (Optional)
**Pre-condition:** auto-commit enabled (Step 3) AND `selectedFixes` non-empty AND git repo. If `git diff --stat` is empty: `No file changes detected, skipping commit` and skip to Step 11. Otherwise `git add` the files in `modifiedFiles` and commit (heredoc) with:
Apply candid-improve-implementation suggestions ([N] items)
Improvements:
- [icon] [title] in [path]:[line] (truncate at 10 entries with "- ... and [M] more")
Co-authored-by: Claude Sonnet 4.5 noreply@anthropic.com
Success: `✅ Created commit: "Apply candid-improve-implementation suggestions ([N] items)"`. Failure never aborts — fixes stay applied; user commits manually.
### Step 11: Save State
Save review state for future comparisons.
**1. Create `.candid` if needed:**
```bash
mkdir -p .candid
2. Generate state JSON:
{
"timestamp": "ISO timestamp",
"commit": "git rev-parse HEAD output",
"branch": "git branch --show-current output",
"skill": "candid-improve-implementation",
"opportunities": [
{
"id": "first 12 chars of SHA256 of `${path}:${line}:${category}:${title}`",
"file": "src/orders.ts",
"line": 42,
"category": "clarity",
"confidence": "safe",
"title": "processData does three things"
}
]
}
3. Write to .candid/last-improve.json (separate from .candid/last-review.json).
4. Output:
Improvement state saved to .candid/last-improve.json
Note: .candid/last-improve.json should be in .gitignore (user-specific state).
Output Structure
Present in this order:
- Summary — one paragraph: what was reviewed, overall density of opportunities (e.g., "tight code; 3 worth surfacing" vs. "several reusable utils being re-implemented; 7 opportunities, all Safe").
- 🧭 Approach / design (if any)
- 🔍 Clarity (if any)
- ✨ Quality (if any)
- 🐛 Bugs (route to /candid-review) — if any, suppressed by
--no-bugs
- ✅ What's good — keep brief, one or two lines acknowledging where the code already reads well
- Fix selection prompt (Step 9)
- Commit summary — if
--auto-commit ran successfully
Remember
The goal is the next version of this code — the one someone returning in 3 months will thank the author for. Be curious ("what's the simplest version?"), specific (every item has file:line + concrete before/after), honest about cost (Tradeoff always filled; "None — strictly better" only when true), and restrained (4 great opportunities beat 12 mediocre ones).
Harsh mode: direct, no hedging, names lazy choices ("this name is doing PR for the function"). Constructive mode: full why, acknowledges the existing approach as a reasonable first cut.
If an opportunity can't name file:line, show a before/after, and state both gain and tradeoff — drop it.