Linter for agent configs. 443 rules across 40 categories.
| Type | Files | Rules |
|---|---|---|
| Skills | SKILL.md | 34 |
| Hooks | settings.json | 27 |
| Memory (Claude Code) | CLAUDE.md, CLAUDE.local.md, .claude/rules/*.md | 13 |
| Instructions (Cross-Tool) | AGENTS.md, AGENTS.local.md, AGENTS.override.md | 6 |
| Agents | agents/*.md | 18 |
| Plugins | plugin.json | 15 |
| Claude Output Styles | .claude/output-styles/*.md | 6 |
| Claude Settings | .claude/settings.json | 24 |
| Prompt Engineering | CLAUDE.md, AGENTS.md | 6 |
| Cross-Platform | AGENTS.md | 10 |
| MCP | tool definitions | 26 |
| XML | all .md files | 3 |
| References | @imports | 4 |
| GitHub Copilot | .github/copilot-instructions.md, .github/instructions/.instructions.md, .github/agents/.agent.md, .github/prompts/*.prompt.md, .github/hooks/hooks.json, .github/workflows/copilot-setup-steps.yml | 25 |
| Cursor Project Rules | .cursor/rules/.mdc, .cursorrules, .cursor/hooks.json, .cursor/agents/**/.md, .cursor/environment.json | 20 |
| Cline | .clinerules, .clinerules/.md, .clinerules/.txt | 7 |
| OpenCode | opencode.json, opencode.jsonc | 47 |
| Gemini Agents | .gemini/agents/*.json | 1 |
| Gemini CLI | GEMINI.md, GEMINI.local.md, .gemini/settings.json (hooks), gemini-extension.json (extensions), .geminiignore | 10 |
| Codex CLI | .codex/config.toml/.json/.yaml | 65 |
| Version Awareness | .agnix.toml | 1 |
| Cursor Skills | .cursor/skills/*/SKILL.md | 1 |
| Cline Skills | .cline/skills/*/SKILL.md | 3 |
| Copilot Skills | .github/skills/*/SKILL.md | 1 |
| Codex Skills | .agents/skills/*/SKILL.md | 1 |
| OpenCode Skills | .opencode/skills/*/SKILL.md | 1 |
| Windsurf | .windsurf/rules/.md, .windsurf/workflows/.md, .windsurfrules | 4 |
| Windsurf Skills | .windsurf/skills/*/SKILL.md | 1 |
| Kiro Steering | .kiro/steering/*.md | 14 |
| Kiro Skills | .kiro/skills/*/SKILL.md | 1 |
| Kiro Agents | .kiro/agents/**/*.{json,md} | 14 |
| Kiro Hooks | .kiro/hooks/*.kiro.hook | 10 |
| Kiro MCP | .kiro/settings/mcp.json | 6 |
| Kiro Powers | .kiro/powers/*/POWER.md | 8 |
| Kiro Settings | .kiro/settings/*.json | 3 |
| Amp Skills | .agents/skills/*/SKILL.md | 1 |
| Amp Checks | .agents/checks/.md, .amp/settings.json | 4 |
| Roo Code Skills | .roo/skills/*/SKILL.md | 1 |
| Roo Code | .roo/rules/*.md, .roomodes, .roorules, .roo/mcp.json, .rooignore | 6 |
agnix/
├── crates/
│ ├── agnix-rules/ # Rule metadata generated from rules.json
│ ├── agnix-core/ # Validation library
│ │ ├── parsers/ # YAML, JSON, Markdown
│ │ ├── schemas/ # Type definitions
│ │ └── rules/ # Validators
│ ├── agnix-cli/ # CLI binary
│ ├── agnix-lsp/ # LSP server
│ ├── agnix-mcp/ # MCP server
│ └── agnix-wasm/ # WebAssembly bindings
├── editors/ # Neovim, VS Code, JetBrains, Zed integrations
├── knowledge-base/ # 443 rules documented
├── scripts/ # Build/dev automation scripts
├── website/ # Docusaurus documentation website
└── tests/fixtures/ # Test cases
The validation process follows these steps:
- Directory Walking (sequential) - Uses
ignorecrate to traverse directories - File Collection - Gathers all relevant file paths with exclusion filtering
- File Type Resolution -
resolve_file_type()applies[files]config overrides, then falls through todetect_file_type() - CRLF Normalization -
normalize_line_endings()converts CRLF and lone-CR to LF before validators run (zero-allocation fast path for LF-only files) - Parallel Validation - Processes files in parallel using rayon
- Result Sorting - Deterministic ordering by severity (errors first) then file path
This architecture ensures fast validation on large projects while maintaining consistent, reproducible output.
Cross-file validation rules (AGM-006, XP-004/005/006, VER-001) require analysis across multiple files to detect:
- AGM-006: Nested AGENTS.md hierarchies across different directories
- XP-004 to XP-006: Conflicting build commands, tool constraints, and instruction layers across CLAUDE.md, AGENTS.md, Cursor rules, and Copilot files
- VER-001: Missing or incomplete version pinning in .agnix.toml
Project-level validation runs:
- On workspace open (LSP
initializedevent) - After any configuration change (LSP
didChangeConfiguration) - After file save events (LSP
didSave) - Explicitly via
agnix.validateProjectRulesLSP command (VS CodeValidate Workspace)
Results are published to all affected files as diagnostics, ensuring users see context-aware feedback for cross-file issues.
resolve_file_type(path, config) determines which validators apply to a file:
- Check
[files].excludepatterns - if matched, returnUnknown(skip) - Check
[files].include_as_memorypatterns - if matched, returnClaudeMd - Check
[files].include_as_genericpatterns - if matched, returnGenericMarkdown - Fall through to
detect_file_type(path)(built-in path-based detection)
Priority: exclude > include_as_memory > include_as_generic > built-in detection.
Patterns use glob syntax, matched against paths relative to the project root. Backslashes are normalized to forward slashes for cross-platform compatibility. Invalid patterns are not silently discarded - validate_project() surfaces them as Warning diagnostics (rule config::glob) so consumers receive actionable feedback rather than seeing stderr output.
agnix implements defense-in-depth security measures:
| Feature | Implementation | Default |
|---|---|---|
| Symlink rejection | file_utils::safe_read_file() |
Always on |
| File size limits | DEFAULT_MAX_FILE_SIZE = 1 MiB |
Always on |
| File count limits | max_files_to_validate |
10,000 |
| ReDoS protection | MAX_REGEX_INPUT_SIZE = 64 KB |
Always on |
| Path traversal detection | normalize_join() in imports validator |
Always on |
See knowledge-base/SECURITY-MODEL.md for complete threat model.
All rules in knowledge-base/VALIDATION-RULES.md
Rule ID Format: [CATEGORY]-[NUMBER]
AS-nnn: Agent Skills (agentskills.io)CC-SK-nnn: Claude Code SkillsCC-HK-nnn: Claude Code HooksCC-MEM-nnn: Claude Code MemoryAGM-nnn: AGENTS.md (cross-tool instructions)CC-AG-nnn: Claude Code AgentsCOP-nnn: GitHub Copilot InstructionsCLN-nnn: Cline RulesOC-nnn: OpenCode configurationCDX-nnn: Codex CLI configurationCC-PL-nnn: Claude Code PluginsMCP-nnn: MCP protocolXML-nnn: XML validationREF-nnn: @import/reference validationPE-nnn: Prompt engineeringXP-nnn: Cross-platform compatibilityVER-nnn: Version awareness
| ID | Severity | Description |
|---|---|---|
| AS-001 | ERROR | YAML frontmatter required |
| AS-004 | ERROR | Name must be kebab-case |
| AS-010 | WARN | Missing trigger phrase |
| CC-SK-001 | ERROR | Invalid model value |
| CC-SK-002 | ERROR | Invalid context value |
| CC-SK-003 | ERROR | Context 'fork' requires agent field |
| CC-SK-004 | ERROR | Agent field requires context: fork |
| CC-SK-005 | ERROR | Invalid agent type |
| CC-SK-006 | ERROR | Dangerous skill without safety flag |
| CC-SK-007 | WARN | Unrestricted Bash access |
| CC-SK-008 | ERROR | Unknown tool name |
| CC-SK-009 | WARN | Too many dynamic injections |
| CC-HK-001 | ERROR | Invalid hook event |
| CC-HK-006 | ERROR | Missing command field |
| CC-HK-007 | ERROR | Missing prompt field |
| CC-HK-008 | ERROR | Script file not found |
| CC-HK-009 | WARN | Dangerous command pattern |
| CC-MEM-004 | WARN | Invalid command reference |
| CC-MEM-005 | WARN | Generic instruction detected |
| AGM-003 | WARN | Character limit exceeded (12000 chars) |
| AGM-005 | WARN | Platform features without guard |
| PE-001 | WARN | Critical content in middle |
| PE-002 | WARN | Chain-of-thought on simple task |
| CC-AG-001 | ERROR | Missing agent name field |
| CC-AG-002 | ERROR | Missing agent description field |
| CC-AG-003 | ERROR | Invalid model value |
| CC-AG-004 | ERROR | Invalid permission mode |
| CC-AG-005 | ERROR | Referenced skill not found |
| CC-AG-006 | ERROR | Tool/disallowed conflict |
| CC-PL-001 | ERROR | Plugin manifest not in .claude-plugin/ |
| CC-PL-002 | ERROR | Components inside .claude-plugin/ |
| CC-PL-003 | ERROR | Invalid semver format |
| CC-PL-004 | ERROR/WARN | Missing required/recommended plugin field |
| CC-PL-005 | ERROR | Empty plugin name |
| XML-001 | ERROR | Unclosed XML tag |
agnix . # Validate directory
agnix --strict . # Warnings = errors
agnix --target claude-code # Claude-specific rules
agnix --fix . # Apply HIGH and MEDIUM confidence fixes
agnix --dry-run . # Preview fixes without modifying files (respects fix mode flags)
agnix --fix-safe . # Only apply HIGH confidence fixes
agnix --fix-unsafe . # Apply all fixes, including LOW confidence
agnix --show-fixes . # Show inline proposed fix diffs in text output
agnix --format json . # JSON output for programmatic consumption
agnix --format sarif . # SARIF 2.1.0 output for CI/CD
agnix --format github . # GitHub Actions annotations
agnix explain MCP-018 # Explain a rule from rules.json
agnix --locale es . # Spanish output
agnix --list-locales # Show available localesextend = [] # Optional base config paths; TOML files may use a string or array
severity = "Warning"
target = "Generic" # Options: Generic, ClaudeCode, Cursor, Codex
locale = "en" # Options: en, es, zh-CN
tools = ["claude-code", "cursor"] # Preferred over target
[rules]
# Category toggles - enable/disable entire rule categories
skills = true # AS-*, CC-SK-* rules
hooks = true # CC-HK-* rules
agents = true # CC-AG-* rules
copilot = true # COP-* rules
cursor = true # CUR-* rules
cline = true # CLN-* rules
opencode = true # OC-* rules
memory = true # CC-MEM-* rules
plugins = true # CC-PL-* rules
mcp = true # MCP-* rules
prompt_engineering = true # PE-* rules
xml = true # XML-* rules
imports = true # REF-*, imports::* rules
cross_platform = true # XP-* rules
agents_md = true # AGM-* rules
# Legacy flags (still supported)
generic_instructions = true
frontmatter_validation = true
xml_balance = true
import_references = true
# Disable specific rules by ID
disabled_rules = [] # e.g., ["CC-AG-001", "AS-005"]
[rules.severity]
# Per-rule severity overrides, e.g. MCP-008 = "Error"
[rules]
# Disable entire validators by name
disabled_validators = [] # e.g., ["XmlValidator", "ImportsValidator"]
exclude = ["node_modules/**", ".git/**", "target/**"]
# Per-file rule overrides (array of tables).
# Each block disables `disabled_rules` for files matching any of `paths`.
# Multiple blocks stack (set union); ordering does not matter.
[[overrides]]
paths = ["CLAUDE.md", "AGENTS.md"]
disabled_rules = ["CC-MEM-005"][[overrides]] is an array of tables. Each entry has two fields:
| Field | Type | Description |
|---|---|---|
paths |
[String] |
Glob patterns matched against project-relative paths (forward-slash separators; same matcher as [files].exclude, with require_literal_separator = true). |
disabled_rules |
[String] |
Rule IDs to disable for matching files. |
For each file linted, the effective disabled-rule set is the union of [rules].disabled_rules and every [[overrides]].disabled_rules whose paths matched the file. The override mechanism is purely additive: it cannot re-enable a globally disabled rule or override a disabled category ([rules].skills = false, etc.).
Files excluded entirely via [files].exclude are skipped before any rule runs, so [[overrides]] on excluded paths is moot. A block with paths = [] is a no-op (no file is ever matched). When .agnix.toml is loaded without a project root (single-file mode), paths patterns are matched against the file name only.
extend loads one or more parent config files relative to the current config file before applying the child file. Tables merge recursively; child scalar values and arrays replace parent values.
Inline suppressions are supported for local exceptions. The configuration guide documents the exact same-line and next-line markers.
agnix validates .agnix.toml files semantically before running validation:
- Rule ID validation:
disabled_rules(in[rules]and[[overrides]]) and[rules.severity]keys must match known patterns (AS-, CC-SK-, CC-HK-, CC-AG-, CC-MEM-, CC-PL-, XML-, MCP-, REF-, XP-, AGM-, COP-, CUR-, CLN-, OC-, CDX-, PE-, VER-, imports::) - Removed rule redirects: removed rule IDs such as
AS-007,AS-010, andAS-014warn with replacement guidance fromknowledge-base/removed-rules.json - Tool validation:
toolsarray must contain valid tool names (claude-code, cursor, codex, copilot, github-copilot, cline, opencode, generic) - Glob validation:
[files].*and[[overrides]].pathspatterns must be syntactically valid glob expressions. Invalid patterns surface as warnings (CLI flow drops them at load and continues; programmaticLintConfigBuilder::build()promotes them to errors). - Override path safety:
[[overrides]].pathsentries must be project-relative. Absolute paths (/...) and traversal segments (..) surface as warnings via the CLI (the override becomes a silent no-op because the pattern can never match a project-relative path); programmaticLintConfigBuilder::build()andbuild_lenient()both reject these as hard errors at build time. - Deprecation warnings:
mcp_protocol_versionis deprecated (usespec_revisions.mcp_protocol)
Warnings are displayed before validation output with suggestions for fixes.
When target is set to a specific tool, only relevant rules run:
- ClaudeCode or Generic: All rules enabled
- Cursor or Codex: CC-* rules disabled (Claude Code specific)
| Category | Config Key | Rules | Description |
|---|---|---|---|
| Skills | skills |
AS-, CC-SK- | Agent skill validation |
| Hooks | hooks |
CC-HK-* | Hook configuration validation |
| Agents | agents |
CC-AG-* | Subagent validation |
| GitHub Copilot | copilot |
COP-* | Copilot instruction validation |
| Memory | memory |
CC-MEM-* | Memory/CLAUDE.md validation |
| Plugins | plugins |
CC-PL-* | Plugin validation |
| MCP | mcp |
MCP-* | MCP tool validation |
| Prompt Engineering | prompt_engineering |
PE-* | Prompt engineering best practices |
| XML | xml |
XML-* | XML tag balance |
| Imports | imports |
REF-* | Import reference validation |
| Cross-Platform | cross_platform |
XP-* | Cross-platform consistency checks |
| AGENTS.md | agents_md |
AGM-* | AGENTS.md-specific validation |
| Cursor | cursor |
CUR-* | Cursor project rule validation |
| Cline | cline |
CLN-* | Cline rules validation |
| OpenCode | opencode |
OC-* | OpenCode configuration validation |
| Codex CLI | codex |
CDX-* | Codex CLI configuration validation |
Version awareness (VER-*) is always active and controlled through tool_versions / spec_revisions pins.
| Metric | Target | Typical |
|---|---|---|
| Single file validation | < 100ms | < 10ms |
| 100-file project | < 500ms | ~200ms |
| 1000-file project | < 5s | ~2s |
| Peak memory | < 100MB | ~50MB |
| Binary size | < 10MB | ~5MB |
- Parallel validation: Uses rayon
par_bridge()for file processing across all CPU cores - Registry caching: ValidatorRegistry is constructed once and shared (7x speedup vs per-file)
- Import cache:
Arc<RwLock<HashMap>>shared across files reduces redundant @import parsing - Static regex patterns:
static_regex!macro (inregex_util.rs) wraps OnceLock for one-time initialization with descriptive panic messages - Directory walking: Sequential via
ignorecrate (required for .gitignore compatibility) - Deterministic output: Results sorted by severity then path for reproducible runs
[profile.release]
lto = "fat" # Link-time optimization
codegen-units = 1 # Single codegen unit for better optimization
strip = true # Strip symbols from binary
opt-level = 3 # Maximum optimization
panic = "abort" # Smaller binary, no unwindingagnix uses a dual-methodology approach for performance measurement:
CI (blocking on regression): iai-callgrind
- Measures CPU instruction counts (100% deterministic)
- Immune to system load, CPU frequency scaling, background processes
- Results are reproducible across CI runs with zero variance
- Blocks merge on regression above configurable threshold
Development (fast feedback): Criterion
- Wall-clock timing for intuitive performance understanding
- Statistical sampling for reliable measurements
- HTML reports with historical comparison
# Fast feedback during development (wall-clock)
./scripts/bench.sh criterion
# Pre-PR validation (instruction counts, matches CI)
./scripts/bench.sh iai
# Check binary size breakdown
./scripts/bench.sh bloat
# Run all benchmarks
./scripts/bench.sh alliai-callgrind reports several metrics:
| Metric | Description | What It Tells You |
|---|---|---|
| Instructions | CPU instructions executed | Primary performance metric |
| L1 Hits/Misses | Level 1 cache performance | Memory access efficiency |
| L2 Hits/Misses | Level 2 cache performance | Working set size |
| RAM Hits | Main memory accesses | Cache effectiveness |
| Estimated Cycles | Weighted cycle estimate | Overall CPU cost |
Instruction counts directly correlate with wall-clock time but without noise from:
- Background processes
- CPU frequency scaling
- VM/container overhead
- Disk I/O variance
- Linux: Full support for both iai-callgrind and Criterion
- macOS x86: Full support for both iai-callgrind and Criterion
- macOS ARM: Valgrind support is experimental; use Criterion for local development
- Windows: No Valgrind support; use Criterion only (CI runs iai on Linux)