{"id":50393053,"url":"https://github.com/leostera/lintbook","last_synced_at":"2026-05-30T19:01:59.195Z","repository":{"id":359748547,"uuid":"1023268398","full_name":"leostera/lintbook","owner":"leostera","description":":book: a fast, reproducible, flexible multi-language linter for the ai age","archived":false,"fork":false,"pushed_at":"2026-05-23T08:23:57.000Z","size":895,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T10:25:59.788Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leostera.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"leostera"}},"created_at":"2025-07-20T22:02:54.000Z","updated_at":"2026-05-23T09:06:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/leostera/lintbook","commit_stats":null,"previous_names":["leostera/lintbook"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/leostera/lintbook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leostera%2Flintbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leostera%2Flintbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leostera%2Flintbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leostera%2Flintbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leostera","download_url":"https://codeload.github.com/leostera/lintbook/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leostera%2Flintbook/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33705207,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-30T19:01:58.416Z","updated_at":"2026-05-30T19:01:59.188Z","avatar_url":"https://github.com/leostera.png","language":"Rust","funding_links":["https://github.com/sponsors/leostera"],"categories":[],"sub_categories":[],"readme":"# lintbook\n\n`lintbook` is an LLM-powered linter for repeatable quality checks that are too project-specific, contextual, or new to wait for a general-purpose lint rule.\n\nYou write the intent of a rule in plain Markdown, let an agent translate it into a Datafox query once, and then run that query locally at lint speed. The LLM is in the authoring path, not the checking path, so `lintbook check` stays deterministic, cacheable, and CI-friendly.\n\n## Why lintbook\n\nAgents are good at noticing issues, but they are a poor runtime for checks you want on every commit:\n\n- They are nondeterministic and can miss the same issue on the next run.\n- They are slow; one model call per file or file group does not scale.\n- They are expensive; repeated commit-time checks burn tokens quickly.\n\nTraditional linters solve those runtime problems, but writing custom rules for different lint engines takes time, tool-specific knowledge, and maintenance energy. Most linters are excellent at enforcing rules that already exist. They are weaker when a team wants to encode local judgment:\n\n- \"Do not use this internal helper outside the API boundary.\"\n- \"Public Rust types in this crate need documentation.\"\n- \"Avoid this Python import pattern because our runtime loader cannot see it.\"\n- \"Flag this migration shape unless it is paired with this rollback statement.\"\n\n`lintbook` is built for those rules. The rulebook lives in your repository, the generated query artifacts are committed, and the fast path runs without a model, network call, or agent session.\n\nThe result is:\n\n- Deterministic: rules compile to Datafox queries.\n- Fast: a roughly 30k line project can run in about 300ms.\n- Cheap: tokens are used only while compiling or authoring lints.\n\n## Install\n\n```sh\nbrew install leostera/lintbook/lintbook\n```\n\nor:\n\n```sh\ncurl https://get.lintbook.sh | sh -\n```\n\n## Quick Start\n\nSet up lintbook in a repository:\n\n```sh\nlintbook setup\n```\n\nThis creates:\n\n- `lintbook.toml`\n- `.lintbook/rules/template.md`\n- `.lintbook/gen/.gitkeep`\n\nIt also prints MCP configuration snippets for agents that can use lintbook's rule-authoring tools. `lintbook setup` does not edit global or project MCP config files automatically.\n\nAdd a rule description:\n\n```sh\nlintbook add \"flag dbg! macro calls in committed Rust code\"\n```\n\nGenerate the missing Datafox query with an agent, then compile it:\n\n```sh\nlintbook compile --agent codex\n```\n\nRun the linter:\n\n```sh\nlintbook check\n```\n\nCheck a smaller target:\n\n```sh\nlintbook check crates/lintbook-cli/src/main.rs\nlintbook check crates/lintbook-rules\nlintbook check \"crates/**/*.rs\"\n```\n\nStream machine-readable output:\n\n```sh\nlintbook check --json\n```\n\nList the built-in rules shipped with the binary:\n\n```sh\nlintbook lints\nlintbook lints --output json\n```\n\n## Rule Files\n\nA project rule starts as a Markdown file in `.lintbook/rules`:\n\n```markdown\n---\nid: rust.no-dbg\nlang: rust\n---\n\nWe do not want dbg! macro calls in production code.\n```\n\nThe Markdown body is the human intent. It becomes the default violation message unless the generated query supplies more specific output.\n\nThe generated query belongs in `.lintbook/gen` with the same rule stem:\n\n```text\nnode(Node, \"macro_invocation\", _, _, _, _), text(Node, Text), contains(Text, \"dbg!\")\n```\n\n`lintbook compile` validates the Markdown and Datafox files, then writes deterministic compiled artifacts in `.lintbook/gen/*.json`. Commit the Markdown, Datafox, and compiled JSON files so `lintbook check` can run quickly in CI and on other machines.\n\nPlain `lintbook compile` is deterministic and agent-free. If a Markdown rule is missing its `.df` query, it reports the missing generated file. Agent generation is opt-in through `lintbook compile --agent codex`.\n\n## How It Works\n\n`lintbook` separates rule authoring from rule execution.\n\nDuring authoring, a person writes the rule intent in Markdown. An agent can use lintbook's MCP guidance to inspect the available facts, Datafox syntax, and examples, then generate a matching `.df` query. The agent's job ends once the query compiles successfully; it should not try to rewrite the codebase to satisfy the new rule.\n\nDuring compilation, lintbook reads `.lintbook/rules/*.md` and same-stem `.lintbook/gen/*.df` files. It validates frontmatter, parses the Datafox query, checks that the rule can be prepared, and writes a compact `.json` artifact. These compiled artifacts are stable build products, not temporary cache files.\n\nDuring checking, lintbook scans the requested files, detects supported languages, parses each file with tree-sitter, and extracts a fact set from the syntax tree. Facts describe nodes, text, parent-child structure, field names, descendants, line numbers, and language-specific helper relations used by the built-in and generated rules.\n\nThose extracted facts are cached by file content hash and required predicate set. If a file has the same SHA-256 and the active rules need the same facts, lintbook reloads the cached facts instead of reparsing and re-emitting the tree-sitter fact graph.\n\nDatafox then evaluates the prepared rule queries over each file's facts. Planning is kept hot through prepared query caches, and results are streamed as files complete. Human output is meant for local use; `lintbook check --json` emits newline-delimited JSON events for editors, CI, and large repositories.\n\nThe important boundary is that `lintbook check` never asks an LLM what to do. The LLM helps create the rule. The committed rule artifacts make the runtime deterministic, local, and fast.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleostera%2Flintbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleostera%2Flintbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleostera%2Flintbook/lists"}