Skip to content
Development
Command

/hygiene

Manual cleanup of dead code, broken type refs, stale config, and schema cruft. Works on TypeScript/Svelte projects, with optional Postgres/Supabase checks. Tailored for the JST stack.

From plugin
jat
24836 skills36 commands
Install
$ npx -y skills add joewinke/jat --agent claude-code

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/hygiene

Context preview

What this command does when you run it.

Manual cleanup of dead code, broken type refs, stale config, and schema cruft. Works on TypeScript/Svelte projects, with optional Postgres/Supabase checks. Tailored for the JST stack.

Command definition

hygiene.md
argument-hint: [--safe-only | --dry-run]

/jat:hygiene - Code Hygiene Pass

Manual cleanup of dead code, broken type refs, stale config, and schema cruft. Works on TypeScript/Svelte projects, with optional Postgres/Supabase checks. Tailored for the JST stack.

**Use this when:** The user wants a hygiene/cleanup pass, or periodic tech-debt grooming.

**Flags:**

  • `--safe-only` — Apply only auto-safe fixes (JSDoc, stale config, dead ts-ignores). Skip all deletion steps.
  • `--dry-run` — Report findings without modifying any files.

**This is NOT for:** Linting/formatting (that's `prettier`/`eslint`), or refactoring.

---

Philosophy

Dead-code tools (knip, ts-prune) produce **candidates, not verdicts.** Every file/dep they flag needs human judgment because of these blind spots:

  • Dynamic string imports (`target: 'pino-pretty'`)
  • Build-time config refs (`vite.config.ts`, static copies)
  • HTML `<script>` tag refs (`app.html`, `static/*.html`)
  • Svelte dynamic components (`<svelte:component this={...}>`)
  • Test fixtures / e2e harnesses outside source tree
  • Type-only exports consumed externally

**Rule:** Apply safe fixes automatically. Verify every deletion candidate by hand.

---

STEP 0 — Stack Detection

Before starting, detect what applies to this project:

# Is there a frontend (Svelte/TS)?
test -f package.json && echo "has-node"
test -d src && ls src/**/*.svelte 2>/dev/null | head -1 && echo "has-svelte"
grep -l "typescript" package.json 2>/dev/null && echo "has-ts"

# Is there a database?
test -d supabase && echo "has-supabase"
test -d migrations && echo "has-migrations"
grep -l '"pg"\|"postgres"\|@supabase' package.json 2>/dev/null && echo "has-pg-client"

# Is this a SvelteKit app?
test -f svelte.config.js && echo "has-sveltekit"

Announce what you detected and skip irrelevant steps.

---

STEP 1 — Safe Auto-Fixes (always run, never ask)

These are pure wins with no behavioral risk. Apply them silently, then mention the total in the report.

1a. Broken JSDoc Type Imports

Find `@type` / `@typedef` / `@param` blocks importing nonexistent files:

# If svelte-check is available, use it
npx svelte-check --output machine 2>&1 | grep -i "cannot find module" || true

# Otherwise grep for JSDoc imports and verify each path
grep -rn "import('\./" src/ --include='*.js' --include='*.ts' --include='*.svelte' | \
  grep -oP "import\('[^']+'" | sort -u

For each broken ref:

  • If the correct path is obvious (file was moved, import path wrong), fix it
  • Otherwise replace with `any` — JSDoc is non-runtime, this is safe

1b. Stale Build Config

Check that every package referenced in build config actually exists in `package.json`:

# Grep for package names in build files
grep -oE "'[a-z0-9@/-]+'" vite.config.ts svelte.config.js 2>/dev/null | sort -u

Remove stale refs in:

  • `vite.config.ts` — `ssr.external`, `optimizeDeps.include`, `rollupOptions.external`, `resolve.alias`
  • `svelte.config.js` — `kit.alias`, preprocessor plugins
  • `tsconfig.json` — `paths`, `types` arrays pointing at deleted `@types/*`

1c. Dead TS-Ignore Comments

# Run tsc and look for "unused @ts-expect-error" errors
npx tsc --noEmit 2>&1 | grep "unused" || true

Remove every `// @ts-expect-error` / `// @ts-ignore` that TypeScript reports as unused.

---

STEP 2 — Knip Scan + Manual Review

Only run if `--safe-only` was not passed.

# Make sure knip is available
npx knip --no-progress 2>&1 | tee /tmp/knip-report.txt

Classify findings into these buckets. **Do not delete anything yet.**

Bucket A: Unused Files

For each flagged file, run these checks before deleting:

# 1. Is it referenced anywhere by basename? (catches dynamic imports, HTML refs)
git grep -F "$(basename FILE .svelte)"

# 2. Is it referenced by relative path? (catches partial matches)
git grep -F "FILE_PATH"

# 3. Is it a SvelteKit convention file? (+page, +layout, +server, +error)
# If yes → KEEP. knip should know but sometimes misses.

# 4. Is it in static/ and loaded from HTML?
grep -r "FILENAME" static/*.html src/app.html 2>/dev/null

**Decision:**

  • 0 hits outside itself → candidate for deletion
  • Any hit → investigate, likely a false positive

Bucket B: Unused Dependencies

For each flagged package, two false-positive patterns to check:

# 1. Dynamic string imports (pino-pretty trap)
git grep -F "'PACKAGE_NAME'"
git grep -F "\"PACKAGE_NAME\""

# 2. Build-time usage
git grep -F "PACKAGE_NAME" vite.config.ts svelte.config.js scripts/ package.json

If either returns a hit, **keep** the dep and note why.

Bucket C: Unused Exports / Types (LOW priority)

Skip unless the user explicitly asks. These have high churn risk and low cleanup value. Unused type exports in particular are cheap to keep and annoying if wrong.

**Exception:** Duplicate exports (same symbol exported twice) — usually safe to consolidate.

---

STEP 3 — Svelte-Specific Checks

Only for projects with `.svelte` files.

# svelte-check should report zero new errors (or only known baseline)
npx svelte-check 2>&1 | tail -20

# Look for runes used in wrong file types
grep -rn '\$state\|\$derived\|\$props' src/ --include='*.ts' --include='*.js' \
  | grep -v '\.svelte\.' || true
# These only work in .svelte / .svelte.ts / .svelte.js files

Flag any runes used outside `.svelte*` files — they're silently broken.

---

STEP 4 — Postgres / Supabase Hygiene (if applicable)

Only for projects with a database. Read-only checks — never modify schema without explicit approval.

# If Supabase CLI is installed
supabase db lint 2>/dev/null || echo "supabase CLI not available"

# Unused indexes (via any PG client the project uses)
# Report only — do NOT drop indexes automatically

Queries to run manually (report results, don't act):

-- Unused indexes (never scanned)
SELECT schemaname, relname AS table, indexrelname AS index, idx_scan
FROM pg_stat_user_
Read more
Ships withjat

Agents ship, suggest, repeat. You supervise — or they run on their own. JAT is the complete, self-contained environment for agentic development. Task management, agent orchestration, code editor, git integration, terminal access—all unified in a single IDE.

Get the whole plugin