Skip to main content

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:

  1. an environment file: -e environment.yaml
  2. 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 .py script, a PEP 723 block, where dependencies are pip packages and [tool.xnb] holds conda packages and channels:
      # /// script
      # dependencies = ["six"]
      # [tool.xnb]
      # dependencies = ["numpy"]
      # ///
      
  3. 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:/dst copies files in. :rw mounts are written back after the run, and only as regular files under src: 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 Fetch interception) denies every request, the proxy refuses everything, and the kernel worker also has connect-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 --strict refuses to run at all.
    • On Windows (and with XNB_CDP_TRANSPORT=ws), DevTools uses a loopback WebSocket port instead of a pipe.

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 local variables 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)

Source distribution for xnotebook 1.0.0
File Size Uploaded
xnotebook-1.0.0.tar.gz 62.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xnotebook 1.0.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page