CLI tool that discovers and manages JupyterLab instances across multiple projects. Prevents port conflicts, finds orphan processes, provides unified status and stop-all functionality. Includes: - bin/jupyter-hub: the CLI (status, ports, stop-all, orphans, which, config) - config/defaults.sh: default scan dirs and port range - docs/LIFECYCLE_SPEC.md: client project requirements - docs/AGENT_PROMPT.md: prompt for coding agents to align projects - install.sh: symlink installer to ~/bin - tests/test_jupyter_hub.sh: 15 functional tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.4 KiB
JupyterManager
Cross-project Jupyter instance manager. Discovers, monitors, and controls JupyterLab instances across multiple projects on the same machine.
The Problem
You have multiple projects with Jupyter notebooks. Each runs its own JupyterLab server. Without coordination:
- Projects fight over port 8888
- Closing a terminal leaves orphan Jupyter processes
- Orphans block ports for other projects
- You can't tell what's running or which project owns which port
What JupyterManager Does
jupyter-hub is a single command that manages everything:
jupyter-hub status # Show all projects (running/stopped)
jupyter-hub ports # Port allocation map (8888-8899)
jupyter-hub stop-all # Stop all Jupyter instances
jupyter-hub orphans # Find untracked processes
jupyter-hub kill-orphans # Kill them
jupyter-hub which 8889 # Which project owns this port?
jupyter-hub config # Show configuration
It discovers projects automatically by scanning configured directories for the scripts/app.sh convention.
Installation
git clone https://github.com/saymrwulf/JupyterManager.git
cd JupyterManager
bash install.sh
This creates a symlink at ~/bin/jupyter-hub pointing to the repo's bin/jupyter-hub. Updates are just git pull.
Ensure ~/bin is in your PATH:
# Add to ~/.zshrc or ~/.bashrc
export PATH="$HOME/bin:$PATH"
Configuration
Configuration lives at ~/.config/jupyter-hub/config.sh (created by install.sh):
# Port range to scan
PORT_RANGE_START=8888
PORT_RANGE_END=8899
# Directories to scan for Jupyter projects
SCAN_DIRS=(
"$HOME/GitClone/ClaudeCodeProjects"
"$HOME/GitClone/CodexProjects"
"$HOME/Projects"
)
A project is recognized if it has scripts/app.sh AND either a notebooks/ directory or jupyter in its pyproject.toml.
Client Project Requirements
For a project to be managed by jupyter-hub, it must follow the Lifecycle Specification documented in docs/LIFECYCLE_SPEC.md. The key requirements:
scripts/app.shwith:bootstrap,start,stop,restart,status,logs- Isolated Jupyter directories under the project root (not system-global)
- Kernel installed with
--sys-prefix(not--user) - Auto port allocation (scan 8888-8899 for free port)
- PID file at
.logs/jupyter.pid - Background + foreground modes
- Graceful stop protocol (SIGTERM, wait, SIGKILL fallback)
Current Client Projects
| Project | Location | Status |
|---|---|---|
| autoresearch-quantum | ClaudeCodeProjects/ |
Fully compliant |
| QuantumLearning | CodexProjects/ |
Detected, partial compliance |
| NTT-learning | CodexProjects/ |
Detected, partial compliance |
For Coding Agents
When instructing an AI coding agent to align a project with this specification, use the prompt in docs/AGENT_PROMPT.md.
Project Structure
JupyterManager/
├── bin/
│ └── jupyter-hub The CLI tool
├── config/
│ └── defaults.sh Default scan dirs, port range
├── docs/
│ ├── LIFECYCLE_SPEC.md Client project specification
│ └── AGENT_PROMPT.md Prompt for coding agents
├── tests/
│ └── test_jupyter_hub.sh Functional tests
├── install.sh Symlink installer
└── README.md
Running Tests
bash tests/test_jupyter_hub.sh