π¨ 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:
Input β NgffImage - Convert various formats to
NgffImageNgffImage β NgffMultiscales - Generate resolution levels via
to_multiscales()NgffMultiscales β OME-Zarr - Write to Zarr stores via
to_ome_zarr()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:
π¬ Open an issue first - For significant changes, open a GitHub issue to discuss your proposal before starting work
π΄ Fork the repository - Create your own fork
πΏ Create a branch - Create a feature branch from
mainβοΈ Make changes - Implement your changes with tests
πΎ Commit - Use Conventional Commit messages
π€ Push - Push to your fork
π¬ 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
π― Scopes (optional but recommended)ΒΆ
π
py- Python package (ngff-zarr)π
mcp- MCP server package (ngff-zarr-mcp)π¦
ts- TypeScript package (@fideus-labs/ngff-zarr)
π‘ 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), plusnode --testagainst the built package and Playwright in real browsersπ MCP: pytest with async patterns
π Pyodide:
py/test/pyodide/run.mjsrunstest_pyodide.pyin Pyodide under Node against the JavaScript package; thepyodidejob 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_casefor functions/variables,PascalCasefor 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 fmtapplies itπ€ Types: Strict TypeScript compiler options, with
erasableSyntaxOnlyso Node can run the.tssources directlyπ¦ Imports: relative imports keep their
.tsextension; 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.
Add the new data to py/test/data, then generate a new tarball and compute its sha256 hash:
cd py pixi run hash-data
Upload the resulting
data.tar.gzas an asset on thetesting-datarelease, renamed with the nextngff-zarr-testing-data-v<version>.tar.gzversion.Update the
urlandtest_data_sha256variables 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! π