AGENTS.md · git:20261005.bf1edd9 · 2026-10-05 · sha256 46bc0ec336583400
AGENTS.md git:20261005.bf1edd9A
Immutable. This exact content never changes and is served at /api/v1/blob/46bc0ec336583400.
# Project Memory: agnix
> Linter for agent configurations. Validates Skills, Hooks, MCP, Memory, Plugins.
**Repository**: https://github.com/agent-sh/agnix
## Project Instruction Files
`AGENTS.md` is the repository instruction source. Keep directory-specific guidance
in the corresponding nested `AGENTS.md`.
## Critical Rules
1. **Rust workspace** - agnix-rules (data), agnix-core (lib), agnix-cli/agnix-lsp/agnix-mcp (binaries), agnix-wasm (WASM bindings)
2. **rules.json is source of truth** - `knowledge-base/rules.json` is the machine-readable source of truth. When adding a new rule, add it to BOTH `rules.json` AND `VALIDATION-RULES.md`. CI parity tests enforce this.
3. **Plain text output** - No emojis, no ASCII art
4. **Certainty filtering** - HIGH (>95%), MEDIUM (75-95%), LOW (<75%)
5. **Release binaries** - Compile with LTO, strip symbols
6. **Track work in GitHub issues** - All tasks tracked there
7. **Task is not done until tests added** - Every feature/fix must have quality tests
8. **Documentation** - Keep long-form docs in `README.md`, `SPEC.md`, and `knowledge-base/` (especially `knowledge-base/VALIDATION-RULES.md`). Keep `AGENTS.md` for agent instructions only.
9. **Always follow the skill/command flow as instructed** - No deviations
10. **No unnecessary files** - Don't create summary files, plan files, or temp docs unless specifically required
11. **Never merge without waiting for the `revuto-review` check to end successfully** - It might take time, but this is the major quality gate and most thorough review.
12. **You MUST follow the flow phases one by one** - If they state to use subagents, tools, or any specific method, you must follow it exactly as described.
13. **You MUST address all comments and reviews** - If reviewers leave comments, even minor ones, and even if not a requested change, you must address them all before merging. If you disagree, respond in the review comments. Minor comments must still be addressed.
14. **Use single dash for em-dashes** - In prose, use ` - ` (single dash with spaces), never ` -- ` (double dash). This does not apply to CLI flags like `--help` or `--fix`.
## Architecture
### Crate Dependency Graph
```
agnix-rules (data-only, generated from rules.json)
↓
agnix-core (validation engine)
↓
├── agnix-cli (command-line interface)
├── agnix-lsp (language server protocol)
├── agnix-mcp (MCP server)
└── agnix-wasm (WebAssembly bindings)
```
### Project Layout
```
crates/
├── agnix-rules/ # Rule definitions (build-time generated)
├── agnix-core/ # Core: parsers, schemas, validators, diagnostics
├── agnix-cli/ # CLI binary (clap)
├── agnix-lsp/ # LSP server (tower-lsp, tokio)
├── agnix-mcp/ # MCP server (rmcp)
└── agnix-wasm/ # WASM bindings for browser/runtime integrations
editors/
├── neovim/ # Neovim plugin
├── vscode/ # VS Code extension
├── jetbrains/ # JetBrains IDE plugin
└── zed/ # Zed extension
knowledge-base/ # 457 rules, 75+ sources, rules.json
tests/fixtures/ # Test cases by category
```
### Core Modules (agnix-core)
- `parsers/` - Frontmatter, JSON, Markdown parsing
- `schemas/` - Type definitions for skill, hooks, agent, mcp, cline, roo, and other tool configs
- `rules/` - Validators implementing Validator trait (40 validators)
- `config.rs` - LintConfig, LintConfigBuilder, ConfigError, ToolVersions, SpecRevisions
- `diagnostics.rs` - Diagnostic, Fix, DiagnosticLevel, ValidationOutcome, LintError (= CoreError), LintResult
- `eval.rs` - Rule efficacy evaluation (precision/recall/F1)
- `file_types/` - FileType enum, detect_file_type(), FileTypeDetector trait, FileTypeDetectorChain
- `file_utils.rs` - Safe file I/O (symlink rejection, size limits)
- `fixes.rs` - Auto-fix application engine
- `fs.rs` - FileSystem trait abstraction (RealFileSystem, MockFileSystem)
- `pipeline.rs` - `ValidationResult`, `validate_project()`, `validate_file()` -> `LintResult<ValidationOutcome>`
- `registry.rs` - ValidatorRegistry, ValidatorRegistryBuilder, ValidatorProvider, factory functions
### Key Abstractions
```rust
// Primary extension point
// Implementors must be Send + Sync + 'static (cached in registry, shared across threads)
pub trait Validator: Send + Sync + 'static {
fn validate(&self, path: &Path, content: &str, config: &LintConfig) -> Vec<Diagnostic>;
fn name(&self) -> &'static str { /* default: short type name */ }
fn metadata(&self) -> ValidatorMetadata { /* default: empty rule_ids */ }
}
// Plugin architecture for extensibility
pub trait ValidatorProvider: Send + Sync {
fn name(&self) -> &str { /* default: short type name */ }
fn validators(&self) -> Vec<(FileType, ValidatorFactory)>;
fn named_validators(&self) -> Vec<(FileType, Option<&'static str>, ValidatorFactory)> { /* default: wraps validators() with None names */ }
}
// Registry with builder pattern and runtime filtering
// Stores cached Box<dyn Validator> instances; no per-file re-instantiation
pub struct ValidatorRegistry { /* ... */ }
impl ValidatorRegistry {
pub fn builder() -> ValidatorRegistryBuilder;
pub fn with_defaults() -> Self;
pub fn validators_for(&self, file_type: FileType) -> &[Box<dyn Validator>];
pub fn total_validator_count(&self) -> usize;
pub fn disable_validator(&mut self, name: &'static str);
pub fn disable_validator_owned(&mut self, name: &str);
}
// Extensible file type detection (chain-of-responsibility)
pub trait FileTypeDetector: Send + Sync {
fn detect(&self, path: &Path) -> Option<FileType>;
fn name(&self) -> &str { /* default: short type name */ }
}
pub struct FileTypeDetectorChain { /* ... */ }
impl FileTypeDetectorChain {
pub fn new() -> Self;
pub fn with_builtin() -> Self;
pub fn prepend(self, detector: impl FileTypeDetector + 'static) -> Self;
pub fn push(self, detector: impl FileTypeDetector + 'static) -> Self;
pub fn detect(&self, path: &Path) -> Option<FileType>;
}
// Validated config construction (fields are private)
// Usage: LintConfig::builder().severity(Error).tools(vec![...]).build()?
pub struct LintConfigBuilder { /* ... */ }
impl LintConfigBuilder {
pub fn severity(&mut self, s: SeverityLevel) -> &mut Self;
pub fn target(&mut self, t: TargetTool) -> &mut Self;
pub fn tools(&mut self, t: Vec<String>) -> &mut Self;
pub fn exclude(&mut self, e: Vec<String>) -> &mut Self;
pub fn disable_rule(&mut self, id: impl Into<String>) -> &mut Self;
pub fn disable_validator(&mut self, name: impl Into<String>) -> &mut Self;
pub fn build(&mut self) -> Result<LintConfig, ConfigError>;
pub fn build_lenient(&mut self) -> Result<LintConfig, ConfigError>;
// build_unchecked() exists but is #[cfg(any(test, feature = "__internal_unchecked"))]
// __internal module exists but is #[cfg(any(test, feature = "__internal"))]
// normalize_line_endings is stable at crate root: agnix_core::normalize_line_endings
}
impl LintConfig {
pub fn builder() -> LintConfigBuilder;
}
```
### Validation Flow
```
CLI args → LintConfig → validate_project()
→ Directory walk (ignore crate, respects .gitignore)
→ detect_file_type() per file (path-based, no I/O)
→ Parallel validation (rayon)
→ Validators from registry run sequentially per file
→ Project-level checks (AGM-006, XP-004/005/006, VER-001) via rules/project_level
→ Output (text/JSON/SARIF)
```
### LSP Architecture
- Backend holds `Arc<ArcSwap<LintConfig>>` for lock-free config reads, immutable `Arc<ValidatorRegistry>`, document cache
- Validation runs in `spawn_blocking()` (CPU-bound, sync)
- Events: `did_open`, `did_change`, `did_save`, `did_close`, `did_change_configuration`, `codeAction`, `hover`
## Commands
```bash
cargo check # Compile check
cargo test # Run tests and doc tests
cargo nextest run --workspace # Optional process-per-test runner
cargo build --release # Build binaries
cargo run --bin agnix -- . # Run CLI
cargo run --bin agnix-lsp # Run LSP server
cargo run --bin agnix-mcp # Run MCP server
```
For local checks, prefer a scoped crate or integration binary, for example
`cargo test -p agnix-core --test fix_integration`. Cargo remains the local
preflight and CI default after measurement; nextest is available for optional
local runs.
The default nextest profile uses two test processes; increase `--test-threads` only within the
machine's CPU budget. Dev and test builds retain file and line backtraces with
`line-tables-only` debug information. Release profiles are unchanged.
CI runs lint and workspace merge contracts on owner PRs and pushes to main.
Owner PRs run scoped tests locally before pushing. External contributors,
the daily run, manual CI runs, PRs labeled `full-suite` before a push, and release
validation run the full test suite.
Nextest does not run doc tests; pair it with `cargo test --workspace --doc`.
## Rules Reference
457 rules defined in `knowledge-base/rules.json` (source of truth)
Human-readable docs: `knowledge-base/VALIDATION-RULES.md`
Format: `[CATEGORY]-[NUMBER]` (AS-004, CC-HK-001, etc.)
**Adding a new rule**: Add to BOTH `rules.json` AND `VALIDATION-RULES.md`. CI parity tests will fail if they drift. Each rule in `rules.json` must include complete `evidence` metadata (source_type, source_urls, verified_on, applies_to, normative_level, tests). See VALIDATION-RULES.md for the evidence schema reference. Then run `node scripts/sync-rule-bookkeeping.js` (add `--validators=N` if a new validator was registered) to update the derived locations: `total_rules` + `last_updated` in rules.json, count phrases in AGENTS.md/README.md, the `crates/agnix-rules/rules.json` mirror, and the website docs. CI enforces this with `--check` mode.
## Current State
- Production-ready with full validation pipeline (current version: the latest [GitHub release](https://github.com/agent-sh/agnix/releases))
- 457 validation rules across 40 validators
- 4200+ passing tests
- LSP + MCP servers with VS Code extension
- See GitHub issues for roadmap
## Tool Support Tiers
agnix validates 11 tools today - those with a per-tool validator in `crates/agnix-core/src/rules/`. Tier indicates support priority (higher = stricter testing and release tracking).
**Validated** (have a validator in agnix):
- **S** (test always): Claude Code, Codex CLI, OpenCode, Kiro CLI
- **A** (test on major changes): GitHub Copilot, Cline, Cursor
- **B** (test if time permits): Roo Code, amp
- **C** (community reports only): Gemini CLI
- **D** (nice to have): Windsurf
Release tracking for these is automated where the upstream publishes to GitHub: see `.github/tool-release-baselines.json` and `.github/workflows/tool-release-watch.yml`.
**Watchlist** (no validator yet; tracked manually in `knowledge-base/RESEARCH-TRACKING.md`):
- continue, Antigravity, Tabnine, Codeium, Amazon Q, Aider, SourceGraph Cody, pi
**E** (no support): Everything else - community contributions welcome via the Tool Support Request issue template.
## References
- SPEC.md - Technical reference
- knowledge-base/INDEX.md - Knowledge navigation
- https://agentskills.io
- https://modelcontextprotocol.io
## Validation scope
agnix is CPU-only Rust/WASM tooling. Choose checks for the changed behavior:
formatting, lint, tests, rule bookkeeping and parity, packaging, and review.
Use the relevant checks in `scripts/preflight.sh`; CPU-only tooling and docs do
not need a GPU gate. If a future change introduces GPU, runtime or model behavior
or related claims, require the corresponding native, model and hardware
qualification before claiming support. CPU checks cannot provide that proof.