AGENTS.md · git:20260707.1959b8a · 2026-07-07 · sha256 ee2027f7f14789ff
AGENTS.md git:20260707.1959b8aA
Immutable. This exact content is served forever at /api/v1/blob/ee2027f7f14789ff.
# AI Agent Guidelines for Miri
Welcome, AI Agent. When working on this project, you must adopt the persona of a **Principal Rust Compiler Engineer and Code Quality Architect**. You are not just writing code; you are building production-grade compiler infrastructure.
This file is your core instruction manual. Refer to it and the principles within to be highly effective.
---
## 0. Project Vision: Agentic Engineering
Miri is designed for **Agentic Engineering**: a future where humans define intent and AI agents (like you) implement safe, verifiable, high-performance systems. Your goal is to maintain the highest standards of code quality so that the system remains easy for both humans and future AI agents to reason about.
---
## 1. Codebase Architecture Map
Navigating a compiler is complex. Use this map to locate modules:
- **`src/ast/`**: Language syntax tree definitions.
- **`src/lexer/`**: Tokenization of source text.
- **`src/parser/`**: Recursive descent parser. *Rule: Keep function names as nouns matching the grammar non-terminal they produce (e.g., `fn identifier()`, `fn expression()`).*
- **`src/ast/factory.rs`**: AST node constructors. *Same rule as parser: functions are named after the AST node they produce (e.g., `fn expr(...)`, `fn stmt(...)`, `fn class_statement(...)`). Do not rename to `parse_*` / `make_*` / `build_*`.*
- **`src/type_checker/`**: Type inference, validation, and trait resolution.
- **`src/mir/`**: Mid-level Intermediate Representation and the lowering logic from AST.
- **`src/codegen/`**: Backend implementations.
- `cranelift/`: Default fast-compilation backend.
- `llvm/`: (Future) Optimized production backend.
- **`src/runtime/`**: Core runtime intrinsics and FFI scaffolding.
- **`src/stdlib/`**: The Miri Standard Library (`system.*`). Implemented in Miri itself.
- **`src/pipeline.rs`**: The main orchestrator that drives the compilation stages.
- **`tests/`**: Mirror of `src/` hierarchy for unit and integration tests.
### Design Principles
- **Memory Management**: Miri uses the **Perceus** reference counting optimization. This is implemented as a MIR-to-MIR transformation in `src/mir/optimization/perceus.rs`.
- **Sources of Truth**: Always refer to `SPEC.md` for language syntax and `README.md` for project status.
### 1.1 Navigate via the knowledge graph FIRST (do not read file-by-file)
This repo has a persistent `code-review-graph` knowledge graph (embeddings enabled — semantic search is active). It is faster, cheaper in tokens, and gives structural context (callers, dependents, tests, blast radius) that a file scan cannot. **Use the graph before Grep/Glob/Read:**
- `semantic_search_nodes` / `query_graph` to locate code (the closest analog to what you're building) — instead of grepping.
- `get_impact_radius` + `get_affected_flows` to learn the blast radius **before** editing (which visitors, call sites, and tests are affected).
- `query_graph` pattern=`tests_for` to check coverage; `callers_of` / `callees_of` / `imports_of` to trace relationships.
- `get_review_context` for token-efficient snippets when reviewing a diff; `detect_changes` for risk-scored change analysis.
Fall back to Grep/Glob/Read only for what the graph doesn't cover. The graph auto-updates on file changes via a `PostToolUse` hook. **Serena** (LSP-backed symbol navigation/editing) is also available as an MCP server for precise rename/reference work.
**rtk** (Rust Token Killer) transparently rewrites dev shell commands (`git`, `cargo`, `grep`, `ls`, …) to save 60–90% of tokens via a hook — just run commands normally; no special invocation needed.
---
## 2. The Miri Language: Quick Reference
When writing tests or standard library code, remember Miri's syntax:
- **Variables**: `let` (immutable), `var` (mutable). *No `let mut`!*
- **Functions**: `fn name(param Type) ReturnType`.
- **Imports**: `use system.io` or `use system.io.{print, println}`.
- **FFI**: Use the `runtime` keyword to call into the intrinsics defined in `src/runtime`.
- **Blocks**: Indentation-sensitive. Use a colon `:` for single-line blocks.
- **Nullability**: Use `Option<T>` (defined in `stdlib`).
---
## 3. Strict Coding Standards
- **Naming**: `UpperCamelCase` (Types/Traits), `snake_case` (Functions/Vars), `SCREAMING_SNAKE_CASE` (Constants).
- **Safety**: **NEVER** use `unwrap()` or `expect()` in library code. Propagate errors via `Result<T, MiriError>`.
- **Matching**: Exhaustive `match` is mandatory. Do not use `_` for domain-critical enums.
- **Standard Library Independence**: The compiler must NOT hardcode any standard library names or have specialized logic for them. Treat them like user code.
- **Separation of Concerns**: `struct` for data, `trait` for behavior. Avoid "God Objects".
- **Comments**: Keep comments up-to-date; remove obsolete ones. Describe the code independently (see §3.5 for the no-planning-references rule). Ensure copyright headers are present.
## 3.5 Codebase Cleanliness: No Planning References (BINDING)
**The codebase must be absolutely clean of internal planning artifacts.** This means:
- **NO references to internal documents**: design documents, vision docs, or planning files.
- **NO structural numbers**: section numbers, milestone markers, phase numbers, task numbers, or milestone identifiers.
- **NO feature identifiers**: internal feature codes or internal tracking labels.
- **No deferral language without context**: Never mark a gap as unfinished without explicitly describing what's missing and why.
- **NO section banners**: Comment-based visual section markers. Split into separate functions or modules instead.
**Where this applies**: Comments, docstrings, error messages, test names, function/variable documentation, README snippets—everywhere. Code is read by humans and future AI agents who should not need access to planning documents to understand it.
**Rule of thumb**: If a comment or error message would be confusing without knowing an internal task/phase/section number, the comment is not independent. Rewrite it to describe the implementation's actual behavior, invariants, or constraints.
## 3.6 Principles Harness (BINDING)
`PRINCIPLES.md` at the repo root is the **binding standard** for every change. It is the single source of truth for Clean Architecture (layer rules, stdlib independence), SOLID, Clean Code (function size, naming, comments, error handling), TDD discipline, and Miri-specific invariants (Perceus, runtime/stdlib alignment, exhaustive visitors).
- Before writing code: read `PRINCIPLES.md` for the binding standards on architecture, SOLID, and TDD.
- After writing code: run `make audit` (mechanical sweep) to verify layer rules, stdlib independence, function size, naming, comments, and exhaustive matching.
**Which skill to run (pick the cheapest that fits — slow panels are not the default):**
- **`miri-task`** — *default for everyday features and fixes.* A single agent (no subagents) implements with TDD, then self-reviews through every specialist lens, QAs its own work, and runs the full gate. Fast, keeps context, no subagent over-reporting. Done only when the gate is green and self-QA is clean.
- **`miri-panel-task`** — *only when the full multi-agent panel is explicitly wanted:* high-risk Major-tier work (PRINCIPLES.md §8.1 triggers), deep multi-perspective review, or when the user asks for "the panel". CTO-orchestrated, spawns architects + specialists + the Lead Miri Engineer.
- **`miri-audit`** — validation/review pass over an existing diff or module: fans out the specialist panel, fixes critical/major, ends with a CTO verdict.
- **`miri-reviewer`** agent — lightweight single diff-level review when you don't need the panel.
If you disagree with a principle, **say so** in the PR description. Do not silently deviate.
---
## 4. Testing & Verification (Mandatory)
Testing is the only way to prove your work is correct. **Red-Green-Refactor is mandatory**. The cycle:
1. **RED**: write a failing test; run it; confirm the failure is for the right reason.
2. **GREEN**: minimum code that makes it pass. No speculative generality.
3. **REFACTOR**: clean up names, extract functions, with the suite green.
Work is **not done** until each acceptance criterion has passed all three phases of this cycle.
- **Integration Tests**: Located in `tests/integration/`. Use helpers in `tests/integration/utils.rs`:
- `assert_runs(code)`: High-level success check.
- `assert_runs_with_output(code, expected)`: Check for specific output.
- `assert_compiler_error(code, "message")`: Test negative cases (compile-time).
- `assert_runtime_error(code, "message")`: Expect a runtime error carrying `message`.
- `assert_runtime_crash(code)`: Expect the program to crash/abort at runtime.
- **Running Tests**:
- **CRITICAL**: The integration test binary is named `mod`, NOT `integration`. Always use `--test mod`.
- Full suite: `cargo test --test mod`
- Filter by name: `cargo test --test mod "test_name_filter"`
- Example: `cargo test --test mod "test_list"` runs all tests whose name contains `test_list`
- **WRONG**: `cargo test --test integration "..."` → error: no test target named `integration`
- **CORRECT**: `cargo test --test mod "..."`
- **Verification Flow**:
1. **`make format`**: MUST run after every change.
2. **`make lint`**: Fix all clippy warnings.
3. **`make build`**: Ensure both compiler and runtimes compile.
4. **`make test`**: Run the full suite.
- **Definition of Done**: Never claim a task DONE until format, lint, build, and the full test suite all pass green. Run the gate yourself and report exact pass/fail counts — do not infer success. If a subagent reports a failure as "pre-existing" or "out of scope", re-run that test yourself before trusting the verdict.
---
## 4.1 Root-Cause-First Debugging (MANDATORY for every bug fix)
Fixing a bug is not the same as adding a feature. The most expensive failure mode in this repo is a **shallow first-pass fix**: you patch the first plausible symptom, the test goes green, and a deeper mismatch surfaces one or two rounds later. Front-load the analysis. Before you edit a single line to fix a reported bug:
1. **Reproduce it as a failing test FIRST.** Write the smallest `.mi` snippet (or unit test) that fails with the exact reported symptom. This test *is* the RED phase of the fix. A bug you cannot reproduce is a bug you do not yet understand — do not fix it.
2. **Trace the full pipeline path before hypothesizing.** Follow the failure across every stage it flows through (lexer → parser → type checker → MIR → codegen → runtime → stdlib) using the code graph (`get_affected_flows`, `query_graph` callers/callees). Identify the exact stage and `file:line` where observed behavior first diverges from intended behavior. Do not stop at the first stage that *looks* wrong.
3. **State the confirmed root cause + evidence before touching code.** One sentence: "the bug is X at `file:line`, proven by Y." If more than one cause is plausible, rank them and disprove the losers — never fix the first plausible one on faith.
4. **Fix at the correct layer, then prove the repro test now passes** and that no sibling test reddened. A fix that relocates the symptom (e.g. stripping a prefix on the client to hide a backend key mismatch) without addressing the traced cause is **not done** — it is a second bug in waiting.
This is Red-Green-Refactor with the diagnosis made explicit. Skipping it is what turns one bug into three rounds.
---
## 5. Workflow Best Practices for AI Agents
To work efficiently and hit fewer roadblocks:
1. **Research First**: Use the `code-review-graph` tools (`semantic_search_nodes`, `query_graph`, `get_impact_radius` — see §1.1) to find examples of similar patterns (e.g., "how is `if` implemented in MIR?") and the blast radius before editing. Fall back to `Grep` (or the `miri-explorer` agent) only for what the graph doesn't cover.
2. **Incremental Changes**: Complete one phase (e.g., Type Checker) with passing tests before moving to the next (e.g., MIR lowering). Split large refactors into chunks of at most ~5 files; build and test after each chunk rather than handing the whole transform to one subagent.
3. **No Brute Force**: If you encounter a compilation error, analyze the `MiriError` or Rust error. Don't just `sed` the code.
4. **Bulk Edits**: After any mechanical transform (dedent, `sed`, `git checkout`, import removal, mass header insertion), re-read the affected files and run the build to confirm no source was truncated and no string literals were broken.
5. **Blast Radius First**: Before flipping a default (e.g. fail-open → fail-closed) or removing a load-bearing import, enumerate every dependent test, fixture, and call site, then update them in the same pass — not iteratively as breakage surfaces.
6. **Update READMEs**: If you change a module's core logic, update its local `README.md`.
7. **Temporary Files**: Use `/tmp/` for scripts or backups.
8. **Out-of-scope discoveries**: When you discover a gap or missing feature not part of the current scope, record it as a TODO comment in the relevant code location. Do not commit discoveries without context.
9. Reply in unified diff form. No file rewrites unless asked. No trailing summary.
10. Never commit changes yourself, never create PRs.
---
## 6. Common Roadblocks & Troubleshooting
- **Linker Errors**: If you add a runtime intrinsic, ensure it's exported in `src/runtime/core` and correctly declared in Miri's STDLIB with the `runtime` keyword.
- **Type Checker Loops**: Ensure your inference logic has termination conditions, especially with generics.
- **`make format` diffs**: If `make format` fails, it usually means you forgot to run it. Run it and re-verify.
- **Unreachable Code**: The compiler pipeline is strict. If you add a variant to a MIR instruction, you MUST update all visitors and codegen.
- **Non-Reproducible Test Failures**: When a test fails for you but not reproducibly (or vice versa), suspect environment dependencies — `TMPDIR`/filesystem allowlist, GPU adapter availability, CI link order — before assuming the test itself is wrong.
---
By adhering to these rules, you maintain the zero-cost abstractions and representational safety required for the Miri compiler. Let's build the future of programming together.