{"id":45990804,"url":"https://github.com/viperadnan-git/nizm","last_synced_at":"2026-05-17T02:26:33.523Z","repository":{"id":341221214,"uuid":"1169327919","full_name":"viperadnan-git/nizm","owner":"viperadnan-git","description":"Lightweight, zero-config pre-commit hooks","archived":false,"fork":false,"pushed_at":"2026-03-01T20:26:15.000Z","size":175,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-05T03:52:46.135Z","etag":null,"topics":["cli","formatter","git","hooks","linter","pre-commit","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/viperadnan-git.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-28T14:20:05.000Z","updated_at":"2026-03-04T22:44:56.000Z","dependencies_parsed_at":"2026-03-01T21:00:57.887Z","dependency_job_id":null,"html_url":"https://github.com/viperadnan-git/nizm","commit_stats":null,"previous_names":["viperadnan-git/nizm"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/viperadnan-git/nizm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viperadnan-git%2Fnizm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viperadnan-git%2Fnizm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viperadnan-git%2Fnizm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viperadnan-git%2Fnizm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/viperadnan-git","download_url":"https://codeload.github.com/viperadnan-git/nizm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viperadnan-git%2Fnizm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30156840,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T22:39:40.138Z","status":"ssl_error","status_checked_at":"2026-03-05T22:39:24.771Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","formatter","git","hooks","linter","pre-commit","rust"],"created_at":"2026-02-28T20:17:19.741Z","updated_at":"2026-05-17T02:26:33.516Z","avatar_url":"https://github.com/viperadnan-git.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cbr\u003e\n\n\u003cimg src=\"https://res.cloudinary.com/viperadnan/image/upload/v1772287432/nizm.svg\" alt=\"nizm\" width=\"120\"\u003e\n\n\u003ch1\u003enizm\u003c/h1\u003e\n\n**Lightweight, zero-config git hooks**\n\n[![Crates.io][crate-badge]][crate-url]\n[![npm][npm-badge]][npm-url]\n[![CI][ci-badge]][ci-url]\n[![License][license-badge]][license-url]\n\n[Quick Start](#quick-start) · [Installation](#installation) · [Configuration](#configuration) · [Commands](#commands) · [How It Works](#how-it-works)\n\n\u003c/div\u003e\n\n**nizm** (from Arabic _nizam_ — system/order) is a fast, native CLI that runs your formatters, linters, and message checks at every git hook stage — `pre-commit`, `commit-msg`, `prepare-commit-msg`, and `pre-push`. It reads hook definitions straight from your existing project manifests — no `.yaml` files, no managed environments. Unlike `pre-commit`, nizm doesn't install tools for you; it trusts the ones already in your dev-dependencies and local `PATH`.\n\n```console\n$ nizm run\nnizm: running against 3 staged files\n  ruff 3 files (120ms)\n  mypy 3 files (340ms)\nnizm: done in 461ms\n```\n\n## Features\n\n- **Zero config** — hooks live in your existing manifest files\n- **Fast** — native Rust binary, no Python/Node runtime overhead\n- **Partial staging** — stashes unstaged changes, runs hooks on staged content only, restores cleanly\n- **Scope filtering** — each hook only sees files matching its glob pattern\n- **Monorepo-ready** — per-directory CWD isolation, multiple manifests, parallel execution\n- **Auto-add** — files modified by formatters are automatically re-staged\n- **Smart init** — scans dev-dependencies, suggests hooks it already knows about\n- **Self-diagnosing** — `nizm doctor` verifies your setup and suggests fixes\n\n## Quick Start\n\n```bash\nnpm install -g nizm-cli   # or: cargo install nizm\nnizm init                 # scans dev-deps, injects hooks, installs git hook\n```\n\nThat's it. Your next `git commit` runs your hooks automatically.\n\n## Installation\n\n\u003cdetails open\u003e\n\u003csummary\u003e\u003cstrong\u003enpm / bun / pnpm / yarn\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\nnpm install -g nizm-cli\n```\n\nPlatform-native binary — zero Node.js overhead at runtime.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCargo (from source)\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\ncargo install nizm\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePrebuilt binaries\u003c/strong\u003e\u003c/summary\u003e\n\nDownload the latest archive for your platform from [GitHub Releases](https://github.com/viperadnan-git/nizm/releases), extract, and place the binary somewhere on your `PATH`.\n\n\u003c/details\u003e\n\n## Configuration\n\nnizm discovers hooks from your project manifests. No separate config file needed.\n\n### pyproject.toml\n\n```toml\n[tool.nizm.hooks]\nruff  = { cmd = \"ruff check --fix {staged_files}\",  glob = \"*.py\" }\nblack = { cmd = \"black {staged_files}\",             glob = \"*.py\" }\nmypy  = { cmd = \"mypy {staged_files}\",              glob = \"*.py\" }\n```\n\n### package.json\n\n```json\n{\n  \"nizm\": {\n    \"hooks\": {\n      \"prettier\": { \"cmd\": \"prettier --write {staged_files}\" },\n      \"eslint\": {\n        \"cmd\": \"eslint --fix {staged_files}\",\n        \"glob\": \"*.{js,jsx,ts,tsx}\"\n      }\n    }\n  }\n}\n```\n\n### Cargo.toml\n\n```toml\n[package.metadata.nizm.hooks]\nclippy  = { cmd = \"cargo clippy --fix --allow-dirty -- -D warnings\", glob = \"*.rs\" }\nrustfmt = { cmd = \"cargo fmt\",                                       glob = \"*.rs\" }\n```\n\n### .nizm.toml\n\nStandalone config for projects that don't use any of the above, or for repo-root overrides:\n\n```toml\n[hooks]\ncheck = { cmd = \"make lint\" }\ntest  = { cmd = \"make test\" }\n```\n\n### Hook fields\n\n| Field     | Type             | Required | Description                                                          |\n| :-------- | :--------------- | :------- | :------------------------------------------------------------------- |\n| `cmd`     | string           | yes      | Shell command to run. Use `{staged_files}` to receive the file list. |\n| `glob`    | string \\| list   | no       | Filter staged files by pattern.                                      |\n| `outputs` | string \\| list   | no       | Files produced/modified by the hook to auto-stage.                   |\n| `type`    | enum             | no       | Git stage: `pre-commit` (default), `pre-push`, `commit-msg`, `prepare-commit-msg`. |\n\n\u003e [!TIP]\n\u003e If `{staged_files}` is omitted, the command runs unconditionally when any file in scope is staged.\n\n### Command placeholders\n\nInside `cmd`, the following tokens are substituted before the shell runs the command:\n\n| Placeholder      | Expands to                                                                |\n| :--------------- | :------------------------------------------------------------------------ |\n| `{staged_files}` | Space-separated list of scoped staged files (shell-escaped).              |\n| `{1}`, `{2}`, …  | Positional arguments forwarded from git (1-based, shell-escaped).         |\n\nThe positional args mirror what git passes to its hook script. Out-of-range references expand to an empty string. Unknown `{name}` tokens are left untouched.\n\n| Hook type            | `{1}`                  | `{2}`     | `{3}` |\n| :------------------- | :--------------------- | :-------- | :---- |\n| `pre-commit`         | _(none)_               | _(none)_  | _(none)_ |\n| `commit-msg`         | path to message file   | _(none)_  | _(none)_ |\n| `prepare-commit-msg` | path to message file   | source    | sha   |\n| `pre-push`           | remote name            | remote url | _(none)_ |\n\n```toml\n[tool.nizm.hooks]\nruff       = { cmd = \"ruff check {staged_files}\", glob = \"*.py\" }\ncommitlint = { cmd = \"commitlint --edit {1}\", type = \"commit-msg\" }\naudit      = { cmd = \"trivy fs --remote {1} .\", type = \"pre-push\" }\n```\n\n### Glob syntax\n\n`glob` and `outputs` accept either a single pattern string or a list of patterns:\n\n```toml\nglob = \"*.py\"                                    # single pattern\nglob = [\"*.py\", \"!**/migrations/**\"]             # list (! = exclude)\nglob = \"*.{js,jsx,ts,tsx}\"                       # brace alternation\noutputs = [\"dist/**\", \"*.min.js\"]                # auto-stage generated files\n```\n\nSupported syntax (per pattern):\n\n| Pattern | Meaning |\n| :------ | :------ |\n| `*` | Any chars except `/` |\n| `?` | Single char except `/` |\n| `**` | Any number of path segments |\n| `[abc]`, `[a-z]`, `[!abc]` | Character classes |\n| `{a,b,c}` | Brace alternation (nests allowed) |\n| `!pattern` | Exclude prefix (only valid as the first char of an entry) |\n\nBare patterns without `/` match at any depth — `*.rs` is equivalent to `**/*.rs`. Anchor with a `/` to restrict depth: `src/*.rs` matches only direct children of `src/`.\n\nExcludes always win: if any `!` pattern matches, the file is filtered out regardless of include order.\n\n## Commands\n\n| Command                       | What it does                                            |\n| :---------------------------- | :------------------------------------------------------ |\n| [`nizm init`](#nizm-init)         | Detect dev-deps and inject hook config                  |\n| [`nizm install`](#nizm-install)   | Bake the git hook script into `.git/hooks/`             |\n| [`nizm run`](#nizm-run)           | Execute hooks (what the git hook calls)                 |\n| [`nizm ls`](#nizm-ls)             | Print configured hooks                                  |\n| [`nizm doctor`](#nizm-doctor)     | Diagnose hook health                                    |\n| [`nizm recover`](#nizm-recover)   | Restore working tree from rescue snapshot               |\n| [`nizm uninstall`](#nizm-uninstall) | Remove hook scripts (and optionally config)           |\n\n### `nizm init`\n\nScans dev-dependencies, suggests hooks, and injects them into your manifest. Pass hook names as arguments to skip the interactive picker (`nizm init ruff prettier`).\n\n```console\n$ nizm init\n  added clippy       cargo clippy --fix --allow-dirty -- -D warnings\n  added rustfmt      cargo fmt\n\n  Cargo.toml — [clippy, rustfmt]\npre-commit hook installed\n```\n\n**Known tools:** `ruff` · `black` · `mypy` · `prettier` · `eslint` · `biome` · `rustfmt` · `clippy`\n\n\u003e [!TIP]\n\u003e For Rust projects, `rustfmt` and `clippy` are suggested automatically when a `[package]` section exists — no dev-dependency needed.\n\n---\n\n### `nizm install`\n\nWrites a git hook script into `.git/hooks/` that calls `nizm run`. Existing non-nizm hooks are preserved.\n\n| Flag              | Description                                                  |\n| :---------------- | :----------------------------------------------------------- |\n| `--config \u003cPATH\u003e` | Bake a specific manifest path (repeatable, skips the picker) |\n| `--parallel`      | Bake the `--parallel` flag into the hook script              |\n| `--force`         | Overwrite a modified nizm block without prompting            |\n\n```console\n$ nizm install\nscanning for manifests...\n  pyproject.toml — [ruff, mypy]\npre-commit hook installed\n```\n\n---\n\n### `nizm run`\n\nExecutes hooks against staged files. Called by the git hook script — you usually don't run this directly. Pass `HOOK` to run a single hook by name; pass `-- ARGS...` to forward positional args to `{1}`, `{2}`, … in `cmd`.\n\n| Flag                 | Description                                              |\n| :------------------- | :------------------------------------------------------- |\n| `--config \u003cPATH\u003e`    | Explicit manifest paths (repeatable, skips auto-discovery) |\n| `--hook-type \u003cTYPE\u003e` | Hook type to run (default: `pre-commit`)                 |\n| `--parallel`         | Run manifests concurrently                               |\n| `--all`              | Run against all tracked files instead of staged          |\n\n```console\n$ nizm run\nnizm: running against 5 staged files\n  clippy 5 files (780ms)\n  rustfmt 5 files (210ms)\nnizm: done in 991ms\n```\n\n---\n\n### `nizm ls`\n\nPrints every configured hook across all discovered manifests.\n\n```console\n$ nizm ls\nCargo.toml\n  clippy   cargo clippy --fix --allow-dirty -- -D warnings  *.rs\n  rustfmt  cargo fmt                                        *.rs\n```\n\n---\n\n### `nizm doctor`\n\nDiagnoses hook health — checks hook scripts, config validity, and tool availability.\n\n```console\n$ nizm doctor\nhooks\n  pre-commit (nizm-managed) ✓\n  └ Cargo.toml ✓\n     ├ clippy (cargo) ✓\n     └ rustfmt (cargo) ✓\n\nall 4 checks passed\n```\n\nExits non-zero if any check fails — safe to wire into CI.\n\n---\n\n### `nizm recover`\n\nRestores your working tree from the rescue snapshot saved before a failed stash operation.\n\n```console\n$ nizm recover\nworking tree restored from rescue snapshot\n```\n\nIf recovery produces conflicts, resolve them manually — the rescue ref (`refs/nizm-backup`) is cleaned up automatically once the restore succeeds.\n\n---\n\n### `nizm uninstall`\n\nRemoves nizm-managed blocks from `.git/hooks/` scripts.\n\n| Flag      | Description                                          |\n| :-------- | :--------------------------------------------------- |\n| `--purge` | Also strip `[tool.nizm.hooks]` blocks from manifests |\n\n```console\n$ nizm uninstall --purge\npre-commit hook removed\n  cleaned Cargo.toml\n```\n\n---\n\n### Environment variables\n\n| Variable    | Description                                              |\n| :---------- | :------------------------------------------------------- |\n| `NIZM_SKIP` | Comma-separated hook names to skip (e.g. `mypy,ruff`)    |\n| `NO_COLOR`  | Disable colored output when set to any non-empty value   |\n\n## How It Works\n\n```\ngit commit\n    │\n    ▼\n.git/hooks/pre-commit        ← baked by `nizm install`\n    │\n    ▼\nnizm run --config pyproject.toml --config package.json\n    │\n    ├─ detect partially staged files\n    ├─ stash unstaged changes (StashGuard)\n    │\n    ├─ for each manifest:\n    │     ├─ cd to manifest directory\n    │     ├─ for each hook:\n    │     │     ├─ scope-filter staged files by glob\n    │     │     └─ execute cmd with {staged_files}\n    │     └─ next hook\n    │\n    ├─ auto-add files modified by hooks\n    ├─ restore unstaged changes from stash\n    └─ exit 0 (pass) or exit 1 (fail → commit blocked)\n```\n\n### Partial staging\n\nWhen you stage only part of a file (`git add -p`), nizm stashes the unstaged changes before running hooks. This ensures formatters and linters see exactly what will be committed — not your working tree. After hooks complete, unstaged changes are restored cleanly.\n\nA rescue ref is saved at `refs/nizm-backup` before every stash operation. If anything goes wrong:\n\n```bash\nnizm recover\n```\n\n### Parallel execution\n\nWith `--parallel`, each manifest's hooks run in a separate thread. Hooks within a single manifest stay sequential (so your formatter runs before your linter). Output is captured per-manifest and printed in order — no interleaving.\n\n### Monorepo support\n\nnizm uses `git ls-files` to discover manifests, respecting `.gitignore` at all levels. Each manifest's hooks run with `cwd` set to that manifest's directory, so tools resolve paths correctly:\n\n```\nrepo/\n├── pyproject.toml          ← ruff, mypy run here\n├── frontend/\n│   └── package.json        ← prettier, eslint run here\n└── services/api/\n    └── package.json        ← separate hooks, separate cwd\n```\n\n## Building from source\n\n```bash\ngit clone https://github.com/viperadnan-git/nizm.git\ncd nizm\ncargo build --release\n# Binary at target/release/nizm\n```\n\n### Running checks\n\n```bash\ncargo fmt -- --check\ncargo clippy -- -D warnings\ncargo test\n```\n\n## License\n\n[MIT](LICENSE)\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\nBuilt with Rust. No runtime dependencies. Just fast hooks.\n\n\u003c/div\u003e\n\n\u003c!-- link references --\u003e\n\n[crate-badge]: https://img.shields.io/crates/v/nizm?style=flat-square\u0026labelColor=1a1a2e\u0026color=e94560\n[crate-url]: https://crates.io/crates/nizm\n[npm-badge]: https://img.shields.io/npm/v/nizm-cli?style=flat-square\u0026labelColor=1a1a2e\u0026color=0f3460\n[npm-url]: https://www.npmjs.com/package/nizm-cli\n[ci-badge]: https://img.shields.io/github/actions/workflow/status/viperadnan-git/nizm/ci.yml?style=flat-square\u0026labelColor=1a1a2e\u0026label=CI\n[ci-url]: https://github.com/viperadnan-git/nizm/actions/workflows/ci.yml\n[license-badge]: https://img.shields.io/badge/license-MIT-16c79a?style=flat-square\u0026labelColor=1a1a2e\n[license-url]: https://github.com/viperadnan-git/nizm/blob/main/LICENSE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviperadnan-git%2Fnizm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fviperadnan-git%2Fnizm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviperadnan-git%2Fnizm/lists"}