--- 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 <id>` 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 — <project> 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="<date>" --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="<existing-epic-id>" # One create per cluster; sleep 0.4 between calls sleep 0.4 N1=$(jt create "Impeccable N1 — <area>" \ --type task --priority 1 --parent "$E" \ --description "Routes (register: <brand|product>): - /path/to/route — description - /path/to/other — description Treatment (one session): 1. \$impeccable critique <route> → Nielsen score + P0-P3 issues 2. \$impeccable audit <route> → /20 3. Findings-driven fixes (<product: layout clarify harden distill> | <brand: typeset colorize layout bolder>) 4. \$impeccable polish 5. Re-critique (target ≥34/40, audit ≥18/20) Guardrails: <paste project guardrails from the existing PRD>. DoD: critique ≥34/40, audit ≥18/20, zero AI-slop, all states, build clean. PRD: <path to existing 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 <id>` (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)