Skip to main content

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.

  1. Start the server on a real .py:percent notebook:
nb-lab serve examples/demo.py
  1. List cells and grab the current version:
nb-lab list
  1. Pick a target cell and run it (incremental, no full replay):
nb-lab run --cell-index 1 --mode incremental
  1. Fetch outputs and inspect both text and plot metadata:
nb-lab show <CELL_ID>
  1. 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
  1. 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 .py file 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 full Cell.

  • POST /cells/{cell_id}/run
    Body: { "mode": "incremental" | "run_above" | "single", "timeout_ms": 60000, "base_version": int }
    Returns ExecutionResult.

  • POST /run_up_to/{cell_id}
    Same body as above. Runs prefix up to cell_id based on mode.

  • GET /outputs/{cell_id}
    Returns { "cell_id": str, "result": ExecutionResult }.

  • POST /cells/{cell_id}/edit
    Body: { "new_source": "...", "base_version": int }
    Returns updated Cell.

  • POST /cells/insert_after
    Body: { "after_id": "cell-id-or-null", "source": "...", "kind": "code" | "markdown", "base_version": int }
    Returns new Cell.

  • 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 stdout
  • stderr: captured stderr
  • repr: last expression repr
  • plot_meta: JSON summary of plot structure and data
  • image_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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nb_lab_runtime-0.1.0.tar.gz (72.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nb_lab_runtime-0.1.0-py3-none-any.whl (21.6 kB view details)

Uploaded Python 3

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

Hashes for nb_lab_runtime-0.1.0.tar.gz
Algorithm Hash digest
SHA256 013c03bf19d6ec528a12325f3df906f9565db35d40d395cb202e47af5686aac2
MD5 afb2f656596ab2323028dc1fcdceb9e3
BLAKE2b-256 873e811ded2aa297825c64bfa4e260010ba22bc14b19eeb5ca62f1e48d34ee6f

See more details on using hashes here.

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

Hashes for nb_lab_runtime-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0a64504002ade8dc2acc7e30d459d0a78871be0acbfee6eddd3b51519aaa1b24
MD5 84a3bb2357d245afd0426bf3c3feb9c6
BLAKE2b-256 ad6cda1e98278cf65a1497e1c93ec4c174334a35f80d84181d0eb69d7295c173

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page