nur
A script discovery and execution engine for your project's tasks.
Run nur in a project and it discovers the tasks your project already defines —
from npm, Make, deno, composer, just, Taskfile, pre-commit, PDM/poe, tox, mise,
cargo-make, moon, xc, VS Code tasks, nox, mask, and Invoke — then lets you run them from a TUI picker or directly from the command line.
Discovery is limited to the current directory. See Features for the
full list of source files.
Table of Contents
- Installation
- Usage
- Support
- Motivation
- Features
- Author
- Analysis
- Contributing
- Development
- Releasing
- Credits
- License
- Changelog
Installation
nur is a standalone command-line tool — install it into an isolated
environment rather than as a project dependency:
uv tool install nur
Or run it without installing:
uvx nur
On macOS/Linux via Homebrew:
brew install hasansezertasan/tap/nur
On Windows via Scoop:
scoop bucket add hasansezertasan https://github.com/hasansezertasan/scoop-bucket
scoop install nur
To install the latest unreleased changes from source:
uv tool install git+https://github.com/hasansezertasan/nur
Or, from a clone:
uv tool install .
Verify the installation
The package root is importable after installation:
>>> import nur
>>> isinstance(nur.__version__, str)
True
Usage
Run nur from the root of a project that contains any supported task file.
TUI
Run with no arguments to open the interactive picker:
nur
Browse and run the discovered tasks in a three-pane Textual UI. Press q to
exit.
CLI
nur test # run a task by name (if unambiguous)
nur make:test # run a task by its qualified name
nur test -- --watch # pass extra args through to the underlying runner
nur list # print all discovered tasks
nur --version
Support ❤️
If you have any questions or need help, feel free to open an issue on the GitHub repository.
Motivation
Every project speaks a different task dialect — make test, npm run test,
just test, task test, pdm run test, poe test, tox -e test, mise run test, xc test. nur gives
you one command that discovers whatever a project already uses and runs it, with no config and
no need to remember which runner lives where. Discovery is pure text/JSON/TOML
parsing, so listing tasks never executes anything (no make -pRrq side effects).
Features
-
Zero-config discovery across eighteen providers, each parsed from a single source file in the current directory:
Provider Prefix Source file npm npmpackage.jsondeno denodeno.json/deno.jsonccomposer composercomposer.jsonMake makeMakefilePDM pdmpyproject.toml([tool.pdm.scripts])poe poepyproject.toml([tool.poe.tasks])tox toxtox.ini,setup.cfg,pyproject.toml, ortox.tomljust justjustfileTaskfile taskTaskfile.ymlpre-commit pre-commit.pre-commit-config.yamlmise misemise.toml(and variants — see below)cargo-make cargo-makeMakefile.tomlmoon moonmoon.ymlxc xcREADME.md(see below)VS Code vscode.vscode/tasks.json(see below)Invoke invoketasks.py(see below)nox noxnoxfile.py(see below)mask maskmaskfile.md(see below)toxreads the first applicable config file present, in priority order:tox.ini,setup.cfg([tox:tox]),pyproject.toml([tool.tox]), thentox.toml. It statically parses environments and never runstoxduring discovery.misereads the first config file present, in priority order:mise.local.toml,mise.toml,.mise.local.toml,.mise.toml,.config/mise.toml.xcreads its task section fromREADME.md— the block marked with an<!-- xc-heading -->comment, or failing that a heading namedTasks(which is how nur discovers the tasks documented in this very file).composerreads the top-levelscriptsobject fromcomposer.json, surfacing only user-defined custom scripts (Composer's reserved lifecycle hooks likepost-install-cmdare filtered out) and taking descriptions from thescripts-descriptionstable when present.pre-commitreads onlyrepos[].hooks[]and runs a selected hook withpre-commit run <id> --all-files; it never invokespre-commitduring discovery.vscodereads version2.0.0.vscode/tasks.json(JSONC) and surfacesshellandprocesstasks with acommand(an untyped task runs as a process, as in VS Code), applying the current platform's overrides, inheriting the document-leveltypeand, for tasks without their owncommand, itscommandandargs, and resolving${workspaceFolder},${workspaceFolderBasename},${pathSeparator}, and${env:NAME}. Tasks nur cannot run faithfully are skipped: hidden tasks, tasks with a non-emptydependsOn, other variables, oroptionssettingenv,shell, or acwdother than the project root. Shell tasks run through$SHELL -con POSIX (falling back to/bin/sh) andcmd.exeon Windows; an object-formcommandis quoted as a single literal token.invokeparsestasks.pyas a Python syntax tree without importing it or runninginv --list. It discovers top-level functions with a single@task,@task(...), or@invoke.taskdecorator, including import aliases. Literalname=and list/tuplealiases=are supported; underscores become dashes following Invoke's default configuration. Tasks run asinvoke <name>with extra CLI flags passed through, and the first docstring line is the description. Command bodies, required parameters, pre/post hooks, imported or dynamic tasks, conditional definitions, custom decorators, and explicitCollectionwiring are not resolved. Explicit namespaces may therefore make the discovered bare names unavailable, and configuration disabling automatic dashes is not read. Names and aliases containing dots or beginning with a dash are excluded because Invoke interprets them as namespace paths or CLI options.noxparsesnoxfile.pyas a Python syntax tree (never importing it, unlikenox --list) and surfaces top-level@nox.session-decorated functions, runnable asnox -s <name>, using an explicit stringname=when given and the docstring's first line as the description.nox-uv's drop-insessiondecorator is recognised too, andpython=[...]/@nox.parametrizevariants appear under their base name (which runs every variant). Only straight-line noxfiles are trusted: module code may use imports, assignments,def/class, andif/tryblocks made of those (such as try-import fallbacks andif sys.version_info < ...: raiseguards);if TYPE_CHECKING:andif __name__ == "__main__":blocks are skipped. A noxfile that uses loops,with,match,assert,raiseinside atry, or that editsnox.sessionor a namespace directly lists no sessions, rather than sessions nox may not register. Discovery is best-effort: it cannot know whether an import or an expression fails in nox's environment, and deliberately unusual module code (aliasing tricks, handler matching insidetry, and similar) may still list a session nox rejects. Running such a session fails with nox's own error; nur never runs noxfile code to discover sessions.maskreadsmaskfile.mdthe way mask does: each heading after the title is a command, a deeper heading is its subcommand, the last fenced block under a heading is its script, and a>blockquote is its description. A subcommand is named by its path and runs with it, so### test lintunder## testis the tasktest lint(nur "test lint"runsmask test lint). Task names are the shell words aftermask, so one command whose own name has a space is quoted:## deploy prodis the task'deploy prod'. A heading becomes a task only when its last code block is fenced with a language tag, since mask needs the tag to pick an interpreter;powershell,batch, andcmdblocks count only on Windows, as in mask. Headings and fences inside HTML blocks (comments,<details>, and the like) are ignored. Fences nested in blockquotes are not recognised. Like mask, a heading's inline markup restarts its name, so## a *b* cis the taskb c. -
CLI Application: run any discovered task by name or qualified
prefix:name, with--passthrough to the underlying runner. -
TUI Application: interactive three-pane task picker built with Textual.
-
Safe by default: discovery parses files; it never shells out to a runner just to list tasks.
-
Type Safety: full type hints checked by mypy, basedpyright, ty, pyrefly, and zuban.
-
Code Quality: comprehensive linting and formatting with ruff, plus architecture-contract enforcement with import-linter.
-
Testing: pytest with coverage reporting and parallel execution.
-
Documentation: Sphinx documentation with the Shibuya theme, GitHub Pages deployment, and live per-PR documentation previews.
-
CI/CD: automated testing, building, and publishing across multiple platforms.
-
Security: CodeQL, OpenSSF Scorecard, dependency review, secret scanning (gitleaks), dependency auditing (pip-audit), GitHub Actions static analysis (zizmor — a blocking prek/CI gate plus a Security-tab dashboard, over hardened least-privilege workflows), and a CycloneDX SBOM attached to every release.
-
Managed
.gitignore: kept in sync with the upstream github/gitignore templates by cobo, with a weekly drift check. -
Modern Python: uv for dependency management, hatch for building.
Author 🫅
This project is maintained by Hasan Sezer Taşan, It's me 👋
Analysis
- Snyk Python Package Health Analysis
- Libraries.io - PyPI
- Safety DB
- PePy Download Stats
- PyPI Download Stats
- Pip Trends Download Stats
- PyPI Map Dependency Graph
Contributing ❤️
Any contributions are welcome! Please follow the Contributing Guidelines to contribute to this project.
Development 🧰
Clone the repository and cd into the project directory:
git clone https://github.com/hasansezertasan/nur
cd nur
install
Install the dependencies:
uv sync
style
Run the style checks:
uv run --locked tox run -e style
ci
Run the CI pipeline:
uv run --locked tox run
docs-build
Build the documentation site:
uv run --locked tox run -e docs-build
docs-server
Start the live-reloading docs server:
uv run --locked tox run -e docs-server
docs-linkcheck
Check the documentation for broken links (also runs weekly in CI):
uv run --locked tox run -e docs-linkcheck
Releasing
Versioning and releases are automated with release-please, driven by Conventional Commit PR titles squash-merged into main. release-please maintains a release PR that bumps the version and CHANGELOG.md; merging it tags the release and publishes to PyPI. See the Contributing Guidelines for the commit conventions, and the Repository setup guide for one-time configuration and optional post-launch integrations such as a social preview, downstream packaging, and Repology.
Credits
This package was created with Copier and the hasansezertasan/copier-pyproject project template.
License 📜
This project is licensed under the MIT License.
Changelog 📝
For a detailed list of changes, see the GitHub Releases. A CHANGELOG.md is generated automatically by release-please on each release.
Metadata
Release files for nur 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nur-0.6.0.tar.gz | 161.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nur-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 265.5 kB
Release files / nur-0.6.0.tar.gz
| Download URL | nur-0.6.0.tar.gz |
|---|---|
| Size | 161.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
70e17ce98b1976e06d180f39819347aa7fe419eb53784892bb070e4f83bd1658
|
|
BLAKE2b-256 checksum How to use checksums |
36a64b4d6036541c2a89d02ee0a0e6639aa320debc240fb2e3c691894269fc44
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency logRelease files / nur-0.6.0-py3-none-any.whl
| Download URL | nur-0.6.0-py3-none-any.whl |
|---|---|
| Size | 103.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f5422ed0bbaff4f349d70fe7ab74a090f8502be13485db051f6dbc9a2a1cc46f
|
|
BLAKE2b-256 checksum How to use checksums |
6967697ddc67ea4fd32ba93fce9addd8337ef35bfb252c73ef56c0535c7144a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency log