Compare commits

...

4 Commits

Author SHA1 Message Date
Gud Boi 068dfc8e1c Add `/lint` skill with `scripts/check.py`
Add a user-invocable `/lint` skill that wraps
`ruff check` with staged-file defaults and piker's
`ruff.toml` config via a PEP 723 script.

The `ruff.toml` (from prior commit) now enforces
piker's `'''` multiline docstring convention with
`D2xx` formatting rules: summary on second line
(D213), closing quotes on separate line (D209), blank
line between summary and description (D205), plus
`W` trailing-whitespace and cherry-picked `D4xx`
content checks.

Deats,
- `scripts/check.py`: pure-stdlib wrapper that
  defaults to staged `.py` files via
  `git diff --cached`, with `--all`, `--fix`,
  `--diff`, and `--stats` flags.
- calls `ruff` from `$PATH` (works with nixpkgs,
  nvim-bundled, or pip-installed).
- prints clear install guidance if `ruff` not found.
- `SKILL.md`: documents usage, common violations
  (D213, D205, D204), and fix patterns for
  converting to piker's docstring style.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-17 21:18:05 -04:00
Gud Boi f2a0825d03 Add pydocstyle and `W` rules to `ruff.toml`
Enable `D2xx` formatting rules to enforce piker's `'''`
multiline docstring convention: summary on second line
(D213), closing quotes on separate line (D209), blank
line between summary and description (D205).

Deats,
- select `D2` (whitespace/formatting) rule group plus
  cherry-picked `D402`/`D403`/`D419` content checks.
- ignore `D200` (allow multiline for short docstrings),
  `D203` (use `D211` instead), `D212` (use `D213`).
- skip `D1xx` (missing-docstring) to avoid noise and
  `D3xx` since `D300` conflicts with `'''` convention.
- add `W` rules for trailing-whitespace detection.

Also,
- enable `docstring-code-format` with 67-char width
  for code examples inside docstrings.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-17 21:18:05 -04:00
Gud Boi 7db598a079 WIP get him to write a ruff conf to match our code 2026-03-17 21:18:05 -04:00
Gud Boi e9cf1d7379 Move commit-msg output to `msgs/` subdir
Relocate generated commit message files from
`.claude/` root into `.claude/skills/commit-msg/msgs/`
and switch timestamp format to filesystem-safe UTC
(`%Y%m%dT%H%M%SZ`).

Also,
- add `msgs/` dir and `git_commit_msg_LATEST.md` to
  `.gitignore`.

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-17 21:18:05 -04:00
5 changed files with 255 additions and 25 deletions

View File

@ -69,13 +69,13 @@ When generating a commit message:
conventions from the conventions from the
[style guide](./style-guide-reference.md). [style guide](./style-guide-reference.md).
4. Add body only for multi-file or complex changes. 4. Add body only for multi-file or complex changes.
5. Write the message to a file in the repo's 5. Write the message to TWO files:
`.claude/` subdir with filename format: - `.claude/skills/commit-msg/msgs/<timestamp>_<hash>_commit_msg.md`
`<timestamp>_<first-7-chars-of-last-commit-hash>_commit_msg.md` * with `<timestamp>` from `date -u +%Y%m%dT%H%M%SZ`
where `<timestamp>` is from `date --iso-8601=seconds`. or similar filesystem-safe format.
Also write a copy to * and `<hash>` from `git log -1 --format=%h`
`.claude/git_commit_msg_LATEST.md` first 7 chars.
(overwrite if exists). - `.claude/git_commit_msg_LATEST.md` (overwrite)
--- ---

View File

@ -0,0 +1,72 @@
---
name: lint
description: >
Run ruff lint checks on piker Python files for
docstring style (D2xx) and code convention
compliance. Checks staged files by default.
user-invocable: true
argument-hint: "[--all|--fix|--stats|paths...]"
allowed-tools: Bash(python3 *), Bash(ruff *), Read, Edit
---
# Ruff Lint Checker
Run piker's ruff config against staged files,
specific paths, or the full codebase.
## Available scripts
- **`scripts/check.py`** — self-contained (PEP 723)
wrapper around `ruff check` that defaults to staged
files and uses the project's `ruff.toml`.
## Usage
```bash
# check staged Python files (default)
python3 scripts/check.py
# check full codebase
python3 scripts/check.py --all
# auto-fix fixable violations
python3 scripts/check.py --fix
# preview fixes without applying
python3 scripts/check.py --diff
# show per-rule violation counts
python3 scripts/check.py --stats
# check specific files
python3 scripts/check.py piker/ui/_style.py
```
## Common violations
| Rule | Meaning | Fixable? |
|------|---------|----------|
| D213 | summary not on 2nd line after `'''` | yes |
| D205 | no blank line after summary | no |
| D204 | no blank line after class docstring | yes |
| D209 | closing quotes not on own line | yes |
| D200 | ignored — piker always multiline | n/a |
| W291 | trailing whitespace | yes |
## Fixing D213 (most common)
Convert this:
```python
"""Summary on first line."""
```
To piker's `'''` multiline style:
```python
'''
Summary on second line.
'''
```
For D205, insert a blank line between the summary
and description paragraphs inside the docstring.

View File

@ -0,0 +1,130 @@
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.12"
# dependencies = []
# ///
'''
Ruff lint checker for piker docstring and code style.
Checks staged files by default, or the full `piker/`
tree with `--all`. Uses the project's `ruff.toml`.
'''
import argparse
import shutil
import subprocess
import sys
def get_staged_py_files() -> list[str]:
'''
Return staged Python file paths (added/copied/modified).
'''
result = subprocess.run(
[
'git', 'diff',
'--cached',
'--name-only',
'--diff-filter=ACM',
'--', '*.py',
],
capture_output=True,
text=True,
)
return [
f for f in result.stdout.strip().split('\n')
if f
]
def main() -> int:
'''
Parse args and run `ruff check` against targets.
'''
ap = argparse.ArgumentParser(
description=(
"Run ruff check with piker's ruff.toml config.\n"
'\n'
'Default: checks staged .py files only.\n'
'Use --all for the full piker/ tree.'
),
formatter_class=argparse.RawDescriptionHelpFormatter,
)
ap.add_argument(
'paths',
nargs='*',
help='files/dirs to check (default: staged)',
)
ap.add_argument(
'--all', '-a',
action='store_true',
dest='check_all',
help='check entire piker/ directory',
)
ap.add_argument(
'--fix',
action='store_true',
help='auto-fix fixable violations',
)
ap.add_argument(
'--diff',
action='store_true',
help='preview fixes as unified diff (dry-run)',
)
ap.add_argument(
'--stats',
action='store_true',
help='show per-rule violation counts only',
)
args = ap.parse_args()
# determine check targets
if args.check_all:
targets: list[str] = ['piker/']
elif args.paths:
targets = args.paths
else:
targets = get_staged_py_files()
if not targets:
print(
'No staged Python files found.\n'
'Use --all for full codebase '
'or pass file paths.'
)
return 0
print(
f'Checking {len(targets)} staged file(s)..\n'
)
# ensure ruff is available on PATH
if not shutil.which('ruff'):
print(
'Error: `ruff` not found on PATH.\n'
'On NixOS: add to flake.nix or '
'`nix-shell -p ruff`\n'
'Otherwise: `uv sync --group lint` or '
'`pip install ruff`'
)
return 127
# build ruff command
cmd: list[str] = ['ruff', 'check']
if args.diff:
cmd.append('--diff')
elif args.fix:
cmd.append('--fix')
if args.stats:
cmd.append('--statistics')
cmd.extend(targets)
result = subprocess.run(cmd)
return result.returncode
if __name__ == '__main__':
sys.exit(main())

2
.gitignore vendored
View File

@ -107,6 +107,8 @@ ENV/
.git/ .git/
# any commit-msg gen tmp files # any commit-msg gen tmp files
.claude/skills/commit-msg/msgs/
.claude/git_commit_msg_LATEST.md
.claude/*_commit_*.md .claude/*_commit_*.md
.claude/*_commit*.toml .claude/*_commit*.toml

View File

@ -35,7 +35,7 @@ exclude = [
line-length = 88 line-length = 88
indent-width = 4 indent-width = 4
# Assume Python 3.9 # !XXX sync with `pyproject.toml`!
target-version = "py312" target-version = "py312"
# ------ - ------ # ------ - ------
@ -44,11 +44,43 @@ target-version = "py312"
[lint] [lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. select = [
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or # pycodestyle error subsets (pre-existing)
# McCabe complexity (`C901`) by default. "E4", "E7", "E9",
select = ["E4", "E7", "E9", "F"] # pyflakes (pre-existing)
ignore = [] "F",
# -- pydocstyle: enforce piker's ''' multiline style --
# D2xx whitespace and formatting rules; most are
# auto-fixable via `ruff check --fix`.
# NOTE: D1xx (missing-docstring) rules intentionally
# excluded to avoid noise across the existing codebase.
"D2",
# D4xx content checks (cherry-picked)
"D402", # first line != function signature
"D403", # capitalize first word
"D419", # no empty docstrings
# NOTE: D3xx skipped entirely since D300 enforces
# triple-double-quotes `"""` which conflicts with
# piker's `'''` convention (the formatter's
# `quote-style = "single"` handles conversion).
# pycodestyle warnings
"W",
]
ignore = [
# -- pydocstyle ignores for piker conventions --
# piker ALWAYS uses multiline docstring style, never
# single-line, so disable the "fit on one line" rule.
"D200",
# piker uses NO blank line before class docstrings
# (D211) not 1-blank-line (D203); these conflict.
"D203",
# piker puts the summary on the SECOND line after
# an opening `'''` (D213); not on the same line as
# the opening quotes (D212); these conflict.
"D212",
]
ignore-init-module-imports = false ignore-init-module-imports = false
[lint.per-file-ignores] [lint.per-file-ignores]
@ -79,16 +111,10 @@ skip-magic-trailing-comma = false
# Like Black, automatically detect the appropriate line ending. # Like Black, automatically detect the appropriate line ending.
line-ending = "auto" line-ending = "auto"
# Enable auto-formatting of code examples in docstrings. Markdown, # Auto-format code examples inside docstrings
# reStructuredText code/literal blocks and doctests are all supported. # (>>> blocks, code fences, etc.)
# docstring-code-format = true
# This is currently disabled by default, but it is planned for this
# to be opt-out in the future.
docstring-code-format = false
# Set the line length limit used when formatting code snippets in # Use piker's 67-char target for code inside docstrings
# docstrings. # (only applies when `docstring-code-format = true`).
# docstring-code-line-length = 67
# This only has an effect when the `docstring-code-format` setting is
# enabled.
docstring-code-line-length = "dynamic"