Skip to content

BrianSigafoos/fast-format-x

Repository files navigation

fast-format-x (ffx)

The only formatter your AI needs to know.

One command. Every file type. All formatters run in parallel.

Stop telling your AI agents how to auto-format your code. Give them one command, ffx, that auto-formats all changed files using the right tool for each file type. Written in Rust for speed.

Installation

Quick Install (Recommended)

Install the latest release with a single command:

curl -LsSf https://ffx.bfoos.net/install.sh | bash
# Then initialize in your repo to install the pre-commit hook
ffx init

This downloads the prebuilt binary for your platform (macOS Apple Silicon or Intel).

Manual Download

Binaries available on GitHub Releases.

Usage

# Format changed files (default)
ffx

# Format staged files only
ffx --staged

# Format files changed vs a base branch (great for PRs)
ffx --base origin/main

# Format all matching files
ffx --all

# Check mode for CI (uses check_args, exits non-zero if issues found)
ffx --check --base origin/main

# Use custom config
ffx --config path/to/.fast-format-x.yaml

# Limit parallel jobs
ffx --jobs 4

# Stop on first failure
ffx --fail-fast

# Verbose output
ffx --verbose

Pre-commit Hook

Run ffx automatically before every commit and scaffold a starter config if you don't have one yet:

ffx init

This installs a pre-commit hook that:

  1. Runs ffx on staged files
  2. Re-stages any files modified by formatters

If .fast-format-x.yaml doesn't exist, ffx init also creates a template with common formatters and a reminder to customize the tools for your repository.

AI Agent Integration

Replace multiple formatting instructions in your AGENTS.md with one line:

## Formatting

Run `ffx` to auto-format every changed file (it runs the correct formatter for each file)

Instead of teaching your AI agent about prettier, standard, rubocop, gofmt, and rustfmt, just tell it to run ffx. One command. No wasted tokens.

Configuration

Create .fast-format-x.yaml in your repo root:

version: 1

tools:
  - name: rubocop
    include:
      - "**/*.rb"
      - "**/*.rake"
    exclude:
      - "vendor/**"
    cmd: bundle
    args: [exec, rubocop, -A] # format mode (default)
    check_args: [exec, rubocop] # check mode (--check flag)

  - name: prettier
    include: ["**/*.md", "**/*.yml", "**/*.yaml", "**/*.js", "**/*.ts"]
    cmd: npx
    args: [prettier, --write]
    check_args: [prettier, --check]

  - name: ktlint
    include: ["**/*.kt", "**/*.kts"]
    cmd: ktlint
    args: [-F]
    check_args: [] # ktlint checks by default

  - name: gofmt
    include: ["**/*.go"]
    cmd: gofmt
    args: [-w]
    check_args: [-l] # list files that differ

  - name: rustfmt
    include: ["**/*.rs"]
    cmd: cargo
    args: [fmt, --]
    check_args: [fmt, --, --check]

Check Mode for CI

Use --check to verify files are formatted without modifying them.

Fast PR Checks with --base (Recommended)

For pull requests, use --base to only check files changed in the PR. This is much faster than checking all files:

# Check only files changed vs the base branch
ffx --check --base origin/main

Example GitHub Actions workflow:

- name: Check formatting
  run: |
    git fetch origin ${{ github.base_ref }} --depth=1
    ffx --check --base origin/${{ github.base_ref }}

The --base flag uses git diff <base>...HEAD to find files changed since branching, so it catches all commits in the PR.

Full Repository Check

For main branch commits or scheduled checks, verify all files:

ffx --all --check

How It Works

When --check is passed, ffx uses check_args instead of args. If check_args is not defined for a tool, it falls back to args.

If any checks fail, ffx shows a "Details" section after the summary with the full output from each failed tool, making it easy to see exactly what needs fixing.

Exit Codes

Code Meaning
0 Success
1 Formatter failure
2 Config error
3 Missing executable

Development

Contributions are welcome.

Setup

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Verify
rustc --version
cargo --version

Build and Run

# Build debug version
cargo build

# Run directly
cargo run
cargo run -- --help
cargo run -- --all

# Build optimized release
cargo build --release

Development Commands

# Check code compiles
cargo check

# Run tests
cargo test

# Format code
cargo fmt

# Lint code
cargo clippy

# Watch for changes
cargo install cargo-watch  # one-time
cargo watch -x check

Releasing

Releases are managed with cargo-release. This ensures Cargo.toml version stays in sync with git tags.

# Install cargo-release (one-time)
cargo install cargo-release

# Release a new version (updates Cargo.toml, commits, tags, and pushes)
cargo release patch  # 0.1.3 → 0.1.4
cargo release minor  # 0.1.3 → 0.2.0
cargo release major  # 0.1.3 → 1.0.0

# Dry run to see what will happen
cargo release patch --dry-run

The push triggers the GitHub Actions release workflow, which builds binaries for all platforms and creates a GitHub Release.

About

The only formatter your AI agent needs to know

Resources

License

Stars

Watchers

Forks