Programmatic Jupyter cell execution with persistent kernels
Project description
jupyter-cli
Programmatic Jupyter notebook cell execution with persistent kernels.
The Problem
Existing Jupyter tools don't support selective cell execution with persistent state:
- papermill/nbconvert/nbexec: Run entire notebooks
- jupyter console: Requires manual interaction
- nbclient: Kernel dies when Python process exits
jupyter-cli fills this gap: execute specific cells while keeping kernel state alive between CLI invocations.
Use Case
A data science notebook with ~60 cells:
- Cells 1-49: Expensive setup (DB queries, model training) - takes ~20 minutes
- Cells 50+: Experimental iterations
With jupyter-cli:
jupyter-cli start notebook.ipynb
jupyter-cli exec notebook.ipynb 0 1 2 ... 49 # Run setup once
jupyter-cli exec notebook.ipynb 50 # Iterate on cell 50
jupyter-cli exec notebook.ipynb 50 # Again, without re-running setup
jupyter-cli stop notebook.ipynb
Installation
pip install jupyter-cli
# Or from source
git clone https://github.com/andrewting19/jupyter-cli.git
cd jupyter-cli
pip install -e .
Requirements:
- Python 3.8+
- jupyter_client
- nbformat
- click
Quick Start
# Start a persistent kernel
jupyter-cli start notebook.ipynb
# Execute cells (0-indexed)
jupyter-cli exec notebook.ipynb 0 1 2
# Stop the kernel
jupyter-cli stop notebook.ipynb
Commands
Kernel Management
| Command | Description |
|---|---|
start <notebook> |
Start persistent kernel |
stop <notebook> |
Stop kernel |
stop --all |
Stop all kernels |
status [notebook] |
Check kernel status |
Cell Execution
| Command | Description |
|---|---|
exec <notebook> <cells...> |
Execute specific cells |
exec <notebook> 0 1 2 --timeout 300 |
With custom timeout |
exec <notebook> 0 --quiet |
Suppress output |
Notebook Exploration
| Command | Description |
|---|---|
list <notebook> |
List all cells with preview |
list <notebook> --code |
Only code cells |
list <notebook> --range 0-10 |
Cell range |
read <notebook> 0 1 2 |
Read full cell source |
read <notebook> --code |
Read all code cells |
search <notebook> "pattern" |
Search cells |
search <notebook> "regex" -r |
Regex search |
outputs <notebook> 5 |
Read stored outputs |
info <notebook> |
Notebook info |
Examples
Exploring a Notebook
# Quick overview
$ jupyter-cli list notebook.ipynb
[0] code: import pandas as pd
[1] code: df = pd.read_csv('data.csv')
[2] code: df.head()
[3] markdown: ## Data Cleaning
[4] code: df = df.dropna()
...
# Find all cells using DataFrame
$ jupyter-cli search notebook.ipynb "DataFrame"
Found 3 match(es):
[5] code: df = pd.DataFrame(data)
[12] code: result = DataFrame.from_dict(...)
[45] code: final_df = pd.DataFrame(results)
# Read specific cells
$ jupyter-cli read notebook.ipynb 5 12
=== Cell 5 (code) ===
df = pd.DataFrame(data)
print(df.shape)
=== Cell 12 (code) ===
result = DataFrame.from_dict(processed_data)
Selective Execution
# Start kernel
$ jupyter-cli start analysis.ipynb
Kernel started. ID: abc123
# Run expensive setup
$ jupyter-cli exec analysis.ipynb 0 1 2 3 4 5
[Cell 0] Executing: import pandas as pd...
[Cell 1] Executing: df = load_data()...
Loading 1M rows from database...
...
# Iterate on experiment cell
$ jupyter-cli exec analysis.ipynb 50
[Cell 50] Executing: model.fit(X, y)...
Accuracy: 0.85
# Edit cell 50 in your editor, then re-run
$ jupyter-cli exec analysis.ipynb 50
[Cell 50] Executing: model.fit(X, y, epochs=100)...
Accuracy: 0.92
# Clean up
$ jupyter-cli stop analysis.ipynb
Kernel stopped.
Reading Previous Outputs
$ jupyter-cli outputs notebook.ipynb --range 10-15
=== Cell 10 output ===
[stdout] Training model...
[stdout] Epoch 1/10: loss=0.5
=== Cell 12 output ===
[result] 0.923456
=== Cell 14 output ===
[error] ValueError: invalid shape
Gap Analysis: CLI vs Manual Jupyter
| Feature | jupyter-cli | Manual Jupyter UI |
|---|---|---|
| Cell execution | Yes | Yes |
| Persistent kernel | Yes | Yes |
| Execute specific cells | Yes | Yes |
| State persistence | Yes | Yes |
| stdout/stderr output | Yes | Yes |
| Rich output (HTML) | Truncated | Full rendering |
| Image output | [Image: PNG] |
Displayed |
| Interactive widgets | No | Yes |
| Cell editing | No (use external editor) | Yes |
| Magic commands | Yes (via kernel) | Yes |
| Auto-complete | No | Yes |
| Inline plots | No (shows placeholder) | Yes |
| Syntax highlighting | No | Yes |
| Variable inspector | No | Extension available |
| Debugging | No | Yes |
| Multiple kernels | Yes (one per notebook) | Yes |
Key takeaway: jupyter-cli is for programmatic automation, not interactive development. Use it when you need:
- Scripted notebook execution
- LLM agent integration
- CI/CD pipelines
- Selective cell re-execution without re-running setup
Architecture
┌─────────────┐ ┌──────────────────┐ ┌────────────┐
│ CLI Client │────▶│ Daemon Process │────▶│ Kernel │
└─────────────┘ └──────────────────┘ └────────────┘
│ │ │
│ connection.json │ keeps alive │ Python
│◀────────────────────│ │ process
│ │ │
└─────────────────────┴───────────────────────┘
- Daemon Process: Starts kernel, keeps it alive, writes connection file
- CLI Client: Reads notebook, connects to kernel via connection file, executes cells
For LLM Agents
See CLAUDE.md for a comprehensive guide on using jupyter-cli with LLM agents, including:
- Token-efficient exploration strategies
- Common workflows
- Best practices
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run specific test class
pytest tests/test_jupyter_cli.py::TestCLIExec -v
License
MIT
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 jupyter_cli-0.1.1.tar.gz.
File metadata
- Download URL: jupyter_cli-0.1.1.tar.gz
- Upload date:
- Size: 18.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
021e82144b5fc8abf4bcf46bf7318754a8b3dff126120773c5d54c5ef1befb5c
|
|
| MD5 |
009ba43bbfb3502df460008a3ebc62db
|
|
| BLAKE2b-256 |
002a9ba14b74edd50b8b5e8ef55e85778d034bb855cbe341cfd8dbef86cee54f
|
File details
Details for the file jupyter_cli-0.1.1-py3-none-any.whl.
File metadata
- Download URL: jupyter_cli-0.1.1-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a30674d31bdf1695aaa10646367d3e33e107788fdeec60e58da9a607cb72006
|
|
| MD5 |
4e548a01cf6d962c88a4a1c684d9be2c
|
|
| BLAKE2b-256 |
faac6c3bd95461df0b2b9caa6c09c137d76e2edb2436642ebbbcba8e98edb524
|