xnotebook
Run Jupyter notebooks and scripts on xeus wasm kernels with emscripten-forge packages, sandboxed inside headless Chromium.
$ pip install xnotebook
$ xnb analysis.ipynb # writes analysis.out.ipynb
$ xnb script.py -d numpy # prints outputs as they come
The command is xnb (xnotebook works too), and the Python module is xnotebook.
The first run downloads a pinned, sha256-verified chrome-headless-shell
(about 120 MB) into the cache. No conda, Node or system browser is needed.
Dependencies
Three sources are merged, and a later source wins for the same package:
- an environment file:
-e environment.yaml - the input file itself:
- notebook metadata
metadata.xnb, which uses the environment.yaml schema:"metadata": {"xnb": {"channels": ["conda-forge"], "dependencies": ["numpy", {"pip": ["six"]}]}}
- or, in a
.pyscript, a PEP 723 block, wheredependenciesare pip packages and[tool.xnb]holds conda packages and channels:# /// script # dependencies = ["six"] # [tool.xnb] # dependencies = ["numpy"] # ///
- notebook metadata
- the CLI:
-d numpy -d "pandas>=2" --pip six -c conda-forge
Channels default to https://prefix.dev/emscripten-forge-4x and conda-forge. The
kernel comes from --kernel, then the notebook's kernelspec, then the file extension:
| kernel | package | extension |
|---|---|---|
xpython |
xeus-python | .py |
xr |
xeus-r | .R |
xlua |
xeus-lua | .lua |
xjavascript |
xeus-javascript | .js |
Solved environments are cached as locks. --lock-out lock.json saves the lock, and
--lock lock.json reuses it without solving.
Widgets
ipywidgets state is saved in metadata.widgets
(application/vnd.jupyter.widget-state+json), like jupyter nbconvert --execute does.
JupyterLab, nbviewer and Voila then render the widgets with the values they had at the
end of the run. Closed widgets are dropped. Use --no-widget-state to turn this off.
See demo/widgets_demo.ipynb.
Scripts are split into cells at # %% markers (percent format). The comment prefix
follows the language, so Lua uses -- %%.
Security model
Notebook code runs in a Web Worker inside Chromium:
- Files: the kernel sees only an in-memory filesystem, so the host disk is out of
reach.
--mount src:/dstcopies files in.:rwmounts are written back after the run, and only as regular files undersrc: no symlinks, no.., with size caps. - Network: none for notebook code.
- Packages are fetched before any package or user code runs. Everything goes through a local caching proxy that verifies each file against the lock's sha256.
- Then the run is sealed. The host firewall (CDP
Fetchinterception) denies every request, the proxy refuses everything, and the kernel worker also hasconnect-src 'none'. - Chromium's own DNS is disabled.
- Processes and environment: not available from a browser worker.
- OS sandbox:
- Chromium's OS sandbox is used when the system allows it. Otherwise xnb warns and
runs with
--no-sandbox, and--strictrefuses to run at all. - On Windows (and with
XNB_CDP_TRANSPORT=ws), DevTools uses a loopback WebSocket port instead of a pipe.
- Chromium's OS sandbox is used when the system allows it. Otherwise xnb warns and
runs with
CLI
xnb FILE [-o OUT|-] [--inplace] [-q]
[-e ENV.yaml] [-d SPEC]... [--pip SPEC]... [-c CHANNEL]... [--kernel NAME]
[--lock FILE] [--lock-out FILE]
[--mount SRC:DST[:ro|rw]]... [--cwd DIR] [--stdin FILE]
[--timeout S] [--cell-timeout S] [--max-memory MB] [--allow-errors] [--no-widget-state] [-v]
[--offline] [--refresh] [--strict] [--browser-path PATH] [--cache-dir DIR] [--debug]
xnb setup [--from chrome-headless-shell.zip]
xnb cache {info,clean,prune}
Exit codes: 0 on success, 1 when a cell fails or times out, 2 for usage or setup errors.
Python API
import xnotebook
nb = xnotebook.run("analysis.ipynb", deps=["numpy"], cell_timeout=60) # returns the executed nbformat dict
res = xnotebook.run(nb_dict, allow_errors=True, return_result=True) # includes status, failedCell, stats
Cache
The cache lives in ~/.cache/xnb by default ($XNB_CACHE_DIR overrides it):
chromium/: the pinned browser;pkgs/<sha256>: packages, fetched lazily and immutable;repodata/: metadata, with ETag and a 1 h TTL;locks/: solved environments.
--offline uses only the cache, and --refresh re-solves and revalidates.
Development
$ cd web && npm ci && npm run build && npm test # bundle -> xnotebook/_web
$ pip install -e ".[test]"
$ pytest # browser tests are skipped without Chromium
$ python tools/pin_chromium.py 154.0.8037.57 # hashes for chromium.PINNED
Known limitations
- Widgets: the final ipywidgets state is saved as a static snapshot. Python callbacks don't run when the saved notebook is opened.
- pip: pure-Python wheels only.
- xeus-lua: each top-level line is evaluated on its own, so
localvariables don't persist across lines. Use globals.
Metadata
Release files for xnotebook 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| xnotebook-1.0.0.tar.gz | 62.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| xnotebook-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 3.4 MB
Release files / xnotebook-1.0.0.tar.gz
| Download URL | xnotebook-1.0.0.tar.gz |
|---|---|
| Size | 62.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b3a8b26fa2ccf9a354f03a9bf84febfd6dbecbce8eeaf4caa5cbca748f20d2b6
|
|
BLAKE2b-256 checksum How to use checksums |
ac89da988bd4fc3bb9c5cb83d3f1aa41a97c7d138054fb370aec21521c56b135
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / xnotebook-1.0.0-py3-none-any.whl
| Download URL | xnotebook-1.0.0-py3-none-any.whl |
|---|---|
| Size | 3.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1329ff2f1df4d846e92a10a3d18d0ff32730cd34c57c78c9d32789547af5524
|
|
BLAKE2b-256 checksum How to use checksums |
b654695589638625832f25008d58bc4c8065cad66cd31e86698d96bcdf552224
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log