Lintropy is a linter for rules your repo actually cares about. It started at
The IDE Reimagined: JetBrains Codex Hackathon,
a two-day San Francisco event focused on building AI-powered developer tools
alongside JetBrains and OpenAI engineers.
[!WARNING]
This project began as hackathon code and is not actively maintained right
now. Expect rough edges, incomplete features, and bugs before using it in
production workflows.
Most linters ship a fixed catalog. Lintropy does the opposite: rules live in
your repo, one YAML file at a time, describing your conventions:
- API code must live in
src/api/
- feature modules cannot import each other directly
dbg!, println!, or .unwrap() are banned outside tests
- migrations require rollback files
- only one module can touch
process.env
Linting for architecture, boundaries, migration policies, and team ceremony —
not just style.
Install
Homebrew (macOS and Linux)
brew tap Typiqally/lintropy
brew install lintropy
From source
Stable Rust 1.95 or newer required.
cargo install --path .
Not yet on crates.io.
Supported languages
- Rust, Go, Python, TypeScript (incl.
.tsx) — structural query rules via tree-sitter
- Any text file — regex
match rules
More tree-sitter languages planned. Vote or contribute via issues.
Demo
$ lintropy check .
warning[no-unwrap]: avoid .unwrap() on `client`; use .expect("...") or ?
--> src/handlers/users.rs:42:18
|
42 | let user = client.unwrap().get(id).await?;
| ^^^^^^^^^^^^^^^ help: replace with `client.expect("TODO: handle error")`
|
= rule defined in: .lintropy/no-unwrap.rule.yaml
error[api-only-in-src-api]: API handlers must live under src/api/
--> src/features/users/create_user.rs:1:1
|
1 | pub async fn create_user(...) { ... }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= rule defined in: .lintropy/architecture/api-only-in-src-api.rule.yaml
Summary: 1 error, 1 warning, 2 files affected.
Why Lintropy
Generic linters are great at universal rules. They are weak at codebase-local
rules that only make sense inside one company, one monorepo, or one product.
Lintropy fills that gap:
- rules stored in the repo, versioned alongside the code they govern
- rules easy to review
- rules simple enough for agents to generate
- diagnostics tell you which rule file fired
- tree-sitter handles structure, regex handles plain text
| Generic linters | Lintropy |
|---|
| Rule source | Built into the tool | Lives in your repo |
| Authoring | Plugin code or complex config | Small YAML files |
| Scope | Language-wide conventions | Project-specific constraints |
| Best use | Style and correctness | Architecture and boundaries |
| Agent support | Incidental | First-class |
How it works
Two rule types:
query: tree-sitter rules for structural patterns
match: regex rules for text patterns
Typical layout:
.
├── lintropy.yaml
└── .lintropy/
├── no-unwrap.rule.yaml
├── no-dbg.rule.yaml
└── architecture/
└── api-only-in-src-api.rule.yaml
Example rule:
# .lintropy/no-unwrap.rule.yaml
severity: warning
message: "avoid .unwrap() on `{{recv}}`; use .expect(\"...\") or ?"
fix: '{{recv}}.expect("TODO: handle error")'
language: rust
query: |
(call_expression
function: (field_expression
value: (_) @recv
field: (field_identifier) @method)
(#eq? @method "unwrap")) @match
Minimal root config:
version: 1
settings:
fail_on: error
default_severity: error
Built for agent workflows
Designed so Codex, Claude Code, and similar agents can write valid rules
without much prompting overhead.
- one rule per file
- low-ceremony YAML
- deterministic repo discovery
- explainable diagnostics
- schema-friendly config
- LSP-driven live feedback for post-edit loops
If agents write code, they should write and respect the repo's guardrails too.
Quickstart