Extension points overview#

This page is a map of safe ways to extend Cellucid Python and a decision guide for when changes require coordination with the web app.

If you are planning a change, start here before coding:


The first decision: “Python-only” vs “contract change”#

Python-only changes (low coordination)#

Examples:

  • add a helper function (e.g., vector field utilities)

  • add a CLI subcommand that doesn’t change the Cellucid-ready AnnData contract

  • add docs pages or notebooks

  • improve error messages, validation, performance inside existing contracts

Usually touches:

  • src/cellucid/*.py

  • docs/

  • tests/

Contract changes (requires coordination)#

Examples:

  • new elements or uns['cellucid'] keys in the Cellucid-ready AnnData

  • new launch defaults

  • new hook event types or new frontend command types

  • changes to session file chunk codecs

These must be coordinated with:

  • the web app loader and UI behavior (cellucid/ repo)

  • cellucid-r, which writes the same Cellucid-ready AnnData and speaks the same viewer channel (the shared viewer-protocol.json)

Start with:


Extension point catalog#

A) Add a new public Python API function/class#

Checklist:

  1. implement in src/cellucid/<module>.py

  2. export via src/cellucid/__init__.py (__getattr__ + __all__)

  3. add docs (user guide or API reference)

  4. add tests for edge cases

Watch out for:

  • importing heavy dependencies at module import time (CLI startup)

B) Add a new CLI command#

Checklist:

  1. add a subparser in src/cellucid/cli.py

  2. keep parser lightweight (no heavy imports)

  3. import heavy deps inside command handler

  4. document in CLI architecture and commands

C) Add something to the Cellucid-ready AnnData (a new element or uns['cellucid'] key)#

This is the most coordination-heavy extension point.

Checklist:

  • read prepare() writer architecture

  • update together:

    • prepare_data/ (the Python writer) and cellucid-r’s cellucid_prepare()

    • the web app’s AnnData reader (cellucid/assets/js/data/anndata/, and anndata-cellucid-metadata.js / requireAnnDataLaunchDefaults for a key)

    • _launch_defaults.py for a launch default, so the server accepts it too

    • Cellucid-ready AnnData specification

D) Add a new hook event or command#

Checklist:

E) Extend session file parsing#

Session files are untrusted input and must remain robust.

Checklist:

  • define one exact schema for every new chunk or codec

  • keep hard caps on decompression and allocations

  • update tests in tests/test_sessions.py (add synthetic bundles; the golden history tests/fixtures/history_golden/ is regenerated by the web repository’s scripts/generate-history-golden.mjs, never by hand)


Contract-change strategy#

When adding new fields/files:

  • update every writer, server adapter, loader, validator, test, and format document in the same change;

  • reject unknown keys and unsupported schemas with a clear error;

  • do not retain alternate schema readers or redirect paths.


Troubleshooting#

Symptom: “I added a key to uns['cellucid'] and the viewer refuses the file”#

Cause:

  • the web app refuses any key it does not know, so a misspelt default never passes unnoticed.

Fix:

  • add the key to the web app’s anndata-cellucid-metadata.js (or requireAnnDataLaunchDefaults) in the same change, and to cellucid-r.

Symptom: “I added an element but the viewer never reads it”#

Cause:

  • the web app’s AnnData reader is not hooked up to it.

Fix:

  • update the web app’s reader in the same change.