brooks-lint
AI code reviews grounded in 12 classic engineering books — decay risk diagnostics with book citations, severity labels, and 6 analysis modes including full-sweep auto-fix
Logic-first AI code review via semi-formal execution tracing (Premises → Trace → Divergence → Trigger → Remedy). Catches behavioral bugs, type-contract breaches & async hazards that linters miss. Six skills · Claude Code · Codex CLI · Gemini CLI.
> /plugin marketplace add hyhmrright/logic-lens> /plugin install logic-lens@logic-lens-marketplace
Repo: hyhmrright/logic-lens
What's inside
"Models using structured (semi-formal) reasoning achieve 87–93% accuracy on code semantics tasks, versus 76–78% for unstructured chain-of-thought — with the largest gains on interprocedural bugs." — Ugare & Chandra, Agentic Code Reasoning (2026, arXiv:2603.01896)
Code review without a trace is a guess. Standard review catches style issues and obvious mistakes. Linters catch syntax. But neither catches the class of bugs where code looks correct in isolation, passes all tests, and still ships broken behavior — because the bug only appears when two functions interact in a way neither author anticipated.
Logic-Lens forces the AI to construct an explicit execution trace before reaching any conclusion. Every finding comes with a documented Premises → Trace → Divergence → Trigger → Remedy chain that shows exactly how the reviewer arrived at the finding — not just what it found.
Logic-Lens evaluates code across nine logic risk dimensions — six derived from the semi-formal reasoning methodology in Agentic Code Reasoning (L1–L6), plus three covering modern hazards that fall outside the paper's single-process scope (L7–L9):
| Code | Risk | What It Catches |
|---|---|---|
| 🔀 L1 | Shadow Override | A name resolves to a different definition than assumed — shadowing, import aliasing, inheritance override |
| 📐 L2 | Type Contract Breach | A function receives a type it can't correctly handle, through implicit coercion or conditional paths |
| 🔲 L3 | Boundary Blindspot | Edge cases not traced: null, empty, zero, max/min bounds, single-element sequences |
| ⚠️ L4 | State Mutation Hazard | Sequential aliasing or mutation-during-iteration hazards on a single execution path |
| 🚪 L5 | Control Flow Escape | An early exit skips required non-lifecycle work — state update, validation, audit event, notification |
| 🔗 L6 | Callee Contract Mismatch | Calling code assumes return value semantics, exception behavior, or idempotency the callee doesn't guarantee |
| 🧵 L7 | Concurrency / Async Hazard | Race across an await / lock / channel boundary; double-acquire; send-after-cancel; missing happens-before |
| 🔁 L8 | Resource Lifecycle Hazard | Acquire/release imbalance — missing release path, double release, ownership transferred without updating release plan |
| 🕒 L9 | Time / Locale Hazard | Naive vs aware datetime, DST jumps, locale-sensitive sort/case, encoding round-trip, decimal-separator drift |
Given this code:
def process_order(order_id, items, discount_code=None):
order = db.get_order(order_id)
total = sum(item['price'] * item['qty'] for item in items)
if discount_code:
discount = coupon_service.get_discount(discount_code)
total = total * (1 - discount)
order['total'] = total
order['items'] = items
db.save_order(order)
email_service.send_confirmation(order['email'], total)
Logic-Lens produces:
Logic Health: 31/100
This function contains a callee contract mismatch that causes a silent divide-by-zero risk, a boundary blindspot on empty item lists, and a resource lifecycle hazard that leaks a database connection on email failure.
get_discount May Return NonePremises: coupon_service.get_discount(code) is assumed to always return a numeric discount rate between 0 and 1.
Trace: discount_code is truthy → get_discount(discount_code) is called → result assigned to discount → total * (1 - discount) is evaluated.
Divergence: get_discount returns None for expired or invalid codes (documented in its docstring). When discount is None, 1 - None raises TypeError. The call reaches db.save_order only on the happy path; a bad coupon code aborts the function without saving.
Trigger: process_order(1, [{'price': 10, 'qty': 1}], discount_code='EXPIRED2024') → TypeError: unsupported operand type(s) for -: 'int' and 'NoneType'; order never saved.
Remedy: Check if discount is not None: before applying. Alternatively, have get_discount raise a typed exception (InvalidCouponError) that the caller can handle explicitly.
items ListPremises: items is assumed to contain at least one element.
Trace: sum(item['price'] * item['qty'] for item in items) → returns 0 for empty list → total = 0 → order['total'] = 0 → saved and confirmed.
Divergence: An order with zero items is silently saved as a $0.00 order and a confirmation email is sent. No business rule validates that an order must contain at least one item.
Trigger: process_order(1, []) → expected a rejection; actual: order persisted with total = 0 and a confirmation email dispatched.
Remedy: Add if not items: raise ValueError("Order must contain at least one item") before the sum. This is a business invariant, not an implementation detail.
Premises: db.save_order and email_service.send_confirmation are assumed to both succeed.
Trace: db.save_order(order) succeeds → connection kept open → email_service.send_confirmation(...) raises SMTPException → function exits via uncaught exception.
Divergence: The database connection is never explicitly released. Depending on the ORM's connection pooling strategy, this may exhaust the pool under sustained email failure.
Trigger: Stub email_service.send_confirmation to raise SMTPException, then call process_order once per pool slot — the pool is exhausted and the next call blocks on checkout.
Remedy: Wrap email_service.send_confirmation in a try/finally block, or separate the email send into an async queue so order persistence is not coupled to email delivery.
(+ 2 more findings)
Claude Code users:
/plugin marketplace add hyhmrright/logic-lens
/plugin install logic-lens@logic-lens-marketplace
/logic-review
Then paste any function. Done. (Short-form commands like /logic-review are auto-installed on first session start.)
For Gemini CLI and Codex CLI, see Installation below.
Logic-Lens ships six skills: logic-review (find behavioral bugs via execution tracing), logic-explain (trace what code actually does step by step), logic-diff (verify two versions are behaviorally equivalent), logic-locate (find the root cause of a failing test or crash), logic-health (aggregate logic health dashboard across a codebase), and logic-fix-all (autonomous audit-and-fix pipeline — after consent, scans the target, applies fixes for every finding, verifies each fix, and reports anything unresolved). See Usage for per-skill commands and Slash Commands for platform-specific syntax.
Logic-Lens is scored against evals/content/v2/evals-v2.json — 104 cases across the six
skills, spanning 12+ languages, with cases modeled on Defects4J, QuixBugs, the Therac-25 and
Ariane 5 inquiries, and Lu et al.'s concurrency-bug study. Every run is graded offline by a
rule-based grader (scripts/grade-iteration.py), not by an LLM judge.
Published logic-review runs (36-case subset, claude-sonnet-4-6):
| Version | Overall pass rate | What changed |
|---|---|---|
| v0.6.5 | 53.9% | First published Sonnet baseline |
| v0.6.6 | 76.2% | Output Skeleton Contract + reachability gate |
| v0.6.9 | 78.3% | Four L-code disambiguation rule groups + no-bug template |
Every frozen run summary is in benchmarks/runs/, cataloged by benchmarks/index.json, with
human-readable reports under benchmarks/reports/. Reproduce any of them with
npm run content-evals.
How to read these numbers. The grader splits each case into a logic sub-score (did it
find the bug and classify the risk correctly?) and a contract sub-score (does the report
carry the literal Iron Law field labels?). overall_pass_rate mixes both, and contract
assertions are ~25% of the total — so overall is a combined record, not a pure measure of
reasoning quality. See benchmarks/README.md for the metric hierarchy and the multi-run
averaging rule (single-run case-level deltas have been observed to swing ±25pp).
What is not measured here. There is no published head-to-head against unassisted Claude in
this repo; the version-over-version numbers above are the honest claim. Results also depend
heavily on the host model actually invoking the skill — see
docs/MODEL_COMPATIBILITY.md, where Haiku in claude -p mode
scores 38.7% almost entirely because it answers directly without loading the skill.
| Logic-Lens | ESLint / Pylint | GitHub Copilot Review | Plain Claude | |
|---|---|---|---|---|
| Detects syntax & style issues | — | ✅ | ✅ | ~ |
| Explicit execution trace per finding | ✅ | ❌ | ❌ | ❌ |
| Premises → Trace → Divergence → Trigger → Remedy | ✅ | ❌ | ❌ | ❌ |
| Consistent severity-labeled findings | ✅ | ✅ | ~ | ❌ |
| Interprocedural bug detection | ✅ | ❌ | ~ | ~ |
| Boundary & null path analysis | ✅ | ~ | ~ | ~ |
| Zero config, works with any language | ✅ | ❌ | ✅ | ✅ |
| Reasoning is auditable / reproducible | ✅ | ✅ | ❌ | ❌ |
~= occasionally / inconsistently
Logic-Lens doesn't replace your linter. It catches what linters can't: callee contract violations, state mutation hazards, and control flow escapes — the bugs that cause production incidents in syntax-clean, lint-passing code.
AI code reviews grounded in 12 classic engineering books — decay risk diagnostics with book citations, severity labels, and 6 analysis modes including full-sweep auto-fix
FAQ
logic-lens is a Claude Code plugin with 11 hand-picked skills for development work, indexed on Flowy. Install it with the command on its page. It includes bump-version, iterate-skill, new-skill. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it