---
id: joewinke/jat/route-makeover
version: "7fe76629"
license: MIT
install: manual
updated: 2026-07-27
---
# Route Makeover — Route Makeover orchestrates a complete app redesign by scanning your SvelteKit project's routes, organizing them into tiers and clusters, and materializing a structured task epic ready for execution. It pairs with the impeccable skill to handle per-route treatment and jat:tasktree to wire dependencies, letting you hand a design team a ready-to-run plan. Use it when you need the whole app redesigned—not just one screen.
Publisher: joewinke · Stars: 248 · Updated: 2026-07-27
Install (manual): `git clone https://github.com/joewinke/jat`
## SKILL.md
Turn a whole SvelteKit app into a structured design makeover: **scan every route → cluster + tier them → write a PRD → materialize an impeccable-treatment epic** (epic + foundation tasks + one task per route cluster, fully dependency-wired).
This skill orchestrates two others: the **impeccable** design skill (the per-route treatment) and **jat:tasktree** (the epic/task materialization). It does not redesign routes itself — it produces the plan and the tasks that do.
## When to use
The user wants the *whole app* (or a tier of it) redesigned, not a single screen. Signals: "give all our routes the design treatment", "full design makeover", "plan the redesign across the app", "turn our routes into a design epic", "hand the design firm a task tree".
For a single page/feature, use `$impeccable craft`/`shape`/`critique` directly instead.
## Preflight (gates — pass before generating anything)
| Gate | Check | If fail |
|---|---|---|
| SvelteKit | `src/routes/` (or `--root`) exists | Ask for the routes root; abort if not a SvelteKit app. |
| impeccable | The `impeccable` skill is reachable (vendored at `.agents/skills/impeccable/` or installed) | Tell the user the makeover depends on it; stop. |
| Context | A real design-authority exists: `PRODUCT.md`/`DESIGN.md`, **or** the project's own equivalent (a design-system doc + its token/state-color/component sources). | If none, run `$impeccable teach`/`document` (or hand-author from the existing token/component files), then resume. Becomes F1 regardless — but you need enough now to set **register + archetype**. |
| Tasks | `jt` CLI available (run bare `jt` for usage — note `jt create` has **no `--help`**, it would make a junk task). | Tell the user tasks can't be created; offer to emit the PRD only. |
## Procedure
### 1. Scan
Run the bundled scanner from the project root:
```bash
node .agents/skills/route-makeover/scripts/scan-routes.mjs --plan docs/route-plan.json
```
It writes `docs/ROUTES.md` (the inventory) and `docs/route-plan.json` (structured clusters with a proposed `tier` ∈ 1–4 and `register` ∈ brand|product per cluster). Read the plan JSON in full. Counts and tier distribution are in `.counts`.
Flags: `--root
` (non-default routes path), `--out ` (inventory path), `--no-md` (skip the inventory), `--plan ` (JSON output; omit → stdout).
### 2. Plan with judgment
**First name the project archetype — it decides register, tier meaning, and guardrails, and the scanner cannot infer it:**
- **Brand / marketing SaaS** (landing + app; a JST-template project): the scanner's `brand` first-impression + `money-path` tiers apply; register is a brand/product mix; use the JST-style guardrails (white-label token-only, multi-theme proof, test on the real deployment).
- **Internal tool / dashboard / admin / dev-tooling** (e.g. the JAT IDE itself): there are **no** marketing/brand/checkout surfaces — register is essentially **all `product`**, and the scanner's brand/money tiers are meaningless. It will dump almost everything into one tier-4 **"Other"** bucket and mislabel entry/search pages as fake tier-1 "brand". **Throw out its tiers** and re-tier by *operator value*: T1 daily-drivers → T2 frequent tools → T3 regular tools → T4 secondary. Guardrails come from the project's **own** design system, not a white-label token policy (see `reference/treatment.md` → "Adapting guardrails per archetype").
Then apply judgment to the clusters themselves — the scanner's clustering is a *proposal*, not the answer:
- **Re-cluster; don't trust the buckets.** For dashboard/internal apps the scanner emits one giant "Other" cluster — decompose it by **functional domain** (the screens an operator thinks of together) and by **shared-component leverage** (routes rendering the same core components redesign together). Ground this in what each route *actually is* — a quick read of each `+page.svelte` (purpose, LOC, primary components) beats guessing; an `Explore`/`general-purpose` agent can characterize all routes in one fan-out.
- **Merge** clusters that share a flow; **split** any cluster too big for one 2–8h session. Size each so one agent can hold its diagnose→fix loop in context.
- **Confirm register** per cluster against the archetype + any `PRODUCT.md` `register` field; override per surface (a marketing hero inside a product app is still brand).
- **Drop** redirect-only / stub / deprecated / already-perfect routes — they have no design surface (the scanner may still list them; e.g. `/`-redirect, legacy `/old → /new`, catch-all 404).
Then **confirm scope with the user** via `AskUserQuestion` (skip only if they already specified): which tiers to materialize now (1–4 full, 1–2 first, or 1 pilot), and confirm the one-task-per-cluster granularity (the right default — keeps the diagnose→fix loop in one agent's context; the per-command alternative fragments it).
### 3. Write the PRD
Using `reference/treatment.md` (the treatment sequence, register policy, guardrails, DoD, foundation phase, and PRD template), write the PRD to `docs/prds/-design-treatment.md` — **or match the project's existing PRD location/naming convention** if it has one (e.g. the JAT IDE keeps PRDs at `ide/docs/prd-*.md`). Fill the template from the plan + scope answers. The per-cluster task list is the (judgment-adjusted) clusters, ordered by tier. Always include the 3 foundation tasks (F1/F2/F3).
**Adapt the guardrails, DoD, and foundation sections to the archetype** — see `reference/treatment.md` → "Adapting guardrails per archetype". JST defaults (token-only/no-oklch-literals, multi-theme white-label proof, jatui reuse, test on the real deployment) are for brand SaaS; an internal tool swaps in its **own** design system as the authority and tests on its own dev server. State the swap explicitly in the PRD so cluster agents don't apply the wrong policy.
### 4. Materialize the epic (tasktree)
Follow `jat:tasktree`. The mechanics below are battle-tested — `jt`'s task-tree behavior has sharp edges that **silently corrupt the tree**:
> ⚠️ **`jt` gotchas:**
> - `jt create` has **no `--help`** — `jt create --help` makes a junk task titled "--help". Run bare `jt` for usage.
> - **Epic children get DOTTED ids** `.N` (e.g. `jat-65q2g.4`). `jt create --parent E …` prints `Created jat-65q2g.4: `. Capture the id by parsing that line — **not** by grepping `jat-[a-z0-9]+`, which stops at the dot and hands you the *parent* every time. `jt create --json` dumps the whole object with no clean top-level id line, so the plain-output parse is easier.
> - `jt delete ` with the **un-dotted** epic id deletes the **epic** (orphaning its `.N` children under a dead prefix). Always delete the full dotted id, and re-`jt show` the epic after any delete.
> - On **postgres-backed** projects, `--parent` sets the parent pointer but does **not** wire epic←child dependency edges — wire every edge manually.
Recipe (capture ids to a temp file — shell state does **not** persist across separate tool calls; `sleep` between creates to dodge create-flake):
```bash
idof(){ sed -n 's/^Created \([^:]*\):.*/\1/p' | head -1; } # robust: handles dotted child ids
# 1. Epic
E=$(jt create "Epic: Design makeover — routes" --type epic --priority 1 \
--labels "design,impeccable,frontend" --description "…PRD path + 'stays open, blocked by all children'…" 2>&1 | idof)
echo "E=$E" > /tmp/makeover-ids.env
# 2. Children: F1,F2,F3 (P0) then one per cluster (tier 1–3 → P1, tier 4 → P2). Each --parent "$E".
# --description embeds: routes + register + condensed treatment footer (sequence + guardrails + DoD
# from reference/treatment.md; point to the PRD for the canonical version).
out=$(jt create "F1 — …" --type task --priority 0 --parent "$E" --description "…" 2>&1)
echo "F1=$(printf '%s' "$out" | idof)" >> /tmp/makeover-ids.env # …repeat for F2,F3,C1…Cn (sleep ~0.4)
# 3. Wire ALL deps manually (jt dep add A B == "A depends on B"):
source /tmp/makeover-ids.env
for c in $F1 $F2 $F3 $C1 … $Cn; do jt dep add "$E" "$c"; done # epic blocked by EVERY child
jt dep add "$F2" "$F1"; jt dep add "$F3" "$F1" # F2,F3 → F1
for c in $C1 … $Cn; do jt dep add "$c" "$F2"; jt dep add "$c" "$F3"; done # each cluster → F2,F3
```
**Do not close the epic.** It stays open + blocked by all children; it becomes the cross-cluster consistency/UAT verification task when they complete.
### 5. Verify + report
```bash
source /tmp/makeover-ids.env
jt show "$E" --json # depends_on must list EVERY child (count == number of children)
jt show "$F1" --json # depends_on == [] (F1 is the only ready task)
jt show "$C1" --json # depends_on == [F2, F3]
```
Verify gating from each task's `depends_on` (entries look like `{id,type:"blocks",…}`), **not** from `jt ready`:
> ⚠️ On **postgres**, `jt ready` returns **all** open tasks (dependency filtering is SQLite-only), so it **cannot** confirm "only F1 is ready". Trust `jt show --json` → `depends_on` instead. (Reads can lag the cache briefly; re-check if a freshly-wired edge is missing.)
Print the tasktree banner: total tasks, P0/P1/P2 counts, the `F1 → {F2,F3} → clusters` dependency graph, and the execution strategy (F1 solo → F2+F3 parallel → fan out by tier). Tell the user to start at `E.1` (`/jat:start E.1`).
## Append mode (new routes after the epic is running)
Use when a feature batch lands (harvest epic, new vertical module, etc.) and adds routes that weren't covered by the original epic. The foundation is already done — skip F1/F2/F3 and add children directly to the existing epic.
### A1. Find the existing epic and baseline
```bash
# Locate the design-treatment epic (search by title or known id)
jt search "impeccable design treatment" --limit 5 --json | jq -r '.[] | "\(.id) [\(.status)] \(.title)"'
```
Note the epic id (`E`). Check which cluster tasks are already closed — those routes are covered. Open children are in-flight.
### A2. Surface new routes via git
The scanner can't know what's "new" — use git to find page routes added since the last run:
```bash
# Routes added in last N days (adjust window to match the feature batch)
git log --since="" --diff-filter=A --name-only --pretty=format:"--- %h %as %s" \
-- "src/routes/**" | grep -v "^---" | grep -v "^$" | grep -E "\+page\.(svelte|server\.ts|ts)$" | sort
```
Cross-reference against the existing cluster task descriptions: a route already named in a closed cluster is covered. A route not mentioned anywhere is new. Routes that fall in the same functional area as a closed cluster but weren't listed (e.g. new sub-pages under an already-treated module) count as new unless the cluster description was broad enough to subsume them — read it and judge.
The scanner excludes API endpoints, cron, webhooks, feeds, and health routes — apply the same exclusion here. Drop redirect-only `+page.svelte` stubs too.
### A3. Cluster the new routes
Group by functional domain using the same sizing rule: one agent should be able to hold the diagnose→fix loop for all routes in a cluster in one session. Typical clusters: 3–8 page routes. Split if larger; merge if a domain has only 1–2 tiny pages.
Confirm register per cluster (brand vs product — see `reference/treatment.md`).
### A4. Create tasks as children of the existing epic
No new epic needed. No F1/F2/F3 — foundation is done.
```bash
idof(){ sed -n 's/^Created \([^:]*\):.*/\1/p' | head -1; }
E=""
# One create per cluster; sleep 0.4 between calls
sleep 0.4
N1=$(jt create "Impeccable N1 — " \
--type task --priority 1 --parent "$E" \
--description "Routes (register: ):
- /path/to/route — description
- /path/to/other — description
Treatment (one session):
1. \$impeccable critique → Nielsen score + P0-P3 issues
2. \$impeccable audit → /20
3. Findings-driven fixes ( | )
4. \$impeccable polish
5. Re-critique (target ≥34/40, audit ≥18/20)
Guardrails: .
DoD: critique ≥34/40, audit ≥18/20, zero AI-slop, all states, build clean.
PRD: " 2>&1 | idof)
echo "N1=$N1"
# …repeat for N2..Nn
```
### A5. Wire epic → new children
```bash
for c in $N1 $N2 … $Nn; do
jt dep add "$E" "$c"
sleep 0.3
done
```
**No dep on F1/F2/F3** — they're closed. New tasks are immediately ready.
### A6. Verify
```bash
# Each new task: blocked_by shows the epic (normal parent-child pattern), depends_on is empty
jt show "$N1" --json | jq '{id:.id, status:.status, blocked_by:.blocked_by, depends_on:.depends_on}'
```
`blocked_by: [epic]` with an empty `depends_on` is correct — it means the epic depends on this task (not that the epic blocks the task from starting). This is the same pattern the original T1–Tn tasks had.
Print a short banner: N new tasks added, clusters listed, tell the user to start any with `/jat:start ` (all parallelize).
---
## Notes
- **One task per cluster, full sequence embedded** is the default and the best-product choice. Resist one-task-per-command: critique emits the fix commands the same session runs, and splitting loses that context across sessions.
- **Foundation gates routes** because shared-system work — tokens, the component primitives, the app shells — propagates to every route. Never let per-route polish run before F2/F3.
- **Shared primitives carry the foundation.** On component-heavy apps a handful of primitives (cards, tables, badges, the skeleton/loading family) render across many routes, so F2 fixing them improves a dozen routes at once — per-cluster tasks then become mostly layout/IA/state work, not rebuilds. Lean on this when sizing clusters, and enumerate those primitives explicitly in F2.
- **`$impeccable` may be vendored as individual skills.** Some projects (e.g. the JAT IDE) install the family as standalone `/critique`, `/audit`, `/polish`, `/typeset`, … with **no `$impeccable` umbrella** — invoke each directly. Check what's actually installed before writing commands into task descriptions.
- The scanner excludes API endpoints, cron, webhooks, feeds/manifests/health, and component demo galleries — those have no design surface. It does **not** detect redirect/stub `+page.svelte`s (e.g. a `goto()` redirect) — you must drop those in step 2.
- Re-running the scanner is safe and idempotent; regenerate `docs/ROUTES.md` after routes change.
[View on SkillFed](https://skillfed.io/joewinke/jat/route-makeover) · [View on GitHub](https://github.com/joewinke/jat)