Skip to content
Back to skills

Upgrade Project

ASecurity

Bring an existing leanwheel project up to the latest skills/stubs/hooks/framework. Detection-based — works even on projects scaffolded before this skill existed. Use when the user says "upgrade project", "sync leanwheel", "update scaffolding", or after pulling new leanwheel-skills changes.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsgoswiftbashrailsgit

Works with

  • claude code

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add rterakedis/leanwheel-skills --skill upgrade-project --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Upgrade Project?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Upgrade Project
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rterakedis-upgrade-project/badge)](https://www.skillsdirectory.com/skills/rterakedis-upgrade-project)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: upgrade-project
description: Bring an existing leanwheel project up to the latest skills/stubs/hooks/framework. Detection-based — works even on projects scaffolded before this skill existed. Use when the user says "upgrade project", "sync leanwheel", "update scaffolding", or after pulling new leanwheel-skills changes.
---

# Upgrade Project Skill

**Goal:** Reconcile a project that was scaffolded by an older `leanwheel-skills`
against the current version — add new assets (hooks, agents wiring, evals, metrics),
refresh stubs that the project hasn't locally edited, and append any new guardrail/
doc sections — **without ever clobbering the user's own edits.**

**Idempotent + non-destructive.** Adds and refreshes; never deletes project content.
Always previews a plan and waits for confirmation before applying.

**Relationship to `/setup`:** `/setup` is first-run scaffolding. `/upgrade-project`
is the recurring sync. Existing projects have no manifest — this skill detects state
by **presence and content**, then writes a manifest going forward.

---

## Step 1 — Locate the skills source

Resolve `{skills_path}`:
1. `.leanwheel/manifest.json` → `skills_path` if present.
2. Else `.bmad-lite/manifest.json` (legacy — projects scaffolded before the leanwheel
   rename). If found, use its `skills_path` and flag the directory for migration in
   Step 4 (renamed to `.leanwheel/`; contents carried over unchanged).
3. Else the `add-dir` target in `.claude/settings.json` startup hook.
4. Else ask the user (e.g. `~/repos/leanwheel-skills`).

Confirm `{skills_path}/.claude/skills/setup/stubs/` exists. If not, stop — wrong path.

## Step 2 — Detect surfaces

Determine what this project uses (so we only sync relevant assets):
- `is_apple` = `docs/setup/swift/` exists OR `.xcodeproj`/`.xcworkspace`/`Package.swift` present
- `is_web` = `docs/setup/web/` exists OR `package.json` with a web framework present
- `has_ux` = `docs/ux/DESIGN.md` exists

## Step 3 — Build the upgrade plan (preview, don't apply yet)

Scan for gaps. For each item, classify as **ADD** (missing), **REFRESH** (stub
unchanged from an older leanwheel version — safe to update), **CONFLICT** (file exists and
was locally edited — skip, flag for manual review), or **OK** (already current).

Check these:

| Area | Detection |
|---|---|
| Guardrail hooks | `.claude/hooks/{guard-secrets,guard-design-tokens,guard-dark-pattern,guard-a11y-id,guard-context-budget,asc-lint,log-activity}.sh` present + executable |
| Hook wiring | `.claude/settings.json` `hooks.PreToolUse/PostToolUse` reference the leanwheel guard scripts |
| Eval set | `docs/evals/README.md` present |
| Metrics ledger | `docs/metrics/README.md` present |
| Swift stubs | each `docs/setup/swift/*.md` vs `{skills_path}/.../stubs/swift/*.md` (only if `is_apple`) |
| Web stubs | each `docs/setup/web/*.md` vs stubs (only if `is_web`) |
| Simplicity doctrine | `docs/setup/simplicity.md` present, and CLAUDE.md references it (all projects — not gated). A legacy inlined `## Simplicity & Anti-Over-Engineering` block in CLAUDE.md counts as missing — see **Missing stubs** below |
| Swift guardrails block | `## Swift/SwiftUI Guardrails` in CLAUDE.md (only if `is_apple`), **and** the block carries the current `<!-- leanwheel:guardrails swift vN -->` marker. A block with an older `vN`, or with no marker at all, is a **stale inlined copy** — see *Re-syncing the guardrails block* below |
| Web guardrails block | `## Web Guardrails` in CLAUDE.md (only if `is_web`) |
| Commit script | `scripts/commit-push.sh` present + executable; `## Git Workflow` in CLAUDE.md **carrying the current `<!-- leanwheel:git-workflow vN -->` marker** — an older `vN` or no marker is stale; see *Re-syncing the git-workflow block* |
| Tracking script | `scripts/gh-track.sh` present + executable |
| Sabotage script | `scripts/sabotage.sh` present + executable |
| Ledger script | `scripts/ledger.sh` present + executable |
| Evals runner | `scripts/evals.sh` present + executable (ADD on any project with `docs/evals/` — before it shipped, RUN parsed the eval files in-context) |
| Simulator harness | `scripts/sim.sh` present + executable, and `docs/setup/swift/simulator.md` present (only if `is_apple`); on CONFLICT also report **capability skew** (below) |
| Docs structure | `## Docs Structure`, `## Task Tracking Emoji` in CLAUDE.md |

**Stub-install verification.** Walk every stub under `{skills_path}/.claude/skills/setup/stubs/`
that applies to this project's surfaces, using the target mapping the rows above already
define (`stubs/swift/*` → `docs/setup/swift/`, `stubs/web/*` → `docs/setup/web/`,
`stubs/hooks/*` → `.claude/hooks/`, `stubs/simplicity.md` → `docs/setup/simplicity.md`,
`stubs/evals|metrics/README.md` → `docs/evals|metrics/`). Report every one that is absent at
its target under a **Missing stubs** heading. A missing stub is a strong hint its content was
**inlined somewhere expensive** — usually CLAUDE.md, which is loaded every turn. For each,
recommend installing the stub and collapsing the inlined copy to a one-line pointer.

**REFRESH vs CONFLICT for stubs** — the safe-overwrite test:
- Compare the project file against **every** historical version of that stub the
  source repo has (use git history of `{skills_path}` if available:
  `git -C {skills_path} log --oneline -- .claude/skills/setup/stubs/<f>`). If the
  project file's content hashes to any committed version of the stub, the user never
  edited it → **REFRESH** (copy the current stub over it).
- If it matches none, the user edited it → **CONFLICT**: do not overwrite. Report it
  with a one-line diff summary so the user can merge manually (or run the relevant
  `/refresh-swift` / `/refresh-web` to reconcile).
- If git history isn't available, fall back to: identical to current stub → OK;
  differs → CONFLICT (never auto-overwrite a differing stub without provenance).

**CONFLICT must still report skew — the silence is the bug, not the refusal.** Vendored
scripts are copied once and only when missing, so a project can hold a stale
`scripts/sim.sh` indefinitely with no signal; refusing to overwrite a locally-modified copy
is correct, but saying nothing about what that copy *lacks* is how a missing `shots --store`
blocked `/appstore-connect assets` in a real project for over a week. For every vendored
script classified CONFLICT, diff the shipped copy's **long-option vocabulary** against the
project's and name what is absent:

```bash
diff <(grep -o -- '--[a-z-]\+' {skills_path}/scripts/sim.sh | sort -u) \
     <(grep -o -- '--[a-z-]\+' scripts/sim.sh | sort -u)
```

Report as, e.g.: `scripts/sim.sh CONFLICT (locally modified) — shipped version adds:
--store, --locale, --assetcapture. Not auto-refreshed; diff and merge by hand.` Flags
present locally but not upstream are project-local features, not skew — do not report those
as missing. This is a **signal only**: no behavior changes, nothing is overwritten.

Two limits of that diff, both real misses:

- **A CONFLICT copy can be *ahead* of the shipped one, not just behind.** A project that
  fixed a bug locally shows no missing flags, so the skew report reads clean while the
  shipped script still carries the defect. When merging a CONFLICT by hand, read the
  local changes as *candidate upstream fixes* and report them back, rather than
  overwriting them away.
- **A flag in the vocabulary is not a flag that works.** `grep -o -- '--[a-z-]+'` matches
  the usage string as readily as the `case` branch, so a flag advertised in usage but
  missing a branch in that subcommand's parser looks present and dies at runtime. For any
  flag the upgrade *depends on*, check it is handled in the subcommand you will call:
  `grep -n -- '--assetcapture)' scripts/sim.sh`.

Present the plan as a table: `ADD / REFRESH / CONFLICT / OK` per item. Summarize:
"Will add N, refresh M, skip K conflicts (need manual merge). Proceed? (y/n)"

## Step 4 — Apply (after confirmation)

In dependency order, applying only ADD and REFRESH items:

1. **Dirs:** create `docs/evals/`, `docs/metrics/` if missing; copy their `README.md`
   from `stubs/evals/` and `stubs/metrics/` (skip if present).
2. **Hooks:** copy missing `stubs/hooks/*.sh` + `README.md` into `.claude/hooks/`;
   `chmod +x` them. Never overwrite an existing hook script unless it's an unedited
   REFRESH (same git-provenance test as stubs).
3. **Hook wiring:** merge the `hooks-settings.json` PreToolUse/PostToolUse blocks into
   `.claude/settings.json` if the leanwheel guard commands aren't already wired. Preserve
   `startup` and any user hooks.
4. **Stubs (REFRESH only):** copy current swift/web stubs over unedited project copies.
   Leave CONFLICTs untouched.
5. **Scripts:** if `scripts/commit-push.sh` is missing, copy from
   `{skills_path}/scripts/commit-push.sh` and `chmod +x`. If `## Git Workflow` is
   missing from CLAUDE.md, append `---` + `stubs/commit-workflow.md`; if present but stale,
   re-sync it per *Re-syncing the git-workflow block* (item 6). Likewise copy
   `{skills_path}/scripts/gh-track.sh` if `scripts/gh-track.sh` is missing and `chmod +x`,
   `{skills_path}/scripts/sabotage.sh` if `scripts/sabotage.sh` is missing and `chmod +x`,
   `{skills_path}/scripts/ledger.sh` if `scripts/ledger.sh` is missing and `chmod +x`,
   and `{skills_path}/scripts/evals.sh` if `scripts/evals.sh` is missing and `chmod +x`.
   On Apple projects (`is_apple`), likewise copy `{skills_path}/scripts/sim.sh` if
   `scripts/sim.sh` is missing, and `chmod +x`. `sim.sh` derives its own
   `.leanwheel/sim.json` on first run — never author that file here.
   These are unedited-overwrite-safe by the same git-provenance test as stubs (REFRESH
   if the project copy matches a historical committed version; CONFLICT otherwise). A
   CONFLICT here is still *reported* with its capability skew (Step 3) — the copy is left
   untouched, but the user is told which shipped flags it lacks.
6. **CLAUDE.md sections:** append any missing guardrail/structure blocks (same logic as
   `/setup` Steps 3/3s/3a/3c) — check-heading-then-append, never modify existing prose.

   **Re-syncing the guardrails block.** The Swift and Web guardrail stubs are **managed
   blocks** delimited by `<!-- leanwheel:guardrails {surface} vN -->` … `<!-- /leanwheel:guardrails {surface} vN -->`.
   They are a pointer to `docs/setup/{swift,web}/` plus tripwires — never an inlined copy of a
   reference file, which drifts from the file it was copied from and is paid for on every turn.

   - **Marker present and `vN` matches the stub** → nothing to do.
   - **Marker present with an older `vN`** → replace everything between the markers with the
     current stub's block. This is the one case where existing CLAUDE.md prose is rewritten, and
     it is safe because the block is declared managed. Report it as a REFRESH.
   - **`## Swift/SwiftUI Guardrails` present with no marker** (a project scaffolded before the
     block was managed, typically carrying an inlined hard-rejection table and a verbose
     patterns section) → this is a **CONFLICT**: the block may carry hand-added project rules.
     Do not overwrite. Show the diff between the project's block and the current stub, name any
     project-specific lines found inside it, and offer to (a) move those lines up into
     `## Critical Rules`, then (b) replace the block with the managed one. Only proceed on
     confirmation.
   - Project-specific rules must never live inside the managed block. If the re-sync finds any,
     surface them by name rather than silently discarding them.

   **Re-syncing the git-workflow block** (all projects). `stubs/commit-workflow.md` is a managed
   block delimited by `<!-- leanwheel:git-workflow vN -->` … `<!-- /leanwheel:git-workflow vN -->`.
   - **Marker matches** → nothing to do. **Older `vN`** → replace between the markers, report REFRESH.
   - **`## Git Workflow` with no marker** (v1, scaffolded before DD-70) → take the section from its
     heading up to the next `---` or `## ` line. If it is the original v1 text (the
     `scripts/commit-push.sh` usage block ending "Do not fall back to the multi-command git
     workflow in this repo.", ignoring whitespace), replace it with the current stub and report
     REFRESH. If it carries anything else, it is a **CONFLICT**: show the diff, name the extra lines,
     and offer to move them *below* the managed block before replacing. Proceed only on confirmation.
   The simplicity doctrine is unconditional but is **not** a CLAUDE.md block: write
   `stubs/simplicity.md` to `docs/setup/simplicity.md` (skip if present) and ensure CLAUDE.md
   carries a one-line pointer to it (check-then-add). If a legacy project has the doctrine
   inlined under `## Simplicity & Anti-Over-Engineering`, install the file and offer to
   collapse the inlined block to the pointer — never inline it again.
6. **Manifest:** if a legacy `.bmad-lite/` directory exists, rename it to `.leanwheel/`
   first (contents unchanged). Then write/update `.leanwheel/manifest.json` with the
   current `scaffolded_at` date, surfaces, and asset flags.

## Step 5 — Report

Print:
- **Added:** new assets installed (hooks, evals/metrics dirs, etc.)
- **Refreshed:** stubs updated from source (with the from→to if a version is known)
- **Missing stubs:** stubs absent at their target path (from the stub-install verification in
  Step 3) — with the note that a missing stub usually means its content was inlined into
  CLAUDE.md, and the recommendation to install + collapse to a pointer.
- **Conflicts (manual):** locally-edited files left untouched — tell the user to merge
  by hand or run `/refresh-swift` / `/refresh-web` to reconcile guidance.
- **Already current:** count only.
- Next steps: if hooks were newly added, note they take effect on the next session
  (Claude Code loads `settings.json` hooks at startup); suggest a quick
  `/status` or a trial `/story-flywheel` run to confirm subagents resolve.

## Notes

- **Token-safe:** this skill reads small files and runs `git log`/hash comparisons —
  no model-heavy work. Run it whenever you pull new leanwheel-skills changes.
- It never touches `docs/epics/` story files, `docs/prd.md`, `docs/architecture.md`,
  or any planning content — only framework scaffolding.
- The CONFLICT path is deliberately conservative: a locally-tuned stub is a feature,
  not drift. We surface it; we never silently overwrite it. "Surface" is load-bearing for
  vendored scripts: refusing to touch a modified `scripts/sim.sh` is right, and reporting
  nothing about what it is missing is what turns a correct refusal into a silent failure
  downstream.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.