konsistent-fix-violations
Run the konsistent CLI, review all reported violations, and fix them in the codebase. Use when the user wants to "fix konsistent violations", "resolve…
npx skills add https://github.com/vercel-labs/konsistent --skill konsistent-fix-violationskonsistent — Fix Violations
Run konsistent, surface what is broken, and resolve violations. The hard part is not the mechanical fix — it is deciding whether the rule or the code is wrong when a single rule has many violations, and which non-trivial violations are worth attempting versus deferring.
The canonical workflow and per-predicate triage rubric are documented in node_modules/konsistent/docs/guides/fixing-violations.md. Read it before classifying violations. This skill layers strict gating, user confirmation, and AskUserQuestion interactions on top of that workflow.
Workflow (strict order)
- Run the CLI and collect all violations as JSON.
- Group violations by rule and identify rules with high violation counts.
- For each high-count rule, ask the user whether to keep, change, or remove the rule.
- Update
konsistent.jsonvia thekonsistent-configskill if any rules need changes. - Re-run the CLI to refresh the violation list, then stop and ask for explicit confirmation before modifying any code.
- Triage remaining violations into trivial vs. non-trivial.
- Surface non-trivial violations to the user and let them decide how to handle each.
- Fix the approved violations and re-run the CLI to verify.
Do not skip steps. Do not collapse them. The asks for user input at steps 3, 5, and 7 are non-negotiable.
1. Run the CLI
Determine the invocation in this order:
- If
package.jsonhas akonsistentscript → use the project's package manager:pnpm konsistent,npm run konsistent, oryarn konsistent(match the lockfile /packageManagerfield). - Else, if
konsistentis indevDependencies→ run via the package runner:pnpm exec konsistent,npx konsistent, etc. - Else, fall back to
npx konsistent.
Run the check command with JSON output and a high diagnostic cap so nothing is truncated:
<runner> konsistent check --format=json --max-diagnostics=1000
Note: when invoking via an npm/pnpm script that already wraps konsistent, you may need -- to forward flags:
pnpm konsistent check --format=json --max-diagnostics=1000
# OR if the script runs konsistent without args:
pnpm konsistent -- check --format=json --max-diagnostics=1000
The JSON output is an array of { severity, conventionName, filePath, predicateName, message }. Exit code is non-zero when errors are present; that is expected — read the JSON regardless. See node_modules/konsistent/docs/reference/cli.md for the full output schema.
If the command fails for reasons other than violations (config not found, invalid config, missing dependency), stop and resolve the underlying issue first. Do not proceed.
2. Group violations by rule
Aggregate the violations by conventionName (and optionally predicateName). Compute a count per group. Report the totals to the user briefly:
Found N violations across M conventions. Rule
Xhas K violations; ruleYhas J violations; …
A rule is "high-count" when it has roughly 5+ violations OR represents more than half of the violating files for that rule's path pattern. Use judgment — a rule with 4 violations across 4 files where the path pattern only matches 5 files is also high-count.
Why this matters: a rule with 1–2 violations almost always means the code is the outlier. A rule with many violations often means the rule itself encodes a convention the codebase has not actually adopted — fixing the code without questioning the rule produces churn and may overwrite the team's real convention.
3. Ask the user: rule vs. code
For each high-count rule, explicitly ask the user to choose. Use the AskUserQuestion tool with concrete options. Do not infer — the user owns this decision.
Frame the question with:
- The rule's name / description / what it enforces.
- The codebase distribution — count how many of the matched files conform vs. violate, and report the split (e.g. "12 of 25 matched packages use pattern A; 13 use pattern B — codebase is roughly 50/50"). This framing dramatically improves the user's ability to decide.
- A short summary of what convention the violating files actually follow (read 2–3 of them — what naming/structure pattern do they share?).
- A few representative examples (file paths or symbol names from each pattern).
Offer at minimum these options:
- Keep the rule, fix the code — code is the outlier; proceed to fix violations.
- Change the rule to match what the code does — the violating pattern is the real convention; update
konsistent.json. - Remove the rule — the convention isn't worth enforcing.
- Other (free-text — e.g. relax to
severity: warning, narrow the path pattern, add an exception via path negation).
Surface meaningful sub-options when "change the rule" admits more than one specific shape. Don't collapse them. Examples of sub-options worth presenting:
- File-naming variants:
${name}-options.tsvs${name}-model-options.ts. - A hybrid rule that splits by a sub-pattern (e.g. "single-word providers ending in
aiuse flat-case; everything else uses camelCase") — this is encodable viakebabToCamelMap/kebabToPascalMapoverrides orplaceholderSatisfiesconstraints. - Mixed-severity (
errorfor the must-have,warningfor the nice-to-have).
If the user picks "change", "remove", or "other", capture the specifics needed to execute the change in step 4.
Skip this step for low-count rules — assume code is wrong and fix in step 8.
4. Update konsistent.json via konsistent-config
If any rule needs to change based on step 3 decisions, defer to the konsistent-config skill for the actual edits. That skill knows the predicate catalog, path placeholder syntax, case map overrides, conditional/iterative blocks, and the project conventions for konsistent.json. Do not edit konsistent.json ad-hoc here.
When delegating, hand over: the rule name(s) being changed, the user's decision, and the concrete change (e.g. "change exportFunctions name template from ${name.toPascalCase()}Service to create${name.toPascalCase()}Service", "add severity: warning", "add path negation for packages/test-utils").
After the config is updated, validate:
<runner> konsistent validate
Fix any config errors before continuing.
5. Re-run and confirm before fixing
After config changes (or after step 3 if no changes were needed), re-run the CLI to get a fresh violation list reflecting the new rules:
<runner> konsistent check --format=json --max-diagnostics=1000
Report the updated count to the user. Then stop and ask for explicit confirmation before touching any code:
"Ready to start fixing N code violations. Proceed?"
Use AskUserQuestion with a clear yes/no. Do not begin code edits until the user confirms. This gate is the user's last chance to review the rule set before mass changes.
If the user says no or wants to adjust further, return to step 3 or 4.
6. Triage: trivial vs. non-trivial
Once confirmed, classify each remaining violation. Read node_modules/konsistent/docs/guides/fixing-violations.md for the per-predicate triage rubric and the search heuristics before classifying.
The headline rules:
- Search the codebase first. A "missing" file or export reported by
konsistentvery often already exists under a different name, in a different file, or in a different casing. These are still trivial fixes — rename, move, or re-export. Before marking anything non-trivial, search by exact name, case variants, stripped prefixes/suffixes, distinctive word stems, sibling locations, and mirror existing successful matches. - When in doubt, classify as non-trivial. False positives in the trivial bucket are worse than in the non-trivial bucket — the former lead to bad code without user input. But do not classify as non-trivial without first searching: a quick grep often turns the violation trivial.
The full per-predicate rubric (haveType, haveFiles, export/exportConstants, exportTypes, exportFunctions, exportInterfaces, exportClasses, import/importTypes) lives in node_modules/konsistent/docs/guides/fixing-violations.md.
7. Surface non-trivial violations
Compile the non-trivial violations into a clear list. For each, include:
- File path and rule.
- The violation message.
- A one-line note on why it is non-trivial (e.g. "type
FooConfigdoes not exist anywhere in the repo", "would require splitting the existing class").
Present the list to the user and ask, per violation or per group, which they want to:
- Defer — leave for later. Offer two follow-ups:
- Draft a GitHub issue title/body capturing the work (the user opens it).
- Add path negation in
konsistent.jsonfor the deferred files via thekonsistent-configskill, so CI stays green and the rule still applies to all other matched files. Remove the negation when the deferred work lands.
- Attempt — let the agent try; prompt the user for additional context that would help (intended types, examples to mirror, references to similar code).
- Skip — explicitly mark as won't-do (e.g. the rule will be relaxed instead — note this and return to step 4 if needed).
Use AskUserQuestion for the decision. For "Attempt", actively prompt for context — do not silently start a non-trivial change without input.
8. Fix approved violations
Before editing any public API, decide on backward-compatibility for renamed exports. This is the most important decision at the start of this step — answer it once, then apply uniformly across the run.
8a. Ask: is the project in a breaking-change window?
Use AskUserQuestion. Frame it: "Renames will affect package-boundary exports. Are breaking changes acceptable, or do we need to keep back-compat via deprecated aliases?"
- Breaking changes acceptable (e.g. major-version bump, beta line, pre-1.0, internal-only project) — plain renames everywhere. No aliases. Skip 8b.
- Need back-compat — proceed to 8b to identify which renames cross the package boundary; only those get aliases.
8b. If back-compat is required, classify each rename
Back-compat only matters for symbols exported across the package boundary. Internal renames within a package are noise to alias.
- Package-boundary export (public API) — the symbol is reachable from outside the package via its entry points. Determine this by checking the
package.jsonexports/main/module/typesfields and tracing what each entry point re-exports (typicallysrc/index.ts). If reachable via any entry point → alias required. - Internal-only export — the
exportkeyword is used between files within the same package, but the symbol is not reachable from any entry point. No alias. Rename freely and update intra-package call sites.
For monorepos, repeat this check per package — a rename in packages/foo/src/utils.ts may be internal to foo even if foo's entry point exports many other symbols.
For each package-boundary rename, keep a deprecated alias alongside the new name in the entry point:
export { newName } from "./impl";
/** @deprecated Use `newName` instead. */
export { newName as oldName } from "./impl";
Update intra-package callers to use the new name. Document the renames in the changelog if the project tracks one.
See node_modules/konsistent/docs/guides/fixing-violations.md for the rationale behind the package-boundary distinction.
Fix in this order:
- All trivial violations from step 6.
- The "Attempt" non-trivial violations from step 7, with the user's context.
Group fixes by file when possible to minimize churn. Do not re-run konsistent between individual fixes — batch the edits.
When done, re-run the CLI:
<runner> konsistent check --format=json --max-diagnostics=1000
Report:
- Violations resolved.
- Violations remaining (deferred + any new ones introduced).
- If new violations appeared, investigate before declaring complete.
Run the project's checks to ensure code edits did not break anything else (read package.json for the actual scripts):
pnpm typecheck
pnpm test
pnpm check
Important guardrails
- Never edit
konsistent.jsonto silence violations after step 4 without going back through step 3. The point of the rule-vs-code decision is to make it deliberate. - Never skip the confirmation gate at step 5. Even when there are zero high-count rules and no config changes, ask before mass-editing code.
- Never classify a violation as trivial just because the message looks short. Read the file first; verify the target symbol/type/file actually exists.
- When fixing renames, search for all references in the codebase and update them — do not leave dangling imports.
- If running konsistent reveals zero violations, report that and stop. There is nothing to fix.