Help us improve
Share bugs, ideas, or general feedback.
From probabl-skills
Enforces Python code style using ruff (lint + format) and numpydoc docstrings. Runs ruff on touched Python files and places a project ruff.toml template.
npx claudepluginhub probabl-ai/skills --plugin probabl-skillsHow this skill is triggered — by the user, by Claude, or both
Slash command
/probabl-skills:python-code-styleThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Single owner of "what does well-styled Python look like in this
Configures Python linting, formatting, type checking, and docstring standards using ruff and mypy/pyright. Use when setting up project tooling, reviewing code style, or enforcing PEP 8 conventions.
Guides ruff configuration and usage for Python linting, formatting, autofixing, and LSP. Covers rule selection strategies, per-file ignores, config inheritance, and replacements for Flake8, Black, isort.
Lints Python code with ruff: fast checks, rule selection, auto-fixing, output formats, configuration. Use for code quality, bug detection, standards enforcement.
Share bugs, ideas, or general feedback.
Single owner of "what does well-styled Python look like in this stack": ruff (lint + format) and numpydoc docstrings. This skill is explicitly manual — Claude runs ruff on the files it has just touched, no hook involved.
update-config — but the default is "Claude runs ruff itself."black / isort / flake8 /
pydocstyle / pylint. Ruff is the canonical linter in this
stack (data-science-python-stack Tier 1). If import ruff /
pixi run ruff --version fails, route through python-env-manager
to install — don't silently fall back.ruff check
reports issues after Claude's first fix, address them once. If the
same issue persists after the second pass, stop editing that
file and surface the remaining diagnostics + diff to the user.
This is the anti-infinite-loop guardrail — do not enter a third
cycle on the same warning.src/<pkg>/, experiments/, audit/, top-level *.py scripts,
and any package directory the user owns. Skip vendored paths,
generated files, and anything under .pixi/, .venv/,
node_modules/, etc.ruff.toml from memory. The bundled
templates/ruff.toml is the single source of truth — it encodes
the per-file ignores (experiments/**), the numpydoc convention,
and the rule selection this stack expects. Initial setup requires
Read .agents/skills/python-code-style/templates/ruff.toml
this turn, then Write <project-root>/ruff.toml verbatim from
that file's content. Authoring a custom ruff.toml from training-
data memory drops half the contract silently. If you catch
yourself typing [lint] / [format] / select = [...] without
having read the template this turn, STOP and Read it first.warnings.filterwarnings(...) unless the user
explicitly asks for it. Same for warnings.simplefilter,
@pytest.mark.filterwarnings, and filterwarnings = [...] in
pytest.ini / pyproject.toml. Warnings are signal in this
stack.Pre-flight (python-code-style):
- [ ] ruff importable in the project's env (`pixi run ruff --version`
succeeds, per `data-science-python-stack` Tier 1)
- [ ] `ruff.toml` present at project root.
If absent AND stack + workspace are already set up: the
bundled template MUST be read **this turn** before being
written verbatim.
Evidence: Read .agents/skills/python-code-style/templates/ruff.toml
(this turn) + Write <project-root>/ruff.toml (this turn)
| "n/a — ruff.toml already at project root"
**Inline-authored ruff.toml from memory is NOT evidence.**
- [ ] File list ready: <abs paths of .py files touched this turn>
- [ ] Decision recorded: this is the first ruff pass on these files
(proceed) | second pass (proceed but stop on persistent
issues) | third pass on same warning (STOP, surface to user)
- [ ] One-fix-per-file rule acknowledged: max two passes per warning,
then surface remaining diagnostics + diff to the user.
ruff format + ruff check --fix + ruff check on Python files Claude has just generated or edited;
authoring numpydoc docstrings on public functions and classes;
dropping the ruff.toml template into a fresh project.For every Python file touched this turn (call them <files>), run
inside the project's environment manager — pixi run for pixi
projects, equivalent for uv / poetry / conda (per
python-env-manager):
pixi run ruff format <files>
pixi run ruff check --fix <files>
pixi run ruff check <files>
Three steps, in order:
ruff format — applies the formatter (line length, quoting,
trailing commas, blank lines around defs). Idempotent.ruff check --fix — auto-fixes everything ruff knows how to
fix in place: import sorting (I), legacy syntax (UP),
detectable bug patterns (B).ruff check (no --fix) — final pass. Anything reported
here needs Claude's attention: missing docstrings (D),
undefined names (F), code structure issues. Address them, then
re-run the trio. Apply the one-fix-per-file rule from Stop
conditions.If a file under experiments/ or audit/ has a D100 ("missing
module docstring") or D103 ("missing function docstring")
warning, that's expected for # %% cells; the bundled
ruff.toml per-file-ignores D100 + D103 (and E402, B018)
for both experiments/** and audit/**. If you're seeing them,
the ruff.toml isn't loaded — check that it lives at the project
root.
Audit files (audit/<NN>_<short_name>.py, owned by
audit-ml-pipeline) lint the same way as experiment files: same
# %% cell convention, same per-file ignores, same NumPyDoc
convention for any helper functions. After writing or editing an
audit file, run the same trio (ruff format → ruff check --fix
→ ruff check).
Public functions and classes carry numpydoc-format docstrings; ruff's
D rules with pydocstyle.convention = "numpy" enforce the shape.
A bare one-line summary is NOT sufficient for public functions.
The Parameters / Returns (and Raises when applicable) sections
are mandatory — even when the function is small, even when the user
says "just the summary is fine". Approving a one-line docstring on
a public function silently fails the contract this skill enforces;
the function looks D-rule-clean (D100/D103 don't fire) but the
parameter shapes and return type that callers actually need are
missing. Private helpers (_leading_underscore) are the only
exception: the default D rules allow them to omit docstrings, but
public callable surfaces always carry the full numpydoc shape.
Skeleton:
def predict_price(X, model, *, n_jobs=1):
"""Predict option prices from a feature matrix.
Parameters
----------
X : pandas.DataFrame
Feature matrix with one row per option.
model : sklearn.base.BaseEstimator
Fitted estimator with a ``predict`` method.
n_jobs : int, default=1
Number of parallel jobs.
Returns
-------
numpy.ndarray of shape (n_samples,)
Predicted prices, one per row of ``X``.
"""
Conventions worth surfacing because they're non-obvious:
numpy convention it
is, so write the period.X : ndarray of shape (n_samples, n_features).Returns section lists the return value; if there are
multiple returns, list each on its own row. Don't omit the type._leading_underscore) don't need a docstring
under the default D rules — ruff allows that.experiments/** per the bundled ruff.toml.ruff.toml templateWhen this skill is invoked on a fresh project that has no
ruff.toml at its root and the stack + workspace have been
scaffolded by their respective skills:
Read .agents/skills/python-code-style/templates/ruff.toml.
The pre-flight Evidence row for the ruff.toml present check
requires this read; an inline-authored config from memory does
not satisfy it.<project-root>/ruff.toml.
No edits, no "improvements", no rule additions. The template
encodes the per-file ignores (experiments/**), the
pydocstyle.convention = "numpy" setting, and the rule
selection this stack expects. Diverging from it drops half the
contract.pixi run ruff check --show-settings . should report the numpy convention and the select list
from the template.Do not fold ruff config into pyproject.toml automatically — the
project may not have one, or the user may prefer a separate file.
The standalone ruff.toml is unambiguous.
Forbidden shortcuts:
| Shortcut | Why it's wrong |
|---|---|
| "I know what ruff.toml should contain" → author from memory | The bundled template carries experiments/** per-file ignores, the numpydoc convention, and a curated rule selection. Memory misses these and the contract silently breaks |
| Read this skill's SKILL.md text describing the template → write from that | The SKILL.md describes; the template file is. Read the file itself, write it verbatim |
A common case: Claude edits one function in a file that already had
unrelated D-rule violations. Ruff will report those too.
This keeps PR scope tight and avoids "while I was here" expansion that the user didn't ask for.
data-science-python-stack — owns the decision that ruff is
Tier 1 mandatory; this skill assumes ruff is already installed.
If pixi run ruff --version fails, return there for the install.python-env-manager — turns "ruff is missing" into the right
install command for the project's manager. Don't run pip install ruff in a pixi project.organize-ml-workspace — sets up the directory layout that
the bundled ruff.toml's per-file ignores (experiments/** and
audit/**) reference. Drop the template after this skill has
run, so the paths it ignores actually exist.audit-ml-pipeline — generates audit files at
audit/<NN>_<short_name>.py. This skill's per-file ignores
cover the audit/ path the same way they cover experiments/.update-config — only relevant if the user explicitly asks
for an automated lint hook later. Default is no hook.ruff.toml lives at the project
root and is the single source of truth. Don't add per-directory
overrides unless the user asks.