Skip to content

Adopt Knip with staged cleanup and blocking CI checks #147

Open

Description

@DevJoaoLopes

Goal

Adopt Knip to identify unused code/dependencies, clean confirmed existing findings, and prevent regressions in CI. Deliver separately reviewable PRs targeting CopilotKit/OpenDots, not the contributor's fork as the destination.

This is an implementation plan, not a report from an actual Knip run. No dependencies were installed or application code changed during planning.

Current project context

Checked against upstream main at 625452e06cde74cb25b0ce319e2c1be0488f5a5f:

  • Single private ESM npm package, no workspaces; Node >=24, CI uses Node 24.
  • React/Vite client, Node/Hono server, separate browser runtime using Playwright.
  • Existing CI: npm ci → formatting → lint → typecheck → tests → build.
  • No conventional source codegen/build prerequisite identified; validate Knip before building in a clean checkout.

Scope and safety policy

  • Default mode is primary, including tests/tooling. Production mode is complementary, with all runtime roots validated before enforcement.
  • Fix discovery/resolution before cleanup or suppression. Exceptions must be narrow, justified and revisable; no global exports/types exclusions, issue-count budgets, or broad autofix.
  • Remove unnecessary export modifiers, not implementations still used within their file.
  • Remove unused eslint-plugin-react-hooks; do not enable new React Hooks lint rules here.
  • Check peers, global types, CLI/config usage, overrides, dynamic imports and external consumers before removal. Protect legitimate @tiptap/pm, @types/*, PostCSS/tooling and runtime Playwright usage.
  • A production-only finding does not authorize deleting code legitimately used by tests/tooling in default mode.
  • Respect .gitignore. Keep credentials, databases, generated reports and internal planning notes out of commits. Implement from an isolated upstream checkout without incorporating unrelated local lockfile changes.
  • No unrelated upgrades, application behavior changes or extra opt-in cycle/namespace/member analyses.

PR 1 — Configuration, discovery and report-only CI

  • Validate published Knip 6.41.0 against Node 24 / TS 6 / Vite 8 / ESLint 10; add an exact devDependency and update the npm lockfile.
  • Add static knip.json with v6 schema; verify automatic Vite/Vitest/TypeScript/ESLint/Prettier discovery, scripts and both tsconfigs.
  • Add npm run knip → knip, and npm run knip:production → knip --production.
  • Protect production roots with trailing ! patterns: src/client/main.tsx!, src/server/index.ts!, src/browser/index.ts!, public/theme.js!, deployment/computers/harden-supervisor.mjs!. Production mode must not depend on discovery of development/browser npm scripts.
  • Delimit project files: src/{client,server,browser,shared}/**/*.{ts,tsx}!, src/build/**/*.ts, tests/**/*.{ts,tsx,js}, public/**/*.js!, deployment/computers/**/*.mjs!, *.{js,ts}. Plugins retain responsibility for their configs/tests; do not turn every source/fixture into an entrypoint or force development tooling into production.
  • Use --debug in both modes to validate entries, resolution, lazy imports, URL-loaded theme JS, Docker-invoked patch, and tests involving string/data-URL imports. Playwright here is runtime, not an @playwright/test suite.
  • Check the nonexistent main: "index.js" metadata; correct it only if it interferes with discovery, without inventing an entrypoint.
  • Record a sanitized baseline here: category/mode, count, files, and disposition (discovery correction, confirmed removal, legitimate exception).
  • Add both commands to existing CI after npm ci and before build, initially with --no-exit-code --reporter symbols --reporter github-actions. Do not use blanket continue-on-error: operational/config-load errors still fail.
  • Add docs/knip.md, link it from CONTRIBUTING.md, and document commands, entry maintenance, triage and exception reasons.

Acceptance: all roots accounted for; both modes work before build in a fresh checkout without application credentials; malformed configuration returns exit 2 even in report-only mode; existing formatting/lint/typecheck/tests/build pass. No application-code cleanup in this PR.

PRs 2.x — Confirmed cleanup by category/area

Order: files → dependencies → exports/types, rerunning analysis after each batch. Skip empty cleanup PRs when a category has no confirmed findings.

  • Files: verify imports, HTML, scripts, Docker and filesystem references before deletion; correct discovery for legitimate external entrypoints.
  • Dependencies: remove eslint-plugin-react-hooks after reconfirming no usage/configuration; remove other packages only with evidence. Update the lockfile without unrelated churn; validate peers/runtime/types in a clean install.
  • Exports/types: remove redundant exports while preserving local functions and framework/SDK callbacks. Review complete default-category results, not just the exports filter.
  • Preserve legitimate test/tooling use when interpreting production-only findings; document precise exceptions.
  • Maintain per-finding decisions and link each PR here.

Candidates to investigate, not confirmed findings: Empty in TaskPresentation.tsx, the slackIdentity reexport in platform.ts, and local-only exports in TaskPresentation, slash-commands and dark-theme. This list is not deletion authorization.

Acceptance per PR: justified removals; both Knip modes rerun; clean installation and formatter/lint/typecheck/tests/build pass; relevant telemetry/deployment/theme/Slack/editor tests and UI smoke checks exercised. Any necessary behavior change requires regression coverage and explicit review.

Final PR — Blocking CI and maintenance

  • Reach zero unaccounted findings in applicable default categories in both validated modes; resolve stale config hints.
  • Add --treat-config-hints-as-errors to both scripts; remove --no-exit-code from CI, retaining readable output/annotations.
  • In a disposable checkout, independently introduce an orphan TS file, an unused export in a consumed module, and an unused runtime dependency. Prove findings and exit 1 in both modes; report-only returns 0 for findings, malformed config returns 2.
  • Remove temporary probes and prove both commands and the existing CI chain return to green. Do not commit probes/reports.
  • Ask maintainers to confirm the existing check job is required by merge rules. A failing workflow alone does not prove merge protection; do not change rulesets without administrative authorization.
  • Update maintenance docs and this issue with PR links, justified exceptions and merge-protection confirmation/status.

Record a genuine production compatibility blocker here before changing the agreed final goal. Intermediate PRs reference this issue; only the final PR closes it after satisfying acceptance criteria.

Activity

  1. DevJoaoLopes commented on Oct 13, 2026

    @DevJoaoLopes
    Author

    Stage 1 is ready for review: #148 — Knip configuration and report-only CI.

    The exact PR commit was verified in a fresh checkout: npm ci, formatting, lint, typecheck, 302 tests across 48 files, both Knip report-only modes before build, and production build all passed.

    Baseline for the published stage:

    Category Default Production
    Unused files 0 0
    Unused devDependencies 1 0
    Unused exports 11 19
    Unused exported types 1 1
    Unused runtime dependencies, unlisted dependencies/binaries, unresolved imports 0 0

    No configuration hints remain. The next PRs will address the unused lint dependency and confirmed exports/types separately, preserving regression-test consumers. Blocking CI follows only after cleanup; this issue remains open.

    Before the final enforcement stage, maintainers should confirm that the existing check job is required by merge rules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions