Code quality scanner that surfaces maintainability issues so teams can prioritize refactoring based on observable signals, not gut feeling.
Built on Bun + oxc, designed for fast repeated runs. JSON-only CLI output for AI agent integration.
bun install
bun run build # → dist/firebat.jsBun behavior is configured in bunfig.toml at the project root.
# Scan the entire project
firebat
# Scan specific files
firebat src/app.ts src/utils.ts
# Select detectors and output JSON
firebat --only waste,lintfirebat [targets...] [options]
firebat scan [targets...] [options]
| Command | Description |
|---|---|
scan |
Run code analysis (default command) |
install |
Set up firebat config files in this project |
update |
Sync config files with latest templates |
cache clean |
Delete cached analysis data (.firebat/*.sqlite) |
| Flag | Default | Description |
|---|---|---|
--min-size <n|auto> |
auto |
Min AST node size for duplicate detection |
--max-forward-depth <n> |
0 |
Max thin-wrapper chain depth |
--only <list> |
all | Comma-separated detectors to run |
--config <path> |
.firebatrc.jsonc |
Config file path |
--log-level <level> |
info |
error | warn | info | debug | trace |
--log-stack |
off | Include stack traces in log output |
All detectors run by default. Use --only to select a subset.
If .firebatrc.jsonc is present and --only is not specified, detectors can be disabled by setting features["<detector>"] to false.
| Detector | What it finds |
|---|---|
| exact-duplicates | Identical AST subtrees across files |
| structural-duplicates | Structurally similar code (clone classes) |
| waste | Dead stores — variables assigned but never read, or overwritten before read |
| nesting | Deep nesting that harms readability, with refactoring suggestions |
| early-return | Functions that would benefit from guard clauses / early returns |
| forwarding | Thin wrappers that only forward calls, and long forwarding chains |
| Detector | What it finds |
|---|---|
| barrel | Barrel file violations: export *, deep imports, missing/invalid index files, cross-module re-exports |
| unknown-proof | Unsafe unknown/any usage: type assertions, unvalidated unknown, inferred any |
| dependencies | Import dependency cycles and edge-cut hints |
| nesting | Cognitive complexity, deep nesting, callback depth, complexity density |
| early-return | Invertible if-else, collapsible conditions, guard clause opportunities |
| collapsible-if | Nested if statements that can be collapsed into a single condition |
| indirection | Thin wrappers, forwarding chains, type remaps, interface rewraps |
| variable-lifetime | Long-lived variables, scope-narrowing opportunities |
| waste | Dead stores, unused variables |
| duplicates | Exact and structural code duplicates |
| temporal-coupling | Order-dependent operations |
| giant-file | Files exceeding configurable line count threshold |
| error-flow | Unsafe error handling patterns |
| Detector | Tool | What it finds |
|---|---|---|
| lint | oxlint | Lint errors and warnings |
| format | oxfmt | Files that need formatting |
| typecheck | tsgo | Type errors and warnings with code frames |
Create .firebatrc.jsonc in your project root:
src/
adapters/ Entrypoints & composition root (CLI)
application/ Use-case orchestration (no direct I/O imports)
ports/ Interfaces for external I/O
infrastructure/ I/O implementations (SQLite, tsgo, oxlint, ast-grep)
engine/ Pure computation (AST parsing, CFG, hashing, detection)
features/ Pure analysis logic per detector
Dependency rules:
application/→ depends onports/only (neverinfrastructure/)infrastructure/→ implementsports/adapters/→ assembles everything (composition root)engine/+features/→ pure, no I/O dependencies
bun test # Run all tests
bun run build # Build to dist/
bun run deps # Check dependency rulesPrivate
{ // Detectors to run (default: all) "detectors": ["waste", "nesting", "lint"], // Per-feature configuration "features": { "unknown-proof": { "boundaryGlobs": ["src/adapters/**"] }, "barrel": { "ignoreGlobs": ["dist/**"] } } }