antipattern-czar: The Linter That Refuses to Hide Your Errors

A Bun-powered TypeScript tool that turns swallowed exceptions, weak logging, and brittle string matching into reliability policy.

8 min read • View on GitHub • More from thedotmack

A black-ink city water main splits into a visible regulated branch and a hidden leak that disappears into a side channel. It explains the repo's core idea: some failures are treated as critical, and the tool is built to keep them visible instead of letting them drain away.
The metaphor is simple. Hidden failure is worse than noisy failure, and the tool is designed to keep it visible.
Key Takeaways

The project is not trying to catch every bug. It is trying to stop invisible ones.

antipattern-czar is not a style cop. It is a reliability gate that treats swallowed exceptions, partial logs, and brittle string matching as evidence that failure is being hidden instead of handled. Most linters ask whether code is tidy. This one asks whether the next person will still be able to see what broke.

That difference matters in systems where the worst bugs are not crashes. They are the errors that turn into success-shaped output, because the exception was narrowed too early, the log lost the object, or the code guessed at an error message with a string match. The repo's whole posture is built around refusing that kind of comfort.

Why it was built this way

The backstory is plain enough in the repo's own material: a long debugging session caused by a broad try-catch made the author decide that vague error handling is not just messy, it is expensive. That kind of pain creates doctrine. Once you have lost hours to a missing stack trace or an overconfident catch block, the desire to make failure visible stops sounding ideological and starts sounding practical.

That is why the tone is so strict. The tool is not saying all exceptions are bad. It is saying that some contexts deserve less forgiveness, especially when the code path is critical and the team has already paid for being generous once.

How the czar decides what to flag

The engine lives in a single TypeScript file, detect-antipatterns.ts, and it follows a simple sequence. It merges .antipatternrc.json with DEFAULT_CONFIG, walks the tree recursively with findFilesRecursive, skips known directories, then applies a set of RegExp checks for the anti-patterns the author cares about most.

Those checks are deliberately opinionated. The scanner looks for things like partial error logging, where only error.message gets reported, and error string matching, where code tries to infer meaning from text instead of inspecting the error itself. Most importantly, criticalPaths raise the stakes. A catch-and-continue in a sensitive file is not just another warning. It becomes a harder failure, unless the developer has explicitly documented an APPROVED_OVERRIDE.

The key idea is not just detection. It is classification. The same pattern can become a warning, a hard failure, or a documented exception depending on context.

Why regex, Bun, and a single-file core are the point

The architecture is tiny on purpose. Bun gives the project fast startup and a direct CLI path, so there is no build step to babysit. A single-file core keeps the logic easy to inspect, easy to copy into other workflows, and easy for contributors to extend without learning a parser framework first.

Regex is the biggest tradeoff, and it is also the point. This is not trying to prove semantic correctness across a whole language grammar. It is trying to catch a narrow set of reliability smells quickly, with enough structure to support policy. For that job, speed and approachability beat AST ceremony.

The other important detail is the .claude/commands material. That turns the repo into something AI-operable, not just human-operable. The checks are not only a script a developer can run. They are also instructions an assistant can follow, which is a small but telling sign of where dev tooling is going.

What it beats, and what it does not try to be

ApproachStrengthWhere antipattern-czar differs
ESLint-style lintingBroad coverage for general correctness and style rules.This repo is narrower and more forceful about failure visibility, especially on critical paths.
AST-based custom analysisHigh precision and deep syntax awareness.This repo trades parser complexity for faster iteration and simpler rule authoring.
Grep or ad hoc scriptsVery quick to write for one-off checks.This repo packages the checks into a repeatable policy layer with documented overrides.
antipattern-czarOpinionated enforcement of error-handling discipline.It is not trying to lint everything. It is trying to make hidden failure hard to ship.

That comparison matters because it keeps the project in scale. It is not an ESLint replacement, and it is not pretending to be. Its value is sharper: it encodes one team's definition of unacceptable error handling, then makes that definition cheap to run and hard to ignore.

What this says about the next generation of dev tools

The most interesting thing about antipattern-czar is how little machinery it needs to exert real policy power. A small CLI, a single analysis file, a handful of regex rules, and a clear override path are enough to turn a preference into an enforceable standard. That is a strong pattern for modern teams, especially when the cost of a mistake is not syntax but silence.

The deeper shift is that the tool is written for both people and assistants. Humans get a fast check on reliability habits. AI agents get a rulebook they can follow when editing code. That combination points toward a future where the best internal tools do not just detect problems. They encode the team's actual tolerance for risk.