An open API service indexing awesome lists of open source software.

https://github.com/dicklesworthstone/ultimate_bug_scanner

Static analysis tool that catches 1000+ bug patterns across all popular programming languages, with auto-wiring into AI coding agent quality guardrails
https://github.com/dicklesworthstone/ultimate_bug_scanner

agent-tools ai-agents bash bugs cli code-quality developer-tools linting static-analysis

Last synced: about 1 month ago
JSON representation

Static analysis tool that catches 1000+ bug patterns across all popular programming languages, with auto-wiring into AI coding agent quality guardrails

Awesome Lists containing this project

README

          

# πŸ”¬ Ultimate Bug Scanner v5.0


Ultimate Bug Scanner - The AI Coding Agent's Secret Weapon

### **The AI Coding Agent's Secret Weapon: Flagging Likely Bugs for Fixing Early On**

[![License: MIT](https://img.shields.io/badge/License-MIT%2BOpenAI%2FAnthropic%20Rider-blue.svg)](./LICENSE)
[![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-blue.svg)](https://github.com/Dicklesworthstone/ultimate_bug_scanner)
[![Version](https://img.shields.io/badge/version-5.2.69-blue.svg)](https://github.com/Dicklesworthstone/ultimate_bug_scanner)

```bash
# One command to catch 1000+ bug patterns (always main, cache-busted)
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/install.sh?$(date +%s)" \
| bash -s --
```

**Or via Homebrew (macOS/Linux):**

```bash
brew install dicklesworthstone/tap/ubs
```

---

Just want it to do everything without confirmations? Live life on the edge with easy-mode to auto-install every dependency, accept all prompts, detect local coding agents, and wire their quality guardrails with zero extra questions:

```bash
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/install.sh?$(date +%s)" \
| bash -s -- --easy-mode
```

Note: Windows users must run the installer one-liner from within Git Bash, or use WSL for Windows.

---

## πŸ€– Agent Quickstart (JSON/TOON)

**Use machine-readable output in agent contexts.** stdout = data, stderr = diagnostics, exit 0 = success.

```bash
# Scan current repo (JSON)
ubs . --format=json

# Token-optimized output (TOON)
ubs . --format=toon

# Scan only staged changes
ubs --staged --format=json

# CI-strict (fail on warnings)
ubs . --profile=strict --fail-on-warning --format=json
```

## πŸ’₯ **The Problem: AI Moves Fast, Bugs Move Faster**

You're coding faster than ever with Claude Code, Codex, Cursor, and other AI coding agents. You're shipping features in minutes that used to take days. **But here's the painful truth:**

### **Even the best AI makes these mistakes:**

**JavaScript/TypeScript example** *(similar patterns exist in Python, Go, Rust, Java, C++, Ruby)*:

```javascript
// ❌ CRITICAL BUG #1: Null pointer crash waiting to happen
const submitButton = document.getElementById('submit');
submitButton.addEventListener('click', handleSubmit); // πŸ’₯ Crashes if element doesn't exist

// ❌ CRITICAL BUG #2: XSS vulnerability
function displayUserComment(comment) {
document.getElementById('comments').innerHTML = comment; // 🚨 Security hole
}

// ❌ CRITICAL BUG #3: Silent failure (missing await)
async function saveUser(data) {
const result = validateUser(data); // πŸ’₯ Should be 'await validateUser(data)'
await saveToDatabase(result); // Saves undefined!
}

// ❌ CRITICAL BUG #4: Always false comparison
if (calculatedValue === NaN) { // πŸ’₯ This NEVER works (always false)
console.log("Invalid calculation");
}

// ❌ CRITICAL BUG #5: parseInt footgun
const zipCode = parseInt(userInput); // πŸ’₯ "08" becomes 0 in old browsers (octal!)
```

**Each of these bugs could cost 3-6 hours to debug in production.** Similar issues plague every language: unguarded null access, missing `await`, security holes from `eval()`, buffer overflows from `strcpy()`, `.unwrap()` panics, goroutine leaks... **You've probably hit all of them.**

---

## 🎯 **The Solution: Your 24/7 Bug Hunting Partner**

### 🧠 Language-Aware Meta-Runner
- `ubs` auto-detects **JavaScript/TypeScript, Python, C/C++, Rust, Go, Java, Ruby, Swift, C#, and Elixir** in the same repo and fans out to per-language scanners.
- Each scanner lives under `modules/ubs-.sh`, ships independently, and supports `--format text|json|jsonl|sarif|toon` for consistent downstream tooling.
- Modules download lazily (PATH β†’ repo `modules/` β†’ cached under `${XDG_DATA_HOME:-$HOME/.local/share}/ubs/modules`) and are validated before execution.
- Results from every language merge into one text/JSON/SARIF report via `jq`, so CI systems and AI agents only have to parse a single artifact.

### πŸ” Supply-Chain Safeguards
- Every lazily-downloaded module (and its helper assets) ships with pinned SHA-256 checksums baked into the meta-runner. Files fetched from GitHub are verified before they can execute, preventing tampering between releases.
- The cache lives under `${XDG_DATA_HOME:-$HOME/.local/share}/ubs/modules` by default; use `--module-dir` to relocate it (e.g., inside a CI workspace) while retaining the same verification guarantees.
- Run `ubs doctor` at any time to audit your environment. It checks for curl/wget availability, writable cache directories, and per-language module integrity. Add `--fix` to redownload missing or corrupted modules proactively.
- Scanner runs still respect `--update-modules`, but an invalid checksum now causes an immediate failure with remediation guidance rather than executing unverified code.
- **Developer Pre-commit Hook**: The repository ships with a `.githooks/pre-commit` hook that auto-updates `SHA256SUMS` when modules change and blocks commits with stale checksums. This ensures every release has verified checksums without manual intervention.
- **Minisign Support**: For additional assurance, set `UBS_MINISIGN_PUBKEY` to verify cryptographic signatures on `SHA256SUMS` via [minisign](https://jedisct1.github.io/minisign/).

### πŸŽ› Category Packs & Shareable Reports
- `--category=resource-lifecycle` focuses the scanners on Python/Go/Java resource hygiene (context managers, defer symmetry, try-with-resources). UBS automatically narrows the language set to those with lifecycle packs enabled and suppresses unrelated categories.
- `--comparison=` diff the latest combined summary against a stored run. Deltas feed into console output, JSON, HTML, and SARIF automation metadata so CI can detect regressions.
- `--report-json=` writes an enriched summary (project, totals, git metadata, optional comparison block) that you can archive or share with teammates/CI.
- `--html-report=` emits a standalone HTML preview showing totals, trends vs. baseline, and per-language breakdownsβ€”ideal for attaching to PRs or chat updates.
- All shareable outputs inject GitHub permalinks when UBS is run inside a git repo with a GitHub remote. Text output automatically annotates `path:line` references, JSON gains `git.*` metadata, and merged SARIF runs now include `versionControlProvenance` plus `automationDetails` keyed by the comparison id.

#### Resource lifecycle heuristics in each language
- **Python** – Category 16 now correlates every `open()` call against matching `with open(...)` usage and explicit `encoding=` parameters, while Category 19 uses the new AST helper at `modules/helpers/resource_lifecycle_py.py` to walk every file, socket, subprocess, asyncio task, and context cancellation path. The helper resolves alias imports, context managers, and awaited tasks so the diff counts (`acquire=X, release=Y, context-managed=Z`) show the exact imbalance per file.
- **Go** – Category 5/17 now run a Go AST walker (`modules/helpers/resource_lifecycle_go.go`) that detects `context.With*` calls missing cancel, `time.NewTicker/NewTimer` without `Stop`, `os.Open/sql.Open` without `Close`, and mutex `Lock`/`Unlock` symmetry. Category 9 also tracks request query/header/form/framework values into response headers unless they strip or reject CR/LF, tracks redirect targets into `http.Redirect`, framework `Redirect` calls, and `Location` headers unless they pass through same-origin or explicit allow-list validation, flags request-derived reverse proxy targets flowing into `httputil.NewSingleHostReverseProxy`, `ProxyRequest.SetURL`, or `Director` URL mutation without HTTPS plus host allow-list validation, flags request-derived SQL text flowing into `ExecContext`/`QueryContext`, sqlx-style helpers, or query-builder predicates unless request data is passed as bound parameters, flags credentialed wildcard or reflected-origin CORS responses, and catches auth/session cookies missing `HttpOnly`, `Secure`, or `SameSite` protections. Findings come straight from the AST/resource helper or taint pass positions, so β€œticker missing Stop()” and header/open-redirect/reverse-proxy/CORS/cookie/SQL lines map to exact `file:line` references instead of coarse regex summaries.
- **Java / Kotlin** – Category 5 surfaces `FileInputStream`, readers/writers, JDBC handles, etc. that were created outside try-with-resources, while Category 19 keeps tracking executor services and file streams that never close. Category 4 also tracks servlet/Spring/Ktor request parameters, headers, and annotated parameters into response headers unless they strip/reject CR/LF or encode header fragments, and into redirect sinks such as `sendRedirect`, `respondRedirect`, Spring `redirect:` views, `RedirectView`, `ModelAndView`, and `Location` headers unless a same-origin or explicit allow-list helper is applied first. The summary text matches the manifest fixtures, so CI will fail if regression swallows these warnings.

#### Shareable output quickstart
```bash
# 1) Capture a baseline JSON (checked into CI artifacts or local history)
ubs --ci --only=python --category=resource-lifecycle \
--report-json .ubs/baseline.json test-suite/python/buggy

# 2) Re-run with comparison + HTML preview for PRs or chat threads
ubs --ci --only=python --category=resource-lifecycle \
--comparison .ubs/baseline.json \
--report-json .ubs/latest.json \
--html-report .ubs/latest.html \
test-suite/python/buggy
```

`latest.json` now contains the git metadata (repo URL, commit, blob_base) plus a `comparison.delta` block, and `latest.html` renders a lightweight dashboard summarising the deltas. SARIF uploads also pick up the comparison id so repeating runs in CI stay grouped by automation id.

---

## πŸ’‘ **Basic Usage**

```bash
# Scan current directory
ubs .

# Scan specific directory
ubs /path/to/your/project

# Verbose mode (show more code examples)
ubs -v .

# Save report to file
ubs . bug-report.txt

# CI mode (exit code 1 on warnings)
ubs . --fail-on-warning

# Quiet mode (summary only)
ubs -q .

# Skip specific categories (e.g., skip TODO markers)
ubs . --skip=11,14

# Custom file extensions
ubs . --include-ext=js,ts,vue,svelte
```

### Handy switches

```bash
# Git-aware quick scans (changed files only)
ubs --staged # Scan files staged for commit
ubs --diff # Scan working tree changes vs HEAD

# Strictness profiles
ubs --profile=strict # Fail on warnings, enforce high standards
ubs --profile=loose # Skip TODO/debug/code-quality nits when prototyping

# Machine-readable output
ubs . --format=json # Pure JSON on stdout; logs go to stderr
ubs . --format=jsonl # Line-delimited summary per scanner + totals
ubs . --format=toon # TOON format (~50% smaller than JSON, LLM-optimized)
ubs . --format=jsonl --beads-jsonl out/findings.jsonl # Save JSONL for Beads/"strung"
```

### Keeping noise low
- UBS auto-ignores common junk (`node_modules`, virtualenvs, dist/build/target/vendor, editor caches, etc.).
- Inline suppression is available when a finding is intentional: `eval("print('safe')") # ubs:ignore`

## πŸš€ **Quick Install (30 Seconds)**

### **Recommended: Homebrew (macOS/Linux)**

```bash
brew install dicklesworthstone/tap/ubs
```

This method provides:
- Automatic updates via `brew upgrade`
- Dependency management
- Easy uninstall via `brew uninstall`

### **Windows: Scoop**

```powershell
scoop bucket add dicklesworthstone https://github.com/Dicklesworthstone/scoop-bucket
scoop install dicklesworthstone/ubs
```

### **Alternative: Automated Install**

```bash
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/install.sh?$(date +%s)" | bash
```

### **Option 2: Integrity-first install (signed checksums)**

```bash
export UBS_MINISIGN_PUBKEY="RWQg+jMrKiloMT5L3URISMoRzCMc/pVcVRCTfuY+WIzttzIr4CUJYRUk"
curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/scripts/verify.sh | bash
```

The verifier downloads `SHA256SUMS` + `SHA256SUMS.minisig` from the matching release, validates them with minisign, checks `install.sh`, and only then executes it. Use `--insecure` to bypass verification (not recommended).

### **Option 3: Nix**

Run directly (no install):

```bash
nix run github:Dicklesworthstone/ultimate_bug_scanner
```

Dev shell for contributors:

```bash
nix develop
```

### **Option 4: Docker / OCI**

Pull & inspect:

```bash
docker run --rm ghcr.io/dicklesworthstone/ubs-tools ubs --help
```

Scan host code (risk-aware: grants container access to host FS):

```bash
docker run --rm -v /:/host ghcr.io/dicklesworthstone/ubs-tools bash -c "cd /host/path && ubs ."
```

⚠️ Use the host-mount pattern only when you understand the write-access implications.

### Deployment & Security

- Release playbook (how we cut signed releases): [docs/release.md](docs/release.md)
- Supply chain & verification model: [docs/security.md](docs/security.md)

The installer will:
- βœ… Install the `ubs` command globally
- βœ… Install/ensure `ast-grep` (required for accurate JS/TS scanning; UBS can auto-provision a pinned binary)
- βœ… Optionally install `ripgrep` (for 10x faster scanning)
- βœ… Optionally install `jq` (needed for JSON/SARIF merging across all language scanners)
- βœ… Optionally install `typos` (smart spellchecker for docs and identifiers)
- βœ… Optionally install `Node.js + typescript` (enables deep TypeScript type narrowing analysis)
- βœ… Auto-run `ubs doctor` post-install and append a session summary to `~/.config/ubs/session.md`
- βœ… Capture readiness facts (ripgrep/jq/typos/type narrowing) and store them for `ubs sessions --entries 1`
- βœ… Set up git hooks (block commits with critical bugs)
- βœ… Set up Claude Code hooks (scan on file save)
- βœ… Add documentation to your AGENTS.md

Need to revisit what the installer discovered later? Run `ubs sessions --entries 1` to view the most recent session log (or point teammates at the same summary).

Need the β€œjust make it work” button? Run the installer with `--easy-mode` to auto-install every dependency, accept all prompts, detect local coding agents, and wire their quality guardrails with zero extra questions:

```bash
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/install.sh?$(date +%s)" \
| bash -s -- --easy-mode
```

**Total time:** 30 seconds to 2 minutes (depending on dependencies)

Need to keep your shell RC files untouched? Combine `--no-path-modify` (and optionally `--skip-hooks`) with the command aboveβ€”the installer will still drop `ubs` into your chosen `--install-dir`, but it will skip both PATH edits and the alias helper entirely.

### **Option 2: Manual Install**

```bash
# Download and install the unified runner
curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/ubs \
-o /usr/local/bin/ubs && chmod +x /usr/local/bin/ubs

# Verify it works
ubs --help

# Install dependencies (ast-grep required for JS/TS scanning)
# Required for JS/TS scanning (syntax-aware AST engine)
brew install ast-grep # or: cargo install ast-grep, npm i -g @ast-grep/cli
brew install ripgrep # 10x faster searching (or: apt/dnf/cargo install)
brew install typos-cli # Spellchecker tuned for code (or: cargo install typos-cli)
npm install -g typescript # Enables full tsserver-based type narrowing checks
```

### **Option 3: Use Without Installing**

```bash
# Download once
curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/ubs \
-o ubs && chmod +x ubs

# Run it
./ubs .
```

### Installer Safety Nets

#### Uninstall from any shell

Run the installer in `--uninstall` mode via curl if you want to remove UBS and all of its integrations:

```bash
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/install.sh?$(date +%s)" | bash -s -- --uninstall --non-interactive
```

This command deletes the UBS binary, shell RC snippets/aliases, config under `~/.config/ubs`, and the optional Claude/Git hooks that the installer set up. Because it passes `--non-interactive`, it auto-confirms all prompts and runs unattended.

| Flag | What it does | Why it matters |
|------|--------------|----------------|
| `--dry-run` | Prints every install action (downloads, PATH edits, hook writes, cleanup) without touching disk. Dry runs still resolve config, detect agents, and show you exactly what *would* change. | Audit the installer, demo it to teammates, or validate CI steps without modifying a workstation. |
| `--self-test` | Immediately runs `test-suite/install/run_tests.sh` after installation and exits non-zero if the smoke suite fails. | CI/CD jobs and verified setups can prove the installer still works end-to-end before trusting a release. |
| `--skip-type-narrowing` | Skip the Node.js + TypeScript readiness probe **and** the cross-language guard analyzers (JS/Rust/Kotlin/Swift/C#). | Useful for air-gapped hosts or environments that want to stay in heuristic-only mode. |
| `--skip-typos` | Skip the Typos spellchecker installation + diagnostics. | Handy when corp images already provide Typos or when you deliberately disable spellcheck automation. |
| `--skip-doctor` | Skip the automatic `ubs doctor` run + session summary after install. | Use when CI already runs doctor separately or when you're iterating locally and want a faster finish. |

> [!WARNING]
> `--self-test` requires running `install.sh` from a working tree that contains `test-suite/install/run_tests.sh` (i.e., the repo root). Curl-piping the installer from GitHub can’t self-test because the harness isn’t present, so the flag will error out early instead of giving a false sense of safety.

> [!NOTE]
> After every install the script now double-checks `command -v ubs`. If another copy shadows the freshly written binary, you’ll get an explicit warning with both paths so you can fix PATH order before running scans.

> [!TIP]
> Type narrowing relies on Node.js plus the `typescript` npm package *and* the Python helpers that power the Rust/Kotlin/Swift/C# checks. The installer now checks Node/TypeScript readiness, can optionally run `npm install -g typescript`, and surfaces the status inside `install.sh --diagnose`. Use `--skip-type-narrowing` if you’re on an air-gapped host or plan to keep the heuristic-only mode.

> [!TIP]
> To avoid global npm permission issues, the installer now detects/installs [bun](https://bun.sh/) just like other dependencies and uses `bun install --global typescript` by default, falling back to npm only if bun isn’t available.
>
> The diagnostics also call out Swift guard readiness: if python3 is available we count `.swift` files under your repo and record whether the guard helper will actually run. That fact shows up in `install.sh --diagnose` output and the auto-generated session log so iOS/macOS teams can tell at a glance whether the ObjC-bridging heuristics are active.

**Common combos**

```bash
# Preview everything without touching dotfiles or hooks
bash install.sh --dry-run --no-path-modify --skip-hooks --non-interactive

# CI-friendly install that self-tests the smoke harness
bash install.sh --easy-mode --self-test --skip-hooks
```

### πŸ”„ **Auto-Update**

The `ubs` meta-runner supports an **opt-in** auto-update check (once every 24 hours). This is **disabled by default** for supply-chain safety.

To enable auto-update:
```bash
export UBS_ENABLE_AUTO_UPDATE=1
```

To disable it (even if enabled):
```bash
export UBS_NO_AUTO_UPDATE=1
# or
ubs --no-auto-update .
```

Ultimate Bug Scanner is like having a senior developer review every line of code **in under 5 seconds**; it's the perfect automated companion to your favorite coding agent:

```bash
$ ubs .

╔══════════════════════════════════════════════════════════════════════╗
β•‘ πŸ”¬ ULTIMATE BUG SCANNER v4.4 - Scanning your project... β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

Project: /Users/you/awesome-app
Files: 247 JS/TS + 58 Python + 24 Go + 16 Java + 11 Ruby + 12 C++/Rust files
Finished: 3.2 seconds

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Summary Statistics:
Files scanned: 247
πŸ”₯ Critical: 0 ← Would have crashed in production!
⚠️ Warnings: 8 ← Should fix before shipping
ℹ️ Info: 23 ← Code quality improvements

✨ EXCELLENT! No critical issues found ✨

```

---

## ⚑ **Why Developers + AI Agents Will Love This Tool**

### πŸš€ **1. Catches What Humans & AI Miss**

**18 specialized detection categories** covering the bugs that *actually* matter:

Category
What It Prevents
Time Saved Per Bug

Null Safety
"Cannot read property of undefined" crashes
2-4 hours

Security Holes
XSS, code injection, prototype pollution
8-20 hours + reputation damage

Async/Await Bugs
Race conditions, unhandled rejections
4-8 hours

Memory Leaks
Event listeners, timers, detached DOM
6-12 hours

Type Coercion
JavaScript's === vs == madness
1-3 hours

+ 13 more categories
100+ hours/month saved

### πŸ’¨ **2. Blazing Fast (Because Your Time Matters)**

```
Small project (5K lines): 0.8 seconds ⚑
Medium project (50K lines): 3.2 seconds πŸš€
Large project (200K lines): 12 seconds πŸ’¨
Huge project (1M lines): 58 seconds πŸƒ
```

**That's 10,000+ lines analyzed per second.** Faster than you can say "but it worked on my machine."

### πŸ€– **3. Built FOR AI Agents, BY Developers Who Use AI**

Unlike traditional linters that fight AI-generated code, this scanner **embraces** it:

```markdown
βœ… Designed for Claude Code, Cursor, Windsurf, Aider, Continue, Copilot
βœ… Zero configuration - works with ANY JS/TS, Python, C/C++, Rust, Go, Java, or Ruby project
βœ… Integrates with git hooks, CI/CD, file watchers
βœ… Actionable output (tells you WHAT's wrong and HOW to fix it)
βœ… Fails fast in CI (catch bugs before they merge)
βœ… React Hooks dependency analysis that spots missing deps, unstable objects, and stale closures
βœ… Lightweight taint analysis that traces req.body/window.location/localStorage β†’ innerHTML/res.send/eval/exec/db.query and flags flows without DOMPurify/escapeHtml/parameterized SQL
```

### πŸ“Š **4. Real-World Impact**

Scenario
Without Scanner
With Scanner

AI implements user auth

β€’ 3 null pointer crashes (9h debugging)

β€’ 1 XSS vulnerability (8h + incident)

β€’ 2 race conditions (4h debugging)

Total: ~21 hours + security incident

β€’ All issues caught in 4 seconds

β€’ Fixed before commit (15 min)

Total: 15 minutes

Savings: 84x faster ⚑

Refactor payment flow

β€’ Division by zero in edge case (3h)

β€’ Unhandled promise rejection (2h)

β€’ Missing error logging (1h)

Total: 6 hours debugging

β€’ Caught instantly (3 sec)

β€’ Fixed before merge (10 min)

Total: 10 minutes

Savings: 36x faster πŸš€

---

## πŸ€– **AI Agent Integration (The Real Magic)**

### On-Device Agent Guardrails

`install.sh` now inspects your workstation for the most common coding agents (the same set listed below) and, when asked, drops guardrails that remind those agents to run `ubs --fail-on-warning .` before claiming a task is done. In `--easy-mode` this happens automatically; otherwise you can approve each integration individually.

| Agent / IDE | What we wire up | Why it helps |
|-------------|-----------------|--------------|
| **Claude Code Desktop** (`.claude/hooks/on-file-write.sh`) | File-save hook that shells out to `ubs --ci` whenever Claude saves JS/TS files. | Keeps Claude from accepting β€œApply Patch” without a fresh scan. |
| **Cursor** (`.cursor/rules`) | Shared rule block that tells Cursor plans/tasks to run `ubs --fail-on-warning .` and summarize outstanding issues. | Cursor’s autonomous jobs inherit the same QA checklist as humans. |
| **Codex CLI** (`.codex/rules/ubs.md`) | Adds the identical rule block for OpenAI's Codex terminal workflow. Supports both file and directory formats (v0.77.0+). | Ensures Codex sessions never skip the scanner during long refactors. |
| **Gemini Code Assist** (`.gemini/rules`) | Guidance instructing Gemini agents to run `ubs` before closing a ticket. | Keeps Gemini’s asynchronous fixes aligned with UBS exit criteria. |
| **Windsurf** (`.windsurf/rules`) | Guardrail text + sample command palette snippet referencing `ubs`. | Windsurf’s multi-step plans stay grounded in the same quality gate. |
| **Cline** (`.cline/rules`) | Markdown instructions that Cline’s VS Code extension ingests. | Forces every β€œtool call” from Cline to mention scanner findings. |
| **OpenCode MCP** (`.opencode/rules`) | Local MCP instructions so HTTP tooling always calls `ubs` before replying. | Makes OpenCode's multi-agent swarms share the same notion of "done". |

#### Codex CLI v0.77.0+ Migration Note

Starting with Codex CLI v0.77.0, the rules storage changed from a **single file** (`.codex/rules`) to a **directory** (`.codex/rules/`) containing individual rule files. The UBS installer handles both formats automatically:

| Codex Version | Rules Location | UBS Installer Behavior |
|---------------|----------------|------------------------|
| < v0.77.0 | `.codex/rules` (file) | Appends UBS quick reference to file |
| β‰₯ v0.77.0 | `.codex/rules/` (directory) | Creates `.codex/rules/ubs.md` |

**If you upgraded Codex and encounter issues**, migrate manually:

```bash
# Convert file to directory structure
mv ~/.codex/rules ~/.codex/rules.backup
mkdir ~/.codex/rules
mv ~/.codex/rules.backup ~/.codex/rules/ubs.md
```

The installer's `append_quick_reference_block()` function detects the storage format at runtime and writes to the appropriate location, so re-running `install.sh` after upgrading Codex will "just work."

### **Why This Matters for AI Workflows**

When you're coding with AI, you're moving **10-100x faster** than traditional development. But bugs accumulate just as quickly. Traditional tools slow you down. This scanner keeps pace:

```
Traditional workflow: AI-powered workflow with scanner:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ AI writes code β”‚ β”‚ AI writes code β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
↓ ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ You review β”‚ β”‚ Scanner runs β”‚
β”‚ (15 min) β”‚ β”‚ (3 seconds) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
↓ ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Tests pass? β”‚ β”‚ Critical bugs? β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ NO! β”‚ YES!
↓ ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Debug in prod β”‚ β”‚ AI fixes them β”‚
β”‚ (6 hours) β”‚ β”‚ (5 minutes) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Ship with β”‚
β”‚ confidence β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Total: 6.25 hours Total: 8 minutes
```

### **Pattern 1: Claude Code Integration (Real-Time Scanning)**

Drop this into `.claude/hooks/on-file-write.sh`:

```bash
#!/bin/bash
# Auto-scan UBS-supported languages (JS/TS, Python, C/C++, Rust, Go, Java, Ruby, Swift, C#, Elixir) on save

if [[ "$FILE_PATH" =~ \.(js|jsx|ts|tsx|mjs|cjs|py|pyw|pyi|c|cc|cpp|cxx|h|hh|hpp|hxx|rs|go|java|rb|cs|csx|ex|exs|eex|heex|leex|sface)$ ]]; then
echo "πŸ”¬ Quality check running..."

if ubs "${PROJECT_DIR}" --ci 2>&1 | head -30; then
echo "βœ… No critical issues"
else
echo "⚠️ Issues detected - review above"
fi
fi
```

**Result:** Every time Claude writes code, the scanner catches bugs **instantly**.

### **Pattern 2: Git Pre-Commit Hook (Quality Gate)**

The installer can set this up automatically, or add to `.git/hooks/pre-commit`:

```bash
#!/bin/bash
# Block commits with critical bugs

echo "πŸ”¬ Running bug scanner..."

if ! ubs . --fail-on-warning 2>&1 | tee /tmp/scan.txt | tail -30; then
echo ""
echo "❌ Critical issues found. Fix them or use: git commit --no-verify"
echo ""
echo "Top issues:"
grep -A 3 "πŸ”₯ CRITICAL" /tmp/scan.txt | head -20
exit 1
fi

echo "βœ… Quality check passed - committing..."
```

**Result:** Bugs **cannot** be committed. Period.

### **Pattern 3: Cursor/Windsurf/Continue Integration**

Add to your `.cursorrules` or similar:

```markdown
## Code Quality Standards

Before marking any task as complete:

1. Run the bug scanner: `ubs .`
2. Fix ALL critical issues (πŸ”₯)
3. Review warnings (⚠️) and fix if trivial
4. Only then mark task complete

If the scanner finds critical issues, your task is NOT done.
```

**Result:** AI agents have **built-in quality standards**.

### **Pattern 4: CI/CD Pipeline (GitHub Actions Example)**

```yaml
name: Code Quality Gate

on: [push, pull_request]

jobs:
bug-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install Bug Scanner
run: |
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/install.sh?$(date +%s)" | bash -s -- --non-interactive

- name: Scan for Bugs
run: |
ubs . --fail-on-warning --ci
```

**Result:** Pull requests with critical bugs **cannot merge**.

### **Pattern 5: The Fix-Verify Loop (For AI Agents)**

This is the golden pattern for AI coding workflows:

```bash
#!/bin/bash
# Have your AI agent run this after implementing features

echo "πŸ”¬ Post-implementation quality check..."

# Run scanner
if ubs . --fail-on-warning > /tmp/scan-result.txt 2>&1; then
echo "βœ… All quality checks passed!"
echo "πŸ“ Ready to commit"
exit 0
else
echo "❌ Issues found:"
echo ""

# Show critical issues
grep -A 5 "πŸ”₯ CRITICAL" /tmp/scan-result.txt | head -30

echo ""
echo "πŸ€– AI: Please fix these issues and re-run this check"
exit 1
fi
```

**Usage pattern:**

```markdown
User: "Add user registration with email validation"

AI Agent:
1. Implements the feature
2. Runs quality check (scanner finds 3 critical bugs)
3. Fixes the bugs
4. Re-runs quality check (passes)
5. Commits the code

Total time: 12 minutes (vs. 6 hours debugging in production)
```

### **Pattern 6: The "AI Agent Decision Tree"**

Train your AI agent to use this decision tree:

```
Did I modify code in any supported language?
(JS/TS, Python, Go, Rust, Java, C++, Ruby)
β”‚
↓ YES
Changed more than 50 lines?
β”‚
↓ YES
Run scanner ←──────────┐
β”‚ β”‚
↓ β”‚
Critical issues found? ───── YES
β”‚ NO β”‚
↓ β”‚
Warnings? β”‚
β”‚ β”‚
↓ YES β”‚
Show to user β”‚
Ask if should fix ────────
β”‚ NO β”‚
↓ ↓
Commit code Fix issues
```

---

> [!IMPORTANT]
> **Copy the blurb below to your project's `AGENTS.md`, `.claude/claude_docs/`, or `.cursorrules` file for comprehensive UBS integration guidance.**

````markdown
## UBS Quick Reference for AI Agents

UBS stands for "Ultimate Bug Scanner": **The AI Coding Agent's Secret Weapon: Flagging Likely Bugs for Fixing Early On**

**Install:** `curl -sSL https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/main/install.sh | bash`

**Golden Rule:** `ubs ` before every commit. Exit 0 = safe. Exit >0 = fix & re-run.

**Commands:**
```bash
ubs file.ts file2.py # Specific files (< 1s) β€” USE THIS
ubs $(git diff --name-only --cached) # Staged files β€” before commit
ubs --only=js,python src/ # Language filter (3-5x faster)
ubs --ci --fail-on-warning . # CI mode β€” before PR
ubs --help # Full command reference
ubs sessions --entries 1 # Tail the latest install session log
ubs . # Whole project (ignores things like .venv and node_modules automatically)
```

**Output Format:**
```
⚠️ Category (N errors)
file.ts:42:5 – Issue description
πŸ’‘ Suggested fix
Exit code: 1
```
Parse: `file:line:col` β†’ location | πŸ’‘ β†’ how to fix | Exit 0/1 β†’ pass/fail

**Fix Workflow:**
1. Read finding β†’ category + fix suggestion
2. Navigate `file:line:col` β†’ view context
3. Verify real issue (not false positive)
4. Fix root cause (not symptom)
5. Re-run `ubs ` β†’ exit 0
6. Commit

**Speed Critical:** Scope to changed files. `ubs src/file.ts` (< 1s) vs `ubs .` (30s). Never full scan for small edits.

**Bug Severity:**
- **Critical** (always fix): Null safety, XSS/injection, async/await, memory leaks
- **Important** (production): Type narrowing, division-by-zero, resource leaks
- **Contextual** (judgment): TODO/FIXME, console logs

**Anti-Patterns:**
- ❌ Ignore findings β†’ βœ… Investigate each
- ❌ Full scan per edit β†’ βœ… Scope to file
- ❌ Fix symptom (`if (x) { x.y }`) β†’ βœ… Root cause (`x?.y`)
````

---

## 🎬 **See It In Action**

*Examples show JavaScript output; each language has equivalent detections (Python: None checks, Go: nil guards, Rust: Option handling, etc.)*

### **Example 1: Catching a Null Pointer Bug**

```bash
$ ubs src/

β–“β–“β–“ NULL SAFETY & DEFENSIVE PROGRAMMING
Detects: Null pointer dereferences, missing guards, unsafe property access

πŸ”₯ CRITICAL (5 found)
Unguarded property access after getElementById
Consider: const el = document.getElementById('x'); if (!el) return;

src/components/form.js:42
const submitBtn = document.getElementById('submit-button');
submitBtn.classList.add('active'); // ← Crashes if element missing

src/utils/dom.js:87
const modal = document.querySelector('.modal');
modal.style.display = 'block'; // ← Runtime crash guaranteed

πŸ’‘ Fix: Always check for null before accessing properties
```

**Before:** 3 production crashes this week
**After:** 0 crashes, caught in 2 seconds

### **Example 2: Security Vulnerability Detection**

```bash
β–“β–“β–“ SECURITY VULNERABILITIES
Detects: Code injection, XSS, prototype pollution, timing attacks

πŸ”₯ CRITICAL (3 found)
innerHTML without sanitization - XSS risk
Use textContent or DOMPurify.sanitize()

src/comments.js:156
element.innerHTML = userComment; // ← XSS vulnerability!

πŸ”₯ CRITICAL (1 found)
Hardcoded API keys detected
Use environment variables or secret managers

src/config.js:23
const apiKey = "sk_live_abc123xyz"; // ← Security breach!
```

**Before:** Security incident, customer data at risk
**After:** Vulnerability caught before git commit

### **Example 3: Async/Await Gotchas**

```bash
β–“β–“β–“ ASYNC/AWAIT & PROMISE PITFALLS
Detects: Missing await, unhandled rejections, race conditions

πŸ”₯ CRITICAL (8 found)
await used in non-async function
SyntaxError in JavaScript

src/api/users.js:67
function saveUser(data) {
await database.insert(data); // ← SyntaxError!
}

⚠️ WARNING (12 found)
Promises without .catch() or try/catch
Unhandled rejections crash Node.js

src/services/email.js:45
sendEmail(user.email).then(result => ...) // ← No error handling!
```

**Before:** Silent failures, mysterious bugs in production
**After:** All async bugs caught and fixed before deploy

---

## πŸ“‹ **What It Detects (The Complete Arsenal)**

*Each language module has specialized detections. Examples below are representative (JavaScript shown; Python has `eval()`, Go has goroutine leaks, Rust has `.unwrap()` panics, C++ has buffer overflows, etc.)*

### πŸ”΄ **Critical Issues (Production Blockers)**

These **WILL** cause crashes, security breaches, or data corruption:

| Pattern | Example | Why It's Dangerous |
|---------|---------|-------------------|
| `eval()` usage | `eval(userInput)` | Allows arbitrary code execution - **RCE vulnerability** |
| Direct NaN comparison | `if (x === NaN)` | Always returns false - **logic bug** |
| Missing await | `asyncFunc()` in async context | Silent failures, race conditions - **data corruption** |
| Prototype pollution | `obj.__proto__ = {}` | Security vulnerability - **privilege escalation** |
| Unguarded null access | `el.style.color` without null check | **Runtime crash** guaranteed |
| `parseInt` without radix | `parseInt("08")` | Returns 0 in some browsers - **calculation bug** |
| Empty catch blocks | `catch(e) {}` | Swallows errors - **debugging nightmare** |
| `innerHTML` with user data | `el.innerHTML = userInput` | **XSS vulnerability** |
| Missing async keyword | `await` without `async function` | **SyntaxError** |
| Hardcoded secrets | `const key = "sk_live..."` | **Security breach** |

### 🟑 **Warnings (Should Fix Before Shipping)**

These cause bugs, performance issues, or maintenance headaches:

| Pattern | Example | Impact |
|---------|---------|--------|
| Promises without `.catch()` | `promise.then(...)` | Unhandled rejections crash Node.js |
| Division without zero check | `total / count` | Returns `Infinity` or `NaN` |
| Event listeners without cleanup | `addEventListener` in React | **Memory leak** (app gets slower over time) |
| `setInterval` without clear | `setInterval(fn, 1000)` | **Timer leak** (infinite timers) |
| `fetch()` without cancellation | `fetch(url)` | Stalled requests can hang workflows and exhaust resources |
| `await` inside loops | `for(...) { await api.call() }` | **Slow** (sequential, not parallel) |
| Array mutation during iteration | `arr.forEach(() => arr.push(...))` | **Skipped/duplicate** elements |
| Missing switch default | `switch(x) { case 1: ... }` | Unhandled values cause silent failures |
| `isNaN()` instead of `Number.isNaN()` | `isNaN("foo")` | Type coercion bugs |

### πŸ”΅ **Info (Code Quality & Best Practices)**

Improvements that make code cleaner and more maintainable:

- Optional chaining opportunities (`obj?.prop?.value`)
- Nullish coalescing opportunities (`value ?? default`)
- TypeScript `any` usage (reduces type safety)
- `console.log` statements (remove before production)
- Technical debt markers (TODO, FIXME, HACK)
- Performance optimizations (DOM queries in loops)
- `var` usage (use `let`/`const` instead)
- Deep property access without guards
- Large inline arrays (move to separate files)
- Complex nested ternaries (readability)

---

## βš™οΈ **Advanced Configuration**

### **Command-Line Options (Full Reference)**

```bash
ubs [OPTIONS] [PROJECT_DIR] [OUTPUT_FILE]

Core Options:
-v, --verbose Show 10 code samples per finding (default: 3)
-q, --quiet Minimal output (summary only)
--ci CI mode (stable output, no colors by default)
--fail-on-warning Exit with code 1 on warnings (strict mode)
--version Print UBS meta-runner version and exit
--profile=MODE strict|loose (sets defaults for strictness)
--baseline=FILE Compare findings against a baseline JSON (alias for --comparison)
-h, --help Show help and exit

Git Integration:
--staged Scan only files staged for commit
--diff, --git-diff Scan only modified files (working tree vs HEAD)

Output Control:
--format=FMT Output format: text|json|jsonl|sarif|toon (default: text)
--beads-jsonl=FILE Write JSONL summary alongside normal output for Beads/"strung"
--no-color Force disable ANSI colors
OUTPUT_FILE Save report to file (auto-tees to stdout)

File Selection:
--include-ext=CSV File extensions (default: auto-detect by language)
JS: js,jsx,ts,tsx,mjs,cjs | Python: py,pyi,pyx
Go: go | Rust: rs | Java: java | C++: cpp,cc,cxx,c,h
Ruby: rb,rake,ru | C#: cs,csx | Custom: --include-ext=js,ts,vue
--exclude=GLOB[,...] Additional paths to exclude (comma-separated)
Example: --exclude=legacy (deps ignored by default)
--skip-size-check Skip directory size guard (use with care)

Performance:
--jobs=N Parallel jobs for ripgrep (default: auto-detect cores)
Set to 1 for deterministic output

Rule Control:
--skip=CSV Skip categories by number (see output for numbers)
Example: --skip=11,14 # Skip debug code + TODOs
--skip-type-narrowing Disable helper-backed guard analysis (falls back to text heuristics)
--rules=DIR Additional ast-grep rules directory
Rules are merged with built-in rules
--no-auto-update Disable automatic self-update
--suggest-ignore Print large-directory candidates to add to .ubsignore (no changes applied)

Environment Variables:
JOBS Same as --jobs=N
NO_COLOR Disable colors (respects standard)
CI Enable CI mode automatically
UBS_MAX_DIR_SIZE_MB Max directory size in MB before refusing to scan (default: 1000)
UBS_SKIP_SIZE_CHECK Skip directory size guard entirely (set to 1)

Arguments:
PROJECT_DIR Directory to scan (default: current directory)
OUTPUT_FILE Save full report to file

Exit Codes:
0 No critical issues (or no issues at all)
1 Critical issues found
1 Warnings found (only with --fail-on-warning)
2 Invalid arguments or environment error (e.g., missing ast-grep for JS/TS)
```

**Directory size guard**

UBS computes scan size **after ignore filters** (defaults + `.ubsignore`) and prints:
`Scan size after ignores: XMB (limit YMB)` before enforcing the limit. Override via
`UBS_MAX_DIR_SIZE_MB` or `UBS_SKIP_SIZE_CHECK=1`, or pass `--skip-size-check`.

### Environment errors (exit 2)

If UBS prints an **Environment error** and exits `2`, a required dependency is missing or unusable.

Most common fix for JS/TS projects:

```bash
ubs doctor --fix
```

Or install the dependency manually:

```bash
brew install ast-grep # or: cargo install ast-grep, npm i -g @ast-grep/cli
```

If you’re intentionally scanning non-JS languages only, exclude JS:

```bash
ubs --exclude=js .
```

### **Examples**

```bash
# Basic scan
ubs .

# Verbose scan with full details
ubs -v /path/to/project

# Strict mode for CI (fail on any warning)
ubs --fail-on-warning --ci

# Save report without cluttering terminal
ubs . report.txt

# Scan Vue.js project
ubs . --include-ext=js,ts,vue

# Skip categories you don't care about
ubs . --skip=14 # Skip TODO/FIXME markers

# Maximum performance (use all cores)
ubs --jobs=0 . # Auto-detect
ubs --jobs=16 . # Explicit core count

# Exclude vendor code
ubs . --exclude=node_modules,vendor,dist,build

# Large directories (size guard)
UBS_MAX_DIR_SIZE_MB=5000 ubs .
UBS_SKIP_SIZE_CHECK=1 ubs .

# Custom rules directory
ubs . --rules=~/.config/ubs/custom-rules

# Combine multiple options
ubs -v --fail-on-warning --exclude=legacy --include-ext=js,ts,tsx . report.txt
```

### JSONL schema

`--format=jsonl` (and `--beads-jsonl=FILE`) emit newline-delimited objects for easy piping into tools like Beads or `jq`:

```jsonl
{"type":"scanner","project":"/path/to/project","language":"python","files":42,"critical":1,"warning":3,"info":12,"timestamp":"2025-11-22T09:04:20Z"}
{"type":"totals","project":"/path/to/project","files":99,"critical":1,"warning":3,"info":27,"timestamp":"2025-11-22T09:04:22Z"}
```

### **Custom AST-Grep Rules**

You can add your own bug detection patterns:

```bash
# Create custom rules directory
mkdir -p ~/.config/ubs/rules

# Add a custom rule (YAML format)
cat > ~/.config/ubs/rules/no-console-in-prod.yml <<'EOF'
id: custom.no-console-in-prod
language: javascript
rule:
any:
- pattern: console.log($$$)
- pattern: console.debug($$$)
- pattern: console.info($$$)
severity: warning
message: "console statements should be removed before production"
note: "Use a proper logging library or remove debug statements"
EOF

# Run with custom rules
ubs . --rules=~/.config/ubs/rules
```

**Common custom rules:**

```yaml
# Enforce specific naming conventions
id: custom.component-naming
language: typescript
rule:
pattern: export function $NAME() { $$$ }
not:
pattern: export function $UPPER() { $$$ }
severity: info
message: "React components should start with uppercase letter"
```

```yaml
# Catch specific anti-patterns in your codebase
id: custom.no-direct-state-mutation
language: typescript
rule:
pattern: this.state.$FIELD = $VALUE
severity: critical
message: "Never mutate state directly - use setState()"
```

### **Excluding False Positives**

If the scanner reports false positives for your specific use case:

```bash
# Skip entire categories
ubs . --skip=11,14 # Skip debug code detection and TODO markers

# Exclude specific files/directories
ubs . --exclude=legacy,third-party,generated

# For persistent config, create a wrapper script
cat > ~/bin/ubs-custom <<'EOF'
#!/bin/bash
ubs "$@" \
--exclude=legacy,generated \
--skip=14 \
--rules=~/.config/ubs/rules
EOF
chmod +x ~/bin/ubs-custom
```

---

## πŸŽ“ **How It Works (Under the Hood)**

### **Multi-Layer Analysis Engine**

The scanner uses a sophisticated 4-layer approach:

```
Layer 1: PATTERN MATCHING (Fast) ──┐
β”œβ”€ Regex-based detection β”‚
β”œβ”€ Optimized with ripgrep β”‚
└─ Finds 70% of bugs in <1 second β”‚
β”œβ”€β”€β–Ί Combined Results
Layer 2: AST ANALYSIS (Deep) ───────
β”œβ”€ Semantic code understanding β”‚
β”œβ”€ Powered by ast-grep β”‚
└─ Catches complex patterns β”‚
β”‚
Layer 3: CONTEXT AWARENESS (Smart) ─
β”œβ”€ Understands surrounding code β”‚
β”œβ”€ Reduces false positives β”‚
└─ Knows when rules don't apply β”‚
β”‚
Layer 4: STATISTICAL (Insightful) β”‚
β”œβ”€ Code smell detection β”‚
β”œβ”€ Anomaly identification β”‚
└─ Architectural suggestions β”‚
↓
Final Report (3-5 sec)
```

### **Technology Stack**

| Component | Technology | Purpose | Why This Choice |
|-----------|-----------|---------|-----------------|
| **Core Engine** | Bash 4.0+ | Orchestration | Universal compatibility, zero dependencies |
| **Pattern Matching** | Ripgrep | Text search | 10-100x faster than grep, parallelized |
| **AST Parser** | ast-grep | Semantic analysis | Understands code structure, not just text |
| **Fallback** | GNU grep | Text search | Works on any Unix-like system |
| **Rule Engine** | YAML | Pattern definitions | Human-readable, easy to extend |

### **AST Rule Architecture: Ancestor-Aware Pattern Matching**

UBS's ast-grep rules use a sophisticated technique called **ancestor traversal** to drastically reduce false positives. The key directive `stopBy: end` ensures patterns check the *entire* ancestor chain rather than just the immediate parent.

**The Problem Without Ancestor Traversal:**

```javascript
// This code is SAFE - the fetch is properly handled:
async function safeFetch() {
try {
fetch('/api'); // Inside try block - exception will be caught
} catch (e) {
handleError(e);
}
}

// Naive AST rule checking only immediate parent:
// ❌ False positive! Reports "fetch without catch" because
// fetch()'s immediate parent is the ExpressionStatement,
// not the try block.
```

**The Solution - Ancestor Traversal with `stopBy: end`:**

```yaml
# ast-grep rule with proper ancestor checking
rule:
all:
- pattern: fetch($ARGS)
- not:
inside:
kind: try_statement
stopBy: end # ← Key directive: traverse ALL ancestors
- not:
inside:
pattern: $_.catch($$) # Check for .catch() in chain
stopBy: end
```

The `stopBy: end` directive instructs ast-grep to walk up the *entire* ancestor tree until it finds a match (or reaches the root). Without it, only the immediate parent is checkedβ€”missing try blocks, function boundaries, and method chains.

**Real-World Impact:**

| Scenario | Without `stopBy: end` | With `stopBy: end` |
|----------|----------------------|-------------------|
| `try { fetch() } catch {}` | ❌ False positive | βœ… Correctly ignored |
| `fetch().then().catch()` | ❌ False positive | βœ… Correctly ignored |
| `return fetch()` | ❌ False positive | βœ… Correctly ignored |
| `fetch()` standalone | βœ… Detected | βœ… Detected |

This technique is applied across 19+ rules in the JavaScript module alone, covering:
- Promise chain detection (`.then()`, `.catch()`, `.finally()`)
- Try-catch context awareness
- Return statement handling
- Async/await scope analysis

### **Inline Suppression Comments**

When a finding is intentional or a known false positive, suppress it inline:

```javascript
// Suppress a single line:
eval(trustedCode); // ubs:ignore

// Suppress with reason (recommended):
eval(adminScript); // ubs:ignore -- admin-only trusted input
```

```python
# Python suppression:
exec(validated_code) # ubs:ignore

# Ruby suppression:
eval(safe_string) # ubs:ignore
```

**Suppression Rules:**
- Must appear on the **same line** as the flagged code
- Works across all 10 supported languages
- Suppresses all findings on that line (use sparingly)
- Survives formatting tools that preserve trailing comments

**Anti-patterns to avoid:**
```javascript
// ❌ Wrong - comment on previous line doesn't suppress:
// ubs:ignore
eval(code); // Still flagged!

// ❌ Wrong - don't blanket-suppress large blocks:
/* ubs:ignore */ // Doesn't work for block comments
```

### **Cross-Language Async Error Detection**

UBS detects unhandled async errors consistently across all 10 languages. The patterns adapt to each language's idioms while providing equivalent coverage:

| Language | Pattern | What UBS Detects |
|----------|---------|------------------|
| **JavaScript/TypeScript** | `promise.then()` without `.catch()`, `new Promise(async ...)`, `forEach(async ...)`, async array predicates, async timer/event/JSX-handler callbacks, `Promise.all(map(...))` without callback return | Dangling promises, missing `await`, unawaitable async callbacks, unhandled rejections |
| **Python** | `asyncio.create_task()` without `await` | Orphaned tasks, missing `await`, unclosed coroutines |
| **Go** | Goroutine without error channel | Fire-and-forget goroutines, leaked contexts |
| **Rust** | `.unwrap()` / `.expect()` after partial guard | Panic after `if let Some`, missing `?` operator |
| **Java** | `CompletableFuture` without `.exceptionally()` | Swallowed exceptions, missing `join()` |
| **Ruby** | `Thread.new` without `.join` | Zombie threads, unhandled thread exceptions |
| **C++** | `std::async` without `.get()` | Ignored futures, exception propagation |
| **Swift** | `Task {}` without error handling | Unstructured concurrency leaks |
| **C#** | `Task.Wait()` / `.Result` / `throw ex;` | Sync-over-async deadlocks, stack-trace loss, unsafe exception surfaces |

**JavaScript Promise Chain Analysis:**

The scanner understands complex promise chains:

```javascript
// βœ… Handled - .catch() at end of chain:
fetch('/api')
.then(r => r.json())
.then(data => process(data))
.catch(handleError); // Scanner recognizes this catches all above

// βœ… Handled - .catch() before .then():
fetch('/api')
.catch(e => fallback) // Early catch
.then(r => r.json());

// ❌ Unhandled - .finally() doesn't catch:
fetch('/api')
.then(r => r.json())
.finally(cleanup); // Flagged: finally doesn't handle rejections

// ❌ Unhandled - no error handling:
async function leaky() {
fetch('/api'); // Flagged: fire-and-forget promise
}
```

### **Helper Script Verification**

Language-specific helper scripts (Python AST walkers, Go analyzers, TypeScript type checkers) are verified with SHA-256 checksums before execution:

```bash
# Helper checksums embedded in each module:
modules/helpers/
β”œβ”€β”€ async_task_handles_csharp.py # SHA-256 verified
β”œβ”€β”€ resource_lifecycle_csharp.py # SHA-256 verified
β”œβ”€β”€ resource_lifecycle_py.py # SHA-256 verified
β”œβ”€β”€ resource_lifecycle_go.go # SHA-256 verified
β”œβ”€β”€ resource_lifecycle_java.py # SHA-256 verified
β”œβ”€β”€ type_narrowing_csharp.py # SHA-256 verified
β”œβ”€β”€ type_narrowing_ts.js # SHA-256 verified
β”œβ”€β”€ type_narrowing_rust.py # SHA-256 verified
β”œβ”€β”€ type_narrowing_kotlin.py # SHA-256 verified
└── type_narrowing_swift.py # SHA-256 verified
```

The `ubs doctor` command validates all helper checksums:

```bash
$ ubs doctor
πŸ₯ UBS Environment Audit
────────────────────────
βœ“ helper checksum verified (resource_lifecycle_py.py)
βœ“ helper checksum verified (type_narrowing_ts.js)
...
```

If a helper is modified or corrupted, the scanner fails safely with remediation guidance rather than executing unverified code.

### **Unified Severity Normalization**

All 10 language modules normalize their findings to a consistent severity scale, ensuring predictable output regardless of source language:

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Language Tool Output β†’ UBS Normalized Severity β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ESLint "error" β†’ critical β”‚
β”‚ Pylint "E" / "F" β†’ critical β”‚
β”‚ Clippy "deny" β†’ critical β”‚
β”‚ Go vet "error" β†’ critical β”‚
β”‚ SpotBugs "High" β†’ critical β”‚
β”‚ RuboCop "Fatal/Error" β†’ critical β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ESLint "warn" β†’ warning β”‚
β”‚ Pylint "W" / "R" β†’ warning β”‚
β”‚ Clippy "warn" β†’ warning β”‚
β”‚ Go vet "warning" β†’ warning β”‚
β”‚ SpotBugs "Medium" β†’ warning β”‚
β”‚ RuboCop "Warning" β†’ warning β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ESLint "suggestion" β†’ info β”‚
β”‚ Pylint "C" / "I" β†’ info β”‚
β”‚ Clippy "note" β†’ info β”‚
β”‚ SpotBugs "Low" β†’ info β”‚
β”‚ RuboCop "Convention" β†’ info β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

**Benefits of normalization:**
- **Consistent exit codes**: Exit 1 always means "critical issues found" across all languages
- **Unified JSON/SARIF output**: Downstream tools parse one schema, not 8 different formats
- **Predictable `--fail-on-warning`**: Same behavior whether scanning Python, Rust, or TypeScript
- **Cross-language metrics**: Compare code quality across polyglot projects fairly

The `normalize_severity()` function in each module handles edge cases like tool-specific severity strings, numeric levels, and legacy format variations.

### **Performance Optimizations**

```bash
# Automatic parallelization (uses all CPU cores)
- Auto-detects: 16-core = 16 parallel jobs
- Manually set: --jobs=N

# Smart file filtering (only scans relevant files)
- JS/TS: .js, .jsx, .ts, .tsx, .mjs, .cjs (auto-skip node_modules/dist/build)
- Python: .py + pyproject/requirements (skip venv/__pycache__)
- C/C++: .c/.cc/.cpp/.cxx + headers + CMake files (skip build/out)
- Rust: .rs + Cargo manifests (skip target/.cargo)
- Go: .go + go.mod/go.sum/go.work (skip vendor/bin)
- Java: .java + pom.xml + Gradle scripts (skip target/build/out)
- Ruby: .rb + Gemfile/Gemspec/Rakefile (skip vendor/bundle,tmp)
- Custom: --include-ext=js,ts,vue

# Efficient streaming (low memory usage)
- No temp files created
- Results streamed as found
- Memory usage: <100MB for most projects

# Incremental scanning (future feature)
- Only scan changed files (git diff)
- Cache previous results
- 10x faster on large projects
```

---

## πŸ† **Comparison with Other Tools**

| Feature | Ultimate Bug Scanner | ESLint | TypeScript | SonarQube | DeepCode |
|---------|---------------------|--------|------------|-----------|----------|
| **Setup Time** | 30 seconds | 30 minutes | 1-2 hours | 2-4 hours | Account required |
| **Speed (50K lines)** | 3 seconds | 15 seconds | 8 seconds | 2 minutes | Cloud upload |
| **Zero Config** | βœ… Yes | ❌ No | ❌ No | ❌ No | ❌ No |
| **Works Without Types** | βœ… Yes | βœ… Yes | ❌ No | βœ… Yes | βœ… Yes |
| **Null Safety** | βœ… Yes | ⚠️ Limited | βœ… Yes | ⚠️ Limited | ⚠️ Limited |
| **Security Scanning** | βœ… Yes | ⚠️ Plugin | ❌ No | βœ… Yes | βœ… Yes |
| **Memory Leaks** | βœ… Yes | ❌ No | ❌ No | ⚠️ Limited | ❌ No |
| **Async/Await** | βœ… Deep | ⚠️ Basic | βœ… Good | ⚠️ Basic | ⚠️ Basic |
| **CI/CD Ready** | βœ… Yes | βœ… Yes | βœ… Yes | βœ… Yes | ⚠️ Cloud |
| **Offline** | βœ… Yes | βœ… Yes | βœ… Yes | ⚠️ Limited | ❌ No |
| **AI Agent Friendly** | βœ… Built for it | ⚠️ Config heavy | ⚠️ Config heavy | ❌ Complex | ⚠️ Cloud |
| **Cost** | Free | Free | Free | $$$$ | $$$ |

**When to use what:**

- **Ultimate Bug Scanner**: Quick scans, AI workflows, no config needed
- **ESLint**: Style enforcement, custom rules, team standards
- **TypeScript**: Type safety (use WITH this scanner)
- **SonarQube**: Enterprise compliance, detailed metrics
- **DeepCode**: ML-powered analysis (if you trust cloud)

**Best combo:** TypeScript + ESLint + Ultimate Bug Scanner = Maximum safety

---

## 🧠 **Project Justification and Rationale**

### **Why This Exists (And Why It's Not "Just Another Linter")**

You might be thinking: *"We already have ESLint, Pylint, Clippy, RuboCop... why build another tool?"*

**Fair question. And honestly, your first reaction is probably right to be skeptical.**

### **The Initial Skepticism is Valid (But Misses the Point)**

When you first look at UBS, it's natural to think:

> *"This is just worse ESLint. It has fewer rules, uses regex (false positives!), and doesn't auto-fix anything. Why would I use this instead of mature, comprehensive linters?"*

**That's analyzing through the wrong lens.**

You're comparing it to tools designed for a **fundamentally different workflow** (human developers writing code manually) when it's solving a **fundamentally different problem** (LLM agents generating code at 100x speed).

It's like comparing a smoke detector to a building inspector:
- **Building inspector (ESLint):** Thorough, comprehensive, finds every issue, takes hours
- **Smoke detector (UBS):** Fast, catches critical dangers, instant alert, always running

**You need both.** But when your house might be on fire (AI just generated 500 lines in 30 seconds), you want the smoke detector first.

### **The Paradigm Shift: AI-Native Development**

Software development is undergoing a **fundamental transformation**:

**2020 (Pre-LLM Era):**
- Developer writes 50-200 lines/day manually
- Deep thought before each line
- Single language per project (mostly)
- Time to review: abundant
- Quality gate: comprehensive linting + code review (hours)

**2025 (LLM Era):**
- AI generates 500-5000 lines/day across projects
- Code appears in seconds
- Polyglot projects standard (microservices in Go, UI in TypeScript, ML in Python, workers in Rust)
- Time to review: scarce
- Quality gate needed: instant feedback (<5s) or the loop breaks

**Traditional tools weren't designed for this.** They were built when "code generation" meant 200 lines/day, not 2000.

### **Here's the Fundamental Difference:**

### **1. This Tool is Built FOR AI Agents, Not Just Humans**

Traditional linters were designed for **human developers** in **single-language codebases**. UBS is designed for **LLM coding agents** working across **polyglot projects**.

**The paradigm shift:**

| Traditional Linting (Human-First) | UBS Approach (LLM-First) |
|---|---|
| **Goal:** Comprehensive coverage + auto-fix
**Speed:** 15-60 seconds acceptable
**Setup:** 30 min config per language
**Languages:** One tool per language
**False positives:** Must be <1% (frustrates humans)
**Output:** Human-readable prose | **Goal:** Critical bug detection + fast feedback
**Speed:** <5 seconds required
**Setup:** Zero config (instant start)
**Languages:** One scan for all 10 languages
**False positives:** 10-20% OK (LLMs filter instantly)
**Output:** Structured file:line for LLM parsing |

### **2. LLMs Don't Need Auto-Fixβ€”They ARE the Auto-Fix Engine**

**Why traditional linters have auto-fix:**
```javascript
// ESLint flags: "Use === instead of =="
if (value == null) // ❌

// ESLint auto-fix (rigid, no context):
if (value === null) // βœ… Technically correct, but...
```

**Why UBS doesn't (and shouldn't):**
```javascript
// UBS flags: "Type coercion bug: == should be ==="
if (value == null) // ❌

// Claude reads the error and understands context:
if (value !== null && value !== undefined) // βœ… Better - handles both
// OR
if (value != null) // βœ… Or keeps == for null/undefined (intentional)
```

**The hard part is DETECTION, not fixing.** Once flagged, LLMs can:
- Understand semantic context
- Consider surrounding code
- Apply the right fix (not just the mechanical one)
- Refactor holistically

Auto-fix would be **worse** because it's context-free. LLMs need to know **WHAT'S wrong** and **WHERE**, then they fix it properly.

### **3. The Multi-Language Zero-Config Design is the Moat**

**Imagine asking Claude to set up quality gates for a polyglot project:**

**Traditional approach (15-30 min per project):**
```bash
# JavaScript/TypeScript
npm install --save-dev eslint @eslint/js @typescript-eslint/parser
# Create .eslintrc.js (200 lines of config)

# Python
pip install pylint black mypy
# Create .pylintrc, pyproject.toml sections

# Rust
# Add to Cargo.toml: [lints]
# Configure clippy rules

# Go
# Install golangci-lint, create .golangci.yml

# Java
# Setup Checkstyle + PMD + SpotBugs + config XMLs

# C++
# Setup clang-tidy, create .clang-tidy config

# Ruby
# Create .rubocop.yml with 150+ lines

# Now run 7 different commands and parse 7 different output formats...
```

**UBS approach (30 seconds):**
```bash
curl -fsSL https://raw.githubusercontent.com/.../install.sh | bash
ubs .

# Done. All 10 languages scanned, unified report.
```

**This matters because:**
- LLMs generate code across languages in one session (Python API β†’ Go service β†’ TypeScript UI β†’ Rust worker)
- Configuring 7 tools is error-prone for LLMs
- Humans don't want to maintain 7 different config files
- CI/CD pipelines want one command, one exit code

### **Type Narrowing Coverage Across Languages**

- **TypeScript** – UBS shells out to `tsserver` (via the bundled helper) whenever Node.js + the `typescript` package are available. The installer surfaces a "Type narrowing readiness" diagnostic so you immediately know if tsserver-powered guards are running. Category 7 also flags bearer tokens, webhook signatures, CSRF values, API keys, HMAC digests, and password-reset secrets compared with `==`, `===`, `!=`, or `!==` instead of timing-safe equality, catches request-derived object merges and dynamic key writes that can allow prototype pollution unless prototype keys are rejected, catches request-derived SQL string construction flowing into raw `db.query`/`sequelize.query`/Prisma `$queryRawUnsafe` execution instead of parameterized calls, catches server-side proxy and rewrite targets from `createProxyMiddleware`, `http-proxy`, `proxy.web`/`proxy.ws`, and `NextResponse.rewrite` when they are request-derived without proxy target validation, and catches JWT decode-only flows, explicit verification bypass options, `none` algorithms, and verifier calls that lack issuer/audience claim binding.
- **Rust** – A Python helper inspects `if let Some/Ok` guard clauses and flags subsequent `.unwrap()`/`.expect()` calls outside of exiting blocks. The Rust security pass also catches bearer tokens, webhook signatures, HMAC/MAC digests, CSRF values, API keys, and password-reset secrets compared with `==` or `!=` instead of `subtle::ConstantTimeEq`, `ring::constant_time::verify_slices_are_equal`, `crypto_memcmp`, or a reviewed constant-time helper; JWT decode/validation bypasses such as `dangerous::insecure_decode`, `dangerous_unsafe_decode`, `insecure_disable_signature_validation()`, `validate_exp = false`, `validate_aud = false`, and `decode` calls whose validation does not bind and require both issuer and audience; archive member paths flowing into extraction destinations without `enclosed_name()`/`unpack_in()`-style containment; predictable temp-file writes that use shared temp paths without `tempfile` or `create_new(true)`; request-derived redirect targets flowing into redirects or `Location` headers without local-path or redirect host allow-list validation; request-derived values interpolated into SQL strings that reach raw sqlx/diesel/rusqlite/postgres execution sinks instead of parameterized placeholders; credentialed wildcard or reflected-origin CORS policies without an explicit trusted-origin allow-list; and request/header values flowing into non-`Location` response headers without CR/LF rejection, `HeaderValue::from_str`, encoding, or a header-safe helper. Fixtures and manifest cases keep these regressions tested.
- **Go** – Category 9 now flags bearer tokens, webhook signatures, HMAC/MAC digests, CSRF values, API keys, and password-reset secrets compared with `==` or `!=` instead of `hmac.Equal`, `subtle.ConstantTimeCompare`, or a reviewed constant-time helper. It also catches JWT verification bypasses such as `ParseUnverified`, `SigningMethodNone`, `WithoutClaimsValidation`, `jwt.Parse` / `ParseWithClaims` callbacks that trust claims without signing-method validation, verified JWTs that omit issuer/audience claim binding, request-derived reverse proxy targets flowing into `httputil.NewSingleHostReverseProxy`, `ProxyRequest.SetURL`, or `Director` URL mutation without HTTPS plus host allow-list validation, and request/form/header values interpolated into SQL execution or query-builder strings instead of passed as parameters.
- **Kotlin** – The Java-family module scans `.kt`/`.kts` sources for `if (value == null)` guards that merely log and keep running before hitting `value!!`, and its security pass now catches request/Ktor params, request paths, and upload filenames flowing into file read/write/serve/delete sinks, request-derived values flowing into response headers without CR/LF safety, request-derived query/header URLs flowing into Ktor-style HTTP client calls, zip extraction that writes `entry.name` / `entry.path` into destination paths without containment checks, and security-sensitive tokens, CSRF nonces, API keys, OTPs, reset codes, and invite codes built from `kotlin.random.Random`, `java.util.Random`, `ThreadLocalRandom`, `UUID.randomUUID`, or predictable time material instead of `SecureRandom`.
- **Swift** – The dedicated `ubs-swift` module now ships the guard-`let` helper directly, so optional chaining/Objective‑C bridging heuristics fire even when you run `ubs --only=swift` locally (no piggybacking on the Java module). It catches cases where code logs and keeps going before force-unwrapping `value!`, protecting iOS/macOS pipelines that blend Swift + ObjC. The Swift security pass also tracks request query, route, URL path, and upload filename values into file read/write/serve/delete sinks unless they are reduced to a basename or pass a standardized root-containment check, flags request-derived redirect targets that reach redirects or `Location` headers without local-url or host allow-list validation, flags request/header/cookie/content values reaching non-`Location` response headers without CR/LF stripping/rejection, encoding, or a header-safe helper, flags request-derived outbound URLs that reach URLSession, URLRequest handoffs, blocking URL reads, or HTTP clients without https scheme and host allow-list validation, and now flags security-sensitive tokens, CSRF nonces, API keys, OTPs, salts, and reset/invite codes built from non-cryptographic Swift randomness or predictable time/process material instead of `SecRandomCopyBytes` or CryptoKit-backed helpers.

### **Resource Lifecycle AST Coverage**

- **Python** – `modules/helpers/resource_lifecycle_py.py` now reasons over the AST, tracking `with`/`async with`, alias imports, and `.open()`/`.connect()` calls so `ubs-python` warns only when a handle is truly leaking. Pathlib `Path.open()` and similar patterns are handled without brittle regexes.
- **Java** – New ast-grep rules (`java.resource.executor-no-shutdown`, `java.resource.thread-no-join`, `java.resource.jdbc-no-close`, `java.resource.resultset-no-close`, `java.resource.statement-no-close`) ensure ExecutorServices, raw `Thread`s, `java.sql.Connection`s, `Statement`/`PreparedStatement`/`CallableStatement`, and `ResultSet` handles all get proper shutdown/close semantics before the regex fallback ever runs.
- **C#** – `modules/helpers/resource_lifecycle_csharp.py`, `modules/helpers/type_narrowing_csharp.py`, and `modules/helpers/async_task_handles_csharp.py` now catch disposable-handle leaks (`CancellationTokenSource`, stream-like readers/writers, `HttpRequestMessage`), null/`TryGetValue` guards that log but still fall through into dereferences, and `Task.Run`/`Task.Factory.StartNew` handles that are created but never observed. The C# security pass also tracks ASP.NET request/query/header/path values and upload filenames into file read/write/serve/delete sinks unless they go through `Path.GetFileName` or `Path.GetFullPath` containment checks, flags request/header/cookie/route values that reach `Redirect`, `Response.Redirect`, `RedirectResult`, or `Location` headers without local-url or host allow-list validation, flags request/query/header/form and annotated action values reaching response headers without CR/LF stripping, rejection, or encoding, and flags request/header-derived outbound URLs reaching `HttpClient`, `HttpRequestMessage`, `WebRequest`, `WebClient`, or REST-style clients without URI parsing plus scheme and host allow-list validation.
- **C++ / Rust / Ruby / Elixir** – These modules already relied on ast-grep rule packs or language-tailored context passes; the β€œUniversal AST Adoption” epic is now complete with every language module (JS, Python, Go, C++, Rust, Java, Ruby, Swift, C#, Elixir) running semantic detectors instead of fragile grep-only heuristics. C++ now tracks CGI/query/header URL values into redirect functions and `Location` headers unless they pass through same-origin local-path checks or explicit redirect host allow-lists, into non-`Location` response headers unless they reject/strip CR/LF, encode header fragments, or pass through a header-safe helper, into libcurl/common HTTP client URL sinks unless they pass through a safe outbound URL helper, and flags security-sensitive tokens, CSRF nonces, API keys, OTPs, salts, reset codes, and invite codes built from `rand`, `random`, implementation-defined `random_device`, Mersenne Twister-style engines, timestamps, hashes, or process IDs instead of OS/crypto-backed random bytes. Rust tracks query/header/env/CLI URL values into `reqwest`, `ureq`, `surf`, `isahc`, and request-builder sinks unless they pass through a safe outbound URL helper or equivalent URL parsing plus host allow-list validation, tracks query/header/host redirect targets into redirect responses or `Location` headers unless they pass through same-origin local-path checks or redirect host allow-lists, tracks request/header values into non-`Location` response headers unless they reject/strip CR/LF, use `HeaderValue` validation, encode header fragments, or pass through a header-safe helper, and tracks request-derived values interpolated into raw SQL strings that reach sqlx, diesel, rusqlite, postgres, or generic query execution sinks without parameter binding. Ruby's security pass now tracks Rack/Rails params and upload filenames into file read/write/serve/delete sinks unless the path is reduced to `File.basename` or guarded by `File.expand_path` containment checks, flags request-derived redirect targets reaching `redirect_to`, Sinatra/Rack `redirect`, or `Location` headers without local-url or host allow-list validation, flags request/header/cookie/env values reaching non-`Location` response headers without CR/LF stripping, rejection, encoding, or a header-safe helper, and flags request-derived outbound URLs reaching common Ruby HTTP clients without URI parsing plus scheme and host allow-list validation. Elixir's security pass tracks Plug/Phoenix params, request paths, and upload filenames into `File.*`, `send_file`, and `send_download` sinks unless the path is reduced to `Path.basename` or guarded by `Path.expand` containment checks, flags request-derived redirect targets reaching Phoenix/Plug redirects or `Location` headers without local-url or host allow-list validation, flags request/header/cookie values reaching non-`Location` response headers without CR/LF stripping, rejection, encoding, or a header-safe helper, flags request-derived outbound URLs reaching Req, HTTPoison, Finch, Tesla, hackney, Mint, or `:httpc` without URI parsing plus scheme and host allow-list validation, and flags Phoenix/Guardian/Joken hardcoded config secrets such as `secret_key_base`, signing salts, JWT/API secrets, and literal `System.get_env/2` fallbacks.

#### Python – AST helper in action

```python
import asyncio, subprocess

fh = open("/tmp/leaky.txt", "w")
proc = subprocess.Popen(["sleep", "1"])

async def leak_task():
task = asyncio.create_task(asyncio.sleep(1))
await asyncio.sleep(0.1)
return task

asyncio.run(leak_task())
```

```
$ ./ubs --only=python test-suite/python/buggy/resource_lifecycle.py
πŸ”₯ File handles opened without context manager/close [resource_lifecycle.py:4]
File handle fh opened without context manager or close()
⚠ Popen handles not waited or terminated [resource_lifecycle.py:7]
```

The helper catches the unguarded file handle, zombie subprocess, and orphaned asyncio task because it walks the AST (tracking aliases and async contexts) instead of grepping for strings.

#### Go – AST helper validating cleanups

```go
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
ticker := time.NewTicker(time.Millisecond * 500)
timer := time.NewTimer(time.Second)
f, _ := os.Open("/tmp/data.txt")

_ = ctx
_ = cancel
_ = ticker
_ = timer
_ = f
```

```
$ ./ubs --only=golang test-suite/golang/buggy/resource_lifecycle.go
πŸ”₯ context.With* without deferred cancel [resource_lifecycle.go:10]
⚠ time.NewTicker not stopped [resource_lifecycle.go:13]
⚠ time.NewTimer not stopped [resource_lifecycle.go:15]
⚠ os.Open/OpenFile without defer Close() [resource_lifecycle.go:17]
```

Because the helper hashes AST positions, the manifest can assert on deterministic substrings (context/ticker/timer/file) and we avoid flakiness from color codes or log headings.

Use `--skip-type-narrowing` (or `UBS_SKIP_TYPE_NARROWING=1`) when you want to bypass all of these guard analyzersβ€”for example on air-gapped CI environments or when validating legacy projects one language at a time.

### **4. Speed Enables Tight Iteration Loops**

The **generate β†’ scan β†’ fix** cycle needs to be **fast** for AI workflows:

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Traditional Linter (30-45 seconds) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Claude generates code: 10s β”‚
β”‚ Run ESLint + Pylint + ... 30s ⏳ β”‚
β”‚ Claude reads findings: 5s β”‚
β”‚ Claude fixes bugs: 15s β”‚
β”‚ Re-run linters: 30s ⏳ β”‚
β”‚ ────────────────────────────────── β”‚
β”‚ Total iteration: 90s β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ UBS (3-5 seconds) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Claude generates code: 10s β”‚
β”‚ Run UBS: 3s ⚑ β”‚
β”‚ Claude reads findings: 2s β”‚
β”‚ Claude fixes bugs: 10s β”‚
β”‚ Re-run UBS: 3s ⚑ β”‚
β”‚ ────────────────────────────────── β”‚
β”‚ Total iteration: 28s β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3x faster feedback loop = 3x more iterations in the same time
```

**When you're shipping 10+ features a day with AI assistance, this compounds.**

### **5. Detecting LLM-Specific Bug Patterns**

UBS targets the bugs **AI agents actually generate**, not every possible code smell.

**Bugs LLMs frequently produce:**

| Pattern | Why LLMs Generate It | Traditional Linters |
|---------|---------------------|---------------------|
| Missing `await` | Forgets `async` keyword, syntax looks fine | ❌ TypeScript only |
| Unguarded null access | "Optimistic" coding - assumes happy path | ⚠️ Requires strict config |
| `eval()` / code injection | Reaches for "easy" dynamic solution | βœ… Most flag this |
| Memory leaks (event listeners) | Doesn't think about cleanup lifecycle | ❌ ESLint plugin needed |
| `innerHTML` XSS | Doesn't threat-model user input | ⚠️ Security plugins only |
| Division by zero | Doesn't consider edge cases | ❌ Most miss this |
| Hardcoded secrets | Uses placeholder, forgets to externalize | ⚠️ Requires secrets scanner |
| Goroutine leaks | Forgets context cancellation | ❌ Go-specific tooling |
| `.unwrap()` panics | Assumes success path | βœ… Clippy catches |
| Buffer overflows | Forgets bounds checking | ⚠️ Sanitizers only |

**UBS is optimized for this specific threat model.**

### **6. Novel Analysis: Deep Property Guard Correlation**

This is genuinely **not available in standard linters**:

```python
# Code LLM generates:
def get_theme(user):
return user.profile.settings.theme # ❌ Unguarded chain

# ESLint/Pylint: βœ… No error (syntactically correct)
# TypeScript: βœ… No error (if types claim non-null)

# UBS Deep Guard Analysis:
# 1. Scans for: user.profile.settings.theme (found at line 42)
# 2. Scans for: if user and user.profile and user.profile.settings
# 3. Correlates: NO MATCHING GUARD FOUND
# 4. Reports: ⚠️ Unguarded deep property access
```

**This requires:**
- AST extraction of property chains across the file
- AST extraction of conditional guards
- Cross-reference matching with context awareness
- Contextual suggestions

**Nobody else does this by default** because it's not a lint ruleβ€”it's a **correlation analysis** across multiple code patterns.

### **7. Complementary, Not Competitive**

**UBS is designed to work WITH existing tools, not replace them:**

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Your Quality Stack (Recommended) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ TypeScript β†’ Type safety β”‚
β”‚ ESLint/Clippy/etc β†’ Comprehensive linting β”‚
β”‚ Jest/PyTest β†’ Unit tests β”‚
β”‚ ✨ UBS β†’ AI-generated bug oracle β”‚
β”‚ GitHub Actions β†’ CI/CD integration β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

**Use UBS for:**
- βœ… Fast multi-language scanning in AI workflows
- βœ… Critical bug detection before commits
- βœ… Git hooks that block obviously broken code
- βœ… Claude/Cursor/AI agent quality guardrails
- βœ… Polyglot projects where configuring 7 linters is painful

**Use ESLint/Pylint/Clippy/etc for:**
- βœ… Comprehensive style enforcement
- βœ… Framework-specific rules (React hooks, etc.)
- βœ… Custom team conventions
- βœ… Auto-formatting
- βœ… Deep single-language analysis

**They solve different problems.** UBS is the "smoke detector" (fast, catches critical issues). Traditional linters are the "building inspector" (thorough, catches everything).

### **8. The Technical Moat**

What makes this hard to replicate:

**Multi-layer analysis:**
```
Layer 1: Ripgrep (regex) β†’ 70% of bugs in 0.5s
Layer 2: ast-grep (AST) β†’ Complex semantic patterns
Layer 3: Correlation logic β†’ Cross-pattern analysis (novel)
Layer 4: Metrics collection β†’ Time-series quality tracking
```

**This combination of speed + semantic understanding + correlation is unique.**

**Unified multi-language runner:**
- Auto-detects 10 languages in one scan
- Parallel execution (Go + Python + Rust simultaneously)
- Unified JSON/SARIF output for tooling
- Module system with lazy download/caching

**LLM-optimized integration points:**
- Git hooks (block bad commits)
- Claude Code file-write hooks
- `.cursorrules` / `.aiconfig` integration
- Clean structured output for LLM parsing

### **9. 30 Rules is Better Than 600 (For This Use Case)**

**You might notice:** ESLint has 200+ core rules, Clippy has 600+ lints, but UBS has ~30 patterns per language.

**That's intentional, not a limitation.**

**The 80/20 rule for AI-generated bugs:**
- **80% of production-breaking bugs** come from ~30 common patterns
- **20% of edge cases** require the other 570 rules

**For LLM workflows, you want:**
```
βœ… Fast scan (3s) that catches 80% of critical bugs
↓
LLM fixes them immediately
↓
βœ… Fast re-scan (3s) confirms fixes
↓
Then run comprehensive linters (30s) for the remaining 20%
```

**Not:**
```
❌ Comprehensive scan (30s) that catches 100% of issues
↓
LLM waits... workflow broken... context switch...
↓
Slower iteration = fewer features shipped
```

**The bugs UBS targets are:**
- Missing `await` (crashes)
- Null pointer access (crashes)
- Security holes: `eval()`, XSS, hardcoded secrets (breaches)
- Memory leaks (performance degradation)
- Race conditions (data corruption)

**The bugs comprehensive linters add:**
- Inconsistent quote style (style)
- Missing trailing commas (style)
- Prefer `const` over `let` when not reassigned (style)
- Function name should be camelCase (style)
- Line too long (style)

**Which matters more when AI just generated 500 lines that might have `eval()` and missing `await` everywhere?**

Target the **critical bugs** that cost hours. Let comprehensive linters handle style in a separate pass.

### **10. Market Timing: This Wouldn't Have Made Sense 3 Years Ago**

**Why this tool exists NOW:**

**2021:**
- GitHub Copilot launches (single-line completions)
- Still mostly human-written code
- Traditional linting workflow works fine

**2023:**
- ChatGPT/GPT-4 can generate full functions
- Claude Code, Cursor emerge
- Devs start AI-assisted workflows
- Pain point appears: "AI is fast but buggy"

**2025:**
- LLMs generate entire features in minutes
- Multi-file refactors happen in seconds
- Polyglot microservices are standard
- **Quality gates can't keep up with generation speed**

**The problem UBS solves didn't exist before LLM coding became mainstream.**

This tool is **perfectly timed** for the AI coding explosion happening RIGHT NOW.

### **11. False Positive Philosophy**

**For human developers:**
- False positive = context switch + investigation + frustration
- Acceptable rate: <1%

**For LLM agents:**
- False positive = parse (0.1s) + analyze (0.5s) + determine safe (0.2s)
- Acceptable rate: 10-20%

**LLMs don't get frustrated.** They evaluate every finding programmatically.

**This means UBS can be more aggressive:**
- Flag suspicious patterns even if not 100% certain
- Catch more bugs at the cost of some noise
- LLMs filter false positives cognitively (for free)

Better to flag 100 issues where 20 are safe than miss 1 critical bug.

---

## **FAQ: Common Questions and Objections**

### **Q: "Isn't this just reinventing the wheel? ESLint already exists."**

**A:** It's not reinventing the wheelβ€”it's building a different vehicle for a different road.

ESLint is a **truck** (heavy, comprehensive, hauls everything).
UBS is a **sports car** (fast, targeted, gets you there quickly).

You wouldn't use a truck for a Formula 1 race. You wouldn't use a sports car to move furniture.

**Different tools, different use cases.** Use UBS for rapid AI iteration, ESLint for comprehensive quality enforcement.

---

### **Q: "Why not just contribute these patterns to existing linters?"**

**A:** Three reasons:

**1. Different design philosophy**
- Existing linters: comprehensive, human-first, single-language
- UBS: fast, LLM-first, multi-language, correlation-based

These are fundamentally incompatible goals. ESLint would never accept "10-20% false positives are fine" or "skip auto-fix entirely."

**2. Multi-language meta-runner**
- The unified runner that auto-detects 10 languages is the core innovation
- This doesn't fit into any single linter's architecture
- Each linter project has different maintainers, philosophies, release cycles

**3. Correlation analysis is novel**
- Deep property guard matching isn't a "lint rule"
- It's cross-pattern analysis that requires a different architecture
- Existing linters don't have this capability baked into their core

Contributing patterns misses the pointβ€”**the integration IS the innovation.**

---

### **Q: "What about Semgrep? Doesn't it do multi-language pattern matching?"**

**A:** Semgrep is excellent and closer to UBS than traditional linters. Key differences:

| Feature | Semgrep | UBS |
|---------|---------|-----|
| **Setup** | Requires config file + rule selection | Zero config |
| **Speed** | ~10-20s on medium projects | ~3s (optimized for speed) |
| **Target user** | Security teams, human developers | LLM agents |
| **Rule focus** | Security + custom patterns | AI-generated bug patterns |
| **Multi-language** | βœ… Yes | βœ… Yes |
| **Correlation analysis** | ❌ Pattern matching only | βœ… Deep guards, metrics |
| **LLM integration** | Not designed for it | Purpose-built |

**Use Semgrep if:** You need custom security rules and have time to configure them.
**Use UBS if:** You want instant AI workflow integration with zero setup.

**They're complementary.** Some users run both.

---

### **Q: "Won't regex-based detection have tons of false positives?"**

**A:** Less than you'd think, and it's acceptable for LLM consumers.

**Reality check:**
- **Layer 1 (ripgrep/regex):** ~15-20% false positive rate on some patterns
- **Layer 2 (ast-grep/AST):** ~2-5% false positive rate (semantic understanding)
- **Layer 3 (correlation):** ~1-3% false positive rate (contextual analysis)

**Blended approach:** ~8-12% overall false positive rate.

**Why this is OK:**
- LLMs don't get frustrated like humans do
- They evaluate findings in 0.8 seconds total
- Better to flag 100 (20 safe) than miss 1 critical bug
- Humans reviewing AI code ALREADY have to check everything anyway

**For critical patterns** (eval, XSS, hardcoded secrets), we use ast-grep (high precision).
**For style patterns**, we use regex (fast, some FP acceptable).

**And we're always improving.** Each release reduces FP rate through better heuristics.

---

### **Q: "Why Bash? Why not Python/Rust/Go?"**

**A:** Controversial choice, but intentional:

**Advantages of Bash:**
- βœ… **Zero dependencies** - runs on any Unix-like system
- βœ… **Universal availability** - every dev machine has Bash 4.0+
- βœ… **Shell integration** - git hooks, CI/CD, file watchers are natural
- βœ… **Module system** - each language scanner is standalone
- βœ… **Rapid prototyping** - adding new patterns is trivial
- βœ… **LLM-readable** - AI agents can understand and modify rules

**Disadvantages:**
- ❌ Not as "elegant" as Python
- ❌ String handling can be verbose
- ❌ No static typing

**Bottom line:** For a tool that orchestrates existing CLI tools (ripgrep, ast-grep, jq, typos) and needs to be universally available, Bash is pragmatic.

**Future:** Core modules might be rewritten in Rust for speed, but the meta-runner will stay Bash for compatibility.

---

### **Q: "Can I use this if I'm NOT using AI coding tools?"**

**A:** Absolutely! It's optimized for AI workflows, but works great for humans too.

**Scenarios where humans love it:**

**1. Code review speed-up**
```bash
# Reviewing a PR with 800+ lines
git checkout feature-branch
ubs .
# Instantly see critical issues before deep review
```

**2. Legacy code audits**
```bash
# "What's dangerous in this 10-year-old codebase?"
ubs /path/to/legacy-app
# Finds all the eval(), XSS, memory leaks
```

**3. Learning new languages**
```bash
# "I'm new to Rust, what am I doing wrong?"
ubs . --verbose
# Shows common Rust pitfalls in your code
```

**4. Polyglot projects**
```bash
# Microservices in 5 languages
ubs .
# One scan, all languages checked
```

**Humans appreciate:**
- Zero setup (no config files to maintain)
- Fast feedback (3s vs 30s)
- Multi-language support (one command)
- Finding bugs ESLint misses (deep guards)

---

### **Q: "How is this different from security scanners like Snyk or GitHub Advanced Security?"**

**A:** Different focus and scope:

**Security scanners (Snyk, Dependabot, etc.):**
- Focus: **Dependency vulnerabilities**
- Checks: npm packages, CVE databases
- Speed: Seconds to minutes
- Output: "Update package X to fix CVE-2024-1234"

**UBS:**
- Focus: **Code-level bugs** in YOUR code
- Checks: Logic errors, null safety, memory leaks, security anti-patterns
- Speed: 3-5 seconds
- Output: "You have unguarded null access at line 42"

**They're complementary:**
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Complete Security Stack β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Snyk/Dependabot β†’ Dependencies β”‚
β”‚ ✨ UBS β†’ Your code bugs β”‚
β”‚ SAST tools β†’ Deep security β”‚
β”‚ GitHub Advanced β†’ Secrets in Git β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

**Security scanners won't catch:** "You forgot `await` and your async function silently fails."
**UBS won't catch:** "Your version of lodash has a known CVE."

Use both.

---

### **Q: "Will you support language X in the future?"**

**A:** Probably! The module system makes it easy to add languages.

**Current:** JavaScript/TypeScript, Python, Go, Rust, Java, C++, Ruby, Swift, C#, Elixir (10 languages)

**Roadmap considerations:**
- **PHP** - High demand, lots of legacy code
- **Kotlin** - Android development
- **Scala** - JVM ecosystem
- **Shell** - DevOps and installer scripts

**How we prioritize:**
1. Community demand (GitHub issues)
2. AI coding tool usage (what LLMs generate most)
3. Module maintainer availability

**Want to contribute?** Writing a new module is ~800-1200 lines of Bash. Check the existing modules as templates.

---

### **Q: "What's the catch? Why is this free?"**

**A:** No catch. It's MIT licensed.

**Philosophy:**
- Built by developers, for developers
- AI coding is exploding, quality tools should be accessible
- Open source enables community contributions (more patterns, better detection)

**Business model:** None currently. This is a **community project**.

**Future possibilities:**
- Enterprise support contracts
- Hosted version for teams
- Premium modules for specific frameworks

But the core tool will always be free and open source.

---

## **The Bottom Line**

**This isn't trying to replace ESLint.** It's solving a different problem:

> **"How do I give LLM coding agents the ability to self-audit across 10 languages with zero configuration overhead and sub-5-second feedback?"**

No existing tool does this because:
- Traditional linters are human-first (need auto-fix, low FP tolerance)
- They're single-language focused (polyglot = 7 different tools)
- They're comprehensive, not fast (30s scan time kills AI iteration loops)
- They're not designed for LLM consumption

**UBS is purpose-built for the AI coding era.**

Use it WITH your existing tools. Let ESLint handle style. Let TypeScript handle types. Let UBS catch the critical bugs that AI agents generate but can't see.

---

## πŸ§ͺ **Development & Internals**

### **Python Tooling (uv + CPython 3.13)**

All helper scripts (manifest runner, fixtures, inline analyzers inside `ubs`) assume a single source of truth: **CPython 3.13 managed by [uv](https://github.com/astral-sh/uv)** living inside `.venv/` at the repo root.

```bash
# 1) Install uv (one-time)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 2) Create the managed environment defined by pyproject.toml / uv.lock
uv sync --python 3.13

# 3) Activate it whenever you work in this repo (puts .venv/bin first on PATH)
source .venv/bin/activate

# 4) Run any Python entrypoint through the env
uv run python test-suite/run_manifest.py --case js-core-buggy
# ...or rely on 'python'/'python3' now that they point at .venv/bin/python3.13
```

> [!NOTE]
> Shell scripts that invoke `python3` (language modules under `modules/`, `test-suite/run_all.sh`, etc.) automatically pick up `.venv/bin/python3` as long as the environment is activated or `.venv/bin` is on your `PATH`. The pinned `pyproject.toml` + `uv.lock` are the single source of truth for this toolchain.

Common uv-powered entrypoints:

- `uv run python test-suite/run_manifest.py --case js-core-buggy` – run the manifest in CI or locally without manually activating the venv.
- `source .venv/bin/activate && python -m pip list` – verify that every inline `python3` invocation maps to CPython 3.13.
- `uv run python - <<'PY' …` – mirrors how the language modules embed Python helpers, but now guaranteed to execute inside the managed interpreter.

---

## 🚫 **Ignoring Paths with `.ubsignore`**

Need repo-wide scans to ignore generated code or intentionally buggy fixtures (like this project’s `test-suite/`)? Drop a `.ubsignore` at the root.

- Format mirrors `.gitignore`: one glob per line, `#` for comments.
- UBS loads `PROJECT/.ubsignore` automatically; override with `--ignore-file=/path/to/file`.
- Built-in ignores already cover `node_modules`, virtualenvs, dist/build/target/vendor, editor caches, and more, so you rarely need to add them yourself.
- Use `--suggest-ignore` to print large top-level directories that might deserve an entry (no files are modified automatically).
- Inline suppression works for intentional one-offs: `eval("print('safe')") # ubs:ignore`.
- Every language module receives the ignore list via their `--exclude` flag, so skips stay consistent.
- This repository ships with a default `.ubsignore` that excludes `test-suite/`, keeping β€œreal” source scans noise-free.

Example:

```text
# Ignore fixtures + build output
test-suite/
dist/
coverage/
```

---

## 🧭 **Language Coverage Comparison**

UBS ships ten language-focused analyzers. The comparison below focuses on the longest-standing mo