Skip to content
Agent Orchestration
Skill

/fix-knip-unused-exports

Fix knip "Unused exports" violations. Handles all violation categories: test-only exports (extract to new file), dead barrel re-exports (remove from index.ts), and internally-only-used exports (un-export). Use when `npm run knip` reports unused exports.

BOOST
From plugin
factory-plugins
11617 skills3 commands
Install
$ npx -y skills add factory-ai/factory-plugins --skill fix-knip-unused-exports --agent claude-code

How it fires

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

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/fix-knip-unused-exports

Context preview

The summary Claude sees to decide when to auto-load this skill.

Fix knip "Unused exports" violations. Handles all violation categories: test-only exports (extract to new file), dead barrel re-exports (remove from index.ts), and internally-only-used exports (un-export). Use when `npm run knip` reports unused exports.

SKILL.md

fix-knip-unused-exports.SKILL.md
name: fix-knip-unused-exports
description: |
  Fix knip "Unused exports" violations. Handles all violation categories: test-only exports
  (extract to new file), dead barrel re-exports (remove from index.ts), and internally-only-used
  exports (un-export).
  Use when `npm run knip` reports unused exports.

Fix Knip Unused Exports

Fix knip "Unused exports" violations. There are several categories of violation, each with a different fix strategy.

When to Use

  • `npm run knip` reports "Unused exports"

When NOT to Use

  • The export is consumed by non-test production code in another file -- something else is wrong

Workflow

1. Identify Violations

npm run knip

Output looks like:

Unused exports (3)
::error file=packages/foo/src/bar.ts,line=42,title=Unused exports::myFunction

2. Classify Each Violation

For each flagged export, grep the **entire repository** (not just the package):

rg "myFunction"

Determine which category it falls into:

| Category | Callers | Fix | |----------|---------|-----| | **Test-only export** | Used in same file + test files only | Extract to new file | | **Dead barrel re-export** | Re-exported from `index.ts`, but production code imports via relative paths or other subpaths instead | Remove the re-export from the barrel | | **Internally-only-used export** | Used only within the same file, not by tests or other files | Remove the `export` keyword | | **Dead code** | No callers anywhere | Delete the export | | **Production consumer exists** | Used by non-test code in another file | Not a knip issue -- investigate further |

**Important**: When grepping, exclude test files to identify production consumers:

rg "myFunction" --glob '!**/*.test.*'

Fix: Test-Only Exports (Extract to New File)

When a function is exported solely for test access but is also used internally in the same file.

Plan the Extraction

Before writing code, answer these questions:

**a) What moves to the new file?**

  • The flagged export function/class/const
  • All private helper functions it depends on
  • All private constants/types it depends on

**b) Are any helpers shared with functions staying behind?**

  • If yes, the helper must be exported from the new file, and the original file imports it
  • This means the new file will have 2+ exports (which is fine for any filename-match-export lint rule)

**c) Will the new file have exactly one exported function?**

  • If your project enforces a `filename-match-export` lint rule, the file MUST be named after that export: `myFunction.ts`
  • If the file has 2+ function exports, the name is flexible

**d) Does a test file with a matching name exist?**

  • If `bar.ts` stays and `bar.test.ts` exists, the test must still import something from `./bar` (if your project enforces a `test-imports-source` rule)
  • If `bar.ts` is deleted (everything moved out), that rule typically only applies when the matching source file exists

**e) Any circular dependency risk?**

  • Draw the import graph: new file -> original file -> new file is circular
  • Fix: move the shared dependency to the new file or a third file

**f) Does it export a constant?**

  • If your project enforces a `constants-file-organization` lint rule, exported constants must live in a file named `constants.ts`
  • If the extracted function depends on a constant that other functions in the original file also use, do NOT export the constant from the new file. Instead, call the function (e.g., replace `BUDGET[effort]` with `getBudget(effort)`) to avoid needing a separate `constants.ts`

Execute the Extraction

Create the new file in the same directory:

// myFunction.ts (new file)
import { SomeType } from '../types';

function privateHelper(): void { /* ... */ }

export function myFunction(): SomeType {
  return privateHelper();
}

Update the original file to import from the new file:

// bar.ts (original file, updated)
import { myFunction } from './myFunction';

function otherFunction() {
  const result = myFunction(); // Now imports from new file
}

Update test files to import from the new file:

// bar.test.ts (updated)
import { myFunction } from './myFunction';
// If bar.ts still exists, you may need to also import something from './bar'
// to satisfy any test-imports-source rule

Watch for Chained Violations

After extracting, run `npm run knip` again. If function A was extracted to a new file alongside function B that A calls, but B is also only consumed by tests externally, knip will flag B too. You need to extract B to its own file so that A's file creates a genuine production import of B.

Example: suppose `throwMappedError` was first extracted alongside `mapResponseFailure` into `error-mappers.ts`. If `throwMappedError` is only called internally within that file (by `mapResponseFailure`), it will still be flagged. Fix: extract it to `throwMappedError.ts`, making the import from `error-mappers.ts` a genuine production consumer.

Fix: Dead Barrel Re-Exports (Remove from index.ts)

When a barrel `index.ts` re-exports something, but no production code imports it through the barrel. This happens when:

  • Production code within the same package uses relative imports (e.g., `import { x } from './source'`) instead of the barrel
  • Production code in other packages imports directly from a subpath (e.g., `@scope/pkg/feature/handlers`) instead of the barrel
  • The re-export was added speculatively but never consumed

How to Identify

Grep excluding test files. If the only hits are:

  • The barrel `index.ts` itself
  • Source files using relative imports within the same package
  • Test files

Then the barrel re-export is unused. Simply remove it from `index.ts`.

Cross-Package Test Imports

If a test in another package imports the symbol through the barrel (e.g., `import { x } from '@scope/pkg/feature'`), you need to provide an alternative import path after removing the barrel re-ex

Read more
Ships withfactory-plugins

Official Factory plugins marketplace containing curated skills, droids, and tools.

Get the whole plugin

Other skills on factory-plugins.