Skip to content

Running lint

adhere lint judges the TypeScript files under the working directory against your rules, and prints a report of what it finds. It asks before it sends anything.

Before it judges anything, lint says on stderr what it found and what judging takes, and asks:

200 files and 14 rules: 2800 checks, 1400 cached.
Judging 100 files takes an estimated 100 requests to Jev, plus 1 or more for each file with a finding.
Those carry about 1.9 million input tokens: about $0.08 at $0.042 per million, and more for locating findings.
Estimates cover only code and workspace-package context; symbol/reference input, possible extra request splits, and size-skips are determined at send time.
? Estimates cover only code and workspace-package context; symbol/reference input, possible extra request splits, and size-skips are determined at send time. Send an estimated 100 requests to Jev, about $0.08? › (Y/n)
  • It asks only when stdin and stdout are terminals, and only when there is something to send. --yes sends without asking.
  • The cost is adhere’s estimate of the input tokens times the model’s price. Jev charges only for input tokens: $0.042 a million for jev-latest, per TypeSafe AI’s models page in September 2026. When type awareness is enabled, the estimate leaves out symbols and references, which adhere reads as it sends each file, so a run can cost more than it says.
  • A run that stops loses nothing: files finished before it stopped are cached, so running again continues from there.
More on unknown prices and blocked files
  • For a model adhere has no price for, the plan gives the tokens alone.
  • The firewall in front of Jev’s API can refuse a request whose code reads to it as an attack, with a 403 and an HTML page rather than Jev’s JSON. It refuses the same request every run, so that file is skipped, the run goes on, and the report lists each such file with Cloudflare’s Ray ID, which TypeSafe AI can look the block up by.
  • When only the question that finds the line is refused, the file’s judgments are kept, and a rerun sends that question alone.
  • adhere lint reads the TypeScript files under the working directory: .ts, .tsx, .mts, and .cts. It does not read declaration files such as .d.ts, adhere’s own config files, or JavaScript.

  • When the working directory contains agents/, apps/, or packages/, only those trees are read.

  • Below the working directory, anything under node_modules/, dist/, coverage/, vendor/, e2e/, references/, .adhere/, .agents/, .claude/, .direnv/, .alchemy/, or .vite/ is skipped. The directories above the working directory do not count.

  • .gitignore is not consulted.

  • A config’s exclude lists globs, relative to the working directory, of files no rule judges, such as generated code. It leaves them out of every run, as --filter '!<glob>' leaves them out of one:

    export default defineConfig({ exclude: ["**/generated/**"] });

Tests are judged only by rules about tests, whose front matter says tests (see Rules as Markdown files). A test is:

  • a .test or .spec file, such as a.test.ts or Button.spec.tsx;
  • a fixture or test helper named as one, such as fixtures.ts, GitHubHttpFixtures.ts, ledger-copy.fixture.ts, linear-test-helpers.ts, or test-utils.ts;
  • any file under a test/, tests/, __tests__/, testing/, fixtures/, fixture/, __fixtures__/, or __mocks__/ directory.
Flag What it does
--preset <names> Add built-in rule sets, or their topics. The config becomes optional. See Presets.
--threshold <0 to 1> Replace the config’s threshold. Per-rule thresholds still apply.
--sufficiency-threshold <0 to 1> Replace the config’s sufficiencyThreshold: a finding warns when its context is below it.
--type-aware Add the compiler’s symbols and references. See What Jev reads.
--yes, -y Send the requests without asking first.
--limit <files>, --rpm <requests>, --filter <glob> Bound how many files a run judges, how fast it sends, and which files it judges. See Limiting a run.
--deny-warnings Fail on warnings as well as errors.
--log-level <level> Log the run’s work on stderr. See Logging a run.

Three flags bound what a run does:

  • --limit <files> sends requests for at most that many files, taken in path order. The rest wait. Since judgments are cached, the next run with the same limit picks up where this one stopped. --limit 0 shows the plan and sends nothing. It counts files, not requests: one file can take several.
  • --rpm <requests> sends at most that many requests to Jev a minute, evenly spaced, retries included. The plan says about how long they take.
  • --filter <glob> judges only the files whose path from the working directory matches, such as src/** or **/*.service.ts. Wrap a glob in single quotes so the shell does not expand it. Repeat the flag for more globs, and start one with ! to leave out what it matches.
Terminal window
adhere lint --filter 'packages/api/**' --filter '!**/generated/**' --limit 100 --rpm 30

--log-level logs the run’s work on stderr:

  • debug logs the config it loaded, how many paths it listed, and how many of them it reads. It logs each request to Jev, with the file it is for, about how many tokens it carries, and how long it took. A failed attempt is logged even when a retry hides it, with the HTTP status, Cloudflare’s Ray ID, and the start of what the API said.
  • trace also logs each file as it is read, planned, and answered from the cache.

stdout still carries only the report, so the log can go to a file of its own:

Terminal window
adhere lint --log-level debug 2> adhere.log
Code When
0 Nothing is reported, or only warnings.
1 An error is reported. With --deny-warnings, a warning too.
1 The run refuses, for example on an invalid config or rule file, a missing API key, or an unknown command or flag. A refusal prints its reason.