Show HN: Badbox – A deterministic bad-pattern detector for codebases Badbox, a deterministic bad-pattern detector for codebases, has reached npm version 0.3.0, letting repositories encode questionable engineering patterns as structural rules and check for them without an LLM. The tool ships no default policies and performs no automatic rewriting, requiring each project to own its rules under `.badbox/` and run on Bun 1.3.14 or newer. Badbox reports evidence on where a pattern occurred, who owns it, and how often, while leaving the decision to a developer or coding agent. Deterministic bad-pattern detection for codebases. Badbox lets a repository encode questionable engineering patterns as structural rules, then check for them without an LLM. It reports evidence—where a pattern occurred, who owns it, and how often— while leaving the decision to a developer or coding agent. Badbox ships no default policies and performs no automatic rewriting. Each project owns its rules under .badbox/ . Current npm version: 0.3.0 Current rule format: badbox 1 experimental Badbox requires Bun https://bun.sh/ 1.3.14 or newer. Install it in a project: bun add --dev badbox Then run it through bunx : bunx badbox check You can also install the CLI globally: bun add --global badbox badbox check Published packages include prebuilt native engines for these platforms: | Platform | Architecture | Native package | |---|---|---| | macOS | Apple Silicon | badbox-darwin-arm64 | | macOS | Intel | badbox-darwin-x64 | | Linux GNU | arm64 | badbox-linux-arm64-gnu | | Linux GNU | x64 | badbox-linux-x64-gnu | | Windows | x64 | badbox-windows-x64 | Installing from npm on a supported platform does not require a local Rust toolchain. Run create from the root of the project you want to check: bunx badbox create project-rules.badbox Badbox creates .badbox/project-rules.badbox with the correct version header and an editable example. Replace that example with a rule for your project: badbox 1 rule rust/excessive-clones for rust { summary "Function contains more clone calls than the configured limit" param limit = 4 find code value value.clone group by nearest callable when count limit report { severity warning message "Function contains excessive clone calls" evidence "clone call sites" } } Check the project: bunx badbox check Or check specific source roots while still loading rules from the project's .badbox/ directory: bunx badbox check src packages A finding is an observation, so findings do not make the command fail. Invalid rules, invalid input, unreadable files, I/O errors, and syntax diagnostics make the check incomplete and return a nonzero exit code. A rule selects syntax, assigns each match to an owner, applies structural conditions, counts the remaining matches, and reports owners above a threshold. php find - where - nearest owner - distinct-range count - threshold - finding This makes rules useful for patterns such as: - excessive cloning, casting, unwrapping, or goroutine creation per function; - syntax inside a loop or another structural boundary; - an owner that contains or lacks supporting evidence; - one statement following or preceding another in the same lexical block; - repository-specific architectural patterns that should not reappear. Badbox detects which supported languages occur under the requested source roots and runs only the relevant rules. The tiny DSL is the primary rule format. Every file starts with a version header: badbox 1 Names declared in code ... become structural captures: find code value value.clone Undeclared identifiers remain literal source syntax. Captures can also be constrained by text: where text method in "unwrap", "expect" Supported text operators are == , = , in , not in , and matches . Rules can inspect containment and evidence around a selected match: where match inside any { node for statement node while statement } where group lacks any { code ctx ctx.cancel } Ordering relations compare statements in the same nearest callable and lexical block: find code statement statement.clearBindings group by nearest callable where match follows any { code statement statement.reset } Repeating statement in both selectors requires the captured source text to be equal. Therefore, first.reset does not satisfy a later second.clearBindings match. Intervening sibling statements are allowed; nested callables and different branch, loop, switch, or error-handling blocks remain separate. See the tiny DSL reference https://github.com/0ctacity/badbox/blob/main/native/tiny-dsl/README.md for the complete grammar, validation rules, relations, parameters, and fixture declarations. Runnable DSL examples live under examples/rules https://github.com/0ctacity/badbox/blob/main/examples/rules . YAML equivalents under examples/yaml https://github.com/0ctacity/badbox/blob/main/examples/yaml exercise the compatibility frontend; they are never loaded automatically. | Area | Supported today | |---|---| | Selection | Source-shaped code ... patterns and raw syntax-node kinds | | Ownership | Nearest callable for Rust, Go, PowerShell, and Zig; explicit nearest node kinds elsewhere | | Capture predicates | == , = , in , not in , and Rust-regex matches | | Containment | where match inside any\|all | | Owner evidence | where group has any\|all and where group lacks any\|all | | Ordering | Statement-level follows and precedes within one callable and lexical block | | Aggregation | Distinct selected ranges counted per owner with strict count threshold | | Parameters | Rule-local scalar defaults with programmatic overrides | | Frontends | Tiny DSL plus YAML compatibility, both compiled to the same Badbox Rule IR | | Output | Deterministically ordered, bounded findings with exact total counts | Badbox bundles 30 parsers. The 28 ast-grep built-in languages are Bash, C, C++, C , CSS, Dart, Elixir, Go, Haskell, HCL, HTML, Java, JavaScript/JSX, JSON, Kotlin, Lua, Markdown, Nix, PHP, Python, Ruby, Rust, Scala, Solidity, Swift, TSX, TypeScript, and YAML. Badbox also statically links PowerShell and Zig parsers. File extensions select relevant language rules. This is language detection, not framework, dependency, build-configuration, or semantic type detection. badbox create