Rust style checker with syntax and semantic analysis, plus a safe auto-fixer for deterministic, rule-driven code layout.
vibe-style enforces a strict Rust style contract with stable rule IDs (RUST-STYLE-*).
It supports:
curate: check and report violations.tune: apply safe automatic fixes, then re-check.coverage: print implemented rule IDs.
The checker implementation is the source of truth for parser- and AST-level edge cases.
Methods are listed from easiest to most advanced.
VERSION="$(curl -fsSL https://api.github.com/repos/hack-ink/vibe-style/releases/latest | grep -oE '"tag_name": "v[^"]+"' | cut -d'"' -f4)"
OS="$(uname -s)"
ARCH="$(uname -m)"
case "${OS}:${ARCH}" in
Linux:x86_64) TARGET="x86_64-unknown-linux-gnu" ;;
Darwin:arm64) TARGET="aarch64-apple-darwin" ;;
*) echo "Unsupported platform: ${OS}/${ARCH}" >&2; exit 1 ;;
esac
ASSET="vibe-style-${TARGET}-${VERSION}.tgz"
curl -fsSLO "https://github.com/hack-ink/vibe-style/releases/download/${VERSION}/${ASSET}"
tar -xzf "${ASSET}"
INSTALL_DIR="$HOME/.cargo/bin"
mkdir -p "${INSTALL_DIR}"
install -m 0755 "vibe-style-${TARGET}-${VERSION}/vstyle" "${INSTALL_DIR}/vstyle"
install -m 0755 "vibe-style-${TARGET}-${VERSION}/cargo-vstyle" "${INSTALL_DIR}/cargo-vstyle"$Repo = "hack-ink/vibe-style"
$Version = (Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest").tag_name
$Target = "x86_64-pc-windows-msvc"
$Asset = "vibe-style-$Target-$Version.zip"
Invoke-WebRequest -Uri "https://github.com/$Repo/releases/download/$Version/$Asset" -OutFile $Asset
Expand-Archive -Path $Asset -DestinationPath .
$InstallDir = "$env:USERPROFILE\.cargo\bin"
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
Copy-Item "vibe-style-$Target-$Version\vstyle.exe" "$InstallDir\vstyle.exe" -Force
Copy-Item "vibe-style-$Target-$Version\cargo-vstyle.exe" "$InstallDir\cargo-vstyle.exe" -Force
setx PATH "$env:PATH;$InstallDir"Open a new terminal after running setx.
Supported prebuilt targets:
x86_64-unknown-linux-gnuaarch64-apple-darwinx86_64-pc-windows-msvc
# Install both binaries (`vstyle` and `cargo-vstyle`).
cargo install vibe-styleAfter installation, you can use both vstyle ... and cargo vstyle ....
# Optional: install cargo-binstall once.
cargo install cargo-binstall
# Then install prebuilt binaries for this crate.
cargo binstall vibe-stylegit clone https://github.com/hack-ink/vibe-style
cd vibe-style
cargo build --releaseBinaries:
target/release/vstyletarget/release/cargo-vstyle
cargo install --path . --bin cargo-vstyleAfter installation, you can run cargo vstyle ....
# Check style.
vstyle curate
# Apply safe fixes, then re-check.
vstyle tune
# Same as tune, but fail if violations remain.
vstyle tune --strict
# Enable verbose output.
vstyle tune --verbose
# Print implemented rule IDs.
vstyle coverage# Workspace-wide.
vstyle curate --workspace
# Selected packages.
vstyle tune -p api -p db-service
# Feature flags.
vstyle tune -p api --features serde,tracing
vstyle tune -p api --all-features --no-default-featurescurate- Exit
0: no violations. - Exit
1: violations found.
- Exit
tune- Exit
0: even if unresolved violations remain. - Exit
1: unresolved violations remain and--strictis used.
- Exit
By default, curate and tune follow cargo default package selection and scan git-tracked *.rs
files inside that package scope.
CI runs vstyle curate (read-only verification) to keep feedback fast and deterministic.
Use vstyle tune locally when you want to apply safe automatic fixes (for example, via cargo make lint-fix).
Release-performance acceptance is based on the locally built vstyle binary, not on an installed
cargo-vstyle subcommand and not on debug-profile timings.
Use the checked-in harness:
cargo make bench-release-vstyleBy default the harness builds the shipping final-release profile from Cargo.toml and runs both
vstyle curate --workspace and vstyle tune --workspace --verbose inside a disposable Git
worktree at the current commit. This keeps tune from rewriting the primary checkout while still
preserving git ls-files semantics for file discovery.
Treat the checked-in self-host benchmark as a release-path regression guard, not as a universal
microbenchmark for every hotspot. On the current workspace it is usually a no-op tune; if
--verbose reports Semantic cache: 0 hit(s), 0 miss(es), that run did not enter semantic
validation and should not be used to judge semantic-path changes in src/style/semantic.rs.
Use a semantic-positive workload before drawing conclusions about semantic validation performance.
The current baseline and checkpoint history live in
docs/benchmarks/2026-03-12_vstyle-release-runtime-baseline.md.
To compare the plain release profile diagnostically:
VSTYLE_BENCH_PROFILE=release cargo make bench-release-vstylecargo make lint-vstyle remains the repo-native style gate, but it is not the release benchmark
source of truth because it routes through cargo vstyle curate --workspace and can resolve to an
installed subcommand outside the locally built binary under test.
Use the semantic-specific harness when a change targets src/style/semantic.rs or semantic
validation fallback behavior:
cargo make bench-semantic-vstyleThis harness builds the local release binary once, creates a disposable Git-tracked fixture crate
based on the tests/let_mut_reorder.rs semantic-validation shape, generates a local Cargo.lock,
and runs vstyle tune --verbose twice:
- a cold run after clearing
target/vstyle-cache/semantic - a warm rerun after restoring the original fixture sources while keeping the cache directory
Use this semantic benchmark to judge XY-95-style work; do not compare semantic-path changes only
against the self-host no-op benchmark above.
The current semantic-path baseline and follow-up history live in
docs/benchmarks/2026-03-12_vstyle-semantic-runtime-baseline.md.
The repository also tracks both benchmark harnesses through a non-blocking GitHub Actions workflow.
Use the Benchmarks workflow for periodic project-level tracking, scheduled baseline refreshes, and
manual reruns when you want artifact-backed evidence without turning performance into a PR gate.
Use direct current-worktree timings first when a local rule change makes the repository's own
sources newly fixable. The checked-in bench-release-vstyle harness builds the current binary but
benchmarks a detached HEAD worktree, so self-host drift in uncommitted files must be fixed and
committed before the harness becomes authoritative again.
Use the release benchmark for general workspace-scan, fix-engine, import, module, spacing, or
quality-path changes. Use the semantic benchmark for src/style/semantic.rs, semantic cache key
changes, or semantic-validation fallback changes. Run both when a change touches both lanes.
The operational runbook for selecting the right benchmark evidence lives in
docs/guide/benchmark_tracking.md.
There is currently no user configuration file. Rules are built into the checker.
VSTYLE_MAX_IMPORT_SUGGESTION_ROUNDS- Controls how many semantic missing-import suggestion rounds
vstyle tunewill perform. - Default:
2. - Increasing this may fix more missing-import cases but will run additional
cargo check --message-format=jsonrounds.
- Controls how many semantic missing-import suggestion rounds
--verboseprints semantic cache hit/miss statistics for each command.- Cache files are written under
target/vstyle-cache/semantic/and keyed by:- vstyle version metadata,
rustc -Vvoutput,Cargo.lockhash,- selected cargo options,
- tracked
*.rsfile fingerprints.
RUST-STYLE-FILE-001: Do not usemod.rs; use flat module files.
RUST-STYLE-MOD-001: Keep top-level item order asmod,use,macro_rules!,type,const,static,trait,enum,struct,impl,fn.RUST-STYLE-MOD-002: Placepubitems before non-pubitems within the same kind. Visibility boundaries define separate batches and must be separated by exactly one blank line.RUST-STYLE-MOD-003: Place non-asyncfunctions beforeasyncfunctions at the same visibility.RUST-STYLE-MOD-004: Do not document modules with outer doc comments on themoddeclaration; place module docs inside the module with//!.RUST-STYLE-MOD-005: Keep each type adjacent to relatedimplblocks, with no blank line between the type and its firstimpl.RUST-STYLE-MOD-007: In#[cfg(test)] mod tests, remove unuseduse super::*;keep-alive imports duringtune.
RUST-STYLE-SERDE-001: Do not use#[serde(default)]onOption<T>fields.
RUST-STYLE-IMPORT-001: Group imports in this order: standard library, third-party, self/workspace/local-module roots.RUST-STYLE-IMPORT-002: Use exactly one blank line between groups; do not use import-group header comments; normalizeuse a::{b, b::c}touse a::{b::{self, c}}.RUST-STYLE-IMPORT-003: Do not alias imports, exceptas _keep-alive imports. Trait imports used only for method resolution must useas _.RUST-STYLE-IMPORT-004: Do not import free functions or macros into scope; use qualified paths. If imported symbols are ambiguous, use fully qualified paths.RUST-STYLE-IMPORT-005: Inerror.rs, do not adduseimports.RUST-STYLE-IMPORT-007: Do not use glob imports (use ...::*or equivalent). Use explicit imports only.RUST-STYLE-IMPORT-008: For non-function, non-macro symbols in type paths and#[derive(...)]attributes, prefer unqualified usage withuseimports when unambiguous; keep fully qualified paths when ambiguous.RUST-STYLE-IMPORT-009: If a symbol is both imported and also used via other qualified type paths, stop importing that symbol and use fully qualified paths consistently.RUST-STYLE-IMPORT-010: Do not usesuperorselfimport prefixes. Rewritesuperimports to crate-absolute imports (use crate::...) when module depth allows it, and rewriteself::...imports to direct module paths.RUST-STYLE-IMPORT-011: Order#[derive(...)]entries like imports:std/core/allocfirst, then third-party derives, then workspace derives; alphabetize within each group.RUST-STYLE-IMPORT-012: Do not add crate keep-alive importsuse dep as _;unless another path in the same package uses that crate.
RUST-STYLE-IMPL-001: UseSelfinstead of concrete type names inimplmethod signatures.RUST-STYLE-IMPL-003: Keepimplblocks contiguous and ordered as inherent, standard-library traits, third-party traits, then workspace-member traits.RUST-STYLE-GENERICS-001: Move trait bounds towhere; do not use inline bounds.RUST-STYLE-GENERICS-002: Remove unnecessary turbofish when the type is already explicit in aletbinding.RUST-STYLE-GENERICS-003: Canonicalize turbofish paths toType::<Args>::Assocform.RUST-STYLE-TYPE-001: Do not add type aliases that are only pure renames.RUST-STYLE-LET-001: Place immutableletbindings before mutable ones when the reorder is semantically safe.
RUST-STYLE-LOG-002: Use structured logging fields and complete-sentence log messages.RUST-STYLE-RUNTIME-001: Do not useunwrap()in non-test code.RUST-STYLE-RUNTIME-002:expect()must use a clear, user-actionable string literal message.
RUST-STYLE-NUM-001: Separate numeric literal suffixes with an underscore (for example,10_f32).RUST-STYLE-NUM-002: Use underscore grouping for integers with more than three digits.
RUST-STYLE-READ-002: Keep functions at or under 120 lines.RUST-STYLE-SPACE-003: Do not insert blank lines within the same statement type. Use exactly one blank line between different statement types. Keep constant declaration groups compact only within the same visibility batch.RUST-STYLE-SPACE-004: Insert exactly one blank line before eachreturnand before final tail expressions unless the body is a single expression.
RUST-STYLE-TEST-001: Use descriptivesnake_casetest names.RUST-STYLE-TEST-002: Reserve#[cfg(test)] mod _testfor keep-alive imports only.
This repository uses cargo make tasks from Makefile.toml.
# Format.
cargo make fmt
cargo make fmt-check
# Lint (clippy + vibe-style).
cargo make lint
# Rust-only clippy.
cargo make lint-rust
# vibe-style only.
cargo make lint-vstyle
# Rust tests.
cargo make test-rust
# Full checks.
cargo make checksLicensed under GPL-3.0.