Skip to content

LINTOs: Codebase Rules & Invariant Enforcement

LINTOs are deterministic rules that evaluate proposed code edits in memory before files touch disk. They guarantee that AI-generated code conforms to your organization’s standards, security policies, and architectural boundaries.

To initialize LINTO rule support in your repository, run:

Terminal window
agento linto init

This creates the .linto/ directory in your repository root:

.linto/
├── README.md # Guide and local conventions
├── no-secrets.md # Starter rule preventing credential leaks
└── linto.d.ts # TypeScript type definitions for function-based rules

LINTO rules can be written in two formats: Markdown rules and TypeScript function rules.

Markdown rules use YAML frontmatter to define triggers, scopes, and gate policies:

---
description: "Prevent committing hardcoded API secrets and private tokens"
scope: ["file"]
gate: "hard"
trigger:
regex:
- "(?i)(api_key|secret_key|private_key|auth_token)\\s*=\\s*['\"][A-Za-z0-9_\\-]{16,}['\"]"
---
# Rule: No Hardcoded Secrets
Do not write raw API keys or tokens into source files. Always use environment variables or secret managers.

2. TypeScript Function Rules (.linto/linto.ts)

Section titled “2. TypeScript Function Rules (.linto/linto.ts)”

For advanced checks (such as AST parsing or conditional logic), define programmatic rules in .linto/linto.ts:

/// <reference path="./linto.d.ts" />
import { defineLinto } from "./linto";
export default defineLinto({
id: "strict-typing-no-any",
description: "Disallow 'any' type assertions in TypeScript source files",
scope: ["file"],
gate: "hard",
trigger: {
glob: ["src/**/*.ts", "src/**/*.tsx"],
},
check: ({ path, content }) => {
if (path.endsWith(".test.ts") || path.endsWith(".spec.ts")) {
return null; // Allow in tests
}
if (content.includes(" as any") || content.includes(": any")) {
return "Forbidden 'any' type found. Use strict types, unknown, or type guards instead.";
}
return null; // Passed
},
});

The scope field specifies what target the rule evaluates:

Scope Target Evaluates
file Proposed file content Checks buffer text before saving to disk.
directory File path / directory Checks whether creating/modifying the file path is permitted.
command Shell command string Checks bash/shell commands before execution.

The gate property defines what happens when a rule matches:

Gate Behavior Usage
hard Strict Rejection. The write is aborted immediately. The agent receives the error message and must rewrite its code. Security policies, strict typing, protected files.
justify Approval Required. Execution halts and prompts the user for confirmation or requires an explicit agent justification. Refactors, package version bumps, database schema edits.

Triggers filter when a rule is evaluated:

trigger:
glob: ["packages/core/**/*.{ts,tsx}", "apps/cli/**/*.ts"]
regex: ["(?i)TODO\\(security\\)"]

---
description: "Ensure all new source files contain the standard license banner"
scope: ["file"]
gate: "hard"
trigger:
glob: ["src/**/*.{ts,go,rs}"]
---
All newly created or modified source files must begin with the standard organizational Apache 2.0 license comment.

Example 2: Protecting Lockfiles & Environment Files

Section titled “Example 2: Protecting Lockfiles & Environment Files”
---
description: "Protect production lockfiles and environment configurations"
scope: ["file", "directory"]
gate: "justify"
trigger:
glob: [".env*", "bun.lock", "package-lock.json", "Cargo.lock"]
---
Modifications to lockfiles or environment files require explicit justification.

Press F1 at any time during an interactive session to open the LINTOs Hub, where you can view all active rules, test triggers, and inspect gate levels.