| name | consolidate-imports |
| description | Use when the user asks to audit, normalize, or consolidate import statements in a codebase. Triggers on phrases like "consolidate imports", "normalize imports", "check import style", "fix import paths", "unify alias usage", "audit imports". Produces a file-by-file report with diffs; does NOT auto-rewrite, because the target style is project-specific. Skip for: type re-exports, generated files, vendor code, or changing import behavior (this skill is style-only). |
Consolidate Imports
Overview
Workflow for auditing import statements and surfacing style inconsistencies as a human-readable report. Reports only; does not auto-rewrite. The reason: the target style is project-specific (path-alias rules, grouping, extensions, ordering), and a wrong auto-rewrite is worse than no rewrite at all. The skill's job is to surface every finding with a ready-to-apply diff for the unambiguous P0/P1 cases; the human applies.
This is the report half of a refactor, not the execute half. Pair it with whatever the project's auto-formatter is (e.g. an import-organizer plugin) for the parts that are mechanical.
When to Use
- "consolidate imports / normalize imports / check import style / fix import paths"
- "unify alias usage" — some files use
@/foo, others use ../../foo
- "audit imports" — a sweep before a refactor or before a formatter migration
- The project has accumulated mixed import styles across iterations
When NOT to Use
- Adding new import statements (this is for auditing existing ones)
- Changing import behavior (e.g. switching from default to named exports) — that's a refactor, not a style fix
- Re-export aggregator files where the import patterns are intentionally diverse
- Generated / vendor / third-party code
- Change is ≤3 lines (do it inline)
General Workflow
Phase 1: Get target style → read project config + ask user for the rest
Phase 2: Scan → anchor-grep + targeted reads
Phase 3: Report → file-by-file markdown report with diffs (no edits)
Phase 4: Hand off → user reviews, then applies the diffs (or runs the formatter)
Do not skip Phase 1. The target style is the only thing that turns "this is inconsistent" into "this needs to change to X."
Step C1 — Get the target style
The target style has five axes. Try to read each one from project config; ask the user only for axes that affect P0/P1 correctness (alias, extension) when config is silent. For lower-priority axes (grouping, ordering), treat a silent config as "no rule enforced" and downgrade those findings to P2/P3.
| Axis | Where to look for the answer |
|---|
| Path aliases | Path alias config (e.g. tsconfig.json paths, jsconfig.json, bundler alias config, package.json imports field) |
| Grouping | Import-order lint rules, project README, or "by convention" |
| Extensions | Module resolution config (e.g. whether extensions are required, forbidden, or optional), lint rules |
| Style | Editor config, formatter config, lint config, or the most common style in the codebase |
| Re-exports | Project convention (often "type re-exports grouped at the bottom" or "no re-exports at all") |
Important: if a finding contradicts what the config says, the config wins. The user can override, but start with the config as the source of truth.
After reading the config, check whether the project already has an import-organizing tool configured (e.g. an import-sort/order lint rule with auto-fix, or a formatter plugin). If it does, note this at the top of the report — P1 mechanical findings may already be handleable by running the existing tool, in which case you only need to list them as a reminder rather than producing full diffs.
Step C2 — Anchor-grep scan
Patterns that signal an import-style issue (adapt to the project's language and import syntax):
- Relative imports that should be aliased: relative path imports (e.g.
../../foo) when an alias is configured
- Mixed extensions: some imports include a file extension, some omit it — pick one per the project's rule
- Namespace/wildcard imports: importing an entire module namespace when only one or two members are used
- Combined default + named in same statement: many style guides require these split into two separate import lines
- Unused imports: any name in an import statement that has no references in the file
- Duplicate imports: the same module imported twice in one file via different paths (e.g.
./foo and ./foo/index)
- Side-effect-only imports mixed with named imports: separate or inline per project rule
- Inconsistent ordering: some files sort alphabetically, some don't, some group external-first — pick the project's rule
Use whatever text-search tool your environment provides (ripgrep, grep, IDE search). Read ±5 lines around each match. Do not full-read every file.
Step C3 — Build the inventory
Group findings by file. For each finding, produce a row:
| Field | Meaning |
|---|
file:line | Location of the offending import statement |
current | The current import (verbatim) |
category | One of: alias, extension, grouping, unused, duplicate, wildcard, merge-split, ordering |
target | What the import should look like (per Step C1) |
priority | P0–P3 (see Step C4) |
diff | A ready-to-apply unified diff for P0/P1; text description for P2/P3 |
Important: a file with 12 alias issues is one inventory row per issue, not one row per file. The report is per-issue, not per-file.
Priority Tiers
Step C4 — Output a prioritized table
| Priority | Criterion | Examples |
|---|
| P0 | Duplicate imports (same module twice in one file) | import { a } from './foo' and import { b } from './foo' in the same file |
| P0 | Unused imports that a linter would catch but isn't running | import { unused } from 'foo' with no unused reference in the file |
| P1 | Relative imports that should use the configured alias (mechanical fix) | from '../../utils/x' → from '<alias>/utils/x' per the project's alias config |
| P1 | Mixed extension style (mechanical fix when the rule is clear) | An import with an explicit extension next to one without, when the project enforces one convention |
| P2 | Namespace/wildcard imports that should be named | import * as Foo from 'foo' where only Foo.bar is used |
| P2 | Combined default + named in same statement (style preference, not a bug) | Split into two separate import lines per project convention |
| P2 | Side-effect-only imports mixed with named imports | Reorder or split per project rule |
| P3 | Ordering preferences — usually not worth touching | Alphabetical vs. unsorted; external-first vs. internal-first when the project is inconsistent |
A finding is P0 only if removing/fixing it is unambiguously correct. If you need to think, it's P1 or lower.
Reporting
Step C5 — Write the file-by-file report
Produce a single markdown document, grouped by file. For each file, show:
## `path/to/file.<ext>` (5 findings)
### P0: duplicate import at line 3
- **Current:**
import { a } from './foo'
import { b } from './foo'
- **Target:**
import { a, b } from './foo'
- **Diff:**
```diff
- import { a } from './foo'
- import { b } from './foo'
+ import { a, b } from './foo'
P1: relative path at line 7
P2: namespace import at line 12
- (no diff — describe the change in prose)
**Important:** the report is the deliverable. Do NOT auto-apply. Do not even open the files in an editor.
### Step C6 — Hand off
After delivering the report:
- Highlight the P0 count (these are safe wins — user can apply mechanically)
- Highlight the P1 count with a one-line note ("P1 is mostly mechanical; check that the alias config matches the diffs")
- Mention the P2/P3 counts as "judgment calls; left for human review"
- Suggest a follow-up: "if the project has an import-organizing tool configured (e.g. an import-sort lint rule with auto-fix), you may not need to apply P1 manually — just run the tool"
- **Wait for the user to apply or reject** — do not move on to a different task
---
# Common Mistakes
| Mistake | Fix |
|---------|-----|
| Auto-rewriting the imports | This skill reports only. The human applies. |
| Inventing a default target style | Ask the user for axes that affect P0/P1 correctness (alias, extension) if config is silent; downgrade others to P2/P3 |
| Treating `import` orderings as a real bug | It's a style preference; P3 unless the project is very strict |
| Calling namespace/wildcard imports a bug | It's a code smell, not a bug; P2 with a description |
| Combining multiple import issues into one "consolidate" rewrite | Each issue is a separate diff; the user can apply them in any order |
| Reporting a relative path as "should be alias" when no alias is configured | Without a target style, there's nothing to report. |
| Skipping the diff for P0/P1 cases | The whole point of the report is that the user can copy-paste and apply. Always include a diff. |
| "I also cleaned up the import grouping" → out of scope | The user asked to audit, not to refactor. |
| Inventing an alias when the project doesn't have one | "You should add an alias to your config" is a separate proposal, not a finding. |
## Anti-Patterns — Reject These
- "Let me also auto-apply the safe P0 ones while I'm at it" → the user asked for a report, not edits
- "I noticed `<file>:<line>` has a real circular dependency" → surface as a separate finding; don't expand scope
- "I'll do a comprehensive import sweep to be safe" → user asked for X, do X
- "Adding a P4 tier for 'low-priority reorderings'" → if user said 3 tiers, give 3 tiers
- "Let me also rewrite the default-vs-named exports to match" → that's a behavior refactor; out of scope
- "I'll just run the auto-formatter and call it done" → a formatter doesn't know about project-specific aliases; that's exactly why this skill exists
- "I'll unify the import style across both `src/` and `test/`" → treat test imports as a separate inventory if their style differs by convention
## Common Workflow Endings
After delivering the report, summarize:
- **File count**: number of files with at least one finding
- **Finding count**: total findings, broken down by priority (P0, P1, P2, P3) and category
- **Top 3 categories**: which kinds of issues dominate (e.g. "32 of 50 findings are `alias` — fixing this is the highest-leverage win")
- **Mechanical vs. judgment**: how many findings are diff-ready (P0/P1) vs. need human review (P2/P3)
- **Follow-up suggestions**: e.g. "consider adding an import-order lint rule with auto-fix to catch the P1 cases going forward"
Then ask if the user wants to:
- Apply the report (mechanical P0/P1 first, then judgment P2/P3)
- Add a formatter rule to auto-handle the P1 cases going forward
- Run this skill on a different scope (e.g. only `test/`)
**Do not auto-apply** — import-style refactors are review-heavy and the user often wants to adjust the diffs before they land.
## See also
- `cleanup-stale-code` — for cleaning up the comments and tests *around* the import statements you've just consolidated
- `find-duplication` — for finding duplicated *code*, which is a related but separate axis from duplicated *imports*
- The project's own import-organizing tool (lint rule auto-fix, formatter plugin, etc.) may already handle the P1 mechanical cases — check before writing diffs for them