πŸ”¨ DevelopmentΒΆ

Welcome! πŸ‘‹ We’re glad you’re interested in contributing to ngff-zarr. Whether you’re fixing bugs, adding features, improving documentation, or helping with testing, your contributions are greatly appreciated. πŸŽ‰

πŸ“œ Code of ConductΒΆ

Please read and follow our Code of Conduct. We are committed to providing a welcoming and inclusive environment for everyone.

πŸ—‚οΈ Project overviewΒΆ

ngff-zarr is a multi-language implementation of the OME-NGFF Zarr specification:

ngff-zarr/
β”œβ”€β”€ py/          # Python package (ngff-zarr)
β”œβ”€β”€ mcp/         # Model Context Protocol server (ngff-zarr-mcp)
β”œβ”€β”€ ts/          # TypeScript package (@fideus-labs/ngff-zarr)
└── docs/        # Documentation

πŸ›οΈ Core architectureΒΆ

The central workflow follows this pattern across all implementations:

  1. Input β†’ NgffImage - Convert various formats to NgffImage

  2. NgffImage β†’ NgffMultiscales - Generate resolution levels via to_multiscales()

  3. NgffMultiscales β†’ OME-Zarr - Write to Zarr stores via to_ome_zarr()

  4. OME-Zarr β†’ NgffMultiscales - Read back via from_ome_zarr()

πŸš€ Getting startedΒΆ

PrerequisitesΒΆ

Install pixi for environment management.

Get the source codeΒΆ

git clone https://github.com/fideus-labs/ngff-zarr
cd ngff-zarr

βš™οΈ Install dependenciesΒΆ

Each package directory (py/, ts/, mcp/) carries its own pixi manifest. Install the Python environments and the Git hooks, which are managed by prek:

cd py
pixi install -a
pixi run prek-install

prek install reads default_install_hook_types from .pre-commit-config.yaml, so it installs shims for both pre-commit (linting and formatting) and commit-msg (commit message validation).

πŸ”„ Contributing workflowΒΆ

We use the standard GitHub flow:

  1. πŸ’¬ Open an issue first - For significant changes, open a GitHub issue to discuss your proposal before starting work

  2. 🍴 Fork the repository - Create your own fork

  3. 🌿 Create a branch - Create a feature branch from main

  4. ✏️ Make changes - Implement your changes with tests

  5. πŸ’Ύ Commit - Use Conventional Commit messages

  6. πŸ“€ Push - Push to your fork

  7. πŸ“¬ Open a pull request - Submit a PR against main

πŸ“‹ Pull request guidelinesΒΆ

  • βœ… CI must pass - All checks must be green before merge

  • πŸ’¬ Be responsive - Please respond to review comments in a timely manner

  • ⏳ Be patient - Reviews may take time; we appreciate your patience

  • πŸ€– Copilot reviews - GitHub Copilot may flag false positives; if you believe a suggestion is incorrect, leave a comment explaining why and resolve as appropriate

πŸ“ Commit messagesΒΆ

We follow the Conventional Commits standard. All commit messages are validated by Commitizen hooks, which run via prek.

πŸ“ FormatΒΆ

<type>(<scope>): <description>

[optional body]

[optional footer]

🏷️ Types¢

  • ✨ feat - New feature

  • πŸ› fix - Bug fix

  • πŸ“– docs - Documentation changes

  • 🎨 style - Code style changes (formatting, etc.)

  • ♻️ refactor - Code refactoring

  • ⚑ perf - Performance improvements

  • πŸ§ͺ test - Adding or updating tests

  • πŸ—οΈ build - Build system changes

  • πŸ”§ ci - CI/CD changes

  • 🧹 chore - Maintenance tasks

πŸ’‘ ExamplesΒΆ

feat(py): add support for zarr v3 sharding
fix(mcp): handle missing metadata gracefully
docs: update installation instructions
chore(ts): update dependencies

πŸ§™ Interactive commit helperΒΆ

If you need help writing compliant commit messages, use the interactive CLI:

# From the repository root, for whichever package you are committing:
(cd py && pixi run commit)
(cd ts && pixi run commit)
(cd mcp && pixi run commit)

This will guide you through creating a properly formatted commit message.

πŸ›‘οΈ Commit message validationΒΆ

The Git hooks automatically validate your commit messages. If a commit message doesn’t follow the Conventional Commits format, the commit is rejected with a helpful error message.

