目录

JupyterCTL

English | 简体中文

JupyterCTL 让本地 Agent 操作多个命名的 JupyterLab 远端环境

让 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

cd JupyterCTL
pipx install .

也可以装进当前 Python 环境:

python -m pip install .

完整安装会自动带上 websocket-client。如果终端检查提示依赖缺失,请重新安装完整项目,不需要使用额外的 jupyter extra。

2. 创建私有配置

jc init

它会创建 ~/.config/jupyterctl/config.env,并在 POSIX 系统上把权限设为 600。配置位置不再跟当前工作目录变化;每次运行时,jc 也会在 stderr 明确打印正在使用的配置文件。

需要放在别处时,可以二选一:

jc --env-file /secure/path/jupyterctl.env envs
JUPYTERCTL_CONFIG=/secure/path/jupyterctl.env jc envs

jc init --force 会覆盖已有配置,只在确认旧内容不再需要时使用。

配置完成后,可以随时查询来源、查看脱敏内容或只做本地校验:

jc config path
jc config show
jc config validate

show 不会输出 Token、Cookie 或 XSRF 值;validate 不连接远端,适合在 Agent 开始工作前先拦住占位符、缺失项和错误默认实例。

3. 获取 JupyterLab 连接信息

每个远端环境需要确认三项信息:浏览器能访问的 JupyterLab 入口、Jupyter Token,以及希望 Shell 默认进入的目录。

  1. 在算力平台点击“打开 JupyterLab”,等页面正常加载后复制浏览器里的完整地址。地址带 /lab/tree?token=... 都可以,JupyterCTL 会整理成 Server 基础地址。
  2. 如果地址里没有 Token,在远端 JupyterLab 终端运行 jupyter server list,把 token= 后面的值填入 JCTL_<名称>_TOKEN。命令若显示 127.0.0.1 或容器内网地址,URL 的主机和代理路径仍以浏览器可访问的入口为准。
  3. 在远端终端运行 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_*

环境变量 如何填写 是否必填
JCTL_INSTANCES 自定义实例名,用英文逗号分隔 多实例必填
JCTL_DEFAULT 默认实例名;每次都传 -i 时可留空 可选
JCTL_<名称>_URL 浏览器可访问的 JupyterLab 入口 必填
JCTL_<名称>_TOKEN token= 后面的值,不含 token=Bearer 通常必填
JCTL_<名称>_CWD 远端 Shell 默认目录 可选
JCTL_<名称>_TRANSFER_ROOT 可写的 Contents 相对目录,用于传输自检,不要以 / 开头 可选
JCTL_<名称>_VERIFY_TLS 公网 HTTPS 保持 true 可选,默认 true
JCTL_<名称>_TIMEOUT API 请求超时秒数 可选,默认 30

.invalid 域名和 replace-meyour-token 一类占位符会被标为 not_configured,不能成为默认目标。这样示例配置不会被 Agent 当成真机器。

4. 验收连接

# 查看名称、脱敏 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 会为每项检查返回稳定的 codestatusdetail 和所属通道。Jupyter HTTP、WebSocket 终端、Shell 文件系统与 Contents API 分开报告;即使其中一项失败,其余已完成的结果仍会留在 checkserrorsdiagnosticschannelscapabilitiesremediation 中。HTTP 401/403 会明确提示 Token 或浏览器会话凭据可能已轮换,不会误导为文件权限问题。

--transfer 只操作自己创建的 .jupyterctl-self-test-*.txt 文件。如果目标目录报告 writable=false,它会返回结构化的 unsupported,并明确给出 write_attempted: false,不会再尝试 PUT。

给 Agent 的干净输出

普通执行保留适合人看的流式终端输出:

jc -i npu-910b x -- npu-smi info

Harness 更适合使用结构化模式:

jc -i npu-910b x --quiet --json -- python train.py

stdout 只返回一个 JSON 对象。命令结果放在 data,常用字段(如 stdoutstderrexit_codeterminalinstanceconfig_file)也保留在顶层,方便已有脚本平滑升级。完整捕获脚本会编码后作为一条命令交给非交互 Bash,Moark 或其他平台的 PS1 只能出现在结果标记之外;不需要猜测并删除某一种提示符。登录欢迎语、ANSI 控制符、内部 stty 和完成标记也不会混进去。配置路径仍写到 stderr,方便追踪来源。

