{"id":49340021,"url":"https://github.com/moonrunnerkc/nborder","last_synced_at":"2026-04-27T03:04:58.126Z","repository":{"id":354062247,"uuid":"1221860028","full_name":"moonrunnerkc/nborder","owner":"moonrunnerkc","description":"A fast, opinionated linter and auto-fixer for Jupyter notebook hidden-state and execution-order bugs.","archived":false,"fork":false,"pushed_at":"2026-04-27T00:36:16.000Z","size":257,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-27T01:22:32.899Z","etag":null,"topics":["code-quality","data-science","dataflow-analysis","github-actions","jupyter-notebook","linter","pre-commit","python","reproducibility","static-analysis"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/nborder/","language":"Python","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/moonrunnerkc.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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-04-26T19:16:21.000Z","updated_at":"2026-04-27T00:36:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/moonrunnerkc/nborder","commit_stats":null,"previous_names":["moonrunnerkc/nborder"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/moonrunnerkc/nborder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moonrunnerkc%2Fnborder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moonrunnerkc%2Fnborder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moonrunnerkc%2Fnborder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moonrunnerkc%2Fnborder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moonrunnerkc","download_url":"https://codeload.github.com/moonrunnerkc/nborder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moonrunnerkc%2Fnborder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32320688,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["code-quality","data-science","dataflow-analysis","github-actions","jupyter-notebook","linter","pre-commit","python","reproducibility","static-analysis"],"created_at":"2026-04-27T03:04:57.444Z","updated_at":"2026-04-27T03:04:58.119Z","avatar_url":"https://github.com/moonrunnerkc.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nborder\n\nA fast, opinionated linter and auto-fixer for Jupyter notebook hidden-state and execution-order bugs.\n\n[![PyPI version](https://img.shields.io/pypi/v/nborder.svg)](https://pypi.org/project/nborder/)\n[![CI](https://github.com/moonrunnerkc/nborder/actions/workflows/ci.yml/badge.svg)](https://github.com/moonrunnerkc/nborder/actions/workflows/ci.yml)\n[![Python](https://img.shields.io/pypi/pyversions/nborder.svg)](https://pypi.org/project/nborder/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n## What this catches\n\n| Code  | Name                                | One-line example |\n|-------|-------------------------------------|------------------|\n| NB101 | Non-monotonic execution counts      | Cell 1 ran with `In [3]:` after cell 0 ran with `In [5]:`. |\n| NB102 | Won't survive Restart-and-Run-All   | `print(df)` references a name no cell in the notebook defines. |\n| NB201 | Use-before-assign across cells      | Cell 0 uses `df`; `df = ...` only appears in cell 1. |\n| NB103 | Stochastic library used without seed | `np.random.rand(3)` runs with no seed call before it. |\n\nEach rule has a docs page under [`docs/rules/`](docs/rules/) explaining the bug class, a bad and good example, and the auto-fix behaviour.\n\n## Quick start\n\n```bash\npip install nborder\nnborder check notebook.ipynb\nnborder check --fix notebook.ipynb\nnborder check --output-format=json notebook.ipynb\n```\n\nThe `--fix` flag reorders cells topologically when the dependency graph is a DAG, injects library-appropriate seed calls for stochastic libraries, and clears execution counts when they no longer reflect a reproducible run order. Every fix is a pipeline stage with a `bailed` outcome that does not block other fixes; running the same fix twice is a byte-stable no-op.\n\n## Pre-commit\n\nAdd this to your `.pre-commit-config.yaml`:\n\n```yaml\nrepos:\n  - repo: https://github.com/moonrunnerkc/nborder\n    rev: v0.1.0\n    hooks:\n      - id: nborder\n```\n\nThen `pre-commit install`. Full setup notes in [`docs/integrations/pre-commit.md`](docs/integrations/pre-commit.md).\n\n## GitHub Actions\n\n```yaml\n- uses: moonrunnerkc/nborder@v0.1.0\n  with:\n    path: notebooks/\n```\n\nDiagnostics show up as inline annotations on the PR. Full options in [`docs/integrations/github-actions.md`](docs/integrations/github-actions.md).\n\n## Configuration\n\n`nborder` reads its configuration from `[tool.nborder]` in `pyproject.toml`:\n\n```toml\n[tool.nborder.seeds]\nvalue = 42\nlibraries = [\"numpy\", \"torch\", \"tensorflow\", \"random\"]\n```\n\nRun `nborder config` to print the effective merged configuration.\n\n## FAQ\n\n**Why not use ruff?** Ruff lints Python source, not notebook structure. It does not see cross-cell dataflow, so it cannot detect that `df` is used in cell 0 and only defined in cell 1. nborder is purpose-built for the cross-cell story; it is complementary to ruff, not competitive.\n\n**How is this different from nbqa?** `nbqa` runs Python linters against notebook cells one at a time. nborder builds a cross-cell symbol dependency graph and reasons about the relationships between cells, which is the part nbqa explicitly does not do.\n\n**Does it work with R or Julia notebooks?** Not in v0.1. Multi-language support is reserved for a future release. Python kernels cover roughly 95% of notebooks in the wild.\n\n**Will it modify my notebook outputs?** No. Outputs, cell metadata, and notebook-level metadata are read-only. The only fix that touches `execution_count` is a clear-to-null operation that runs as part of the reorder fix.\n\n**What about magics?** `%line`, `%%cell`, `!shell`, and shell-assignment forms (`files = !ls`) are stripped to typed metadata before parsing. Magic-defined bindings (e.g., `%%capture out` defines `out`) are recorded in the dataflow graph; see [`docs/known-limitations.md`](docs/known-limitations.md) for the limits.\n\n**How do I suppress a false positive?** Add `# nborder: noqa` (suppress all rules in the cell) or `# nborder: noqa: NB201,NB102` (suppress specific rules) to any line in the cell.\n\n**What if I want to disable a rule entirely?** Rule selection lands in v0.2. For now, use `# nborder: noqa: NB201` to suppress a rule for one cell.\n\n**What is on the roadmap?** v0.2 adds project-wide rule selection and the opt-in fresh-kernel `--reproduce` pass. The static linter remains the default path.\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n## License\n\nMIT. See [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoonrunnerkc%2Fnborder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoonrunnerkc%2Fnborder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoonrunnerkc%2Fnborder/lists"}