# Toolchain — CleverAgents Project

> ⚠️ Rules here override `cleverthis-guidelines`. Apply these exactly.

---

## Toolchain Overview

| Tool | Role | Entry point |
|------|------|-------------|
| **nox** | Task automation — ALL quality operations | `nox` or `nox -s <session>` |
| **Hatch** | Project and environment management | `hatch env create`, `hatch build` |
| **pyproject.toml** | ALL project configuration (single source) | — |
| **Pyright** | Static type checking (strict) | `nox -s typecheck` |
| **ruff** | Linting + auto-formatting | `nox -s lint`, `nox -s format` |
| **Slipcover** | Coverage measurement | `nox -s coverage_report` |
| **bandit** | Python security scanning | `nox -s security_scan` |
| **semgrep** | Cross-language security rules | `nox -s security_scan` |
| **vulture** | Unused code detection | `nox -s dead_code` |
| **Radon** | Complexity analysis | `nox -s complexity` |
| **ASV** | Airspeed Velocity benchmarks | `nox -s benchmark` |
| **Hypothesis** | Property-based testing | `nox -s unit_tests` (integrated) |
| **Behave** | BDD unit tests | `nox -s unit_tests` |
| **Robot Framework + pabot** | Integration + e2e tests | `nox -s integration_tests`, `nox -s e2e_tests` |
| **MkDocs** | Documentation builder | `nox -s docs` |
| **Commitizen** | Commit message guidance | `git cz` |
| **pre-commit** | Git hook automation | `scripts/setup-dev.sh` |

---

## nox — The Only Entry Point

**Never invoke any tool directly.** All quality operations go through nox.

```bash
# WRONG:
behave features/
robot robot/
pyright src/
ruff check src/
bandit -r src/

# RIGHT:
nox -s unit_tests
nox -s integration_tests
nox -s typecheck
nox -s lint
nox -s security_scan
```

If a session is missing from `noxfile.py` → add it before running.

### Complete session reference

```bash
nox                             # all default sessions (full quality gate)

# Quality:
nox -s lint                     # ruff linting + format check
nox -s format                   # auto-format with ruff
nox -s format -- --check        # format check only — CI mode
nox -s typecheck                # Pyright strict
nox -s security_scan            # bandit + semgrep + vulture
nox -s dead_code                # vulture dead code
nox -s complexity               # Radon (nightly quality sweep)

# Tests:
nox -s unit_tests               # Behave BDD
nox -s integration_tests        # Robot Framework via pabot
nox -s e2e_tests                # Robot Framework (real LLM keys)
nox -s coverage_report          # Slipcover (≥ 97% required)
nox -s benchmark                # ASV performance benchmarks
nox -s benchmark_regression     # ASV regression check

# Build / docs:
nox -s docs                     # MkDocs build
nox -s build                    # wheel distribution
```

---

## Pyright — Static Type Checking

- Configuration: `pyproject.toml` under `[tool.pyright]`
- Run: `nox -s typecheck`
- All code must pass Pyright strict mode
- **Zero tolerance** for type errors

### Absolute prohibitions

```python
# This is NEVER acceptable:
x: int = some_value  # type: ignore

# This is also NEVER acceptable:
# Disabling Pyright in pyproject.toml:
# [tool.pyright]
# typeCheckingMode = "off"   ← PROHIBITED
```

**If Pyright reports an error, fix the underlying code.** There are no valid
reasons to suppress type checking in this project. Not performance, not
convenience, not temporary workarounds.

---

## ruff — Linting and Formatting

- Configuration: `pyproject.toml` under `[tool.ruff]`
- Linting + format check: `nox -s lint`
- Auto-format: `nox -s format` (modifies files)
- Format check only (CI mode): `nox -s format -- --check`

---

## Hatch — Project Management

```bash
hatch env create      # create the project's virtual environment
hatch build           # build the project (alternative to nox -s build)
```

All project configuration lives in `pyproject.toml` — no Makefiles, no
wrapper shell scripts, no ad-hoc build commands. Commands must be native
to the Hatch/nox toolchain.

---

## pyproject.toml — Single Source of Truth

**Every tool in this project is configured in `pyproject.toml`:**

- `[tool.ruff]` — linting and formatting rules
- `[tool.pyright]` — type checking configuration
- `[tool.commitizen]` — commit message format rules
- `[tool.coverage.report]` — coverage threshold and exclusions
- `[tool.bandit]` — security scan configuration
- `[tool.hatch.*]` — environment and build configuration

Do not create separate config files (`.pylintrc`, `setup.cfg`, `tox.ini`, etc.).
All configuration belongs in `pyproject.toml`.

---

## Pre-commit Hooks

Configured in `.pre-commit-config.yaml`.

```bash
# Set up hooks (run once after cloning):
scripts/setup-dev.sh
```

Hooks run on every `git commit` and enforce:
- Code formatting (ruff)
- Linting (ruff)
- Type checking (Pyright)
- Security scanning (bandit)
- Commit message format validation (Commitizen)

**Never bypass with `--no-verify`.** If a hook fails, fix the underlying issue.

---

## Commitizen — Commit Messages

```bash
# Install (once):
npm install -g commitizen@2.8.6 cz-customizable@4.0.0

# Use (replaces git commit):
git cz
```

Commitizen guides you interactively through the Conventional Changelog format.
Configuration lives in `pyproject.toml` under `[tool.commitizen]`.

All CleverThis repositories use `cz-customizable@4.0.0` as the adapter.

---

## Import Rules (Python-specific for this project)

```python
# ALL imports at the top of the file — always:
import os
import sys
from pathlib import Path
from typing import TYPE_CHECKING

from third_party import SomeClass

from mypackage.module import LocalClass

# The ONLY exception — type-only imports for circular dependency avoidance:
if TYPE_CHECKING:
    from mypackage.other_module import OtherType

# PROHIBITED — imports inside functions, methods, or blocks:
def some_function():
    import os          # ← NEVER
    from x import Y    # ← NEVER

if condition:
    import something   # ← NEVER

try:
    import optional    # ← NEVER
except ImportError:
    pass
```

Import style:
- Prefer `from module import ClassName` over `import module`
- No wildcard imports (`from module import *`)
- ruff enforces import ordering and grouping (standard → third-party → local)

---

## Error Handling (Python-specific examples)

### Argument validation pattern (mandatory in all public/protected methods)

```python
def process_data(self, data: list[str], threshold: int) -> None:
    """Process data with full argument validation first."""
    # Validate ALL arguments before any logic:
    if data is None:
        raise ValueError("data cannot be None")
    if not data:
        raise ValueError("data cannot be empty")
    if not all(isinstance(item, str) for item in data):
        raise TypeError("data must contain only strings")
    if threshold < 0 or threshold > 100:
        raise ValueError(f"threshold must be between 0 and 100, got {threshold}")

    # Only now: actual logic
    ...
```

### Exception propagation rules

```python
# WRONG — suppresses the error:
try:
    risky_operation()
except Exception:
    pass

# WRONG — logs and swallows:
try:
    risky_operation()
except Exception as e:
    logger.error(str(e))

# WRONG — returns None silently:
def find_user(user_id: int) -> User | None:
    try:
        return db.get(user_id)
    except DatabaseError:
        return None  # ← silent failure

# CORRECT — let it propagate:
risky_operation()

# CORRECT — catch only when you have real recovery logic:
try:
    result = risky_operation()
except TransientNetworkError:
    time.sleep(1)
    result = risky_operation()  # retry logic — meaningful handling
```