所有机器可读 JSON 使用同一套顶层协议:schema_versioncommandtargetstarted_atelapsed_secondssuccesserrordata。失败时,error 至少包含 codephaseretryablesuggested_action;即使远端命令退出码非零,也会返回完整的 stdout / stderr,再由调用方决定是否重试。

只想压掉终端噪声、保留纯文本时:

jc -i npu-910b x --quiet -- pwd

常用短命令

短命令 完整命令 用途
p doctor 做真实的控制通道检查
check self-test 一键安全验收
x exec 执行 Shell 命令
r resolve 预览 Contents 路径对应的 Shell 绝对路径
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 才会删除。

取消任务不会只凭一个 PID 发信号。JupyterCTL 会核对 /proc 中的 PID 启动时刻、runner 路径、启动时写入的随机任务标识,以及进程组身份;随后通过 Linux pidfd 再确认一次并定向发出终止信号。任何身份信息缺失或发生变化都会拒绝取消,以免 PID 复用后误伤别的进程。命令内容会写入私有状态目录,因此不要把 Token 等凭据直接拼进命令行。

短时的一次性命令使用临时终端,结束后自动清理:

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

Contents 路径如何解析

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 会明确输出类似:

{
  "shell_default_cwd": "/data",
  "contents_root_maps_to": "/data"
}

如果根目录映射到 /datajc stat data 实际访问的是 /data/data。要查看 /data 自身,应使用 jc ls;访问其中的文件时,直接传相对于 /data 的路径。

不确定时先解析,不做写操作:

jc -i nvidia r data/foo

结果会同时给出 configured_cwdinput_pathcontents_api_pathcontents_root_maps_toresolved_path。如果 /data 是 Contents 根,输入 data/foo 会明确显示为 /data/data/foo 并给出重复根目录警告。statmkdiruploaddownload 的 JSON 回执也带有同一组 path_resolution 字段;若终端通道不可用,Contents 操作仍可返回结果,并在路径解析部分单独报告错误。

上传下载默认使用 --transport auto:先尝试 Contents API,失败后只有在适合回退的情况下才使用终端通道。回退成功的回执会写明 transport=terminalfallback_reason;终端上传会复用一个临时终端分块写入,避免大文件撞上 Shell 参数长度限制,再对整份文件做 SHA-256 校验并原子替换。需要排查通道时可以强制选择:

jc -i nvidia u ./bundle.tar.gz bundles/bundle.tar.gz --transport contents
jc -i nvidia d results.json ./results.json --transport terminal

Contents 只读时的通道选择

doctor 报告 capabilities.contents_write=read_only 时,channelstransfer_channels 会继续检查 Shell 文件系统。Shell 可写时,普通 upload/download --transport auto 会使用终端通道完成传输;mkdirself-test --transfer 保持为 Contents API 检查,并返回结构化的 unsupportedwrite_attempted=false

这份诊断会完整保留 Contents 故障,方便平台或服务器维护者处理。JupyterCTL 将服务器配置留给维护者管理,包括权限、所有权、ServerApp.root_dir 和 Jupyter Server 生命周期;提交问题时附上 doctorcheckserrorswarningschannelscapabilitiesremediation 即可。

JCTL_<名称>_TRANSFER_ROOT 用于指定维护者已经提供的可写 Contents 相对目录。填写前运行 jc -i 名称 s 相对路径,确认返回 type=directorywritable=true;没有合适目录时保持为空。

Cookie 登录、Token Query 与旧版单实例变量

浏览器会话认证的平台,可以从开发者工具中找到一个成功访问 /api 的请求,把完整 Cookie 请求头放入 JCTL_<名称>_COOKIE,页面的 协议://主机名 放入 JCTL_<名称>_ORIGIN。Cookie 中有 _xsrf 时会自动提取;只有平台单独发送 XSRF 请求头时才填写 JCTL_<名称>_XSRF_TOKEN

只有平台明确要求把 Token 放进查询参数时,才启用 JCTL_<名称>_TOKEN_QUERYJCTL_<名称>_WS_TOKEN_QUERY

旧版单实例变量 JUPYTER_BASE_URLJUPYTER_TOKENJUPYTER_DEFAULT_CWD 仍可使用,但不会再从当前目录自动寻找 .jupyterctl.env。请用用户级配置、--env-fileJUPYTERCTL_CONFIG 明确指定来源。

和 MoarkCTL 怎么分工

工具 负责什么 常用短命令
JupyterCTL 机器内部的远端命令、终端与文件 jc xjc ujc d
MoarkCTL 模力方舟容器生命周期与计费边界 mc onmc offmc 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 环境。

250.0 KB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号