ov-layers/skills/jupyter/SKILL.md
Lightweight JupyterLab with real-time collaboration (jupyter-collaboration) on port 8888. No GPU required. Use when working with collaborative notebooks, jupyter-collaboration, or lightweight Jupyter environments without ML/CUDA dependencies.
npx skillsauth add overthinkos/overthink-plugins jupyterInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Property | Value |
|----------|-------|
| Dependencies | supervisord |
| Sub-layers | jupyter-mcp |
| Ports | 8888 |
| Service | jupyter (supervisord) |
| Volume | workspace at ~/workspace |
| MCP provides | jupyter at http://{{.ContainerName}}:8888/mcp (streamable HTTP) |
| Install files | layer.yml (rpm: git), pixi.toml |
conda-forge: JupyterLab >= 4.4.0, ipywidgets, ipykernel, jupyterlab-git, jupyter-resource-usage, matplotlib, seaborn, pandas, numpy, scikit-learn, scipy, polars, pyarrow, duckdb, black, pytest
PyPI: jupyter-collaboration >= 4.1.0
RPM: git
No custom environment variables. Inherits PATH from pixi layer (~/.pixi/envs/default/bin).
Real-time collaborative editing via jupyter-collaboration (Y-CRDT). Multiple users editing the same notebook see shared cursors and live changes. The backend uses jupyter_server_ydoc with pycrdt-websocket for CRDT synchronization. No external database required — document state is managed in-memory by default, with optional SQLite persistence.
Collaboration is enabled by default when jupyter-collaboration is installed. The WebSocket endpoint at /api/collaboration/room/ handles document sync.
The service supports optional token-based authentication via the JUPYTER_TOKEN_FILE environment variable. If set and the file exists, its contents are used as the auth token. Otherwise, authentication is disabled (empty token, no password) for development convenience.
The workspace volume is mounted at ~/workspace. JupyterLab serves notebooks from this directory via --notebook-dir=$HOME/workspace.
# image.yml
jupyter:
base: fedora
layers:
- agent-forwarding
- jupyter
- dbus
- ov
ports:
- "8888:8888"
| | jupyter | jupyter-ml |
|---|---|---|
| Base dependency | supervisord | cuda, supervisord |
| GPU | No | CUDA required |
| Platforms | amd64 + arm64 | amd64 only |
| Focus | Collaboration + data science | ML/AI training |
| Key packages | jupyter-collaboration, pandas, polars | PyTorch, vLLM, Unsloth, llama.cpp |
| Image size | ~3.4 GB | ~15+ GB |
The jupyter layer declares mcp_provides for cross-container and pod MCP discovery. The URL template http://{{.ContainerName}}:8888/mcp resolves to the actual container name at deploy time (e.g., http://ov-jupyter:8888/mcp), or to http://localhost:8888/mcp in combined images where both services run in the same container.
http)jupyter-mcp extension (see below)OV_MCP_SERVERS env var -- no manual MCP registration neededlocalhost in combined images where hermes and jupyter share a containerjupyter_mcp)The layer includes a built-in MCP (Model Context Protocol) server at /mcp on port 8888. AI agents can create, read, edit, and execute notebook cells programmatically — with changes syncing live to all connected JupyterLab clients via CRDT.
Tornado (Jupyter Server, :8888)
└── /mcp → TornadoASGIHandler → FastMCP ASGI App (Starlette, in-process)
└── RTCAdapter → YNotebook (CRDT)
YDocWebSocketHandler.prepare() logic including lazy websocket server startNotebook Management:
| Tool | Parameters | Returns |
|------|-----------|---------|
| list_notebooks | — | [{"path": "...", "name": "..."}] |
| get_notebook | path | Full notebook dict (CRDT if room open, else disk) |
| create_notebook | path | {"path": "...", "name": "..."} |
Cell Operations (CRDT — changes sync live to all collaborators):
| Tool | Parameters | Returns |
|------|-----------|---------|
| get_cell | path, index | Cell dict (source, cell_type, metadata, outputs) |
| update_cell | path, index, source, cell_type? | "Cell N updated" |
| insert_cell | path, index, source, cell_type="code" | "Cell inserted at index N" |
| delete_cell | path, index | "Cell N deleted" |
| execute_cell | path, index | [{"type": "stream", "content": {...}}] |
Room Management:
| Tool | Parameters | Returns |
|------|-----------|---------|
| open_notebook_session | path | "Collaboration room opened for ..." |
| close_notebook_session | path | "Collaboration room closed for ..." |
Change Watching:
| Tool | Parameters | Returns |
|------|-----------|---------|
| watch_notebook | path, timeout=30 | {"changed": true, "cell_count": N} or {"changed": false} |
Collaboration Awareness:
| Tool | Parameters | Returns |
|------|-----------|---------|
| get_active_users | — | [{"id": "...", "name": "..."}] |
| get_active_sessions | — | [{"room_id": "..."}] |
The MCP extension is installed by the jupyter-mcp sub-layer (composed via layers: [jupyter-mcp]):
pip install "fastmcp>=3.2.0" + opentelemetry runtime deps (not pixi -- cross-platform resolver conflicts with opentelemetry-api on aarch64)pip install --no-deps /ctx/jupyter_mcp (extension package from sub-layer directory)jupyter_server_config.d/jupyter_mcp.jsonlayers/jupyter-mcp/
├── jupyter_mcp/
│ ├── pyproject.toml # hatchling package, no deps (--no-deps install)
│ └── jupyter_mcp/
│ ├── __init__.py # Extension entry point
│ ├── app.py # Registers /mcp handler + ASGI lifespan
│ ├── tornado_asgi.py # Tornado↔ASGI bridge (SSE streaming, disconnect handling)
│ ├── mcp_server.py # FastMCP tool definitions (13 tools)
│ └── rtc_adapter.py # CRDT access via YNotebook + kernel execution
# (in layer.yml tasks:) # Build-time: pip install fastmcp + extension + enable
└── layer.yml
Multiple MCP clients can edit the same notebook simultaneously:
watch_notebook uses a fan-out NotebookWatcher — each watcher gets an independent asyncio.Event, signaled when any CRDT change occursjupyter lab directly, not via pixi run. Pixi multi-stage builds copy only ~/.pixi/envs/ to the final image — pixi.toml is not present at runtime.start-jupyter pixi task in pixi.toml is for build-time verification only.The layer ships 2 declarative checks embedded in the org.overthinkos.tests
OCI label (see /ov:test for the full schema):
ov image test):
workspace-dir — ${HOME}/workspace exists as a directoryov test against a live service):
jupyter-api — GET http://${CONTAINER_IP}:${HOST_PORT:8888}/api
returns 200 with a body containing "version". The ${HOST_PORT:8888}
substitution means the check works unchanged when deploy.yml remaps
the host port./ov-images:jupyter/ov-layers:jupyter-ml -- GPU-accelerated variant with full CUDA ML stack + same CRDT MCP server/ov-layers:jupyter-mcp -- MCP server implementation (sub-layer, 13 tools for programmatic notebook access)/ov-layers:notebook-templates -- Starter notebooks (data layer, used alongside this layer in images)/ov-layers:hermes -- MCP consumer (mcp_accepts)/ov-layers:supervisord -- process manager dependency/ov-layers:python -- Python runtime (transitive via supervisord)/ov:mcp -- end-to-end testing of the layer's MCP endpoint (ov test mcp ping, list-tools, call); the layer ships 3 deploy-scope mcp: declarative checks against list_notebooks/insert_cell/execute_cellUse when the user asks about:
jupyter layerwatch_notebook or change notifications/ov:layer — layer authoring reference (layer.yml schema, task verbs, service declarations)development
Claude Code multi-agent support in Overthink — sub-agents, dynamic workflows, and agent teams, and how each drives the existing `ov eval` disposable beds to test and verify. MUST be invoked before authoring or invoking an ov sub-agent / dynamic workflow / agent team, wiring agent-lifecycle hooks, or asking "which primitive should drive the R10 beds?".
tools
Mounts a virtiofs share tagged `workspace` at /workspace inside a VM guest via a systemd .mount unit. Use when a kind:vm entity shares a host directory into the guest and you need it auto-mounted (and re-mounted at every boot).
development
MUST be invoked before any work involving: the `kind: android` schema kind, a `target: android` deploy, the `apk:` layer package format (installing Android apps declaratively), AndroidDeployTarget, an in-pod emulator OR a remote/physical adb-endpoint device, or nested `pod → android` deployment. The first-class Android device + app surface that sits above `ov eval adb`/`appium`.
tools
Use when committing, branching, pushing, merging, tagging, creating PRs, or approving/merging PRs with gh — the feat/-branch, R10-gated, never-force-push landing workflow across the main repo + the plugins submodule + image/<distro> submodules. Covers sync-to-upstream, branch/worktree pruning, the fork+PR path for contributors without write access, and cross-repo @github landing order.