Claude-powered chat side panel for JupyterLab / Notebook 7.
Project description
pynote
PyPI distribution:
jupyter-pynote· Python import:pynote· Lab extension id:pynote
Claude-powered chat side panel for JupyterLab 4 and Jupyter Notebook 7.
Open any notebook, crack open the side panel, and talk to Claude about the code. When Claude proposes changes to the notebook, type apply in chat and they're written into real cells — no dialog box, no reload, no token-pasting.
Features
- Right-hand side panel docked into the Lab shell; follows the currently active notebook.
- Chat with Claude about the current notebook's cells (their source is sent as context each turn).
- Structured cell edits via Claude tool-use — replace existing cells or insert new ones by stable cell id, not brittle index.
apply/cancelare typed in chat; no modal or popup.- Edits go through Lab's own shared model, so undo / autosave / RTC all Just Work.
- Server extension proxies the Claude call, so
ANTHROPIC_API_KEYlives in the Jupyter process — never in the browser.
Prerequisites
- Python 3.9+
- JupyterLab 4 or Notebook 7
- An Anthropic API key
Install from PyPI
pip install jupyter-pynote
That's it — the wheel ships the prebuilt labextension, so no Node, no jupyter labextension install, no post-install step. Both the server extension and the Lab plugin auto-enable.
Provide your Anthropic key once (persistent across shells; auto-loaded by the server at startup):
mkdir -p ~/.pynote
echo 'ANTHROPIC_API_KEY=sk-ant-...' > ~/.pynote/.env
chmod 600 ~/.pynote/.env
Or export it in your shell (~/.zshrc, direnv, per-venv activate scripts — anything that gets into the environment of the jupyter lab process).
Launch:
jupyter lab
Open any .ipynb. You'll see a PyNote tab in the right sidebar.
Install from source (dev)
From jupyter-pynote/:
# 1. Install the Python side (server extension) in editable mode
pip install -e ".[dev]"
# 2. Install npm deps and build the labextension assets
jlpm install
jlpm build
# 3. Wire the labextension into JupyterLab
jupyter labextension develop . --overwrite
# 4. Enable the Jupyter server extension
jupyter server extension enable pynote
# 5. Provide your API key (or put it in ~/.pynote/.env — auto-loaded)
export ANTHROPIC_API_KEY=sk-ant-...
# 6. Launch Jupyter
jupyter lab
Verify the extension is loaded:
jupyter labextension list # should show: pynote v0.1.0 enabled ok
jupyter server extension list # should show: pynote enabled
Open any .ipynb. You'll see a pynote tab in the right sidebar.
Model / tokens
Override via env vars before launch:
export PYNOTE_MODEL=claude-sonnet-4-6 # default
export PYNOTE_MAX_TOKENS=4096 # default
How the chat works
- You type a question — "plot the last column" or "explain cell 3". pynote sends your message plus a snapshot of every cell's id, type, and source to the server extension.
- The server forwards it to Claude with a system prompt that describes the
propose_notebook_changestool. - Claude replies with prose, and optionally calls the tool with a list of changes
{op, target_cell_id, source}. - The panel shows the prose + a compact preview of each proposed change.
- You type
apply→ pynote walks the change list and callssharedModel.setSource(...)/sharedModel.insertCell(...)inside a single transaction. One undo reverts the whole batch. - Type
cancel/discard/noto drop the proposal, or just keep chatting — a follow-up question clears the pending proposal automatically.
There's no apply button, no modal, no popup — everything is in the chat line.
Smoke test without Lab
Quickly verify Claude integration without running Jupyter:
export ANTHROPIC_API_KEY=sk-ant-...
python scripts/smoke_test.py
Expected: a proposal with at least one replace or insert_after change targeting the empty cell.
Dev workflow
# In one terminal — rebuild on TS changes
jlpm watch
# In another — Lab picks up the changes on refresh
jupyter lab
On Python-side changes, restart Lab.
Uninstall
jupyter server extension disable pynote
jupyter labextension uninstall pynote
pip uninstall jupyter-pynote
Troubleshooting
- Panel doesn't appear: run
jupyter labextension list; ifpynoteisn't there, redo step 3. - Panel says "No notebook open": that's literal — open a
.ipynbin the same Lab window. ANTHROPIC_API_KEY is not set: the server process (the one runningjupyter lab) didn't inherit the env var. Export it in that shell before launch.403 / xsrfin browser console: shouldn't happen since requests go through@jupyterlab/services— but if you see one, disable any other extension that proxies Lab API calls.
License
MIT — see LICENSE.
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_pynote-0.1.0.tar.gz.
File metadata
- Download URL: jupyter_pynote-0.1.0.tar.gz
- Upload date:
- Size: 133.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a0129204324c389a58e52b3aaffe6811fcdb0ef652346675905a98555e0b8570
|
|
| MD5 |
09fe904bc8a29feb706f28d177daceb5
|
|
| BLAKE2b-256 |
30fe394220cca13b3fd53df248282e26d8fc4195bfc3271c268f24f6ce797305
|
File details
Details for the file jupyter_pynote-0.1.0-py3-none-any.whl.
File metadata
- Download URL: jupyter_pynote-0.1.0-py3-none-any.whl
- Upload date:
- Size: 54.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e35a7a1bf3604507a1e8de6a80be9e49a3dadbe4ea6fab329bc6921f64316530
|
|
| MD5 |
4715c965d7b75079375323659bc48fcf
|
|
| BLAKE2b-256 |
5cfd318ba5442177ae48ad8ee7e59097836fbe6ec7c53024eff973b1dedaae6f
|