Refine JupyterCTL project narrative
English | 简体中文
让 Agent 直接调用现成的 JupyterLab 算力环境。 一份私有配置管理多台 GPU / NPU 机器,复用 Jupyter Server 已有的终端与文件接口。
Python 3.10+ · jc 短命令 · Terminal WebSocket · Contents API
Python 3.10+
jc
科研算力平台通常已经配好 JupyterLab。它有稳定的终端会话、清楚的文件管理和成熟的权限体系,正适合承载远端实验。JupyterCTL 把这些能力整理成 Agent 可以直接调用的短命令。
配置一次 URL、Token 和工作目录,本地的 Claude Code、Codex 或其他 Harness 就能按名称进入不同环境。NVIDIA 模型微调、昇腾算子验证和长时间 benchmark 可以由同一个 Agent 连续调度;Shell 输出、任务状态与文件传输结果都有结构化回执。
推荐用 pipx,安装后同时得到 jupyterctl 和短命令 jc:
pipx
jupyterctl
cd JupyterCTL pipx install .
也可以装进当前 Python 环境:
python -m pip install .
完整安装会自动带上 websocket-client。如果终端检查提示依赖缺失,请重新安装完整项目,不需要使用额外的 jupyter extra。
websocket-client
jupyter
jc init
它会创建 ~/.config/jupyterctl/config.env,并在 POSIX 系统上把权限设为 600。配置位置不再跟当前工作目录变化;每次运行时,jc 也会在 stderr 明确打印正在使用的配置文件。
~/.config/jupyterctl/config.env
600
需要放在别处时,可以二选一:
jc --env-file /secure/path/jupyterctl.env envs JUPYTERCTL_CONFIG=/secure/path/jupyterctl.env jc envs
jc init --force 会覆盖已有配置,只在确认旧内容不再需要时使用。
jc init --force
配置完成后,可以随时查询来源、查看脱敏内容或只做本地校验:
jc config path jc config show jc config validate
show 不会输出 Token、Cookie 或 XSRF 值;validate 不连接远端,适合在 Agent 开始工作前先拦住占位符、缺失项和错误默认实例。
show
validate
每个远端环境需要确认三项信息:浏览器能访问的 JupyterLab 入口、Jupyter Token,以及希望 Shell 默认进入的目录。
/lab
/tree
?token=...
jupyter server list
token=
JCTL_<名称>_TOKEN
127.0.0.1
pwd
JCTL_<名称>_CWD
Jupyter Server 的 Token 说明见官方安全文档。不要把 Token、Cookie、XSRF 值或带 Token 的 URL 发到聊天里。
编辑 ~/.config/jupyterctl/config.env:
JCTL_INSTANCES=nvidia,npu-910b JCTL_DEFAULT=nvidia JCTL_NVIDIA_URL=https://provider.example/jupyter/lab JCTL_NVIDIA_TOKEN= JCTL_NVIDIA_CWD=/root/autodl-tmp # JCTL_NVIDIA_TRANSFER_ROOT=workspace JCTL_NVIDIA_VERIFY_TLS=true JCTL_NPU_910B_URL=https://provider.example/another/lab JCTL_NPU_910B_TOKEN= JCTL_NPU_910B_CWD=/data JCTL_NPU_910B_VERIFY_TLS=true
把两个空 Token 换成各自的真实值;如果 Token 已经在 URL 查询参数中,对应 TOKEN 可以留空。名称不区分大小写,连字符在变量前缀中会变成下划线,因此 npu-910b 对应 JCTL_NPU_910B_*。
TOKEN
npu-910b
JCTL_NPU_910B_*
JCTL_INSTANCES
JCTL_DEFAULT
-i
JCTL_<名称>_URL
Bearer
JCTL_<名称>_TRANSFER_ROOT
/
JCTL_<名称>_VERIFY_TLS
true
JCTL_<名称>_TIMEOUT
30
.invalid 域名和 replace-me、your-token 一类占位符会被标为 not_configured,不能成为默认目标。这样示例配置不会被 Agent 当成真机器。
.invalid
replace-me
your-token
not_configured
# 查看名称、脱敏 URL、配置状态和实际配置文件 jc envs # HTTP API + WebSocket 终端往返 + 临时终端清理 + Contents API jc -i npu-910b doctor --json # 同一套安全验收;可选做小文件上传、下载、SHA-256 和自动清理 jc -i npu-910b self-test jc -i npu-910b self-test --transfer
doctor --json 会为每项检查返回稳定的 code、status、detail 和所属通道。Jupyter HTTP、WebSocket 终端、Shell 文件系统与 Contents API 分开报告;即使其中一项失败,其余已完成的结果仍会留在 checks、errors、diagnostics、channels、capabilities 和 remediation 中。HTTP 401/403 会明确提示 Token 或浏览器会话凭据可能已轮换,不会误导为文件权限问题。
doctor --json
code
status
detail
checks
errors
diagnostics
channels
capabilities
remediation
--transfer 只操作自己创建的 .jupyterctl-self-test-*.txt 文件。如果目标目录报告 writable=false,它会返回结构化的 unsupported,并明确给出 write_attempted: false,不会再尝试 PUT。
--transfer
.jupyterctl-self-test-*.txt
writable=false
unsupported
write_attempted: false
普通执行保留适合人看的流式终端输出:
jc -i npu-910b x -- npu-smi info
Harness 更适合使用结构化模式:
jc -i npu-910b x --quiet --json -- python train.py
stdout 只返回一个 JSON 对象。命令结果放在 data,常用字段(如 stdout、stderr、exit_code、terminal、instance 和 config_file)也保留在顶层,方便已有脚本平滑升级。完整捕获脚本会编码后作为一条命令交给非交互 Bash,Moark 或其他平台的 PS1 只能出现在结果标记之外;不需要猜测并删除某一种提示符。登录欢迎语、ANSI 控制符、内部 stty 和完成标记也不会混进去。配置路径仍写到 stderr,方便追踪来源。
data
stdout
stderr
exit_code
terminal
instance
config_file
stty
所有机器可读 JSON 使用同一套顶层协议:schema_version、command、target、started_at、elapsed_seconds、success、error 和 data。失败时,error 至少包含 code、phase、retryable 与 suggested_action;即使远端命令退出码非零,也会返回完整的 stdout / stderr,再由调用方决定是否重试。
schema_version
command
target
started_at
elapsed_seconds
success
error
phase
retryable
suggested_action
只想压掉终端噪声、保留纯文本时:
jc -i npu-910b x --quiet -- pwd
p
doctor
check
self-test
x
exec
r
resolve
u
d
upload
download
s
stat
md
mkdir
j
job
ts
terminals
tc
td
terminal-create
terminal-delete
四五十分钟的训练、Harness 或 benchmark,优先交给可恢复任务模式。任务在远端独立运行,本地断线后仍能重新查询:
jc -i nvidia job start --name full13 -- bash run_train.sh jc -i nvidia job list --json jc -i nvidia job status full13 jc -i nvidia job logs full13 --tail 200 jc -i nvidia job wait full13 --timeout 21600 --json # 必须确认要终止这个任务时 jc -i nvidia job cancel full13 --json jc -i nvidia job remove full13 --json # 先预览,再删除七天前已结束的任务状态 jc -i nvidia job prune --older-than 604800 --json jc -i nvidia job prune --older-than 604800 --yes --json
状态与日志保存在远端 ~/.local/state/jupyterctl/jobs/<name>。任务名必须唯一;wait 会把远端退出码作为本地退出码。remove 只接受已经结束、丢失或确认 PID 已失效的任务;prune 默认只预览,必须传 --yes 才会删除。
~/.local/state/jupyterctl/jobs/<name>
wait
remove
prune
--yes
取消任务不会只凭一个 PID 发信号。JupyterCTL 会核对 /proc 中的 PID 启动时刻、runner 路径、启动时写入的随机任务标识,以及进程组身份;随后通过 Linux pidfd 再确认一次并定向发出终止信号。任何身份信息缺失或发生变化都会拒绝取消,以免 PID 复用后误伤别的进程。命令内容会写入私有状态目录,因此不要把 Token 等凭据直接拼进命令行。
/proc
短时的一次性命令使用临时终端,结束后自动清理:
jc -i nvidia x --timeout 21600 -- bash run_train.sh
需要保留 Shell 状态时,使用命名终端:
jc -i nvidia tc --name training jc -i nvidia x --terminal training -- bash run_train.sh jc -i nvidia x --terminal training -- tail -n 80 train.log jc -i nvidia td training
jc -i nvidia ls jc -i nvidia s checkpoint/config.json --hash jc -i nvidia u ./bundle.tar.gz bundles/bundle.tar.gz jc -i nvidia d results.json ./results.json
Contents API 路径始终相对于 Jupyter 根目录;Shell 的 --cwd 是远端文件系统路径,可以是绝对路径。doctor 会明确输出类似:
--cwd
{ "shell_default_cwd": "/data", "contents_root_maps_to": "/data" }
如果根目录映射到 /data,jc stat data 实际访问的是 /data/data。要查看 /data 自身,应使用 jc ls;访问其中的文件时,直接传相对于 /data 的路径。
/data
jc stat data
/data/data
jc ls
不确定时先解析,不做写操作:
jc -i nvidia r data/foo
结果会同时给出 configured_cwd、input_path、contents_api_path、contents_root_maps_to 和 resolved_path。如果 /data 是 Contents 根,输入 data/foo 会明确显示为 /data/data/foo 并给出重复根目录警告。stat、mkdir、upload 和 download 的 JSON 回执也带有同一组 path_resolution 字段;若终端通道不可用,Contents 操作仍可返回结果,并在路径解析部分单独报告错误。
configured_cwd
input_path
contents_api_path
contents_root_maps_to
resolved_path
data/foo
/data/data/foo
path_resolution
上传下载默认使用 --transport auto:先尝试 Contents API,失败后只有在适合回退的情况下才使用终端通道。回退成功的回执会写明 transport=terminal 与 fallback_reason;终端上传会复用一个临时终端分块写入,避免大文件撞上 Shell 参数长度限制,再对整份文件做 SHA-256 校验并原子替换。需要排查通道时可以强制选择:
--transport auto
transport=terminal
fallback_reason
jc -i nvidia u ./bundle.tar.gz bundles/bundle.tar.gz --transport contents jc -i nvidia d results.json ./results.json --transport terminal
当 doctor 报告 capabilities.contents_write=read_only 时,channels 和 transfer_channels 会继续检查 Shell 文件系统。Shell 可写时,普通 upload/download --transport auto 会使用终端通道完成传输;mkdir 与 self-test --transfer 保持为 Contents API 检查,并返回结构化的 unsupported 与 write_attempted=false。
capabilities.contents_write=read_only
transfer_channels
upload/download --transport auto
self-test --transfer
write_attempted=false
这份诊断会完整保留 Contents 故障,方便平台或服务器维护者处理。JupyterCTL 将服务器配置留给维护者管理,包括权限、所有权、ServerApp.root_dir 和 Jupyter Server 生命周期;提交问题时附上 doctor 的 checks、errors、warnings、channels、capabilities 与 remediation 即可。
ServerApp.root_dir
warnings
JCTL_<名称>_TRANSFER_ROOT 用于指定维护者已经提供的可写 Contents 相对目录。填写前运行 jc -i 名称 s 相对路径,确认返回 type=directory、writable=true;没有合适目录时保持为空。
jc -i 名称 s 相对路径
type=directory
writable=true
浏览器会话认证的平台,可以从开发者工具中找到一个成功访问 /api 的请求,把完整 Cookie 请求头放入 JCTL_<名称>_COOKIE,页面的 协议://主机名 放入 JCTL_<名称>_ORIGIN。Cookie 中有 _xsrf 时会自动提取;只有平台单独发送 XSRF 请求头时才填写 JCTL_<名称>_XSRF_TOKEN。
/api
Cookie
JCTL_<名称>_COOKIE
协议://主机名
JCTL_<名称>_ORIGIN
_xsrf
JCTL_<名称>_XSRF_TOKEN
只有平台明确要求把 Token 放进查询参数时,才启用 JCTL_<名称>_TOKEN_QUERY 或 JCTL_<名称>_WS_TOKEN_QUERY。
JCTL_<名称>_TOKEN_QUERY
JCTL_<名称>_WS_TOKEN_QUERY
旧版单实例变量 JUPYTER_BASE_URL、JUPYTER_TOKEN 和 JUPYTER_DEFAULT_CWD 仍可使用,但不会再从当前目录自动寻找 .jupyterctl.env。请用用户级配置、--env-file 或 JUPYTERCTL_CONFIG 明确指定来源。
JUPYTER_BASE_URL
JUPYTER_TOKEN
JUPYTER_DEFAULT_CWD
.jupyterctl.env
--env-file
JUPYTERCTL_CONFIG
jc x
jc u
jc d
mc on
mc off
mc re
doctor 负责验证 Agent 到 Jupyter 的控制链路。随后继续检查加速卡、磁盘、缓存、进程和实验产物,就能形成完整的真机验收。给 Agent 的紧凑操作流程见 SKILL.md。
python -m pip install -e '.[dev]' pytest
本项目采用 Apache License 2.0,版权归 AkkoYK 所有,详见 NOTICE。
Control named remote JupyterLab environments from local coding agents. 让本地编程 Agent 管理多个命名的远端 JupyterLab 环境。
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
JupyterCTL
English | 简体中文
让 Agent 直接调用现成的 JupyterLab 算力环境。
一份私有配置管理多台 GPU / NPU 机器,复用 Jupyter Server 已有的终端与文件接口。
Python 3.10+·jc短命令 · Terminal WebSocket · Contents API科研算力平台通常已经配好 JupyterLab。它有稳定的终端会话、清楚的文件管理和成熟的权限体系,正适合承载远端实验。JupyterCTL 把这些能力整理成 Agent 可以直接调用的短命令。
配置一次 URL、Token 和工作目录,本地的 Claude Code、Codex 或其他 Harness 就能按名称进入不同环境。NVIDIA 模型微调、昇腾算子验证和长时间 benchmark 可以由同一个 Agent 连续调度;Shell 输出、任务状态与文件传输结果都有结构化回执。
三分钟跑通
1. 安装
推荐用
pipx,安装后同时得到jupyterctl和短命令jc:也可以装进当前 Python 环境:
完整安装会自动带上
websocket-client。如果终端检查提示依赖缺失,请重新安装完整项目,不需要使用额外的jupyterextra。2. 创建私有配置
它会创建
~/.config/jupyterctl/config.env,并在 POSIX 系统上把权限设为600。配置位置不再跟当前工作目录变化;每次运行时,jc也会在 stderr 明确打印正在使用的配置文件。需要放在别处时,可以二选一:
jc init --force会覆盖已有配置,只在确认旧内容不再需要时使用。配置完成后,可以随时查询来源、查看脱敏内容或只做本地校验:
show不会输出 Token、Cookie 或 XSRF 值;validate不连接远端,适合在 Agent 开始工作前先拦住占位符、缺失项和错误默认实例。3. 获取 JupyterLab 连接信息
每个远端环境需要确认三项信息:浏览器能访问的 JupyterLab 入口、Jupyter Token,以及希望 Shell 默认进入的目录。
/lab、/tree或?token=...都可以,JupyterCTL 会整理成 Server 基础地址。jupyter server list,把token=后面的值填入JCTL_<名称>_TOKEN。命令若显示127.0.0.1或容器内网地址,URL 的主机和代理路径仍以浏览器可访问的入口为准。pwd,把希望命令默认进入的目录填入JCTL_<名称>_CWD。Jupyter Server 的 Token 说明见官方安全文档。不要把 Token、Cookie、XSRF 值或带 Token 的 URL 发到聊天里。
编辑
~/.config/jupyterctl/config.env:把两个空 Token 换成各自的真实值;如果 Token 已经在 URL 查询参数中,对应
TOKEN可以留空。名称不区分大小写,连字符在变量前缀中会变成下划线,因此npu-910b对应JCTL_NPU_910B_*。JCTL_INSTANCESJCTL_DEFAULT-i时可留空JCTL_<名称>_URLJCTL_<名称>_TOKENtoken=后面的值,不含token=或BearerJCTL_<名称>_CWDJCTL_<名称>_TRANSFER_ROOT/开头JCTL_<名称>_VERIFY_TLStruetrueJCTL_<名称>_TIMEOUT30.invalid域名和replace-me、your-token一类占位符会被标为not_configured,不能成为默认目标。这样示例配置不会被 Agent 当成真机器。4. 验收连接
doctor --json会为每项检查返回稳定的code、status、detail和所属通道。Jupyter HTTP、WebSocket 终端、Shell 文件系统与 Contents API 分开报告;即使其中一项失败,其余已完成的结果仍会留在checks、errors、diagnostics、channels、capabilities和remediation中。HTTP 401/403 会明确提示 Token 或浏览器会话凭据可能已轮换,不会误导为文件权限问题。--transfer只操作自己创建的.jupyterctl-self-test-*.txt文件。如果目标目录报告writable=false,它会返回结构化的unsupported,并明确给出write_attempted: false,不会再尝试 PUT。给 Agent 的干净输出
普通执行保留适合人看的流式终端输出:
Harness 更适合使用结构化模式:
stdout 只返回一个 JSON 对象。命令结果放在
data,常用字段(如stdout、stderr、exit_code、terminal、instance和config_file)也保留在顶层,方便已有脚本平滑升级。完整捕获脚本会编码后作为一条命令交给非交互 Bash,Moark 或其他平台的 PS1 只能出现在结果标记之外;不需要猜测并删除某一种提示符。登录欢迎语、ANSI 控制符、内部stty和完成标记也不会混进去。配置路径仍写到 stderr,方便追踪来源。所有机器可读 JSON 使用同一套顶层协议:
schema_version、command、target、started_at、elapsed_seconds、success、error和data。失败时,error至少包含code、phase、retryable与suggested_action;即使远端命令退出码非零,也会返回完整的 stdout / stderr,再由调用方决定是否重试。只想压掉终端噪声、保留纯文本时:
常用短命令
pdoctorcheckself-testxexecrresolveu/dupload/downloadsstatmdmkdirjjobtsterminalstc/tdterminal-create/terminal-delete长任务与保留终端
四五十分钟的训练、Harness 或 benchmark,优先交给可恢复任务模式。任务在远端独立运行,本地断线后仍能重新查询:
状态与日志保存在远端
~/.local/state/jupyterctl/jobs/<name>。任务名必须唯一;wait会把远端退出码作为本地退出码。remove只接受已经结束、丢失或确认 PID 已失效的任务;prune默认只预览,必须传--yes才会删除。取消任务不会只凭一个 PID 发信号。JupyterCTL 会核对
/proc中的 PID 启动时刻、runner 路径、启动时写入的随机任务标识,以及进程组身份;随后通过 Linux pidfd 再确认一次并定向发出终止信号。任何身份信息缺失或发生变化都会拒绝取消,以免 PID 复用后误伤别的进程。命令内容会写入私有状态目录,因此不要把 Token 等凭据直接拼进命令行。短时的一次性命令使用临时终端,结束后自动清理:
需要保留 Shell 状态时,使用命名终端:
Contents 路径如何解析
Contents API 路径始终相对于 Jupyter 根目录;Shell 的
--cwd是远端文件系统路径,可以是绝对路径。doctor会明确输出类似:如果根目录映射到
/data,jc stat data实际访问的是/data/data。要查看/data自身,应使用jc ls;访问其中的文件时,直接传相对于/data的路径。不确定时先解析,不做写操作:
结果会同时给出
configured_cwd、input_path、contents_api_path、contents_root_maps_to和resolved_path。如果/data是 Contents 根,输入data/foo会明确显示为/data/data/foo并给出重复根目录警告。stat、mkdir、upload和download的 JSON 回执也带有同一组path_resolution字段;若终端通道不可用,Contents 操作仍可返回结果,并在路径解析部分单独报告错误。上传下载默认使用
--transport auto:先尝试 Contents API,失败后只有在适合回退的情况下才使用终端通道。回退成功的回执会写明transport=terminal与fallback_reason;终端上传会复用一个临时终端分块写入,避免大文件撞上 Shell 参数长度限制,再对整份文件做 SHA-256 校验并原子替换。需要排查通道时可以强制选择:Contents 只读时的通道选择
当
doctor报告capabilities.contents_write=read_only时,channels和transfer_channels会继续检查 Shell 文件系统。Shell 可写时,普通upload/download --transport auto会使用终端通道完成传输;mkdir与self-test --transfer保持为 Contents API 检查,并返回结构化的unsupported与write_attempted=false。这份诊断会完整保留 Contents 故障,方便平台或服务器维护者处理。JupyterCTL 将服务器配置留给维护者管理,包括权限、所有权、
ServerApp.root_dir和 Jupyter Server 生命周期;提交问题时附上doctor的checks、errors、warnings、channels、capabilities与remediation即可。JCTL_<名称>_TRANSFER_ROOT用于指定维护者已经提供的可写 Contents 相对目录。填写前运行jc -i 名称 s 相对路径,确认返回type=directory、writable=true;没有合适目录时保持为空。Cookie 登录、Token Query 与旧版单实例变量
浏览器会话认证的平台,可以从开发者工具中找到一个成功访问
/api的请求,把完整Cookie请求头放入JCTL_<名称>_COOKIE,页面的协议://主机名放入JCTL_<名称>_ORIGIN。Cookie 中有_xsrf时会自动提取;只有平台单独发送 XSRF 请求头时才填写JCTL_<名称>_XSRF_TOKEN。只有平台明确要求把 Token 放进查询参数时,才启用
JCTL_<名称>_TOKEN_QUERY或JCTL_<名称>_WS_TOKEN_QUERY。旧版单实例变量
JUPYTER_BASE_URL、JUPYTER_TOKEN和JUPYTER_DEFAULT_CWD仍可使用,但不会再从当前目录自动寻找.jupyterctl.env。请用用户级配置、--env-file或JUPYTERCTL_CONFIG明确指定来源。和 MoarkCTL 怎么分工
jc x、jc u、jc dmc on、mc off、mc redoctor负责验证 Agent 到 Jupyter 的控制链路。随后继续检查加速卡、磁盘、缓存、进程和实验产物,就能形成完整的真机验收。给 Agent 的紧凑操作流程见 SKILL.md。开发与许可证
本项目采用 Apache License 2.0,版权归 AkkoYK 所有,详见 NOTICE。