AI-native notebooks from plain Python files.
Project description
nb-lab
AI-native notebooks from plain Python files.
nb-lab turns .py:percent scripts (with # %% cells) into notebook-style sessions with a simple HTTP API so humans and AI agents can read, edit, and run cells, and understand plots without .ipynb.
Install
Package name on PyPI is nb-lab-runtime; the CLI remains nb-lab.
Use uv:
uv add nb-lab-runtime
For local development:
uv sync
This installs the nb-lab CLI entry point.
If you prefer, you can also use uv run nb-lab ... without installing globally.
Recommended (after release): uvx
Once nb-lab-runtime is published, you can run it without cloning:
uvx --from nb-lab-runtime nb-lab serve /path/to/your-ds-repo/notebook.py
Quick start
Create a .py file with # %% cells:
# %% [markdown]
# Simple example
# %%
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 200)
y = np.sin(x)
# %%
plt.plot(x, y)
plt.title("Sine wave")
plt.show()
Start the server:
nb-lab serve path/to/script.py
If binding fails, use an ephemeral port:
nb-lab serve path/to/script.py --port 0
Troubleshooting (restricted environments)
If you see cache or permission errors, set writable cache directories:
export NB_LAB_CACHE_DIR=/tmp/nb-lab-cache
export MPLCONFIGDIR=/tmp/mpl-cache
export UV_CACHE_DIR=/tmp/uv-cache
Using nb-lab with another repo
Run nb-lab from this repo but point at a different project:
cd /path/to/nb-lab
uv sync
nb-lab serve /path/to/your-ds-repo/notebook.py
If nb-lab is not on your PATH, re-run uv sync.
Recommended for multi-repo use (uv tool install)
Install nb-lab once and use it across projects:
uv tool install -e /path/to/nb-lab
nb-lab serve /path/to/your-ds-repo/notebook.py
This keeps your data science repo’s dependencies separate from nb-lab’s runtime.
Helper script:
bash scripts/install_tool.sh
List cells:
nb-lab list
Run a cell:
nb-lab run <CELL_ID> --mode incremental
Show outputs:
nb-lab show <CELL_ID>
Suppress image payloads:
nb-lab run <CELL_ID> --no-images
nb-lab show <CELL_ID> --compact
Check server status:
nb-lab status
Tip: --base-version is optional. If omitted, nb-lab fetches the latest version automatically.
You can also use --cell-index N to refer to the Nth cell in nb-lab list.
Cache commands
nb-lab cache info
nb-lab cache list
nb-lab cache clear --yes
nb-lab cache clear --all
nb-lab cache clear --path path/to/notebook.py
Smoke demo
Run an end-to-end demo that starts the server, runs a cell, and fetches outputs:
uv sync
bash scripts/smoke_demo.sh
Live workflow demo (agent-in-the-loop)
Here is a concrete end-to-end workflow that shows why nb-lab exists. The agent never touches .ipynb and still iterates like a notebook.
- Start the server on a real
.py:percentnotebook:
nb-lab serve examples/demo.py
- List cells and grab the current version:
nb-lab list
- Pick a target cell and run it (incremental, no full replay):
nb-lab run --cell-index 1 --mode incremental
- Fetch outputs and inspect both text and plot metadata:
nb-lab show <CELL_ID>
- Let the agent edit a cell in the middle and rerun just what’s needed:
cat <<'PY' | nb-lab edit --cell-index 1 --from-stdin
<NEW_CODE>
PY
- Re-run the changed cell; nb-lab replays only the dirty prefix:
nb-lab run --cell-index 1
This is the critical workflow: the agent can read/edit/run cells and reason about plots via plot_meta without JSON notebooks or manual state management.
Mini transcript (agent loop)
User: "Check if the sine plot has a mean offset, and annotate it."
Agent -> GET /cells
Agent: Finds plot cell id = c3, base_version = 7
Agent -> POST /cells/c3/run
Agent -> GET /outputs/c3
Agent: Sees plot_meta.summary_text = "Line plot with 1 series."
Agent -> POST /cells/c2/edit
Agent: Inserts mean calculation and axhline overlay
Agent -> POST /cells/c3/run
Agent: Receives updated plot_meta + image_png
User: "Looks good—ship it."
Execution semantics
- The
.pyfile is the source of truth. Any edit (API or manual) writes to disk and triggers a reparse. - Runs are incremental: when you run a cell, nb-lab replays only the minimal dirty prefix (cells whose source changed) up to the target cell.
- If nothing is dirty, nb-lab returns the cached output for that cell.
This favors iteration speed over strict correctness and mirrors how users actually iterate in notebooks.
Cell ID storage
Stable cell IDs are stored in a user cache directory (default ~/.cache/nb-lab). Set NB_LAB_CACHE_DIR to override.
HTTP API (MVP)
Base URL: http://localhost:8787
-
GET /cells
Returns{ "version": int, "cells": [CellSummary...] } -
GET /status
Returns{ "version": int, "running_cell_id": string | null, "running_since": float | null } -
GET /cells/{cell_id}
Returns fullCell. -
POST /cells/{cell_id}/run
Body:{ "mode": "incremental" | "run_above" | "single", "timeout_ms": 60000, "base_version": int }
ReturnsExecutionResult. -
POST /run_up_to/{cell_id}
Same body as above. Runs prefix up tocell_idbased on mode. -
GET /outputs/{cell_id}
Returns{ "cell_id": str, "result": ExecutionResult }. -
POST /cells/{cell_id}/edit
Body:{ "new_source": "...", "base_version": int }
Returns updatedCell. -
POST /cells/insert_after
Body:{ "after_id": "cell-id-or-null", "source": "...", "kind": "code" | "markdown", "base_version": int }
Returns newCell. -
DELETE /cells/{cell_id}
Body:{ "base_version": int }
Returns updated cell list.
Concurrency: If base_version does not match the current notebook version, the server returns 409.
Output payloads
ExecutionResult.outputs is a list of OutputItem:
text: captured stdoutstderr: captured stderrrepr: last expression reprplot_meta: JSON summary of plot structure and dataimage_png: PNG image encoded as hex
Note: plot_meta.series[].sample is downsampled (default max 200 points), while n_points reports the full series length.
Agent tooling
See docs/agent-tools.md for function-calling tool definitions and suggested usage patterns.
For a copy-pasteable, agent-ready prompt that drives a full analysis run, see docs/agent-prompting.md.
For a human-readable demo flow, see docs/demo-transcript.md.
OpenAPI + MCP
- OpenAPI schema:
docs/openapi.json - MCP manifest:
docs/mcp.json - Tool examples:
docs/tool-examples.md - MCP hosting note:
docs/mcp-hosting.md
To regenerate the OpenAPI schema:
bash scripts/gen_openapi.sh
Status
nb-lab is early and experimental. Contributions, issues, and ideas are welcome.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nb_lab_runtime-0.1.0.tar.gz.
File metadata
- Download URL: nb_lab_runtime-0.1.0.tar.gz
- Upload date:
- Size: 72.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
013c03bf19d6ec528a12325f3df906f9565db35d40d395cb202e47af5686aac2
|
|
| MD5 |
afb2f656596ab2323028dc1fcdceb9e3
|
|
| BLAKE2b-256 |
873e811ded2aa297825c64bfa4e260010ba22bc14b19eeb5ca62f1e48d34ee6f
|
File details
Details for the file nb_lab_runtime-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nb_lab_runtime-0.1.0-py3-none-any.whl
- Upload date:
- Size: 21.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a64504002ade8dc2acc7e30d459d0a78871be0acbfee6eddd3b51519aaa1b24
|
|
| MD5 |
84a3bb2357d245afd0426bf3c3feb9c6
|
|
| BLAKE2b-256 |
ad6cda1e98278cf65a1497e1c93ec4c174334a35f80d84181d0eb69d7295c173
|