from solveit_modal.sandbox import *kernel
Connecting a solveit kernel to a Modal sandbox
flowchart TD
A[Start a remote IPython kernel] --> B[Register the remote IPython kernel]
B --> C[Swap SolveIt's IPython kernel with the remote one]
We’ll first spin up a sandbox.
app = mk_app('solveit-sandbox')
img = mk_img(pips=['ipykernel', 'torch'], apts=['openssh-server'])
vol = mk_vol('solveit-volume')
sb = mk_sandbox(app, img, vol, timeout=600, gpu='T4', secrets={})
host,port = get_tunnel(sb)
inject_pubkey(sb, get_pubkey()); start_ssh(sb)
ssh = mk_ssh(host, port)
verify_ssh(ssh)INFO - ∞ creating sandbox; this may take 5-10 minutes if you are creating this sandbox for the first time... | 2026-06-17 06:27:28,629
INFO - ✔ sandbox ready | 2026-06-17 06:28:25,941
INFO - ✔ gotten tunnel: r451.modal.host:34457 | 2026-06-17 06:28:41,496
INFO - ✔ public key injected | 2026-06-17 06:28:42,020
INFO - ✔ started ssh service | 2026-06-17 06:28:42,656
System: Linux
Hostname: modal
User: root
Kernel: 4.4.0
Architecture: x86_64
OS Type: GNU/Linux
GPU: Tesla T4
Next up is starting a remote IPython kernel.
start_remote_kernel
def start_remote_kernel(
ssh:Callable, # SSH caller from mk_ssh
kernel_path:str='/root/.local/share/jupyter/runtime/kernel-ipyf.json', # kernel JSON path
):
Start remote kernel and wait until ready.
start_remote_kernel(ssh)INFO - ∞ starting kernel | 2026-06-17 06:28:45,403
INFO - ✔ remote kernel ready: /root/.local/share/jupyter/runtime/kernel-ipyf.json | 2026-06-17 06:28:49,862
We’ll also need to fetch which Python is being used.
get_remote_python
def get_remote_python(
ssh:Callable, # SSH caller from mk_ssh
)->str: # path to remote python
Return the path of Python on the remote machine.
p = get_remote_python(ssh); p'/usr/local/bin/python3'
Now that the an IPython kernel is up and running on the Modal sandbox, it’s time to register that kernel to SolveIt, and then swap it.
We’ll be doing that with Dr. Scott Hawley’s awesome ipyfernel library.
I’d do _all_ = ipyfernel.core.__all__, but nbdev would through an error.
register_remote_kernel(remote_python=p)
connect_existing_kernel(f'{host}:{port}')ipyf_remote_kernel is already a registered kernel
/app/data/.ssh/config file updated.
Successfully created connection file and forwarded ports!
Success: connected to remote kernel via r451.modal.host:34457
And we’re done! Use the %remote line magic or %%remote cell magic to run code on Modal’s sandbox.
#%%remote <-- cell magic (remove # when actually using)
import platform
platform.uname()uname_result(system='Linux', node='modal', release='4.4.0', version='#1 SMP Sun Jan 10 15:06:54 PST 2016', machine='x86_64')
#%%remote <-- cell magic (remove # when actually using)
!nvidia-smiWed Jun 17 06:28:53 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.95.05 Driver Version: 580.95.05 CUDA Version: 13.0 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 Tesla T4 On | 00000000:E7:00.0 Off | 0 |
| N/A 30C P8 9W / 70W | 0MiB / 15360MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
Alternatively, ipyfernel also has a sticky mode allowing us to run code remotely by default.
set_sticky()Code cells will now execute remotely.
import torch/usr/local/lib/python3.12/site-packages/torch/_subclasses/functional_tensor.py:362: UserWarning: Failed to initialize NumPy: No module named 'numpy' (Triggered internally at /pytorch/torch/csrc/utils/tensor_numpy.cpp:84.)
cpu = _conversion_method_template(device=torch.device("cpu"))
torch.cuda.is_available()True
%%local to run code locally.
#%%local <-- cell magic (remove # when actually using)
unset_sticky()Code cells will now run locally.
stop_remote()Code cells will now run locally.
Shutting down remote kernel
sb.terminate()