# Format Code

> Format, clean up, and style-check changed files, matching the project's CI style gate. Formats Python with black + ruff and C/C++ with clang-format using the repository's .clang-format, and can also run check-only to reproduce the CI gate locally without editing files. Use when the user says "format code", "clean up code", "lint", "format before commit", "/format-code", wants to reproduce the "Check Python Code Style" or "Check C++ Code Style" CI jobs locally, is fixing a CI style failure, is about to push Python or C/C++ changes, or mentions black, ruff, or clang-format.

- Skill: `rocm/format-code` (Agent Skill)
- Install (CLI): `npx skillmds@latest add rocm/format-code`
- Raw SKILL.md: https://api.skillmd.com/api/skills/rocm/format-code/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: rocm (https://skillmd.com/u/rocm)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/rocm/format-code

---


# Format Code

Format and clean up changed files before committing. Prefer repository-provided style
wrappers when they exist, because they encode the same file selection and tool flags as CI.
For FlyDSL, use `bash scripts/check_python_style.sh --fix` for Python style fixes.

If there is no project wrapper, operate only on files that are staged (`git diff --cached`)
or modified in the working tree (`git diff`), so unchanged files are never touched.

## Pipeline

For each changed file, the pipeline runs in order:

1. **Project wrapper**: run the repo's style script when present, e.g. FlyDSL's `scripts/check_python_style.sh --fix`
2. **Python (.py)**: `ruff check --fix` (remove unused imports/variables, sort imports) -> `black` (format)
3. **C/C++ (.c, .cc, .cpp, .cxx, .h, .hh, .hpp, .hxx, .cu, .cuh)**: clang-format using the repository's `.clang-format`

## Steps

### 1. Prefer the project wrapper

First check whether the repo has a formatter wrapper. In FlyDSL, run:

```bash
bash scripts/check_python_style.sh --fix
```

This wrapper runs `black -> ruff check --fix -> black` on the committed diff, exactly matching
CI. If it succeeds, inspect the resulting diff and skip the generic Python steps below unless
additional non-Python formatting is still needed. If required tooling is missing, use the
repo's install option, e.g. `bash scripts/check_python_style.sh --install`.

### 1b. C/C++ has its own CI gate

CI runs two style jobs from `.github/workflows/pre-checks.yaml`: `python-style`
("Check Python Code Style") and `cpp-style` ("Check C++ Code Style"). The C++
job runs `./.github/scripts/check_cpp_style.sh`, which clang-format-*checks*
(does not rewrite) the C/C++ files in the diff. Reproduce it locally:

```bash
# Match what CI sees on a PR branch
BASE_SHA=origin/main CLANG_FORMAT=clang-format-18 bash .github/scripts/check_cpp_style.sh
```

Without `BASE_SHA`, the script falls back to `HEAD^`, so it checks only the last
commit rather than the whole branch. It also diffs **committed** revisions only:
with no C/C++ files in that range it prints "No changed C++ files to check" and
exits 0, so uncommitted edits pass locally and then fail in CI. Commit (or stage
and amend) before trusting a green result. It reports offenders; use the in-place
`clang-format-18 -i` steps below to fix them, and for files outside the diff range.

### 2. Ensure generic tools are installed

Check each tool and install any that are missing. Match the versions CI uses so local output
matches the CI gate: FlyDSL's CI runs `clang-format-18`.

```bash
# Check availability
command -v black &>/dev/null || NEED_PY=1
command -v ruff &>/dev/null || NEED_PY=1
command -v clang-format-18 &>/dev/null || command -v clang-format &>/dev/null || NEED_CF=1

# Install if needed
if [ -n "$NEED_PY" ]; then
  pip install black ruff
fi
if [ -n "$NEED_CF" ]; then
  sudo apt-get install -y clang-format-18 2>/dev/null || pip install clang-format
fi
```

### 3. Collect changed files

Gather the union of staged and unstaged changed files (no duplicates):

```bash
(git diff --name-only --cached; git diff --name-only) | sort -u
```

If no files are changed, tell the user there is nothing to format and stop.

### 4. Format Python files

For every `.py` file in the changed set (run from the repo root so `pyproject.toml` config is
picked up). This mirrors CI, which checks `black` formatting and `ruff check` (rules E/W/F/I):

```bash
# Remove unused imports/variables and sort imports, then format
ruff check --fix "$file"
black "$file"
```

### 5. Format C/C++ files

For every `.c`, `.cc`, `.cpp`, `.cxx`, `.h`, `.hh`, `.hpp`, `.hxx`, `.cu`, `.cuh` file in the
changed set. Do **not** pass `--style`: clang-format reads the repository's `.clang-format`
(FlyDSL uses LLVM style with ColumnLimit 100), which is what CI checks. Prefer the CI version:

```bash
${CLANG_FORMAT:-clang-format-18} -i "$file"
```

### 6. Inspect diff and report summary

Always inspect the diff after automatic fixes. Ruff can remove variables that appear unused
after simplifying a branch, but those variables may have been intentionally preserving a
compile-time decision or local readability. If an auto-fix changes behavior instead of only
format/import hygiene, restore the behavioral logic and rerun the formatter.

After formatting, print a summary listing:
- How many Python files were cleaned and formatted
- How many C/C++ files were formatted
- The names of all formatted files

If any files were staged before formatting, remind the user to re-stage them
(`git add <files>`) since the in-place edits made them show as modified again.

## Check only (reproduce the CI gate without editing files)

When the user wants to know whether the `Check Python Code Style` or `Check C++ Code Style`
CI job will pass -- before
pushing, or when that job has already failed -- run the wrapper without `--fix` so nothing is
modified:

```bash
# Python gate
bash scripts/check_python_style.sh            # check committed Python diff vs origin/main (matches CI)
bash scripts/check_python_style.sh --install  # install the black/ruff versions CI uses, if missing

# C++ gate (see 1b -- committed revisions only, so commit before trusting a pass)
BASE_SHA=origin/main CLANG_FORMAT=clang-format-18 bash .github/scripts/check_cpp_style.sh
```

What it checks:

- By default it only checks the committed branch range (`origin/main`..HEAD), matching what CI
  sees on a pushed branch.
- Add `--include-local` to also check uncommitted, staged, and untracked Python files:
  `bash scripts/check_python_style.sh --include-local`.

To fix what the check reports, re-run with `--fix` (the formatting path above); add
`--include-local` to also format local uncommitted/untracked files:

```bash
bash scripts/check_python_style.sh --fix
bash scripts/check_python_style.sh --fix --include-local
```

If local checks pass but PR CI still flags unrelated files, the PR branch is likely behind
`main`. Fetch `origin/main`, merge it into the PR branch when appropriate, rerun the check,
then push the merge commit.

## Notes

- This skill never adds or removes files from git staging -- it only modifies file contents in place.
- Files that are not Python or C/C++ are silently skipped.
- In FlyDSL, `scripts/check_python_style.sh --fix` is the source of truth for CI Python style.
  It checks the committed Python diff against `origin/main`; use `--include-local` when the
  user explicitly wants uncommitted or untracked Python files included too.
- `ruff check --fix` removes unused imports (F401) and simple unused variables (F841) and sorts
  imports (I). It does not remove unused functions or classes -- that requires manual review.
- black and ruff read `pyproject.toml` ([tool.black] / [tool.ruff], line-length 120) automatically
  when run from the repo root. Pin clang-format to the CI version (clang-format-18) so local
  formatting does not drift from the CI check.

