# CLAUDE.md - AI Assistant Guide for Mehen

## Project Scope
- `mehen` is a **CLI-only** Rust project focused on code analysis and metrics.
- The analyzer/engine/CLI code is **not** a library or API for external use; it is internal to the CLI tool. The sole exception is the generated-only `crates/mehen-<lang>-parser/` crates, which are intentionally **publishable** so external tools can consume the vendored ANTLR parsers standalone (they carry no mehen-specific logic — just the generated lexer/parser + grammar on `antlr4_runtime`).

## Repository Structure (current)
- `crates/mehen-cli/`: CLI binary (entry point, command routing, exit codes).
- `crates/mehen-engine/`: pipeline orchestration (`run_diff`, `run_top_offenders`, registry, language detection).
- `crates/mehen-core/`: parser-neutral domain types and the `LanguageAnalyzer` trait.
- `crates/mehen-metrics/`: shared metric formulas, accumulators, and finalization helpers.
- `crates/mehen-<lang>/`: per-language analyzers — each owns parsing (walker) and metric interpretation. Tree-sitter-backed languages keep their own `grammar.rs`; ANTLR-backed ones (e.g. `mehen-kotlin`, `mehen-java`, `mehen-csharp`) depend on a separate generated-only crate `crates/mehen-<lang>-parser/` that holds the vendored grammar + generated lexer/parser.
- `crates/mehen-<lang>-parser/`: generated-only, **publishable** crates holding the ANTLR-generated lexer/parser + vendored `.g4` grammar for an ANTLR-backed language (`mehen-kotlin-parser`, `mehen-java-parser`, `mehen-csharp-parser`). Split out so external tools can depend on just the parser via a git tag (the way this repo consumes ruff/oxc/sqruff). They depend only on `antlr4_runtime`.
- `crates/mehen-tree-sitter/`: shared tree-sitter wrapper and CST traversal helpers.
- `crates/mehen-antlr/`: shared support for ANTLR-backed analyzers — re-exports the `antlr4_runtime` runtime and provides span conversion (char→byte), recovered-error diagnostics, and hidden-channel comment (CLOC) extraction.
- `crates/mehen-markdown/`: Markdown analyzer with embedded-code dispatch via `LanguageDispatcher`. Backed by `pulldown-cmark` (not tree-sitter): its `src/syntax_tree.rs` reifies the event stream into a small owned tree whose node kinds are a hand-authored enum in `src/kind.rs` — there is no generated `grammar.rs` here.
- `crates/mehen-sql/`: SQL analyzer (sqruff-backed). Like Markdown, it publishes a dedicated flat-key family (`sql.*`) instead of the source-code metric families; the sqruff CST is confined to `facts.rs` behind a parser-neutral `SqlFileFacts` adapter.
- `crates/mehen-git/`, `crates/mehen-report/`: git operations and rendering (JSON, GitHub Markdown).
- `xtask/`: developer-only commands (kind-enum codegen, AST dumps, audits).
- `docs/`: Mintlify documentation site (replaces the legacy `mehen-book/`).

## Build and Lint
Run from repo root:

```bash
cargo check
cargo build
cargo fmt --all
cargo clippy --all-targets --all-features --locked
```

For dead-code cleanup work, use:

```bash
cargo clippy --all-targets --all-features --locked -- -W dead_code -W unreachable_pub
```

## Testing (nextest-first)
Use `nextest` by default when available.

Detection + fallback:

```bash
if cargo nextest --version >/dev/null 2>&1; then
  cargo nextest run --all-features
else
  cargo test --all-targets --locked
fi
```

## Snapshot Tests (`insta`)
`insta` is heavily used in metric tests.

Always pass `--workspace`. Without it, `cargo insta` only runs tests
from the default-member (`mehen-cli`) and reports every other crate's
snapshots as `unreferenced`, making `--unreferenced reject` falsely fail.

Check snapshots (CI-style):

```bash
cargo insta test --workspace --all-features --check --unreferenced reject --test-runner nextest --no-test-runner-fallback --disable-nextest-doctest
```

Update snapshots intentionally:

```bash
cargo insta test --workspace --all-features --review --test-runner nextest --no-test-runner-fallback --disable-nextest-doctest
```

## Language/Grammar Changes
Hard rule: never edit `crates/mehen-*/src/grammar.rs` directly. These files are generated by `cargo xtask tree-sitter generate <language>` and direct edits will be overwritten on the next regeneration. CI runs `cargo xtask tree-sitter check-generated` to catch drift. (This applies only to tree-sitter-backed crates. `mehen-markdown` is `pulldown-cmark`-backed and has no `grammar.rs`; its node-kind enum in `src/kind.rs` is hand-authored and edited directly.)

When adding or updating a tree-sitter-backed language:
1. Pin the grammar in the owning `crates/mehen-<lang>/Cargo.toml` (and in `xtask/Cargo.toml` so the codegen links the same version).
2. Add a `GeneratorTarget` entry to `xtask/src/tree_sitter.rs::TARGETS`.
3. Run `cargo xtask tree-sitter generate <lang>` and commit the resulting `grammar.rs`.
4. Register the analyzer in `mehen-engine`'s registry (`crates/mehen-engine/src/registry.rs`).
5. Add per-language metric tests under `crates/mehen-<lang>/tests/`.

ANTLR-backed languages (e.g. Kotlin, Java, C#) follow the same hard rule for generated code, but the generated modules now live in the dedicated `crates/mehen-<lang>-parser/` crate: never edit `crates/mehen-<lang>-parser/src/generated/*.rs` or the JSON sidecars beside them — they are produced by `cargo xtask antlr generate <lang>` from the vendored `.g4` grammar in `crates/mehen-<lang>-parser/grammar/`. Each generated `.rs` self-wraps in a `#[rustfmt::skip] mod __antlr4_rust_generated` and is loaded via `#[path] pub mod` from the parser crate's `lib.rs`. xtask links the workspace-pinned `antlr-rust-codegen` crate directly, so no external generator binary is needed; keep its pin in lockstep with `antlr-rust-runtime`. `cargo xtask antlr check-generated` always guards drift (`.rs`, JSON sidecars, and parser-crate README). Generation always uses the equivalent of `--sem-unknown error --require-full-semantics`: every grammar semantic helper must be lowered via the target's `grammar/patterns.toml` (pure pattern or typed hook), hook-implemented grammar options acknowledged via the target's `option_hooks`, and `hook` lowerings backed by a hand-written port in the parser crate's `src/hooks.rs` (installed with `with_typed_hooks`; see `mehen-java`). See `docs/developers/new-language.mdx` ("Adding an ANTLR-backed language") and `crates/mehen-kotlin-parser/grammar/PROVENANCE.md`.

## Coding Expectations
- Keep internals internal (`pub(crate)`/private) unless a real external API is needed.
- Prefer explicit imports over wildcard re-exports.
- Avoid dead code; this is a CLI-focused codebase.
- Preserve deterministic metric behavior across platforms.

## Useful References
- `README.md`
- `AGENTS.md`
- `docs/developers/new-language.mdx`
