Skip to main content

langstage-jupyter — chat with your LangGraph agent inside JupyterLab

Bring LangChain agents into your JupyterLab workflow


  • Source code: github.com/dkedar7/langstage-jupyter
  • Installation: pip install -U langstage-jupyter (renamed from deepagent-lab — the old name now just installs this one, and the deepagent-lab command still works)

A JupyterLab extension to allow your LangChain agents access to JuputerLab notebooks and files, enabling natural language interactions with your data science projects directly from JupyterLab.

DeepAgent Lab Demo

Watch the full demo video here: https://www.youtube.com/watch?v=vGA2vzMSQzo

Every stage for your LangGraph agent

langstage-jupyter is the JupyterLab stage of the LangStage family: write your agent once — any LangGraph CompiledGraph — and run it on every stage with the same spec string (module:attr or path/to/file.py:attr), the same langstage.toml config file, and the same LANGSTAGE_* environment variables.

Stage Package Try it
Web app langstage langstage run --agent my_agent.py:graph
JupyterLab langstage-jupyter you are here
Terminal langstage-cli langstage-cli -a my_agent.py:graph
VS Code langstage-vscode chat participant + stdio sidecar
Reference agent langstage-hermes LANGSTAGE_AGENT_SPEC=langstage_hermes.agent:graph on any stage
Shared core langstage-core typed events + config resolver + AG-UI bridge behind every stage

Serve over AG-UI

The chat sidebar already streams every turn through the in-process AG-UI adapter. Your agent — any LangGraph CompiledGraph — can also be served over the AG-UI protocol as a standalone HTTP endpoint:

pip install "langstage-core[agui]"
langstage-agui --agent my_agent.py:graph

📖 Full documentation: https://dkedar7.github.io/langstage-docs/

Features

  • Chat Interface: Sidebar for natural conversations with your agent
  • Notebook Manipulation: Built-in tools for creating, editing, and executing Jupyter notebooks
  • Human-in-the-Loop: Review and approve agent actions before execution
  • Context Awareness: Automatically sends workspace and file context to your agent
  • Custom Agents: Use your own langgraph-compatible agents seamlessly
  • Auto-Configuration: Zero-config setup with automatic Jupyter server detection

Installation

pip install langstage-jupyter

Quick Start

Instead of jupyter lab, use langstage-jupyter command for automatic setup.

The easiest way to get started is using the langstage-jupyter launcher command, which automatically configures everything for you:

# Set your API key (if using the default agent)
export ANTHROPIC_API_KEY=your-api-key-here

# Start JupyterLab with auto-configuration
langstage-jupyter

That's it! The launcher will:

  • Auto-detect an available port (starting from 8888)
  • Generate a secure authentication token
  • Set the required environment variables
  • Launch JupyterLab with the proper configuration

Using custom arguments:

# All jupyter lab arguments are supported
langstage-jupyter --no-browser
langstage-jupyter --port 8889

# Pick the agent right from the launcher (same spec format as every
# LangStage stage; sets LANGSTAGE_AGENT_SPEC for you)
langstage-jupyter -a my_agent.py:graph

# No agent or API key yet? Launch with the keyless demo agent
langstage-jupyter --demo

# Print the resolved configuration (each value, its source, and the
# env var / langstage.toml key that sets it) and exit
langstage-jupyter --show-config

Running several sessions at once: just launch the command again with a different agent — each session is its own process, picks the next free port (scanning 8888-8987), gets its own token, and its notebook tools only ever talk to its own Jupyter server, so sessions don't interfere:

langstage-jupyter -a agent_a.py:graph    # -> localhost:8888
langstage-jupyter -a agent_b.py:graph    # -> localhost:8889

Widen the scan with LANGSTAGE_JUPYTER_PORT_ATTEMPTS (default 100), or pin a port with --port (or --ServerApp.port). A pinned port that is busy fails the launch instead of moving to another port, because the agent's notebook tools are pointed at the port you pinned. --port 0 is refused for the same reason. Note that two sessions launched from the same directory serve the same notebooks on disk — launch from different directories if you want separate workspaces.

Preflight checks (--verify, --serve-check, --check-connection)

Three headless, no-browser preflights that exit 0/1 — handy in CI or before a deploy:

# Preflight the AGENT OBJECT: load the configured (or --demo) agent and run one real
# turn through it. Catches a bad API key / broken tool / non-runnable graph. (For the
# default agent with no key it now names the missing variable, e.g. ANTHROPIC_API_KEY.)
langstage-jupyter --verify

# Preflight the SERVED ENDPOINT: boot the server extension, poll /langstage-jupyter/health
# until the agent is loaded, then POST one turn to /langstage-jupyter/chat and assert the
# SSE stream completes. Catches route/registration/handler regressions that --verify can't
# (it never touches HTTP). Defaults to the keyless demo agent; add -a to test a real one.
langstage-jupyter --serve-check
langstage-jupyter -a my_agent.py:graph --serve-check

