# Quality Run Linting Formatting

> Runs ruff linting and formatting with configuration details and common fixes. Use when checking code style, formatting files, fixing lint violations, or before commits. Explains ruff check vs ruff format, --fix flag, configuration in pyproject.toml, and common violation patterns. Works with Python .py files, targets Python 3.12.

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

---


# Run Linting and Formatting Workflow

## Table of Contents

**Quick Start** → [Purpose](#purpose) | [When to Use](#when-to-use) | [Quick Start](#quick-start)

**Core Operations** → [Run Linting](#step-1-run-linting-ruff-check) | [Auto-Fix](#step-2-auto-fix-violations) | [Formatting](#step-3-run-formatting-ruff-format)

**Configuration** → [Ruff Config](#step-4-understand-ruff-configuration) | [Violation Codes](#step-5-common-violation-codes) | [Common Fixes](#fixing-common-violations)

**Workflows** → [Common Workflows](#common-workflows) | [Output Interpretation](#interpreting-lint-output) | [Integration](#integration-with-other-skills)

**Help** → [Troubleshooting](#troubleshooting) | [Requirements](#requirements)

---

## Purpose

Master ruff usage for linting (code quality) and formatting (code style) in temet. Understand when to check vs format, how to auto-fix violations, and interpret common error codes.

## When to Use

**Use this skill when:**
- Running code quality checks before commits
- Fixing linting violations
- Formatting code to match project standards
- Understanding ruff error codes (F401, E501, etc.)
- Configuring ruff for project-specific rules

**User trigger phrases:**
- "run linting"
- "format code"
- "fix lint errors"
- "ruff check"
- "what does E501 mean?"

## Quick Start

**Most common workflows:**

```bash
# Check for lint violations (don't modify files)
ruff check src/ tests/

# Auto-fix violations (safe fixes only)
ruff check src/ tests/ --fix

# Format code (modifies files)
ruff format src/ tests/

# Check formatting without modifying
ruff format src/ tests/ --check

# Full workflow (lint + format)
ruff check src/ tests/ --fix && ruff format src/ tests/
```

---

## Instructions

### Understanding Ruff vs Other Tools

**Ruff replaces multiple tools:**

| Tool | What It Did | Ruff Equivalent |
|------|-------------|-----------------|
| `black` | Code formatting | `ruff format` |
| `isort` | Import sorting | `ruff check --select I` |
| `flake8` | Linting | `ruff check` |
| `pylint` | Linting | `ruff check` |
| `pyupgrade` | Python version upgrades | `ruff check --select UP` |
| `autoflake` | Remove unused imports | `ruff check --select F401 --fix` |

**Why ruff:**
- ⚡ **10-100x faster** than other tools (written in Rust)
- 🎯 **One tool** replaces 5-6 tools
- 🔧 **Auto-fix** for most violations
- 📝 **Configurable** (select/ignore rules)

---

### Step 1: Run Linting (ruff check)

**Basic usage:**
```bash
ruff check src/ tests/
```

**Output (success):**
```
All checks passed!
```

**Output (with violations):**
```
src/temet/core/event_bus.py:15:1: F401 [*] `logging` imported but unused
src/temet/core/event_bus.py:42:80: E501 Line too long (102 > 100)
src/temet/plugins/hooks/session_start/plugin.py:23:5: B008 Do not perform function call `dict` in argument defaults
Found 3 errors.
[*] 1 fixable with the `--fix` option.
```

**Understanding output:**
- **File:line:col** - Location of violation
- **Code** - Error code (e.g., F401, E501, B008)
- **[*]** - Fixable with --fix
- **Message** - Description of violation

---

### Step 2: Auto-Fix Violations

**Safe auto-fix (recommended):**
```bash
ruff check src/ tests/ --fix
```

**What gets fixed:**
- ✅ Unused imports removed
- ✅ Imports sorted (isort-compatible)
- ✅ Unnecessary parentheses removed
- ✅ Quoted strings normalized
- ✅ Whitespace issues fixed
- ⚠️ Does NOT fix: Complex violations requiring manual intervention

**Check what would be fixed (dry-run):**
```bash
ruff check src/ tests/ --fix --diff
```

**Unsafe fixes (use with caution):**
```bash
ruff check src/ tests/ --fix --unsafe-fixes
```

**When to use:**
- `--fix`: Before every commit (auto-fix safe issues)
- `--fix --diff`: Preview changes before applying
- `--unsafe-fixes`: Only when you understand the changes

---

### Step 3: Run Formatting (ruff format)

**Format files in-place:**
```bash
ruff format src/ tests/
```

**Output:**
```
3 files reformatted, 244 files left unchanged
```

**Check formatting without modifying:**
```bash
ruff format src/ tests/ --check
```

**Output (violations):**
```
Would reformat: src/temet/core/event_bus.py
Would reformat: src/temet/plugins/hooks/session_start/plugin.py
2 files would be reformatted, 245 files left unchanged
```

**See what would change (dry-run):**
```bash
ruff format src/ tests/ --diff
```

**When to use:**
- `ruff format`: Before commits (format all code)
- `ruff format --check`: In CI/CD (verify formatting)
- `ruff format --diff`: Review formatting changes

---

### Step 4: Understand Ruff Configuration

**temet ruff configuration** (`pyproject.toml`):

```toml
[tool.ruff]
line-length = 100  # Max line length
target-version = "py312"  # Python 3.12

[tool.ruff.lint]
select = ["ALL"]  # Enable ALL rules by default
ignore = [
    "D",        # pydocstyle (docstrings not enforced)
    "COM812",   # Trailing comma (conflicts with formatter)
    "ISC001",   # Single-line implicit concat (conflicts with formatter)
    "T201",     # print() allowed (CLI tool needs print)
    "BLE001",   # Catching Exception allowed (plugin error handling)
    "ARG001",   # Unused function args (test fixtures, protocols)
    "ARG002",   # Unused method args (test fixtures, protocols)
]

[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = [
    "S101",     # assert allowed in tests
    "ANN",      # Type annotations optional in tests
]

[tool.ruff.format]
quote-style = "double"  # Use " not '
indent-style = "space"  # 4 spaces (not tabs)
```

**Key rules:**
- **Line length:** 100 characters (not 80)
- **Target:** Python 3.12 (uses modern syntax)
- **Quotes:** Double quotes preferred
- **Indentation:** 4 spaces

---

### Step 5: Common Violation Codes

**Import-related (F):**

| Code | Description | Fix |
|------|-------------|-----|
| F401 | Imported but unused | `ruff check --fix` removes |
| F403 | `from module import *` | Specify imports explicitly |
| F811 | Redefined unused variable | Rename or remove duplicate |

**Code style (E/W):**

| Code | Description | Fix |
|------|-------------|-----|
| E501 | Line too long (> 100) | Break line or shorten |
| E711 | Comparison to None should be `is` | Use `is None` |
| W291 | Trailing whitespace | `ruff check --fix` removes |

**Best practices (B):**

| Code | Description | Fix |
|------|-------------|-----|
| B008 | Function call in argument defaults | Use `default_factory` or None |
| B006 | Mutable default argument | Use `None` and create in function |
| B011 | `assert False` instead of `raise` | Use `raise AssertionError` |

**Type checking (ANN):**

| Code | Description | Fix |
|------|-------------|-----|
| ANN001 | Missing type annotation (arg) | Add type annotation |
| ANN201 | Missing return type | Add `-> ReturnType` |
| ANN401 | `Any` type (too vague) | Use specific type |

**See:** [Ruff rule reference](https://docs.astral.sh/ruff/rules/) for complete list

---

## Common Workflows

### Workflow 1: Pre-Commit (Fix + Format)

```bash
# Fix lint violations + format code
ruff check src/ tests/ --fix && ruff format src/ tests/

# Verify no violations remain
ruff check src/ tests/
ruff format src/ tests/ --check
```

**Time:** 1-2 seconds

---

### Workflow 2: Development (Check Only)

```bash
# Check for violations (don't modify files)
ruff check src/ tests/

# If violations: Fix manually or use --fix
```

**Time:** < 1 second

---

### Workflow 3: CI/CD (Verify Only)

```bash
# In CI pipeline: Verify linting and formatting
ruff check src/ tests/
ruff format src/ tests/ --check

# If violations: Fail CI (developer must fix locally)
```

**Time:** < 1 second (fast feedback)

---

### Workflow 4: Format on Save (IDE Integration)

**VSCode settings.json:**
```json
{
  "[python]": {
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.organizeImports": true,
      "source.fixAll": true
    }
  }
}
```

**Result:** Auto-fix + format on every file save

---

## Interpreting Lint Output

### Example Output

```
src/temet/core/event_bus.py:15:1: F401 [*] `logging` imported but unused
src/temet/core/event_bus.py:42:80: E501 Line too long (102 > 100)
src/temet/core/event_bus.py:67:5: B006 [*] Do not use mutable data structures for argument defaults
src/temet/plugins/hooks/session_start/plugin.py:23:10: ANN001 Missing type annotation for function argument `event`
Found 4 errors.
[*] 2 fixable with the `--fix` option.
```

**Breakdown:**
1. **F401** - Unused import (fixable) → `ruff check --fix`
2. **E501** - Line too long → Break line manually
3. **B006** - Mutable default (fixable) → `ruff check --fix`
4. **ANN001** - Missing annotation → Add type manually

**Action plan:**
```bash
# 1. Auto-fix what's possible
ruff check src/ tests/ --fix

# 2. Manually fix remaining issues
# - E501: Break long line
# - ANN001: Add type annotation

# 3. Verify all fixed
ruff check src/ tests/
```

---

## Fixing Common Violations

### Violation 1: F401 - Unused Import

**Error:**
```
src/temet/core/event_bus.py:15:1: F401 [*] `logging` imported but unused
```

**Fix (auto):**
```bash
ruff check src/ tests/ --fix
```

**Or manually:**
```python
# ❌ Before
import logging  # Unused
from typing import Any

# ✅ After
from typing import Any  # Removed unused import
```

---

### Violation 2: E501 - Line Too Long

**Error:**
```
src/temet/core/event_bus.py:42:80: E501 Line too long (102 > 100)
```

**Fix (manual):**
```python
# ❌ Before (102 characters)
def process_event(event: Event, handlers: list[Callable], config: dict[str, Any]) -> dict[str, Any]:

# ✅ After (break line)
def process_event(
    event: Event,
    handlers: list[Callable],
    config: dict[str, Any],
) -> dict[str, Any]:
```

---

### Violation 3: B006 - Mutable Default Argument

**Error:**
```
src/temet/core/event_bus.py:67:5: B006 [*] Do not use mutable data structures for argument defaults
```

**Fix (auto or manual):**
```python
# ❌ Before (dangerous - shared mutable default)
def process(data: dict[str, Any] = {}):
    data["key"] = "value"  # Modifies shared default!

# ✅ After (safe - create new dict each call)
def process(data: dict[str, Any] | None = None):
    if data is None:
        data = {}
    data["key"] = "value"
```

---

### Violation 4: ANN001 - Missing Type Annotation

**Error:**
```
src/temet/plugins/hooks/session_start/plugin.py:23:10: ANN001 Missing type annotation for function argument `event`
```

**Fix (manual):**
```python
# ❌ Before
def handle(self, event):
    return event.data

# ✅ After
def handle(self, event: Event) -> dict[str, Any]:
    return event.data
```

---

## Integration with Other Skills

**Before linting:**
- `setup-temet-project` - Ensure ruff installed
- `run-type-checking-workflow` - Fix type errors first (easier to lint)

**After linting:**
- `run-quality-gates` - Run all gates (includes ruff)
- `git-commit-push` - Lint passes as pre-commit requirement

**During development:**
- `interpret-check-all-output` - Understand check_all.sh results (includes ruff)

---

## Troubleshooting

### Issue: `ruff: command not found`

**Solution:**
```bash
# Use uv run prefix
uv run ruff check src/ tests/

# Or ensure ruff installed
uv pip install -e ".[dev]"
```

---

### Issue: Too many violations to fix manually

**Solution:**
```bash
# Auto-fix everything possible
ruff check src/ tests/ --fix

# Then fix remaining violations one file at a time
ruff check src/temet/core/event_bus.py --fix
```

---

### Issue: Conflict between ruff and pyright

**Symptoms:** Ruff suggests one fix, pyright suggests another

**Solution:**
```bash
# 1. Fix pyright errors first (type safety)
pyright src/ tests/

# 2. Then run ruff (code style)
ruff check src/ tests/ --fix
```

**Rationale:** Type safety > code style. Fix types first, style second.

---

### Issue: `--fix` breaks code

**Symptoms:** Auto-fix changes behavior or introduces bugs

**Solution:**
```bash
# 1. Review changes before applying
ruff check src/ tests/ --fix --diff

# 2. If looks wrong, skip auto-fix
# 3. Fix manually with understanding

# 4. If auto-fix is wrong, report bug to ruff
# (Rare - ruff is well-tested)
```

---

### Issue: Want to ignore specific violation

**Solution (per-line ignore):**
```python
# Ignore specific rule on one line
result = some_call()  # noqa: E501
```

**Solution (file-level ignore):**
```toml
# In pyproject.toml
[tool.ruff.lint.per-file-ignores]
"src/temet/legacy/*.py" = ["E501", "F401"]  # Ignore in legacy code
```

**Rule:** Only ignore with justification comment:
```python
# noqa: E501 - API URL cannot be broken
api_url = "https://very-long-api-url.example.com/v1/endpoint/with/many/parameters"
```

---

## Requirements

**Dependencies (auto-installed with `[dev]`):**
- `ruff` - Linter and formatter

**Configuration files:**
- `pyproject.toml` - Ruff configuration (required)
- `.vscode/settings.json` - IDE integration (optional)

**No manual installation needed** - included in `pyproject.toml`.

---

## Expected Output

### Success (No Violations)

```bash
$ ruff check src/ tests/
All checks passed!

$ ruff format src/ tests/ --check
247 files already formatted
```

**✅ Ready to commit**

---

### Violations Found

```bash
$ ruff check src/ tests/
src/temet/core/event_bus.py:15:1: F401 [*] `logging` imported but unused
src/temet/core/event_bus.py:42:80: E501 Line too long (102 > 100)
Found 2 errors.
[*] 1 fixable with the `--fix` option.

$ ruff format src/ tests/ --check
Would reformat: src/temet/core/event_bus.py
1 file would be reformatted, 246 files left unchanged
```

**🔧 Fix with:**
```bash
ruff check src/ tests/ --fix && ruff format src/ tests/
```


