# Development Notes that supplement [Development](../README.md#development) in the README, which covers the `make setup` and `make ci` flow. ## Prerequisites Development assumes [mise](https://mise.jdx.dev/). The Rust version is pinned in `mise.toml`, and every Makefile target calls `cargo` of that version through `mise exec --`, so the version is the same even when mise is not activated in the shell. Besides mise, you need a C compiler (to build the tree-sitter parsers; Xcode Command Line Tools on macOS) and git (the integration tests create temporary repositories and run `git`). To use `cargo` on `PATH` without mise, add `SYSTEM_TOOLS=1`. The Rust version may then differ from `mise.toml`. ```bash make ci SYSTEM_TOOLS=1 make install SYSTEM_TOOLS=1 ``` ## Same Checks as CI The CI quality jobs (Linux and macOS) only run `make setup` and `make ci`, so a local `make ci` runs the same checks. Tests run with the default features, the same as the released binary. Clippy runs with both the default features and `--all-features`, to check the heap profiler code (the `dhat-heap` feature) as well. Quality checks, Windows tests, and the six release-target builds start independently. Windows tests use two runners: one runs `cargo test --locked --lib --bins` and `cargo test --locked --doc`; the other runs every integration target with `cargo test --locked --test '*'`. Unit and binary tests use `RUST_TEST_THREADS=8` to overlap Git and file I/O. Integration tests keep the default CPU-based concurrency because they include stress tests with processing deadlines. Both test jobs read the existing Windows build cache; the build job saves it. All profiles, features, test cases, and processing deadlines remain the same. Cargo commands get `--locked` by default. When a `[patch]` in `.cargo/config.toml` swaps in local tree-sitter crates, `Cargo.lock` changes only on your machine and `--locked` stops the build. Empty `CARGO_FLAGS` in that case, as in `make ci CARGO_FLAGS=`. After installing the binary, `make install` also writes the skills for Claude Code and Codex. `SKILL_TARGETS` selects which ones (default `claude codex`). ```bash make install SKILL_TARGETS= # no skills make install SKILL_TARGETS=claude # the Claude Code skill only ``` `make uninstall` removes only the binary and keeps the skills it wrote. After an install, check `command -v astro-sight` and `astro-sight --version`. If a mise shim is selected, `mise which astro-sight` shows the actual executable. A different copy can take precedence over the default `/usr/local/bin` installation. Set `INSTALL_PATH` to the directory containing the selected executable, for example `make install INSTALL_PATH="$HOME/.cargo/bin"`; do not replace the shim itself. The Bash, Swift, and TypeScript grammars have local patches. Their dependency versions match the vendored package versions exactly so a dependency update cannot silently bypass the patches. Update each grammar and its regression tests together. Kotlin 0.3.5 remains pinned because newer releases require an incompatible tree-sitter runtime. ## Heap Profiling With the `dhat-heap` feature, a run writes a breakdown of the heap to `dhat-heap.json` in the working directory. Use it to measure where memory goes on a large repository. ```bash mise exec -- cargo run --release --locked --features dhat-heap -- symbols --dir . ``` ## Usage Statistics Tool `tools/usage-stats` ([Usage Statistics](integrations.md#usage-statistics)) is a Cargo project separate from the root, and `make ci` does not cover it. To install it as a command, run `make -C tools/usage-stats install`. ## Releases Run **Actions > Release > Run workflow** on GitHub Actions. One run goes through the following steps in order. 1. Rewrite the version in `Cargo.toml` and `Cargo.lock`, commit it, tag it `v`, and push 2. Build 6 targets (Linux x86_64 / x86_64 musl / ARM64, macOS Intel / Apple Silicon, Windows x86_64) and create a GitHub Release with the archives and `SHA256SUMS` 3. Rewrite the formula in the Homebrew tap (`owayo/homebrew-astro-sight`) to point directly at this version's archives, and submit an update manifest to winget-pkgs The version format is `yy.m.counter` (for example `26.9.103`). The year and month follow Japan Standard Time; the counter goes back to 100 when the month changes and increases by 1 with every release within the same month. If a tag for the same version already exists, the run stops without doing anything. With `dry_run` enabled, the run only computes the next version and prints it to the log, without a commit, a tag, a build, or a release. The CI build job builds the 6 targets with the same settings on every push to main and every PR. When the repository lacks the settings for the tap or for winget-pkgs, that job prints a warning and is skipped, and the release itself does not stop. The results appear in the run's Summary. ## Reference Scan Performance With Python 3.9 or later, compare two release binaries using the same Rust toolchain and release profile: ```powershell python tools/bench-refs.py ` --baseline C:/temp/astro-before.exe ` --candidate C:/temp/astro-after.exe ` --output-directory C:/temp/astro-refs-bench --mode session --repeats 9 ``` Use `--mode session` for request times inside one persistent process per case, or `--mode cli` (the default) to include process startup. The mixed-language session case sends the three names as separate requests. The script saves deterministic inputs, checks identical stdout for every run, warms up each binary once, and alternates their order. Cases cover a name deep inside Rust `use` paths, repeated path segments, a leaf name, an absent name, ordinary shallow functions, and the mixed-language fixtures. It writes every elapsed-time and peak-working-set measurement to `samples.csv`, with medians, ranges, executable hashes, and environment metadata in `summary.json`. On Windows, the peak comes from GetProcessMemoryInfo after each CLI process exits, or after each request in session mode and includes mapped pages; it is not an allocation count. Session peaks include the warmup and earlier requests within that case. Other platforms record null for this metric. Keep generated inputs outside the repository so they do not become extra sources for reference and API analyses. Record the source revision, dependency versions, toolchain, build command, machine load, and whether the file cache was warm with the results. Compare large improvements against the full range of samples; small differences can be scheduler noise. Rust closure binding and usage-role checks still have separate ancestor walks, so these measurements do not establish linear time for every Rust reference query.