# Preflight the MANUAL-CONFIG CONNECTION: confirm the configured
# LANGSTAGE_JUPYTER_SERVER_URL + LANGSTAGE_JUPYTER_TOKEN actually reach a running,
# auth-matching Jupyter (GET {url}/api/status with the token). Only meaningful for the
# manual-config flow below — the launcher auto-manages these values. (--check-server alias.)
langstage-jupyter --check-connection

--check-connection names the distinct failure modes:

$ langstage-jupyter --check-connection
[ ok ] reached http://localhost:8888 — token accepted (Jupyter Server 2.20.0)

# wrong port / server not up:
[fail] http://localhost:8888 unreachable — is a Jupyter server running there? ...

# URL right, token wrong (a stale token, a drifted --IdentityProvider.token):
[fail] http://localhost:8888 returned 403 — LANGSTAGE_JUPYTER_TOKEN does not match ...

Unlike --serve-check (which boots its own ephemeral server with a fresh token), --check-connection tests your configured URL+token against an already-running server.

One-shot chat (--ask)

The preflights above prove the agent runs; --ask "<prompt>" runs one turn and prints what it actually says — the terminal inner loop (change agent -> see the reply) with no browser, no persistent server, no token juggling. It resolves the agent exactly like --verify (honoring -a / --demo / LANGSTAGE_AGENT_SPEC / LANGSTAGE_AGENT_MODULE + LANGSTAGE_AGENT_VARIABLE), prints the reply to stdout and status to stderr, and exits 0 complete / 1 error / 2 interrupted:

# One turn, print the reply, exit
langstage-jupyter -a my_agent.py:graph --ask "summarize data.csv in one line"
langstage-jupyter --demo --ask "hello"          # keyless, no API key

# stdout is just the reply, so it pipes cleanly for CI behavior assertions:
langstage-jupyter -a my_agent.py:graph --ask "2+2?" | grep -q 4

The extension serves its REST/SSE routes under /<base_url>langstage-jupyter/: health (GET), chat (POST, SSE), resume (POST, SSE), reload (POST), cancel (POST).

Alternative: Manual Configuration

If you prefer manual control or need to use jupyter lab directly, you can set the environment variables yourself:

  1. Configure environment variables (create a .env file or export):
# Required: Jupyter server configuration
export LANGSTAGE_JUPYTER_SERVER_URL=http://localhost:8888
export LANGSTAGE_JUPYTER_TOKEN=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")

# If using the default agent, set your API key
export ANTHROPIC_API_KEY=your-api-key-here
  1. Start JupyterLab with matching configuration:
jupyter lab --port 8888 --IdentityProvider.token=$LANGSTAGE_JUPYTER_TOKEN

Important: The server URL and token must match between your environment variables and JupyterLab's startup parameters.

Verify they do — before you start chatting — with the connection preflight:

langstage-jupyter --check-connection
# [ ok ] reached http://localhost:8888 — token accepted (Jupyter Server 2.20.0)

It exits 0 when the configured LANGSTAGE_JUPYTER_SERVER_URL + LANGSTAGE_JUPYTER_TOKEN reach a running, auth-matching Jupyter, and 1 (naming the reason) when the server is unreachable or the token is rejected.

Using Custom Agents

langstage-jupyter is designed to work with any langgraph-compatible agent. You can easily use your own langgraph-compatible agents instead of the default agent.

Creating a Custom Agent

Create a file with your agent (e.g., my_agent.py):

from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
import os

# The notebook tools (create_notebook, insert_code_cell, execute_cell, ...).
# Your agent only gets them if you pass them in.
from langstage_jupyter.notebook_tools import NOTEBOOK_TOOLS

# langstage-jupyter sets this before it imports your agent: the pinned
# workspace, else the directory JupyterLab serves.
workspace = os.getenv('LANGSTAGE_WORKSPACE_ROOT', '.')

# Create your custom agent
agent = create_deep_agent(
    name="my-custom-agent",  # Optional: name shown in chat interface
    model="anthropic:claude-sonnet-4-20250514",
    backend=FilesystemBackend(root_dir=workspace, virtual_mode=True),
    checkpointer=MemorySaver(),
    tools=[*NOTEBOOK_TOOLS],  # add your own tools too, e.g. [*NOTEBOOK_TOOLS, my_tool]
)

Leave out NOTEBOOK_TOOLS and the agent can still read and write files, but it can't create, edit or run notebook cells.

Configuring the Extension to Use Your Agent

Set the LANGSTAGE_AGENT_SPEC environment variable to point to your agent:

# Format: path/to/file.py:variable_name
export LANGSTAGE_AGENT_SPEC=./my_agent.py:agent

Then launch as normal:

# With the launcher (recommended)
langstage-jupyter

# Or manually
jupyter lab --port 8888 --IdentityProvider.token=$LANGSTAGE_JUPYTER_TOKEN

The chat interface will automatically display your custom agent's name (if you set the name attribute).

Agent Portability

Agents configured for langstage-jupyter work seamlessly with every other LangStage stage:

