···11+# CLAUDE.md
22+33+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44+55+## Project Overview
66+77+Shutter is a snapshot testing library for Go, inspired by Rust's [insta](https://github.com/mitsuhiko/insta) and Gleam's [birdie](https://github.com/giacomocavalieri/birdie). It provides functions for capturing test output as snapshots and tools for reviewing snapshot changes.
88+99+## Build Commands
1010+1111+```bash
1212+# Build the TUI binary
1313+just build
1414+1515+# Run tests with coverage
1616+just test
1717+1818+# Clean snapshots and run tests
1919+just clean-test
2020+2121+# Run the TUI review tool (after building)
2222+just review
2323+2424+# Run CLI review tool
2525+just cli
2626+```
2727+2828+Direct Go commands:
2929+```bash
3030+go test ./... # Run all tests
3131+go test ./... -run TestName # Run specific test
3232+go test -v ./internal/transform/... # Run tests in specific package
3333+cd ./cmd/shutter && go build -o shutter ./main.go # Build TUI
3434+```
3535+3636+## Architecture
3737+3838+```
3939+┌─────────────────────────────────────────────────────────────────┐
4040+│ Public API (shutter.go) │
4141+│ Snap() | SnapMany() | SnapString() | SnapJSON() │
4242+├─────────────────────────────────────────────────────────────────┤
4343+│ Options (scrubbers.go, ignore.go) │
4444+│ Scrubbers: text transformation before snapshot │
4545+│ IgnorePatterns: field removal (SnapJSON only) │
4646+├─────────────────────────────────────────────────────────────────┤
4747+│ Internal Modules │
4848+│ ├─ internal/snapshots/ - Core comparison logic │
4949+│ ├─ internal/files/ - Snapshot file I/O (YAML headers) │
5050+│ ├─ internal/transform/ - JSON ignore pattern application │
5151+│ ├─ internal/diff/ - Histogram diff algorithm │
5252+│ ├─ internal/pretty/ - Formatting and display boxes │
5353+│ └─ internal/review/ - Review workflow logic │
5454+├─────────────────────────────────────────────────────────────────┤
5555+│ Review Tools │
5656+│ ├─ cmd/shutter/ - TUI (Bubbletea) - separate go.mod │
5757+│ └─ cmd/cli/ - CLI review tool │
5858+└─────────────────────────────────────────────────────────────────┘
5959+```
6060+6161+**Data flow:** Test Value → Pretty format (utter) → Ignore Patterns → Scrubbers → Snapshot file
6262+6363+**Snapshot storage:** `__snapshots__/` directories contain YAML-header files with metadata (title, test_name, file_name, version) followed by `---` delimiter and content.
6464+6565+## Key Design Decisions
6666+6767+- **Option interface pattern**: `Scrubber` and `IgnorePattern` both implement `Option` for type-safe compile-time separation
6868+- **IgnorePatterns only work with SnapJSON()** - using them with Snap/SnapMany/SnapString returns an error
6969+- **TUI is a separate Go module** (cmd/shutter/) to keep Bubbletea dependencies optional
7070+- **Execution order**: Ignore patterns run first, then scrubbers
7171+7272+## Module Structure
7373+7474+- Root module (`go.mod`): Main library - Go 1.23.12+
7575+- TUI module (`cmd/shutter/go.mod`): Separate module with Bubbletea dependencies - Go 1.25.2
7676+- `/editors/`: Tree-sitter grammar for snapshot format (Node.js/Rust/Python/Swift bindings)
···11+from typing import Final
22+33+# NOTE: uncomment these to include any queries that this grammar contains:
44+55+# HIGHLIGHTS_QUERY: Final[str]
66+# INJECTIONS_QUERY: Final[str]
77+# LOCALS_QUERY: Final[str]
88+# TAGS_QUERY: Final[str]
99+1010+def language() -> object: ...
···11+//! This crate provides Snapshot language support for the [tree-sitter] parsing library.
22+//!
33+//! Typically, you will use the [`LANGUAGE`] constant to add this language to a
44+//! tree-sitter [`Parser`], and then use the parser to parse some code:
55+//!
66+//! ```
77+//! let code = r#"
88+//! "#;
99+//! let mut parser = tree_sitter::Parser::new();
1010+//! let language = tree_sitter_snapshot::LANGUAGE;
1111+//! parser
1212+//! .set_language(&language.into())
1313+//! .expect("Error loading Snapshot parser");
1414+//! let tree = parser.parse(code, None).unwrap();
1515+//! assert!(!tree.root_node().has_error());
1616+//! ```
1717+//!
1818+//! [`Parser`]: https://docs.rs/tree-sitter/0.25.10/tree_sitter/struct.Parser.html
1919+//! [tree-sitter]: https://tree-sitter.github.io/
2020+2121+use tree_sitter_language::LanguageFn;
2222+2323+extern "C" {
2424+ fn tree_sitter_snapshot() -> *const ();
2525+}
2626+2727+/// The tree-sitter [`LanguageFn`] for this grammar.
2828+pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_snapshot) };
2929+3030+/// The content of the [`node-types.json`] file for this grammar.
3131+///
3232+/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types
3333+pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");
3434+3535+// NOTE: uncomment these to include any queries that this grammar contains:
3636+3737+// pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
3838+// pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");
3939+// pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");
4040+// pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm");
4141+4242+#[cfg(test)]
4343+mod tests {
4444+ #[test]
4545+ fn test_can_load_grammar() {
4646+ let mut parser = tree_sitter::Parser::new();
4747+ parser
4848+ .set_language(&super::LANGUAGE.into())
4949+ .expect("Error loading Snapshot parser");
5050+ }
5151+}