Metadata-Version: 2.4
Name: jupyterhub-exec
Version: 0.1.0
Summary: Execute code on a remote JupyterHub kernel from any terminal — zero dependencies.
License: MIT
Project-URL: Homepage, https://github.com/quantiota/jupyterhub-exec
Project-URL: Repository, https://github.com/quantiota/jupyterhub-exec
Project-URL: Issues, https://github.com/quantiota/jupyterhub-exec/issues
Keywords: jupyterhub,jupyter,kernel,gpu,offload,agent
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# jupyterhub-exec

Execute code on a remote JupyterHub kernel from any terminal — zero external dependencies.

```
pip install jupyterhub-exec
```

## Why

JupyterHub provides GPU compute. Your agent terminal does not.
`jh-exec` bridges the two using the Jupyter kernel protocol over a raw WebSocket —
no browser, no notebook UI, no library dependencies beyond the Python standard library.

```
┌─────────────────────────┐        WebSocket         ┌──────────────────────────┐
│   Agent Terminal (CPU)  │ ───────────────────────► │  JupyterHub Kernel (GPU) │
│   Claude Code / CLI     │ ◄─────────────────────── │  PyTorch / CUDA          │
└─────────────────────────┘        stdout stream      └──────────────────────────┘
```

## Usage

```bash
# Execute a script on the remote GPU kernel
jh-exec run train.py

# Execute inline code
jh-exec exec "import torch; print(torch.cuda.is_available())"

# List running kernels
jh-exec kernels

# Start a new kernel
jh-exec new-kernel
```

## Configuration

Set via environment variables or a `.env` file in the working or home directory:

```bash
JH_HOST=192.168.1.100
JH_PORT=8000
JH_USER=agent-01
JH_TOKEN=your_token_here
JH_TIMEOUT=600
```

Or pass directly:

```bash
jh-exec --host 192.168.1.100 --user agent-01 --token your_token run script.py
```

## Python API

```python
from jh_exec import execute, list_kernels, new_kernel

# Execute code, stream output to stdout
execute("import torch; print(torch.cuda.get_device_name(0))")

# List running kernels
kernels = list_kernels()

# Start a new kernel, get its ID
kid = new_kernel()
```

## Dedicated GPU per agent

In `jupyterhub_config.py`:

```python
def assign_gpu(spawner):
    gpu_map = {
        "agent-01": "0",
        "agent-02": "1",
        "agent-03": "2",
    }
    spawner.environment["CUDA_VISIBLE_DEVICES"] = gpu_map.get(spawner.user.name, "")

c.Spawner.pre_spawn_hook = assign_gpu
```

## License

MIT
