klint is the bridge between vibe coding and agentic engineering — architecture-level rules your AI cannot ignore, declared in YAML, enforced at the Stop hook.
bun add -d @konvert7/klintOr it did, then it forgot. Or it drifted three turns later. Instructions in a prompt are a contract with no enforcement — a model that's context-starved or just wrong will violate them silently and ship anyway.
AGENTS.md tells the model what to do.
klint ensures it actually did.
Four primitives. One YAML file. Every rule you'd otherwise hide in AGENTS.md and pray, expressed declaratively and enforced structurally.
# yaml-language-server: $schema=./klint.schema.yaml include: ["src", "!**/node_modules/**"] plugins: [sonar] arch: layers: core: ["src/hooks/lib/**", "src/tools/**"] skills: ["assets/skills/**"] dao: ["src/dao/**"] imports: # skills must stay portable — no cross-layer reach - from: skills deny: core message: "Skills must be self-contained and portable" severity: warn # dao gets a strict allowlist — anything else is denied - from: ["src/dao/**"] allow: ["src/dao/**", "src/prisma/**", "src/types/**"] forbidden: - pattern: "console.log(" in: core message: "Leaks into the agent event stream" singleton: - pattern: "process.env.API_KEY" only: "src/lib/auth.ts"
Name your architectural zones once. Reference them everywhere — no glob copy-paste, no drift between rules.
Deny lists, allowlists, type-only exceptions. The dependency graph your README claims you have.
Block literal strings — console.log, process.exit, raw SDK fetches — scoped to the layer.
Pin a pattern to one file. Every other touch is a violation — the only honest way to enforce a module of record.
The full compatibility path: type-aware checks, custom rules, plugins, and fixes.
Portable architecture checks and syntax-local rules backed by tree-sitter.
Rust-supported rules run natively while TypeScript-owned rules stay semantic.
bun add -d @konvert7/klintPrimary path for TypeScript projects and the full CLI surface.
brew install klintNative CLI for local architecture checks on macOS.
pip install klintPyPI package wrapping the native architecture engine.
$ bun klint ✗ src/skills/email/send.ts:14 arch/imports Skills must be self-contained and portable → remove import from "src/hooks/lib/paths" ✗ src/dao/user.ts:42 no-floating-promise Promise-returning call whose result is discarded → await it, or .catch() it explicitly ! src/hooks/lib/auth.ts:8 arch/singleton process.env.API_KEY must only appear in src/lib/auth.ts ────────────────────────────────────────────── 2 errors, 1 warning in 184ms exit 2
{ "violations": [ { "rule": "arch/imports", "file": "src/skills/email/send.ts", "line": 14, "severity": "error", "message": "Skills must be self-contained...", "fix": null }, { "rule": "no-floating-promise", "file": "src/dao/user.ts", "line": 42, "severity": "error" } ], "summary": { "errors": 2, "warnings": 1 } }
Every agent edit ends with klint. Exit 2 means the session can't close. The model reads the structured violations, fixes them, and tries again — no human in the loop, no silent drift to production.
import { runHook } from "./run-hook"; const exitCode = runHook([ "bun", "klint/cli.ts", "--json", ]); process.exit(exitCode);
The model writes whatever its context permits — refactor, feature, bug fix. No interference during the work loop.
Before the agent's turn closes, klint runs against the changed layers and emits machine-readable diagnostics on stdout.
Violations land in the agent's event stream as structured JSON. The session can't end until they're resolved — fix or explicit override.
The model reads the rule, the file, the line, and the message it wrote itself. Then it does the right thing. Quietly. Every time.
[ works with any agent that runs a stop hook ]
An agent that knows the boundaries spends zero cognitive overhead second-guessing them. It just executes — confidently, fast, inside the zone you defined. That is the freedom. The tighter the harness, the wider the runway.
Formatters and language linters enforce local correctness. klint enforces project boundaries and policies an agent must not bypass.
A warning the model ignores is the same as no rule at all. klint exits with intent — the Stop hook respects it, the session waits, the fix lands.
Architecture rules belong in declarative config a reviewer can read in ten seconds. Escape hatch to TypeScript exists, but most of the time you'll never reach for it.
[ install ]
bun add -d @konvert7/klint