# Same configuration works everywhere!
export LANGSTAGE_AGENT_SPEC=./my_agent.py:agent
export LANGSTAGE_WORKSPACE_ROOT=/path/to/project

# Run in JupyterLab
langstage-jupyter

# Or in the browser / terminal
langstage run
langstage-cli

With a pinned LANGSTAGE_WORKSPACE_ROOT, langstage-jupyter serves that directory in JupyterLab (it passes --ServerApp.root_dir), so the file browser, the agent's file tools and its notebook tools all use the same directory. The notebook tools go through JupyterLab's contents API, so they always work in the directory JupyterLab serves. If you pass your own --notebook-dir / --ServerApp.root_dir, or run plain jupyter lab, and it differs from the pinned workspace, the launcher and the server log print a warning: file tools then use the workspace and notebook tools use the serving root.

Environment Variables

All configuration uses the LANGSTAGE_ prefix (the pre-rename DEEPAGENT_ names still resolve as deprecated fallbacks):

Variable Purpose Default When to Set
LANGSTAGE_AGENT_SPEC Custom agent location (path:variable) Uses default agent Optional: for custom agents
LANGSTAGE_WORKSPACE_ROOT Working directory for agent (set before your agent is imported) JupyterLab root Optional
LANGSTAGE_JUPYTER_SERVER_URL Jupyter server URL Auto-detected Manual config only
LANGSTAGE_JUPYTER_TOKEN Jupyter auth token Auto-generated Optional: pins the launcher's token
LANGSTAGE_MODEL_TEMPERATURE Default agent's sampling temperature 0.0 Optional
ANTHROPIC_API_KEY Anthropic API key None Required for default agent

When using the langstage-jupyter launcher, LANGSTAGE_JUPYTER_SERVER_URL and LANGSTAGE_JUPYTER_TOKEN are automatically configured and don't need to be set. To pin the launcher's token, set LANGSTAGE_JUPYTER_TOKEN (or jupyter.token in langstage.toml). The launcher picks the token in this order: --IdentityProvider.token, then LANGSTAGE_JUPYTER_TOKEN (legacy DEEPAGENT_JUPYTER_TOKEN, with a deprecation notice), then JUPYTER_TOKEN, then a generated one.

LANGSTAGE_MODEL_TEMPERATURE must be a finite number from 0 up to the provider's maximum (1 for Anthropic, 2 for OpenAI and Gemini). Any other value is ignored with a note: and the default 0.0 is used.

See .env.example for a complete configuration template.

Interface Controls

  • ⟳ Reload: Reload your agent without restarting JupyterLab (useful during agent development)
  • Clear: Start a new conversation thread
  • Status Indicator (hover for details):
    • 🟢 Green: Agent ready — it can actually run a turn
    • 🟠 Orange: Loaded but not ready — e.g. the default agent's ANTHROPIC_API_KEY isn't set (the first turn would fail), or an uncompiled graph was exported. The tooltip says what to fix.
    • 🔴 Red: Agent error — the agent module didn't load

Development

See CONTRIBUTING.md for development setup and guidelines.

License

MIT License - see LICENSE for details.

Release files for langstage-jupyter 0.6.33

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for langstage-jupyter 0.6.33
File Size Uploaded
langstage_jupyter-0.6.33.tar.gz 816.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for langstage-jupyter 0.6.33
File Interpreter ABI Platform
langstage_jupyter-0.6.33-py3-none-any.whl Python 3 none any Details

Total release size: 1.1 MB

Release files / langstage_jupyter-0.6.33.tar.gz

Download URL langstage_jupyter-0.6.33.tar.gz
Size 816.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e21df534017e205b849b77e0892d1f8be14af5a7fb58f899eb4ecc1df7378598
BLAKE2b-256 checksum
How to use checksums
da2e5043d3ee0d38a5d1c79c3b3d0a0fe7350779119e2f4bb722bbd6c36252f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / langstage_jupyter-0.6.33-py3-none-any.whl

Download URL langstage_jupyter-0.6.33-py3-none-any.whl
Size 273.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
30ea498c02e43f3fcd7ecdcfc72d913b7a412b01a8957c76bbfe4899938f4633
BLAKE2b-256 checksum
How to use checksums
726feee20d7978e69ca9328dc2ae4d6986ef54a4f63021321a2ab6ed46246325
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.6.33 This release

2 release files

0.6.32

2 release files

0.6.31

2 release files

0.6.30

2 release files

0.6.26

2 release files

0.6.25

2 release files

0.6.24

2 release files

0.6.23

2 release files

0.6.22

2 release files

0.6.21

2 release files

0.6.19

2 release files

0.6.18

2 release files

0.6.17

2 release files

0.6.16

2 release files

0.6.15

2 release files

0.6.14

2 release files

0.6.13

2 release files

0.6.11

2 release files

0.6.9

2 release files

0.6.8

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.12

2 release files

0.5.11

2 release files

0.5.10

2 release files

0.5.9

2 release files

0.5.8

2 release files

0.5.7

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.0.1

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