🏷️ Version management¢

Each package is versioned independently. Check the current version of a package with:

(cd py && pixi run version-check)   # Python package version
(cd ts && pixi run version-check)   # TypeScript package version
(cd mcp && pixi run version-check)  # MCP package version

πŸ› οΈ Development commandsΒΆ

All development uses pixi for consistent environments. Run the commands from the corresponding package directory.

🐍 Python (py/)¢

cd py
pixi install -a                 # Install all environments
pixi run test                   # Run the test suite
pixi run lint                   # Run the prek hooks (ruff, codespell, ...)
pixi run build-docs             # Build the documentation

Run a single test with pytest directly:

pixi run -e test pytest test/test_to_multiscales.py::test_downsamples_when_size_is_exactly_double_chunk

Run the package inside Pyodide, hosted by Node 25 or newer (JSPI on by default; Node 24 needs --experimental-wasm-jspi). The harness installs the built wheel with micropip, registers the @fideus-labs/ngff-zarr npm package as the ngff_zarr_js module and runs py/test/pyodide/test_pyodide.py:

pip wheel py/ -w py/dist --no-deps        # from the repository root
cd py/test/pyodide && npm ci && node run.mjs

πŸ”Œ MCP server (mcp/)ΒΆ

cd mcp
pixi install -e dev             # Install the development environment
pixi run test                   # Run tests
pixi run typecheck              # Type checking (mypy)
pixi run format                 # Format code
pixi run lint                   # Run linting

🟦 TypeScript (ts/)¢

cd ts
pixi run install                # npm ci (once, and after lockfile changes)
pixi run test                   # Vitest suite
pixi run lint                   # Oxlint
pixi run fmt                    # Oxfmt
pixi run check                  # Format + lint + type check
pixi run build                  # Emit dist/
pixi run test-node              # Node tests against the built package
pixi run test-browser           # Playwright browser tests

The pixi tasks alias the npm scripts in ts/package.json, which run Vite+ (vp); npm run <script> works equally well.

πŸ§ͺ TestingΒΆ

  • 🐍 Python: pytest, with fixtures in py/test/conftest.py

  • 🟦 TypeScript: Vitest (vp test), plus node --test against the built package and Playwright in real browsers

  • πŸ”Œ MCP: pytest with async patterns

  • 🌐 Pyodide: py/test/pyodide/run.mjs runs test_pyodide.py in Pyodide under Node against the JavaScript package; the pyodide job of the Python workflow runs it in CI

Run the tests before submitting a pull request to ensure nothing is broken. βœ…

🎨 Code style¢

🐍 Python¢

  • πŸ“ Line length: 88 characters (Ruff standard)

  • πŸ“¦ Imports: Absolute imports, grouped by standard/third-party/local

  • πŸ”€ Types: Use type hints for public APIs

  • 🏷️ Naming: snake_case for functions/variables, PascalCase for classes

  • πŸ“ Docstrings: Required for public functions and classes

Ruff, via the prek hooks, enforces the style automatically. Run cd py && pixi run lint before committing.

🟦 TypeScript¢

  • 🎨 Style: Oxfmt (80 char width, 2 space indent, semicolons, double quotes); pixi run fmt applies it

  • πŸ”€ Types: Strict TypeScript compiler options, with erasableSyntaxOnly so Node can run the .ts sources directly

  • πŸ“¦ Imports: relative imports keep their .ts extension; bare package names for dependencies; node: prefix for Node built-ins

πŸ“– Build the documentationΒΆ

If needed, build and update the documentation. This serves the docs locally and rebuilds them as you edit:

cd py
pixi run dev-docs

To build the HTML once, without the auto-reloading server:

cd py
pixi run build-docs

πŸ—ƒοΈ Update the test dataΒΆ

If needed, update the testing data.

  1. Add the new data to py/test/data, then generate a new tarball and compute its sha256 hash:

    cd py
    pixi run hash-data
    
  2. Upload the resulting data.tar.gz as an asset on the testing-data release, renamed with the next ngff-zarr-testing-data-v<version>.tar.gz version.

  3. Update the url and test_data_sha256 variables in py/test/_data.py to point at the new asset and its hash.

❓ Questions?ΒΆ

If you have questions, please open a GitHub issue.

Thank you for contributing! πŸ’–