Skip to content

Repository files navigation

fini

CI Crates.io License: MIT

A lightweight file normalization CLI tool for AI coding agents.

Standardizes file formatting as a finishing step after code editing.

Installation

Cargo

cargo install fini

Nix

nix run github:tsukasaI/fini -- .
nix profile install github:tsukasaI/fini

Homebrew

brew tap tsukasaI/fini https://github.com/tsukasaI/fini
brew install tsukasaI/fini/fini

Pre-built binaries

Download from GitHub Releases.

Pre-commit / Prek

Add to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/tsukasaI/fini
    rev: v0.3.0  # Use the latest release tag
    hooks:
      - id: fini        # Auto-fix mode
      # or
      - id: fini-check  # Check-only mode (for CI)

Note: Requires fini to be installed (cargo install fini or via Homebrew/Nix).

Usage

fini .                    # Fix current directory
fini src/main.rs          # Fix specific file
fini --check .            # Check only, exit 1 if problems
fini --diff .             # Preview changes
fini --quiet .            # Output only filenames
fini -v .                 # Verbose: show all processed files
fini --init               # Generate fini.toml template
cat file.txt | fini --stdin  # Read from stdin, output to stdout

Options

-v, --verbose           Show all processed files (including clean ones)
--stdin                 Read from stdin, output to stdout
--color                 Force colored output
--no-color              Disable colored output
--no-progress           Hide progress bar
--max-blank-lines <N>   Limit consecutive blank lines to N
--keep-zero-width       Keep zero-width characters (default: remove)
--keep-leading-blanks   Keep leading blank lines (default: remove)
--fix-code-blocks       Remove code block remnants (```lang markers)
--exclude <PATTERN>     Exclude files matching glob pattern (repeatable)
--init                  Generate fini.toml configuration template
--config <PATH>         Use specific config file

Configuration

Create fini.toml in your project root (or run fini --init):

# Exclude files matching these patterns (gitignore-style globs)
# exclude = ["vendor/", "node_modules/", "*.min.js"]

[normalize]
max_blank_lines = 2        # Limit consecutive blank lines
remove_zero_width = true   # Remove zero-width characters
remove_leading_blanks = true
fix_code_blocks = false    # Remove ``` markers

Priority

CLI arguments > fini.toml > defaults

Config Discovery

Searches upward from current directory, stops at git root.

.editorconfig

fini reads .editorconfig and warns if settings conflict with its fixed behaviors (always trims whitespace, always LF, always adds final newline).

Features

Rule Description Default
EOF newline Add \n if missing, normalize multiple trailing newlines On
Line endings CRLF/CR to LF On
Trailing whitespace Remove trailing spaces and tabs On
Full-width spaces Fix U+3000 to regular space (with warning) On
Leading blank lines Remove blank lines at file start On
Zero-width characters Remove ZWSP, ZWJ, ZWNJ, etc. (preserve BOM at start) On
Consecutive blank lines Limit to N blank lines (--max-blank-lines) Off
Code block remnants Remove ``` markers (--fix-code-blocks) Off

Inline Ignore

Suppress detections per-line with fini:ignore directives. Works with any comment syntax.

# TODO: intentional reminder fini:ignore
print("debug") # fini:ignore debug

# fini:ignore-next-line
API_KEY = "sk_test_example"
Directive Effect
fini:ignore Suppress all detections on this line
fini:ignore todo,debug Suppress only listed kinds
fini:ignore-next-line Suppress all detections on the next line
fini:ignore-next-line secret Suppress only listed kinds on the next line

Kind identifiers: todo, fixme, debug, secret, line-length, fullwidth, zero-width, leading-blanks, blank-lines, code-block

Suppressions are counted in the run summary. Suppressed secret detections are always reported on stderr with file:line (even with --quiet) so they remain auditable.

Secret detection and output

Secret detections are reported hint-only — the matched value is never printed. --diff output masks lines matching a secret pattern ([line masked: potential …]), but a secret that no pattern matches will appear verbatim in a diff: be careful publishing CI logs that include --diff output.

Disabling secret detection via fini.toml (detect_secrets = false) prints a warning to stderr that --quiet does not suppress.

Skipped

  • Binary files (null bytes in first 8KB)
  • UTF-16 and other non-UTF-8 text files (unsupported encodings)
  • Symlinks (never followed or rewritten)
  • Empty files
  • Hidden files (.foo)
  • .git/ directory
  • .gitignore patterns

Skipped binary / non-UTF-8 / symlink files are counted in the run summary; use --verbose to list them individually with the skip reason.

Claude Code Integration

Add to .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write|NotebookEdit",
      "hooks": [{
        "type": "command",
        "command": "fini \"$TOOL_INPUT.file_path\""
      }]
    }]
  }
}

GitHub Action

- uses: tsukasaI/fini@v0.4.0

Pin to a release tag as above, or to a full commit SHA for supply-chain hardening.

The action runs fini --check by default. Note that fix mode (without --check) never fails on detection-only problems (TODOs, debug code, secrets) — always use --check when gating CI.

Options

- uses: tsukasaI/fini@v0.4.0
  with:
    files: 'src/ tests/'         # Files/directories to check (default: .)
    check: 'true'                # Check mode, fail if issues found (default: true)
    version: 'v0.3.0'            # Specific version (default: latest)
    verify-attestation: 'false'  # Verify SLSA build provenance via `gh attestation verify`
                                 # (default: false). Set to 'true' once your pinned fini
                                 # version has attestations (releases after v0.3.0).

VS Code Extension

See editors/vscode for a VS Code extension that runs fini on save.

Exit codes

Code Meaning
0 Success (no problems / fix completed)
1 Problems found (--check)
2 Runtime error (I/O failure, invalid config or exclude pattern)

Fix mode (without --check) exits 0 even when detection-only problems (TODOs, debug code, secrets) are reported — they are informational there. Use fini --check as the CI gate.

Development

Pre-commit Hooks

This project uses prek for pre-commit hooks.

# Install prek
cargo install prek

# Install git hooks
prek install

# Run hooks manually
prek run --all-files

License

MIT

About

file normalization CLI tool for AI coding agents

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages