Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/commands/lint.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ description: Check code quality
Run read-only local quality checks (formatting, lint rules, type checking, copyright).

* Run with: `mise run check`
* Runs `mise run format-check` (ruff format + ruff check + copyright) + `mise run typecheck` (ty)
* Runs the `check:*` leaves for formatting, lint rules, type checking, lock state, copyright headers, and Mise task validation
* Always run after `mise run format`
8 changes: 4 additions & 4 deletions .agents/skills/github-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ CI jobs map to local commands:

| CI Job | Local Command |
|--------|---------------|
| Format | `mise run format` (fix) or `mise run format-check` (check) |
| Format (lock) | `mise run lock-check` |
| Typecheck | `mise run typecheck` |
| Format | `mise run format` (fix) or `mise run check:format ::: check:lint ::: check:license:headers` (check) |
| Format (lock) | `mise run check:lock` |
| Typecheck | `mise run check:type` |
| Unit Tests | `mise run test:ci` |

Path filtering may skip format/typecheck/unit-test when only non-source files change. Run `mise run validate` locally or add a relevant source/test/config change to trigger CI.
Format and type checks run on every pull request. The local pre-PR gate is `mise run check ::: test`; specialized CI and GPU suites remain separate.

## Issues

Expand Down
8 changes: 4 additions & 4 deletions .agents/skills/uv-build/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ uv add --group test <package>
# Change CPU or CUDA runtime extras
# Edit cuda_deps.toml, regenerate pyproject.toml, then lock.
uv run --frozen tools/gen_cuda_deps.py cuda_deps.toml --pyproject pyproject.toml
uv lock
mise run lock:update
```

After any change: `uv lock` to regenerate `uv.lock`. Pre-commit verifies the lock is up to date.
After any change: `mise run lock:update` to regenerate `uv.lock`. Pre-commit verifies the lock is up to date.
The generated CPU/CUDA sections of `pyproject.toml` must not be edited directly;
`mise run lock-check` verifies that they match `cuda_deps.toml`. The
`mise run check:lock` verifies that they match `cuda_deps.toml`. The
generator owns the complete `[tool.uv.sources]` and `[[tool.uv.index]]`
sections, so add every source or index there through `cuda_deps.toml`.

Expand Down Expand Up @@ -140,5 +140,5 @@ Build backend: `hatchling` with wheel target `packages = ["src/nemo_safe_synthes
2. Use `--frozen` in CI and Make targets to prevent lock updates
3. Use `uv run` to run tools (pytest, mkdocs, etc.)
4. uv version is pinned in `.mise.toml`.
5. Edit non-generated `pyproject.toml` sections directly (e.g. dependency groups); CPU/CUDA extras go through `cuda_deps.toml` instead, then `uv lock`
5. Edit non-generated `pyproject.toml` sections directly (e.g. dependency groups); CPU/CUDA extras go through `cuda_deps.toml` instead, then `mise run lock:update`
6. Use `uv add` for base/group deps
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

Ensure that the following pass:

- [ ] `mise run format && mise run check` or via prek validation.
- [ ] `mise run test` passes locally
- [ ] `mise run format` leaves only intended formatting changes.
- [ ] `mise run check ::: test` passes locally.
- [ ] `mise run test:e2e` passes locally
- [ ] `mise run test:ci-container` passes locally (recommended)
- [ ] GPU CI status check passes -- comment `/sync` on this PR to trigger a run (auto-triggers on ready-for-review)
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ The `ci-checks.yml` workflow runs on every push to `main` and on pull requests.

| Job | mise task | What it checks |
| --- | --- | --- |
| Format | `format-check` | `dprint check` for TOML + `ruff format --check` + `ruff check` + SPDX copyright headers |
| Format (lock) | `lock-check` | generated CUDA metadata matches `cuda_deps.toml` + `uv.lock` matches `pyproject.toml` |
| Typecheck | `typecheck` | `ty check` (excludes per `pyproject.toml [tool.ty.src]`) |
| Format | `check:format`, `check:lint`, `check:license:headers` | `dprint check` for TOML + `ruff format --check` + `ruff check` + SPDX copyright headers |
| Format (lock) | `check:lock` | generated CUDA metadata matches `cuda_deps.toml` + `uv.lock` matches `pyproject.toml` |
| Typecheck | `check:type` | `ty check` (excludes per `pyproject.toml [tool.ty.src]`) |
| Unit Tests | `test:ci` | pytest with coverage (excludes slow, e2e, gpu, smoke) |
| Smoke Tests | `test:smoke` | CPU smoke tests (training/generation hot paths, tiny models) |

Expand All @@ -133,8 +133,8 @@ Docs source paths include `docs/*.py`, `docs/**/*.py`, and `mkdocs.yml`. These p
To replicate CI locally:

```bash
mise run check # format-check + typecheck
mise run lock-check # verify generated CUDA metadata and uv.lock
mise run check # all read-only static checks
mise run check:lock # verify generated CUDA metadata and uv.lock
mise run test:ci # CI unit tests with coverage selectors
mise run test:smoke # CPU smoke tests
```
Expand Down
14 changes: 10 additions & 4 deletions .github/workflows/ci-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,17 @@ jobs:
- name: Bootstrap
run: mise run bootstrap-nss dev

- name: Check formatting, linting, and copyright headers
run: mise run format-check
- name: Check formatting
run: mise run check:format

- name: Check lint rules
run: mise run check:lint

- name: Check copyright headers
run: mise run check:license:headers

- name: Check uv.lock is up to date
run: mise run lock-check
run: mise run check:lock

typecheck:
name: Typecheck
Expand All @@ -117,7 +123,7 @@ jobs:
run: mise run bootstrap-nss cpu

- name: Run ty type checks
run: mise run typecheck
run: mise run check:type

wheel-install:
name: End-user Wheel Install
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-sync-lock.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

# ---------------------------------------------------------------------------
# After Dependabot bumps a Python dependency in pyproject.toml, regenerate
# uv.lock so that `mise run lock-check` passes in CI.
# uv.lock so that `mise run check:lock` passes in CI.
#
# Uses a PAT (secrets.PAT) to push the updated lockfile so that CI is
# triggered automatically on the new commit.
Expand Down
52 changes: 31 additions & 21 deletions .mise/tasks/quality.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,48 @@ run = [
"uv run --script tools/codestyle/copyright_fixer.py .",
]

["format-check"]
description = "Check TOML and Python formatting, lint rules, and SPDX copyright headers without modifying source files. Safe for CI and local pre-review checks."
["check:format"]
description = "Check TOML and Python formatting without modifying tracked files."
run = [
"dprint check --incremental=false",
"bash tools/codestyle/format.sh --check",
"bash tools/codestyle/ruff_check.sh",
"uv run --script tools/codestyle/copyright_fixer.py --check .",
]

[typecheck]
["check:lint"]
description = "Check Python lint rules without modifying tracked files."
run = "bash tools/codestyle/ruff_check.sh"

["check:type"]
description = "Run ty type checks through the repo wrapper. Requires Python dependencies installed; does not modify files."
run = "bash tools/codestyle/typecheck.sh"

["lock-check"]
description = "Verify generated CUDA metadata and uv.lock match their sources."
["check:lock"]
description = "Verify generated CUDA metadata and uv.lock match their sources without modifying tracked files."
run = [
"uv run --offline --frozen tools/gen_cuda_deps.py cuda_deps.toml --pyproject pyproject.toml --check",
"uv lock",
"git diff --exit-code uv.lock",
"uv lock --check",
]

[check]
description = "Run local read-only quality checks: format-check and typecheck. Dependencies are independent and may run in parallel."
depends = ["format-check", "typecheck"]
run = "echo 'quality checks passed'"
["check:license:headers"]
description = "Check SPDX copyright headers without modifying tracked files."
run = "uv run --script tools/codestyle/copyright_fixer.py --check ."

[validate]
description = "Run the standard pre-PR validation suite: check, lock-check, then CI unit tests."
alias = "ci"
run = [
{ task = "check" },
{ task = "lock-check" },
{ task = "test:ci" },
"echo 'validation passed'",
["check:tasks"]
description = "Validate public Mise task definitions and usage declarations without modifying tracked files."
run = "mise tasks validate"

["lock:update"]
description = "Regenerate uv.lock from pyproject.toml. Modifies uv.lock in place."
run = "uv lock"

[check]
description = "Run all read-only format, lint, type, lock, license-header, and Mise task checks. Dependencies may run in parallel."
depends = [
"check:format",
"check:lint",
"check:type",
"check:lock",
"check:license:headers",
"check:tasks",
]
run = "echo 'quality checks passed'"
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ repos:
files: '\.(py|sh|md|yaml|yml)$'

- id: uv-lock
name: Run uv lock and check for uv.lock drift
entry: bash -c 'uv lock && git diff --exit-code uv.lock'
name: Check generated CUDA metadata and uv.lock
entry: mise run check:lock
language: system
files: 'pyproject\.toml$'
files: '^(pyproject\.toml|cuda_deps\.toml)$'
pass_filenames: false
verbose: true

Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ See [STYLE_GUIDE.md](STYLE_GUIDE.md) for detailed code style conventions (Python

Use `uv` for everything -- never `pip` or raw `python`. Python 3.11–3.14 with modern syntax (`X | Y`, `list[str]`, `Self`).

Common commands: `mise run test` (unit tests), `mise run format` (auto-fix formatting + lint + copyright), `mise run check` (read-only local quality checks), `mise run validate` (pre-PR quality, lock, and CI unit checks), `mise run typecheck` (ty only). Always use mise tasks or the wrapper scripts in `tools/` instead of running `ruff` or `ty` directly. Use `uv run` for Python execution. When in doubt, inspect `mise tasks` and `pytest --markers`.
Common commands: `mise run test` (unit tests), `mise run format` (auto-fix formatting + lint + copyright), `mise run check` (all read-only local quality checks), `mise run check ::: test` (the local pre-PR gate), and `mise run check:type` (ty only). Always use mise tasks or the wrapper scripts in `tools/` instead of running `ruff` or `ty` directly. Use `uv run` for Python execution. When in doubt, inspect `mise tasks` and `uv run --frozen pytest --markers`.

The canonical `uv sync` command for a full GPU/dev environment is:

Expand All @@ -29,7 +29,7 @@ uv sync --frozen --extra cu129 --extra engine --group dev

Bare `uv sync --frozen` (without extras) installs an incomplete environment -- `ty`, import checks, and GPU tests will fail.

The CPU/CUDA optional-dependency and `[tool.uv.sources]`/`[[tool.uv.index]]` sections of `pyproject.toml` are generated from `cuda_deps.toml` by `tools/gen_cuda_deps.py` -- never hand-edit the `# >>> BEGIN GENERATED ... <<<` blocks in `pyproject.toml`. To add or change a CUDA/CPU dependency, edit `cuda_deps.toml`, then run `uv run --frozen tools/gen_cuda_deps.py cuda_deps.toml --pyproject pyproject.toml` followed by `uv lock`. `mise run lock-check` verifies both are in sync with `cuda_deps.toml`.
The CPU/CUDA optional-dependency and `[tool.uv.sources]`/`[[tool.uv.index]]` sections of `pyproject.toml` are generated from `cuda_deps.toml` by `tools/gen_cuda_deps.py` -- never hand-edit the `# >>> BEGIN GENERATED ... <<<` blocks in `pyproject.toml`. To add or change a CUDA/CPU dependency, edit `cuda_deps.toml`, then run `uv run --frozen tools/gen_cuda_deps.py cuda_deps.toml --pyproject pyproject.toml` followed by `mise run lock:update`. `mise run check:lock` verifies both are in sync with `cuda_deps.toml`.

Feature branches off `main`. Branch names often include an issue number prefix (e.g., `<author>/123-short-name`).

Expand Down
22 changes: 10 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ This section is the canonical source. To add, rename, or remove a label, open a
3. Make your changes and commit using [conventional commits](#conventional-commits)
4. Run tests locally:
```bash
mise run test
mise run check ::: test
```
5. Push your branch:
```bash
Expand Down Expand Up @@ -558,23 +558,21 @@ Use mise tasks instead of running `ruff` or `ty` directly. The tasks use pinned

```bash
mise run format # auto-fix: dprint TOML + ruff format/import sorting + copyright headers
mise run check # read-only local quality checks (format + lint + typecheck + copyright)
mise run check # all read-only local quality checks
mise run test # unit tests
# or just
mise run format && mise run check && mise run test
mise run check ::: test # local pre-PR gate: static checks + unit tests
```

We use `dprint` for TOML, `ruff` for Python formatting and linting, and `ty` for type checking, wrapped with settings for consistency.

CI calls the same tools through atomic read-only mise tasks. Declarative tasks live in `.mise/tasks/*.toml`; bash-heavy tasks are executable file tasks under `.mise/tasks/`. Shared shell helpers live in `.mise/tasks/_lib.sh`, which is sourced by file tasks but is not executable and does not appear in `mise tasks`. `mise run check` replicates format-check + typecheck locally; `mise run validate` runs the broader pre-PR graph (`check`, `lock-check`, and `test:ci`). Pre-commit hooks (`pre-commit install`) provide faster feedback by checking only staged files, but are not a substitute for the mise tasks.
CI calls the same tools through atomic read-only `check:*` tasks. Declarative tasks live in `.mise/tasks/*.toml`; bash-heavy tasks are executable file tasks under `.mise/tasks/`. Shared shell helpers live in `.mise/tasks/_lib.sh`, which is sourced by file tasks but is not executable and does not appear in `mise tasks`. `mise run check` aggregates the read-only static checks. The standard local gate is the explicit `mise run check ::: test`; no shorthand alias is defined. Pre-commit hooks (`pre-commit install`) provide faster feedback by checking only staged files, but are not a substitute for the Mise tasks.

Useful task graph commands:

```bash
mise tasks # public tasks
mise tasks --hidden # helper and legacy alias tasks
mise tasks deps check # inspect the quality-check graph
mise tasks deps validate # inspect the pre-PR validation graph
```

You can also run tools directly on specific files:
Expand All @@ -590,11 +588,11 @@ All mise tasks check the entire project. Pre-commit scopes checks to staged file

| Check | CI task | `mise run format` / `mise run check` | Pre-commit |
|---|---|---|---|
| dprint TOML format | `mise run format-check` | `format`: auto-fix; `check`: read-only | not run |
| ruff format + lint | `mise run format-check` | `format`: auto-fix; `check`: read-only | staged files (auto-fix) |
| ty typecheck | `mise run typecheck` | read-only | all files |
| copyright headers | `mise run format-check` | `format`: auto-fix; `check`: read-only | staged files (auto-fix) |
| generated CUDA metadata and uv lock drift | `mise run lock-check` | not checked | on `pyproject.toml` or `cuda_deps.toml` changes |
| dprint TOML format | `mise run check:format` | `format`: auto-fix; `check`: read-only | not run |
| ruff format + lint | `mise run check:format` and `mise run check:lint` | `format`: auto-fix; `check`: read-only | staged files (auto-fix) |
| ty typecheck | `mise run check:type` | read-only | all files |
| copyright headers | `mise run check:license:headers` | `format`: auto-fix; `check`: read-only | staged files (auto-fix) |
| generated CUDA metadata and uv lock drift | `mise run check:lock` | read-only | on `pyproject.toml` or `cuda_deps.toml` changes |
| DCO signoff | branch protection | not checked | commit-msg hook |

## Documentation
Expand Down Expand Up @@ -680,7 +678,7 @@ This project supports AI coding assistants. Configuration is layered so that con

Conventions defined in `AGENTS.md` (code style, markdown style, testing, etc.) apply universally. Durable module-level guidance belongs in Python docstrings and source comments so it appears in the generated API reference; test-suite guidance belongs in `tests/TESTING.md`. Tool-specific config (`.cursor/rules/`, `CLAUDE.md`) reinforces those conventions for its respective tool.

Before contributing, run `mise run format` and `mise run check`. See `AGENTS.md` for full conventions.
Before contributing, run `mise run format`, review its changes, then run `mise run check ::: test`. See `AGENTS.md` for full conventions.

## Releasing

Expand Down
7 changes: 2 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ setup: install-mise ## Install dev tools and create the virtual environment via
MISE_YES=1 mise run setup

.PHONY: run
run: ## Run a mise task. Usage: make run TASK=format-check [MISE_ARGS="..."] [ARGS="..."]
run: ## Run a mise task. Usage: make run TASK=check [MISE_ARGS="..."] [ARGS="..."]
@if [ -z "$(TASK)" ]; then \
echo "Error: missing TASK. Usage: make run TASK=format-check [MISE_ARGS=\"...\"] [ARGS=\"...\"]" >&2; \
echo "Error: missing TASK. Usage: make run TASK=check [MISE_ARGS=\"...\"] [ARGS=\"...\"]" >&2; \
exit 1; \
fi
mise run $(MISE_ARGS) "$(TASK)" $(ARGS)
Expand Down Expand Up @@ -75,8 +75,6 @@ $(eval $(call deprecated_target,docs-build,docs:build))
$(eval $(call deprecated_target,docs-deploy,docs:deploy))
$(eval $(call deprecated_target,docs-serve,docs:serve))
$(eval $(call deprecated_target,format,format))
$(eval $(call deprecated_target,format-check,format-check))
$(eval $(call deprecated_target,lock-check,lock-check))
$(eval $(call deprecated_target,publish-internal,publish:internal))
$(eval $(call deprecated_target,publish-pypi,publish:pypi))
$(eval $(call deprecated_target,test,test))
Expand All @@ -98,7 +96,6 @@ $(eval $(call deprecated_target,test-smoke-gpu-timeseries,test:smoke:gpu:timeser
$(eval $(call deprecated_target,test-smoke-gpu-train-only,test:smoke:gpu:train-only))
$(eval $(call deprecated_target,test-tool-install,test:tool-install))
$(eval $(call deprecated_target,test-unit-slow,test:unit-slow))
$(eval $(call deprecated_target,typecheck,typecheck))

.PHONY: test-nss-%-ci
test-nss-%-ci:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ Project commands run through mise tasks under `.mise/tasks/`: `*.toml` files for
```bash
mise tasks # list public tasks
mise tasks --hidden # include helper and legacy alias tasks
mise tasks deps validate # inspect the pre-PR validation graph
mise run validate # check + lock-check + CI unit tests
mise tasks deps check # inspect the read-only quality-check graph
mise run check ::: test # local pre-PR gate: static checks + unit tests
```

### Running
Expand Down
Loading
Loading