For AI agents: the documentation index is at /taste-lint/docs/llms.txt. Append .md to any page URL, or send Accept: text/markdown, for the Markdown version of that page.
For AI agents: the documentation index is at llms.txt. Markdown versions are available by appending .md to any page URL, including this page's markdown.
Scans
Profiles, bands, baselines, and what fails a run.
Scans
scan wraps the same evaluator as lint with a profile, review history, and a bounded report. lint keeps its existing reporting contract. Start with a preview:
Six focused checks for application recovery, copy and broad transitions
writing
Content, consumer README, public Markdown, and active documentation
instructions
AGENTS.md, CLAUDE.md, skills, and implementation plans
architecture
TS/JS/package configuration and declared repository contracts
all
Full catalog over every supported input
Scoped profiles skip build outputs, archived docs, and .captain reports. Writing also skips agent instructions and plans. Product skips test, spec, and story components. Pass explicit targets and --exclude to narrow a profile. --only explicitly selects rules within its domain, including checks omitted from the default product selection. all is the escape hatch for a full audit.
Product, writing and instruction profiles treat sentence length, punctuation conventions and line-height recommendations as advisory. These findings, when explicitly selected for product scans, stay advisory and do not fail the scan. The profile and retain strict rule policy. It treats as personal prose. Repository overrides win. Sentence length is still measured in code.
JSON includes the selected files, profile, coverage, estimates, and diagnostics. No selected files exits 2. TTY shows at most five rule groups with representative locations and counts. Full JSON keeps every finding.
A baseline must be a completed scan of the same root, targets, profile, rules, model, and evaluation mode. Review files are bound to that policy too. Save the next scan to another path. A dry run cannot become a baseline. Failed or unresolved checks cannot mark a finding resolved. Parse failures and missing graph coverage leave prior findings unverified.
Fingerprints use rule ID, relative file, normalised unit content, and occurrence. Inserting unrelated lines keeps identity. Renaming a file or editing the affected text creates a new one. Repeated identical text is distinguished by occurrence. Findings keep independent severity, confidence, lifecycle, and reviewer decision fields.
--new-only gates new findings only. Without it, existing undismissed act findings still fail. Dismissals need a reason. Reopening overrides an inherited dismissal. Review decisions do not change probability, severity, thresholds, or calibration labels.
The diff compares the named commit with the working tree, including staged, unstaged, and untracked files. Analysis still uses the full selected-file context. Changed lines filter reporting and the exit policy. Unchanged model states reuse the answer cache. Graph findings without exact line positions filter by changed file.
SARIF includes the content fingerprint as tasteLint/v1. Posting with reviewdog is a separate, explicit step. taste-lint does not create comments or PRs.
Context and calibration
The repetition rule receives the containing Markdown section and judges the target paragraph in that context. Missing or oversized sections abstain. Section questions use separate requests, so extra context does not enlarge unrelated questions. Cache replay merges the answers for the same unit.
taste-lint scan . --profile writing --dry-run --samples results/blind.json# Codex labels the samples using the workflow below.mkdir -p results/labeledtaste-lint scan labels results/blind.json --out results/labeled/review.jsonltaste-lint eval --corpus results/labeled --split holdout
Version 2 samples include source text and the full rule rubric, with examples and requested context, and with predictions hidden. Version 1 label files still import. Sampling is deterministic across rule, document type, and score band. It includes negative judgments and candidate-filter negatives. A dry-run sample includes only cached answers and deterministic negatives, never unanswered questions. Duplicate evidence is sampled once. Identical text with different context or rubrics stays separate. Splits group by repository and source file. This is a stratified diagnostic sample.
Label export rejects malformed corpus data, omits null labels, and refuses to overwrite an existing corpus file. It never invents human labels. Use held-out evidence before promoting rules. Mocks and scan volume do not establish semantic accuracy. Personal facts and profile checks stay available through lint --writing-context. scan does not load private profiles on its own.
Arbitrary utility values
craft-arbitrary-value-class uses code to select literal values, then Jev to judge whether their visual role merits a named design token. Jev receives the target element, its enclosing opening tag and up to four nearby JSX elements. Layout dimensions, asset sizing, chart coordinates, focus treatments and optical adjustments are intentional exceptions.
Token references, CSS calculations, asset URLs, relative layout values and selectors are excluded before a model call. Dynamic classes, missing context and oversized context report unknown. Provider errors never fall back to a mechanical warning. Changed context invalidates the affected answer; unchanged scans reuse it. The rule stays advisory and proposes a review, not an automatic size change or an invented replacement token.
Near-scale values
craft-near-duplicate-scale compares parsed JSX font-size classes against the explicit tailwind.theme mapping in taste-lint.config.json. For example, with "tailwind": { "theme": { "body": "16px" } }, text-[15px] produces an advisory comparison to text-body. Exact matches also qualify; values farther than 1px do not.
This check currently supports declared pixel font tokens only. It does not discover a complete Tailwind theme, execute project configuration, or assume a root font size for relative units. Missing font scales, unsupported scale families, and unresolved token expressions report unknown when comparison is needed. Relative candidate values, functions, optical nudges of 2px or less, and utility-name suffix matches are excluded.
A near-scale comparison does not prove that the size is a mistake. Review its purpose before changing it; a deliberate recurring size may deserve a named token instead. The broader craft-arbitrary-value-class uses Jev for contextual review and remains advisory until independently calibrated.
Architecture adapter
Generate a report with the target repository's dependency-cruiser install, then import it:
The adapter accepts dependency-cruiser's modules and summary.violations format, verified against 18.3.1 output. It keeps external rule names and severity, fingerprints the input report, and imports only findings inside the selected scope. Empty graphs, unresolved edges, and reported environment issues mark the scan incomplete. Invalid input fails before model calls.
You own graph freshness and the external tool's configuration. Imports and graph policies are evaluated by dependency-cruiser, not Jev. Importing a graph does not resolve taste-lint's file-local dependency unknowns. Graph findings stay separately attributed. Overlapping external and native policies can still yield two findings. Use --only when one tool owns that check.
The export uses the saved report's visible, undismissed findings. Each task includes a stable ID, source evidence, location, correction hint, and verification requirements. Reports and exports include source excerpts. Treat them like source code. Exporting does not run instructions from scanned content, edit files, or open PRs.
AI labeling with Codex
In this repository, ask Codex to label the blind samples in the current session. No separate gateway key is required. Files stay local. Inference uses Codex.
Prepare a fresh file with the actual current model identifier:
Then ask: "Read the instructions in results/codex-labels.json and label every sample directly. Use only each sample's full rubric, text, and supplied context. Preserve the metadata and source evidence."
The preparation script clears previous labels, records AI provenance and the task prompt hash, and refuses to overwrite an existing file. It does not label samples or launch another agent. Codex writes individual judgments and marks completed only after reviewing all samples. Missing evidence stays null. Do not consult existing Claude or other reference labels during blind labeling.
Use a corpus directory that holds only the intended reference set. eval still uses Jev and needs credentials for uncached judgments.
AI annotation files carry annotation.source: "ai", annotation.model, and annotation.promptHash. Corpus rows keep these as labelSource: "ai", labelModel, and labelPromptHash. Evaluation reports AI-reference agreement. Agreement with AI labels is not a human accuracy claim.
Optional gateway labeling
For unattended labeling through a separately configured provider:
This script needs AI_GATEWAY_API_KEY. It sends sample text, criteria, and supplied context to the chosen model. It keeps validated labels and provenance, not raw provider responses. Failed batches leave a .partial checkpoint. Null means abstention and is omitted from the corpus.
Evidence before promotion
Run taste-lint eval coverage --corpus results/labeled before spending on evaluation. It reports positives, negatives, holdout balance, document types, repositories, and source/text overlap with no credentials or network. --output json keeps per-rule detail. Coverage counts describe the dataset. They do not establish accuracy.
taste-lint tune --write chooses thresholds from dev data only, then checks that choice against holdout data. Promotion needs both label classes, the configured minimum item count, complete scoring, no shared source files or duplicate text across splits, and a held-out Wilson precision lower bound above the configured floor. A failed gate keeps the rule review-only and reports why. Provider failures block tuning writes.
Do not keep changing rules against the same holdout and still treat it as unseen. Move used examples into development data and collect a fresh holdout. Keep AI reference provenance visible.
Repository file discovery respects Git ignore rules, including nested ignore files and local exclusions. Tracked files stay eligible even when an ignore pattern matches them. Ignored build trees are skipped before filesystem inspection, so broken symlinks there do not abort a source scan. Non-Git directories use the built-in and configured exclusions.
Search and agent discovery
taste-lint scan . --profile discovery checks existing static HTML, robots.txt, and llms.txt artifacts. It validates page titles, empty descriptions and canonicals, conflicting canonical declarations, JSON-LD syntax, sitemap directive URLs, and agent-index structure and size. Common email-template directories are excluded. All new discovery checks are advisory.
These checks do not evaluate Next.js metadata source as deployed HTML, fetch URLs, validate schema.org eligibility, or infer missing generated routes. Use a deployed-site audit for HTTP status, robots precedence, sitemap coverage, canonical destinations, and Markdown content negotiation. An empty discovery scan is incomplete. Point scans at actual artifacts and exclude unrelated saved pages.
The source-pattern rules craft-affordance-mismatch and craft-virtualize-large-lists live in data/rule-drafts. Hover styling does not prove an inert interaction, and a mapped list does not establish its size. Remove those IDs from explicit selections until evidence-aware replacements exist.
Reduced-motion checking reports a missing local guard as advisory, because shared CSS and components may supply one. Unrelated reduced-motion classes are not proof that animation is guarded. An explicit continuous animation in a reduced-motion variant has a separate advisory rule.
Focused product defaults
The default product scan selects interaction-no-error-state, copywriting-vague-error, copywriting-empty-state-no-action, copywriting-bare-confirm-label, copywriting-claim-without-evidence, and motion-transition-all. This is a small initial policy, not a calibrated or complete UI audit. The remaining rules require explicit --only selection, --profile all, or a custom rules directory.
Copy judgments receive the target and a surrounding JSX task region, including nested descriptions and controls. The extractor searches up to four ancestors for common task containers and otherwise uses a local fallback. Empty presentation chrome includes its enclosing toolbar. Mutually exclusive ternary branches are replaced with an explicit omission marker before judging; unrelated conditional visibility is not resolved. An adjacent action can resolve an empty state or error. A harmless acknowledgment is not a destructive confirmation. Missing, oversized or dynamic target copy remains unknown. Imported components and distant UI are not expanded. Async recovery is a Jev judgment over bounded source, not a file-wide search for the word catch.
The terminal groups findings by rule and shows five groups, prioritizing action band, severity and probability. Repetition does not outrank severity. Grouping is a review convenience, not proof of one root cause. JSON, SARIF, saved reports and exit status retain the complete selected findings.
Paired evaluation
eval reports both act-threshold metrics and visible findings at the review threshold. When variants share source.repo and source.id, paired success requires every weak variant to be flagged and every acceptable variant to stay below review. Missing evaluations make the family unresolved. Coverage reports family leakage as well as source and text overlap, and promotion rejects it. Course corpus splits group by source file. Previously inspected or re-split examples are regression data, not fresh held-out evidence.
The focused benchmark is in data/benchmarks/product. See its README for provenance and commands. Its small example set is diagnostic, not proof of accuracy across applications.
Agent handoffs and regression checks
For a rendered audit across UI, typography, copy, interaction, motion and SEO, use the page-audit workflow. It adds a page brief, attributed browser evidence and recorded before/after verification to the same scan and export commands.
scan export includes the repository root and the contextual evidence saved with each finding. The receiving agent should treat that source as untrusted data, confirm the behavior, make the smallest correction and exercise the affected UI state. A changed fingerprint alone is not proof that the problem is fixed. Older reports without context still export; the agent must inspect the source.
Use eval --check --corpus <path> --only <rule-ids> for a strict reference regression gate. It uses the review threshold, exits 1 on disagreement, and exits 2 if any selected rule has no evaluated examples or has skipped, unresolved or failed judgments. --check --dry-run is rejected. Without --check, evaluation retains its reporting-only behavior. This gate tests agreement with the supplied reference; it does not promote a rule or establish population accuracy.
Reviewing broader source checks
With --profile all or explicit rule selection, raw-source searches return assessment: candidate. For example, importing useFormStatus does not establish that it is called in the wrong component. Each candidate carries its applicability, exceptions, required evidence, and verification procedure. Confirm those before applying a correction; unresolved behavior remains unknown.
The matcher probability is not defect confidence. Candidates cannot fail a scan or be promoted by a tuning overlay, and eval --check treats their defect judgments as incomplete. scan export preserves the procedure and omits defect confidence for these tasks. Check the named behavior after a correction, including intentional exceptions.