loam.dev
v0.1.4 · preview DE

How it works

loam.dev reads your Dart/Flutter project semantically and across the whole codebase — not file by file — and turns it into a deterministic pass/fail decision in CI. A baseline tolerates the code you already have, so only newly introduced problems block the build. It does this in a six-stage pipeline, without guessing, without regex shortcuts, without false positives from generated code.

The pipeline

01
Loader

The ProjectLoader feeds your entire project into Dart's own AnalysisContextCollection. Every file is parsed and fully resolved into a typed element model — the same model the Dart SDK uses internally. This is the foundation that makes everything downstream semantic, not syntactic.

02
Rules

A set of Rules runs over the resolved model. Each Rule is a self-contained analysis unit behind a shared interface; adding a new capability never changes the pipeline — only the rule list. Rules are either deterministic (pure AST/element-model, reproducible offline) or LLM-backed (planned, always verdict-cached before hitting CI).

03
Findings

Each Rule emits Findings — structured results of the form { ruleId, severity, location, message, fingerprint }. Every Finding carries a stable Fingerprint (a position-robust hash) that survives reformats and line-number shifts. This is the key that makes baseline diffing exact.

04
Baseline

The Baseline is a frozen snapshot of accepted Findings stored in baseline.json. When you onboard an existing project, you run a full audit, clean up what you can, and then freeze the rest with loam baseline --write. From that point on the Gate only cares about new Findings — not the ones you already know about.

05
Gate

The Gate is the CI decision point: it compares the current Findings against the Baseline and returns a structured exit code. Zero regressions → exit 0. New Finding → exit 1. No surprises at merge time.

06
Report

The Reporter formats results for humans or machines: human for terminal output, json / sarif / markdown for agent pipelines, and html for an interactive self-contained report file with a built-in fix-prompt builder.

loam scan vs. loam gate

Two commands, two purposes. Knowing which to reach for keeps your workflow clean.

loam scan

Full audit · baseline-independent

Runs every active Rule over the entire project and shows all Findings regardless of what the Baseline says. Use this when you first bring loam.dev into an existing repo — see the full picture, clean up what you can, then freeze the rest with loam baseline --write.

loam gate

CI ratchet · Baseline-aware

The everyday CI command. By default it runs in Ratchet mode: only Findings that are new (not in the Baseline) fail the build. The score can only improve over time — your codebase ratchets forward, never backward. For greenfield projects or pipelines that require zero findings, pass --absolute to enforce a hard threshold instead.

Typical onboarding sequence: loam scan → fix what matters → loam baseline --writeloam gate in CI from then on.

Semantics over syntax

The most important architectural decision in loam.dev is what the analysis runs on.

dart analyze reports type errors, missing imports, and style lint violations — all things that can be caught at the declaration level. What it does not do is reason about the graph of references across your entire project: which public API members are actually reachable from outside their own library, which class boundaries are being crossed, which helpers exist in two copies that happen to look the same.

Catching those things with regex or string matching is brittle. A regex that looks for an identifier name has no way to distinguish a definition from a reference, a local variable from a public export, or a generated file from hand-written code.

loam.dev uses the resolved element model: every symbol is a typed element with a canonical identity, every reference is a resolved pointer. Rules operate on that model, not on raw text. This means:

  • No false positives from coincidentally similar names.
  • Generated files are excluded automatically (the same way the SDK knows about them).
  • Renaming a class is invisible to the rule — what matters is whether the element is referenced, not what it is called.
  • Cross-library and cross-package references are tracked correctly.

This is what "semantics over syntax" means in practice: the Rules see your code the way the compiler sees it, not the way a text editor does.

Going deeper

The Developer Guide covers the full CLI reference, output formats, configuration, and worked examples — including the complete baseline onboarding sequence and how to integrate loam gate into GitHub Actions.