Skip to content

CLI 命令参考 ​

anet 管理 Hub、账号、Network、节点和外部 Channel。本页只保留当前命令与容易误操作的行为;专题配置请进入对应指南。

安装与帮助 ​

bash
# 稳定版
npm install -g @sleep2agi/agent-network@latest

# 预览版
npm install -g @sleep2agi/agent-network@preview

anet --help
anet <command> --help
anet <command> <subcommand> --help   # 例如 anet node delete --help
anet -v

需要 Node.js 22.13+ 和 Bun 1.2+。--help(或 -h)只显示帮助,不会创建 token、启动服务或执行其他业务操作。每个命令和子命令都有自己的用法说明,退出码 0。

最短启动路径 ​

bash
# 终端 1
anet hub start

# 终端 2
anet login --hub http://127.0.0.1:9200 --username admin

# 登录后
anet node create my-agent
anet node start my-agent

初始密码随发布频道不同:stable(@latest)使用固定默认值,可在 anet hub start --help 的 --password 说明中查看;preview(@preview)首次启动会打印一次性随机密码。登录后立即运行 anet passwd。

完整安装与首次配置见 快速开始。

Hub ​

命令作用
anet hub start启动 Hub;默认监听 127.0.0.1:9200
anet hub stop [--port <p>]停止指定端口上的本机 Hub
anet hub status [--port <p>]显示监听状态、PID 和服务版本
anet hub dashboard启动 Dashboard,默认端口 3000
anet hub config查看或修改本机 Hub 启动配置
anet hub admin reset-user --username <user>在 Hub 主机上重置用户密码和用户 token

常用启动参数:

参数说明
--port <port>Hub 端口,默认 9200
--host <host> / --ip <host>绑定地址,默认仅本机的 127.0.0.1
--username <user>首次启动时指定管理员用户名
--password <pass>首次启动时显式指定管理员密码
--dev-open关闭鉴权,仅限隔离开发环境
--version <v>指定要启动的 commhub-server 版本(精确版本号,或 latest / preview)
--channel <c>latest 或 preview,覆盖默认按 anet 自身通道选版本的结果

启动的 Hub 版本:不带 --version 时,anet hub start 先按已装 anet 的版本对照 @sleep2agi/agent-network 的 dist-tags 判断通道(等于或落后于 latest 判为 latest,比 latest 新的预发布版判为 preview;不能只看 -preview.N 后缀,latest 本身也带这个后缀),再取该通道对应的 @sleep2agi/commhub-server dist-tag,交给 bunx 精确版本号启动;该 tag 若比当前 anet 支持的最低版本还旧,则改用最低版本。启动时会打印一行 Hub version: @sleep2agi/commhub-server@<版本> [source: registry | cache | explicit | pinned minimum],说明版本和来源。查不到 npm registry 时,使用本机 bun 缓存里不低于最低版本的最新一版并告警;缓存里只有更旧的版本时不会静默启动它,而是打印两个版本号的告警,并提示用 --version <缓存版本> 显式启动。

不要把 --dev-open 或直接暴露的 0.0.0.0:9200 用于生产。公网部署见 生产部署。

停止 Hub(anet hub stop):只停监听在该端口上、且命令行确认是 commhub-server 的进程,不按进程名匹配。找监听进程不依赖 lsof:Linux 依次用 /proc/net/tcp(6) 的 socket inode 对 /proc/<pid>/fd、ss -ltnp、lsof、netstat,macOS 用 lsof、netstat -anv,Windows 用 netstat -ano,取第一条能运行的;都不能运行时,用 anet hub start 写的 ~/.anet/server/hub-<port>.pid.json(PID 已退出或已被别的程序复用时忽略)。输出会列出每条探测的结果、找到的 PID 和命令行,以及实际停掉了哪个 PID。先 SIGTERM,3 秒后仍在则在再次确认命令行后 SIGKILL。

情况动作退出码
找到 commhub-server 并已停止停止0
该端口没有监听、/health 也不应答不动0
端口被别的程序占用,或读不到它的命令行 / 属主拒绝,打印 PID 和命令行1
/health 有应答,但本机找不到它的 PID(没有任何探测可用,也没有 pid 文件)不动,提示用启动它的进程管理器(pm2、systemd 等)停1
SIGKILL 后进程仍在,或 /health 仍有应答—1
--port 不是合法端口—2

账号、Network 与 Token ​

账号 ​

命令作用
anet register创建账号
anet login使用用户名和密码登录
anet login --token <token>使用已有 API token 登录
anet logout先在 Hub 上撤销本次登录会话,再删除本机保存的登录 token(见下方 退出登录)
anet whoami显示当前用户和可访问的 Network
anet passwd修改密码并轮换当前登录 token

退出登录(anet logout):用保存的 token 调 GET /api/auth/sessions 取得 current_token_id,再 DELETE /api/auth/sessions/<token_id> 撤销这一条登录会话(与 app「设置 → 账号 → 登录设备 → 退出」同一对端点,见 登录设备 API),然后删除 ~/.anet/config.json 里的 token / user / network_id / network_name(保留 hub)。输出只显示 token id,不显示 token。

情况本地服务端退出码
撤销成功 / token 在 Hub 上本来就已失效(401)删除已失效0
Hub 连不上、Hub 早于 v0.9.0-preview.70(/api/auth/sessions 404)删除仍有效,打印 ⚠ 警告与撤销方法0
保存的是 anet login --token 用的显式 API token 或节点 token删除不撤销(它可能还在别处用),打印 ⚠ 警告;用 anet token revoke <token-id> 撤0
本地配置文件写不了未删除—1

服务端仍有效时的撤销办法:app「设置 → 账号 → 登录设备」里退出那台设备;或重新 anet login 后 anet passwd(改密码会撤销其他所有登录会话)。anet init project 写进各项目 .anet/.env 的 COMMHUB_TOKEN 是同一个 token 的副本,服务端撤销后一起失效。

Network ​

命令作用
anet network ls列出当前用户加入的 Network
anet network create <name>创建 Network
anet network use <name>切换当前 Network
anet network info查看当前 Network
anet network rename <old> <new>重命名 Network
anet network delete <name> --force删除 Network
anet network invite [options]创建邀请码
anet network join <code>使用邀请码加入 Network
anet network members列出当前 Network 成员

邀请码可使用 --role admin|member|viewer、--uses <n> 和 --expires <days>。

Token ​

命令作用
anet token / anet token ls列出当前用户的 API token
anet token create <name>创建 API token;明文只显示一次
anet token revoke <token-id>撤销 token

Token 类型、作用域与兼容规则见 Token 体系。

节点 ​

交互菜单:anet node ​

不想记命令:在节点目录里直接敲 anet node(不带参数)。它列出当前目录的所有节点 —— 节点名、runtime(claude-agent-sdk / claude-code-cli / codex-* / grok-* / opencode-cli)、状态(running / stopped)、模型,codex 节点另有登录列 —— 选一个节点再选操作:启动、停止、重启、进入 TUI(attach)、看最近日志、换模型、删除。

  • 每个操作执行前都会打印等价的 anet … 命令,回答 y 才执行;删除要输入节点名确认。执行的就是打印出来的那条命令,菜单本身不做任何生命周期动作。
  • codex 节点选中后交给 codex 专属操作(登录、接着聊、复制等),与 anet node codex 相同,见 Codex 节点速查。
  • 不是终端(管道、脚本、agent 调用)时只打印节点表、一份速查和原来的用法行,退出码 0;输出不含任何 token。
  • anet node --help / anet node help 与以前一样只打印帮助。

codex 节点不想记命令:在节点目录里敲 anet node codex,选节点、选操作,执行前会打印等价命令并确认。速查表见 Codex 节点速查:我想……就敲……。

命令作用
anet node create <name>创建节点;未指定 runtime 时进入向导
anet node start <name>在当前终端启动节点
anet node start <name> --tmux在 tmux 中启动或连接节点
anet node stop <name>停止节点及其同名 tmux session
anet node restart <name>停止后重新启动单个节点
anet node resume <name> [--session <id>]请求恢复保存或指定的会话;能否恢复取决于 runtime,下方说明 V1 共存限制
anet node delete <name> --force删除本地节点配置,并删掉它在 Hub 上的那一行
anet node rename <ref> <new>重命名已在 Hub 注册的节点
anet node clone <src> <new>复制节点设置,生成一个新身份的节点(见下文「复制节点」)
anet node edit <ref> [--runtime <id>] [--model <id>]改已存在节点的 runtime / 模型;要重启才生效
anet node ls列出本地节点及网络状态
anet node ls --all [--network <id|name>] [--json]列出 Hub 上当前 Network 里你能看到的全部节点,按机器(hostname)分组(只读,见下文)
anet node <start|stop|restart> <alias> --remote启动 / 停止 / 重启另一台机器上的节点:start / stop 由那台机器的 daemon 去做,restart 直接发给节点自己(见下文「远程管理节点」)
anet node edit <alias> --model <id> --remote给另一台机器上的节点换模型(不需要 daemon)
anet info <name>显示节点配置、进程和近期任务
anet logs <name> [--follow]查看或追踪节点日志
anet node migrate-token-to-envref <name>将配置中的明文 secret 改为 envRef,并先生成备份

OpenCode V1 共存恢复需要该节点的有效历史快照。 旧 CLI 2.3.0-preview.171 / runtime 2.5.0-preview.137 不恢复旧 session。新配对候选 CLI 2.3.0-preview.172 / runtime 2.5.0-preview.138 支持在新的运行数据目录 导入节点私有快照并核对原 session/history;导入失败不静默新建。没有快照的 旧节点仍会新建会话,不能直接重启试探恢复:首次升级前需要按手册在原桥 运行且任务/TUI空闲的窗口导出。崩溃恢复只保证最近成功保存的快照;外部 文件引用暂不支持迁移。候选通过 main 正式发布门前不是可下载版本。 完整边界见仓库运行手册 V1 重启与软件升级。

anet node ls --all 不看当前目录,而是用你 anet login 的身份读 Hub(/api/status + /api/host-supervisors), 把当前 Network(或 --network <id|name> 指定的那个,按 id、名字或唯一 id 前缀匹配)里的节点按机器分组列出: 别名、runtime、状态与最后心跳、模型,以及那台机器上有没有在线的 daemon(anet daemon,有在线 daemon 的机器以后才能被远程管理)。

text
Network: team (net_0123456) — 3 node(s) on 2 machine(s)

  host-alpha   daemon: alpha-daemon online — remote-manageable
    ALIAS     RUNTIME           STATUS   LAST SEEN  MODEL
    a-coder   claude-agent-sdk  idle     12s ago    claude-sonnet-4-5
    a-writer  codex-app-server  working  1m ago     gpt-5

  host-beta   daemon: none visible
    ALIAS     RUNTIME           STATUS   LAST SEEN  MODEL
    b-runner  grok-build-cli    offline  3d ago     -
  • 权限完全按 Hub 返回的来:被限制了 Agent 访问的成员只看到授权给他的节点;Hub 对这类成员不返回 daemon, 所以显示 daemon: none visible(「没看到」,不等于「没有」)。
  • 只用登录令牌(~/.anet/config.json 的 token),不用 COMMHUB_TOKEN 或任何节点令牌。
  • --json 输出 { network, daemons_readable, machines: [{ hostname, daemon, daemons, nodes }] }。
  • 不加 --all 时 anet node ls 行为不变。

远程管理节点(--remote) ​

在任何一台登录了 anet login 的机器上,管理住在另一台机器上的节点(#562):

bash
anet node stop    coder-b --remote             # 先显示节点在哪台机器、daemon 是否在线,再问 y/N
anet node start   coder-b --remote --yes       # 脚本里用 --yes 跳过确认
anet node restart coder-b --remote --wait 90   # 等结果最多 90 秒(默认 60,--wait 0 不等)
anet node edit    coder-b --model m2 --remote  # 换模型(节点会重启一次来生效)
text
Node coder-b — on machine-b, daemon daemon-b online; hub state: active / idle

Will run 将执行:
  anet node stop coder-b --remote --network net_271eb4d9e48c --yes
  (ask the hub to have daemon daemon-b on machine-b stop "coder-b" (its config is kept; start it again with --remote))
Run it? 执行? [y/N]: y
Dispatched (stop_node sr_c6dd58d6e565).
Waiting up to 60s for the hub to show the result …
✓ "coder-b" is stopped on machine-b
  • 走的是 Hub 上已有的生命周期工具(和 app 一样):start / stop 由那台机器的 daemon(anet daemon)执行; restart / 换模型由 Hub 直接发给节点自己,节点处理完当前回合后退出(退出码 75),由它自己的 anet node start 外壳重新拉起—— 不管这个外壳是 daemon 起的还是人手工起的。
  • start / stop 的前提:节点所在机器上有在线的 daemon,且节点是由这个 daemon 创建的(app「新建节点」选那台机器)。 否则在派发之前就拒绝并说明原因,例如 this machine can't be managed remotely: no daemon online on machine-c; 手工 anet node start 起的节点要在它自己的机器上 start / stop。
  • restart / 换模型(#570)不需要 daemon,手工起的节点也可以。前提是节点正在运行,并且上报了 config_update_capable(即它跑在 anet node start 外壳下,退出 75 会被重新拉起)。不满足就在派发前拒绝: "<alias>" can't be restarted remotely: it doesn't support config updates (started without `anet node start`?); restart it on its machine ——例如用 pm2 / systemd 直接跑的 agent-node,退出后不会有人拉起它。确认时会写明做法,例如 ask "hand-b" on machine-b itself, through the hub, to restart (it's not managed by a daemon)。
  • 重启 / 换模型的结果以 Hub 为准:节点重新上报(配置版本前进、心跳更新、不是离线)才算成功;超时时如实说明最后看到的状态 (已离线一直没回来 → 去那台机器上看;仍在 working → 当前回合结束后才会重启)。
  • 权限完全由 Hub 判:viewer 会看到 Hub 的 permission_denied;被限制 Agent 访问的成员看不到 daemon、也读不到节点配置, start / stop / restart / 换模型都在派发前就被拒绝并说明原因,节点不受影响。
  • 只用登录令牌(~/.anet/config.json 的 token),不用 COMMHUB_TOKEN;保存的若是节点令牌则拒绝。
  • 不在终端里(脚本 / 管道)且没带 --yes:什么都不做,退出码 1。超时会如实说「请求已被 Hub 接受但还没看到结果」,用 anet node ls --all 查看。
  • --network <id|name> 选别的 Network;本地专用的参数(--tmux、--copresence 等)和 --remote 一起用会被拒绝(退出码 2)。 stop --force 用于节点还有进行中的任务时强停(Hub 记审计)。远程删除不在这一步的范围内。

anet node delete <name> --force 先做一遍和 anet node stop 相同的停止(共存节点的 tmux 会话也一起停: codex 共存按标记 + CODEX_HOME 认,其余只认完整会话名、不按前缀),再删本地(.anet/nodes/<id>/),最后删 Hub 上这个节点的那一行, 这样它不会在 app / dashboard 里一直显示「离线」。停不干净就报错退出,什么都不删。

  • 节点不在当前目录(clone / codex fork 用了 --workdir)时,anet 按源目录 .anet/child-workdirs.json 和 codex 登录索引找到它, 不替你删,而是打印 cd <目录> && anet node delete <name>,退出码 1。

  • 同名的节点有好几个时拒绝删除,列出每一个按 node_id 删的命令。

  • Hub 上的行只按本地配置里的 node_id 匹配,从不按名字。别的机器上同名的节点(名字复用) 不会被删;anet 会打印 Left untouched: … belong to other node_id(s)。

  • Hub 连不上或拒绝时,本地照样删掉,anet 打印警告和原样可用的重试命令,退出码 1:

    bash
    anet node delete <node_id> --hub-only            # 只删 Hub 上那一行
    anet node delete <node_id> --hub-only --hub <url> # 节点用的不是当前登录的 Hub 时
  • 没配置 Hub 时只删本地,退出码 0。很早的节点配置里没有 node_id,那时 Hub 上的行无法安全匹配, anet 不碰它并提示到 app / dashboard 里删。

node delete 不会自动撤销该节点已签发的 ntok_;需要彻底失效时另行执行 anet token revoke <token-id>。

anet node stop 只发 SIGTERM,最多等 8 秒,不会升级到 SIGKILL(它没有 --force)。 节点在 8 秒内没退出时,anet 打印 pid <n> survived SIGTERM、保留 pidfile、退出码 1 —— 它宁可报错也不谎称已停,因为一个还活着的旧进程会继续心跳并把 rename 顶回去。 同样的原因,node restart 和 node delete 这时也会拒绝执行。 唯一会主动发 SIGKILL 的是 anet node rename --force。

COMMHUB_TOKEN 不是 CLI 参数,也不存在 anet node start --token。节点鉴权按节点配置、全局配置、legacy COMMHUB_TOKEN 环境变量的顺序取值;anet login --token 登录的是 CLI 用户,不是向 node start 临时注入节点 token。

创建节点时常用参数:

参数说明
--runtime <runtime>指定 runtime;可用值以当前频道的创建向导和 Runtime 对比 为准
--model <id>覆盖 runtime 默认模型
--resume <id>claude-code-cli:绑定指定 Claude Code session
--resume-latestclaude-code-cli:绑定当前项目最近的 session
--tools <list>为支持该选项的 runtime 配置工具集

anet session ls 可列出当前目录下的 Claude Code sessions。不同 runtime 的会话语义不同,不要把 Claude session ID 当作 Codex thread ID 使用。

复制节点 ​

完整说明(clone 与 fork 的对照、复制项清单、codex 登录、怎么删干净)见 复制节点(clone / fork)与清理。

想要「再来一个和它一样的节点」,用:

bash
anet node clone <源节点> <新名字>
# 等价写法
anet node create <新名字> --from <源节点>

新节点会在 Hub 上重新注册(和 anet node create 走同一个接口),拿到自己的 node_id 和 ntok_; 不加 --start 不会启动。完成后会打印一张表,逐项列出 copied / regenerated / skipped。

类别内容
复制runtime、模型、工具、权限 flags、system prompt、非机密 env、commhub channel;--workdir 时还有规则文件(CLAUDE.md / AGENTS.md)、skills 目录、.mcp.json(其中 env / header 的值清空);codex 节点的 codex-home/config.toml、AGENTS.md、skills/
重新生成node_id、别名、ntok_、claude-code-cli 的 session id、grok 共存 socket、codexProjectDir
不复制token、所有 session / thread id、日志、pid / 锁、goals、inbox、channel 的 bot 凭据、codex auth.json、共存身份文件、机密 env 的值(只保留键名,改成指向新节点的 envRef,启动前自己填)
参数说明
--workdir <dir>放到另一个项目目录(不存在会创建);路径必须是英文 / ASCII(节点名可以是中文,目录不行)。不加时和源节点在同一个项目目录,规则文件和 skills 共用
--model <id>换一个模型
--start建完立即启动(有待填的机密时不启动,并提示先填)

会拒绝:目标已存在、新名字和源节点同名、目标落在源节点自己的目录里、非 ASCII 的 --workdir、 opencode-cli 节点(运行时绑定和登录在节点配置之外,请用 anet node create --runtime opencode-cli 新建)、 host daemon(role=host_supervisor)。

codex 节点的登录不会被复制。一个登录只给一个节点(refresh token 一次性,共用会互相顶掉): 启动前先给新节点自己登录 CODEX_HOME=<新节点目录>/codex-home codex login --device-auth。 没登录就启动时,anet 会把本机 ~/.codex 的登录放进去——但如果本机已有别的节点在用这份登录, 就拒绝启动(exit 1,--allow-shared-codex-login 可强行共享,不安全;见 一个登录只给一个节点)。要用登记过的账号,用 anet node codex account install <新名字> --source codex-login:<profile-id>。 要连 codex 会话历史一起带走,用 anet node codex fork(见 Codex 共存)。 在 anet 之外直接用 codex 开过的对话,用 anet node codex adopt <新名字> --thread <id> 收编成节点(见 复制节点)。

不要 cp -r 节点目录

.anet/nodes/<name>/config.json 里存着节点的 node_id 和 ntok_。原样拷贝出来的「新节点」 和源节点是同一个 Hub 身份:两个进程都订阅同一个收件箱,同一个任务会被执行两次、回两次复, 而且 Dashboard 分不清是谁在回。日志、session、codex 登录也一起被共用。复制节点请一律用 anet node clone。

项目批量管理 ​

这些命令扫描当前目录的 .anet/nodes/:

命令作用
anet project up启动所有未运行节点
anet project restart重启所有节点
anet project down停止所有节点并上报离线

共享参数:

  • --stagger <seconds>:节点间错峰,默认 3 秒,0 表示关闭。
  • --only a,b:只处理列出的 alias 或 node ID。
  • --exclude x,y:跳过列出的 alias 或 node ID。

批量创建和清理见 批量 Agent。

Channel ​

命令作用
anet channel add telegram <node> --bot-token <token> --allow <uid>添加 Telegram
anet channel add feishu <node> ...添加飞书;当前为 preview 能力
anet channel allow feishu <node> ...修改飞书私聊或群聊白名单
anet channel ls [node]列出 Channel
anet channel status [node]显示 Telegram 实际配置路径和白名单

Channel 配置不会热加载,修改后需要重启节点。anet channel add wechat 尚未发布。完整命令见 Channel 接入。

Goal ​

命令作用
anet goal list [node]列出本地 goal
anet goal show <node> <id>查看详情与进度记录
anet goal wake-log <node> <id> [--tail N] [--json]导出完整 wake 历史
anet goal edit <node> <id> ...修改 interval、文本或状态
anet goal cancel <node> <id>标记为 cancelled
anet node loop <node> "<task>" [--every 5m]向在线节点创建周期任务,并等待最多 15 秒确认

node loop 通过 Hub 投递 /aloop;goal edit/cancel 则直接修改 .anet/nodes/<node>/goals.json。运行中的节点不会自动重载外部文件修改,使用 edit/cancel 后请重启节点。Dashboard 原生 /goal、/loop 与 ANet /aloop、/agoal 的语义、状态和自管理工具见 Goal 与 Loop。

诊断与维护 ​

命令作用
anet status显示当前 Network 的节点和任务概览
anet tasks [status] [--limit <n>]查询任务
anet doctor检查配置、Hub、依赖、secret 与 Channel
anet doctor --fix执行兼容迁移并修复可自动恢复的 token 问题;会修改配置
`anet upgrade [--channel latestpreview] [--dry-run]`
anet config / anet config path / anet config json查看全局配置摘要、路径或 JSON(token 打码)
anet init配置 Hub URL;换到另一个 Hub 时,先在旧 Hub 上撤销保存的登录会话(尽力而为,失败只警告),再从配置里删掉旧 Hub 的 token 与登录信息——旧 token 不会发给新 Hub。之后重新 anet login。anet login --hub <另一个 Hub> 同样处理
anet init project在当前目录创建 CommHub MCP 项目配置
anet setup安装所选 runtime 的依赖

升级细节见 升级指南。

anet status 的四个数字怎么读 ​

  CommHub: http://127.0.0.1:9200
  Agents: 127 idle, 0 working, 1 needs attention, 143 offline
          └─ 18 掉线 1-3 天, 27 掉线超过 3 天
  SSE:    12 connected
  Tasks:  10 recent
数字含义
idle空闲,等派活
working正在推进一个回合(含 waiting_input —— 回合还在,只是在等人)
needs attention需要人看一眼:blocked / error,以及任何本版本不认识的状态
offline心跳过期,或已正常停止

四个数相加等于节点总数。needs attention 为 0 时那一格不显示。

offline 下面那一行:它掉了多久 ​

有 offline 节点时会多印一行分档。**「刚停的」和「掉了三天没人发现的」原先是 同一个数字。**实测过一次(84 台节点):45 台 offline 里 27 台超过 3 天、 18 台 1-3 天、近 6 小时内 0 台 —— 「当前没有活故障」和「有 45 台掉了」 是完全不同的两个结论,而屏幕上原本只有后者。

拿不到时间戳的节点单独归入「无时间戳(不知道掉了多久)」,不并进最新那一档 —— 「我不知道它掉了多久」和「它刚掉」是两件事。

🔴 blocked 没有对应的时长,而且不该有。 名册里没有「何时变成 blocked」 这个字段;updated_at 被心跳一直刷,拿它当已 blocked 时长,会给一个卡了很久的 节点印出「4 分钟前」—— 比不显示更糟。详见 这个节点还活着吗。

🔴 blocked / error 不算在 working 里。 它们的含义是「卡住了」而不是 「在干活」—— 一个卡住的节点如果被算进 working,运维看到「N working」会以为 一切正常。needs attention 大于 0 时,下面会列出是哪几个节点、它们自报的状态、 以及当时的任务。

⚠️ 这些状态是 agent 自报的,不含活性成分。 一个进程已经死掉但还没被心跳 清扫的节点,在这里仍可能显示成 idle。要确认它还在不在,发一条任务试试 —— anet status 回答的是「它上次说自己怎么样」,不是「它现在还在不在」。

手工节点收编(预览源码,board #626) ​

Linux daemon 配置 adopt_roots 为允许收编的工作目录绝对路径列表,默认空列表拒绝收编。 配置修改后由操作员按既有 daemon 启动流程加载;不要把根目录或整个 HOME 当作节点工作目录。 使用自己的 anet login 人类账号,在手工节点的工作目录运行:

bash
anet daemon adopt demo --daemon <daemon-node-id>
anet daemon adopt demo --daemon <daemon-node-id> --yes
anet daemon adopt --all --daemon <daemon-node-id> --yes
anet daemon unadopt demo --yes

不带 --yes 只展示计划。--all 仅枚举当前目录 .anet/nodes,不扫描机器其它目录。 请求成功只代表 pending,不代表收编成功;daemon 独立检查 UID、路径、配置身份、 /proc、HOME 和可重建环境,再原子登记并确认。收编及撤销都不重启、不发进程信号。 仅支持 bare / 默认 tmux socket;co-presence 或无法重建的环境会拒绝,错误只列环境键名。 从 daemon 工作目录运行 anet daemon adopted,列出同时具有本机登记和 Hub 有效绑定的节点。

adopt_path_writable_by_others:工作目录、.anet、.anet/nodes、节点目录或 config.json 对组 / 其他用户可写。修法是对报出的路径 chmod go-w。共享团队目录(如 2775)不想去掉组写时, 仅工作目录本身可改为加粘滞位:目录属 daemon 用户且 chmod +t <workdir>(如 drwxrwsr-t)也被接受, 因为粘滞位下其他用户无法改名或删除其中属 daemon 的 .anet;.anet 及以下仍必须 go-w。

此增量只完成收编协议,收编节点的远程停启需后续 board #627;当前会明确拒绝, 不会落入旧 daemon 子进程清理路径。登记文件是 daemon 工作目录下 .anet/child-workdirs.json,节点配置及密钥仍在原目录。空机恢复需恢复这些私有文件和 Hub 数据备份;只 clone 仓库不会恢复绑定、账号或密钥。撤销绑定不删除工作目录。

Preview 专属能力 ​

开发中、尚未发布(#1053):Daemon/节点环境密钥管理不再只依赖演示表单。 客户端经 daemon_provider_snapshot 的 secret_* 管理动作发起 owner/admin 请求,所属 Daemon 用 anet daemon secret <daemon> 低层适配器读取私有 JSON stdin,回读只有名称/来源。 该适配器不接受命令行密钥值,也不启动或重启节点。Daemon 默认值由节点继承, 节点同名值优先;已有显式进程/config/Provider 配置保持优先。 值在节点下次完整启动时加载,单独重启 Bridge 不等于原生 TUI/server 已更新。 完整契约与恢复边界见仓库 docs/scoped-secrets.md;0.2.248 演示入口不能计为已支持。

以下能力存在于当前 preview,不应写成 stable 已支持:

命令作用
anet daemon up [name]创建并启动 host_supervisor(版本要求见 哪些版本有 anet daemon)
anet daemon init <name> / start <name> / restart <name> / list管理本机 daemon(版本要求同上;restart 另见 daemon 页)
anet node start <name> --copresence启动 Codex app-server、桥和共享 TUI
anet opencode ...管理 OpenCode preview 集成

OpenCode V2 共享 Server:创建时的复用与逃生门 ​

创建 opencode-cli V2 节点时,除代际与 unsafe 授权外,还有三个与「主机共享 Server」相关的源码选项;对应版本须实际发布后才可使用。细节、凭据与迁移边界见运行手册:

开关作用
--opencode-shared-server-url <字面量 http://127.0.0.1:<port>>显式指定复用哪个 loopback Server(与下面那项必须成对)
--opencode-shared-server-password-file <绝对路径>该 Server 的私有密码文件路径;文件须为私有普通文件,密码值不得写进命令行/URL/日志
--opencode-new-server显式让新节点自建 Server,不用共享;可与 clientBinDir 并用,但不会继承共享 URL/密码文件

主机用户也可以在私有 ~/.anet/opencode-shared-server.json 里登记 { "url": ..., "passwordFile": ..., "clientBinDir": ... },此后新建 V2 节点默认复用它。

源码状态(daemon 创建准入,父 #1302 / #1326):登记是操作者维护的候选登记——它只提供连接候选,不提供进程身份或代际证明。daemon 创建 V2 节点时按「观察 → 代际绑定 → 准入通过」三步判定,三步都过才复用:进程观察(同 uid、真实 pid/startTicks、监听绑定复核)→ 与既有包/文件 attestation 绑定代际 → 准入放行;任何一步拒绝(登记陈旧、进程已死、他人 uid、无法完整观察、代际不可证)都回退为节点自有 Server,不写共享 URL/密码文件。--opencode-new-server 的显式逃生门仍然有效。上述均为源码实现:不代表 npm 已发布或现役 daemon 已采用(完整原生启动验收已于 PR #2790 通过:exact-head 收据 = Actions run 38809788212 / job 116679815373,产物 source=506902c4…,合并提交 079daa31);CLI 直接创建/显式连接须单独核对,不能用 daemon 接线代替其验收;命令可用性以本机 anet -v、anet node create --help 与对应发布说明为准。

开发中、尚未发布(#906):anet daemon provider list <daemon> 回读该 daemon 的脱敏 Provider → Runtime → 认证方式 → 模型配置;anet daemon provider put <daemon> --revision N 从 stdin 保存私有 JSON,key 不接受命令行参数。配置成功不等于登录、模型请求或节点切换成功。 源码已接入受权限保护的配置保存/回读;anet daemon provider scan <daemon> 从 stdin 读取 Hub 归属清单(node_id/alias),只读扫描已有 Codex 配置与脱敏认证信息。客户端在同一管理页展示, 扫描不复制登录文件、不改节点、不触发模型调用;账号/节点实际切换仍在接入,不代表现有安装包已有此能力。

🔴 停 / 删 / 看没有 daemon 版。 daemon 就是一个 role=host_supervisor 的 agent-node, 所以用 node 级命令:anet node stop <name> 停、anet node delete <name> 删、 anet node ls 看它在不在跑(anet daemon list 只列本机配置过的 daemon,不含活性)。 anet daemon restart 内部调的正是 anet node stop 用的那个 stop。

daemon 的两个反直觉之处

① 对已存在的 daemon,anet daemon init <name> 什么都不改。 它打印 ✓ "<name>" already a host_supervisor daemon 后直接返回 —— 一个绿色的对勾, 配置一个字节没动。要改配置必须带 --force(保留 node_id,但会重新签发 token,且改完要重启该 daemon 才生效)。

② 配置里的 runtime 清单是写入那一刻的快照,不会自愈。 之后新增的 runtime 不会补进已有 daemon 的配置,表现为客户端「选服务器」里那台机器可选的 runtime 比别人少。anet daemon list 发现这种情况时会直接打出缺哪几个和回填命令。

Codex 的 --copresence 用于 runtime=codex-app-server。其默认沙箱为只读;开启完整文件系统和网络访问需要 --dangerously-allow-full-access。TTY 会要求输入 yes,非 TTY 还必须同时提供 --yes-danger-full-access。

恢复共存节点时仍应使用 anet node start <name> --copresence,不能改用普通 node start。

opencode-cli 的 V2 TUI 共存与共享 Server 是上文说明的独立预览路径,要求显式 unsafe 授权;不能套用 Codex 的只读沙箱说明,发布状态须按实际版本核对。grok-build-cli 共享 Grok TUI 也未进入当前 preview 包;当前可用的 grok-build-acp 不支持 attach。

其他命令 ​

命令作用
anet import [alias]从 Hub 导入可恢复的本地节点配置
anet run --alias <name>启动不调用 LLM 的最小 SSE echo agent
anet demo [name]运行实验性演示;不作为生产编排方案
anet batch <verb>管理 anet create --batch 创建的批次
anet license / anet activate <key>legacy 许可证兼容命令;Apache-2.0 用户通常无需使用

旧别名 anet create、anet start 等仍为兼容保留,新文档统一使用 anet node ...。

退出码 ​

退出码含义
0成功;或只打印帮助(例如不带子命令的 anet node、anet network,或任何命令 / 子命令加 --help、-h)
1失败:未初始化 / 未登录 / 登录已过期、Hub 连不上或返回错误、找不到对象、本地写入失败、拒绝执行
2用法错误:缺少必需参数、未知子命令、非法取值

脚本和 CI 可以直接用 anet … || exit 1 判断。下列情况在 #515 之前打印了错误却退出 0,现已改为非零:

命令情况之前 → 现在
anet whoami未登录 / 登录已过期 / Hub 连不上0 → 1
anet network <ls|use|info|create|delete|rename|invite|join|members>未 init / 未登录、Hub 返回错误、找不到 Network、连不上0 → 1
anet network create|use|delete|rename|join(缺参数)、anet network <未知子命令>用法错误0 → 2
anet token ls|create|revoke未登录、Hub 返回错误、连不上0 → 1
anet token revoke(缺 token id)用法错误0 → 2
anet passwd未登录、两次密码不一致、Hub 拒绝、连不上0 → 1
anet activate未 init、激活失败、连不上 / 缺 license key0 → 1 / 0 → 2
anet status、anet tasks没有配置 Hub;anet tasks 连不上0 → 1
anet hub startHub 15 秒内没起来(含缺 Bun)0 → 1
anet hub stop见上方 停止 Hub0 → 1 / 2
anet hub admin reset-user缺 --username / 找不到 DB、重置失败0 → 2 / 0 → 1
anet hub <未知子命令>、anet node <未知子命令>、anet session <未知子命令>、anet batch <未知动词>用法错误0 → 2
anet node resume(缺节点名)、anet logs(缺节点名)、anet batch <动词>(缺前缀)用法错误0 → 2
anet project down(有节点停失败)、anet node delete(节点进程拒绝退出)已经设置了退出码 1,但被 CLI 收尾的 process.exit(0) 覆盖0 → 1
anet upgrade有包升级失败或查不到 registry0 → 1
anet node delete --force本地已删,但 Hub 上那一行没删掉(连不上 / 被拒);会打印 --hub-only 重试命令新行为:1
anet create --batch、anet batch cleanup缺 Hub、预设/参数非法、自动登录失败、一个节点都没建成0 → 1 / 2
anet demo …缺 Hub / token / key、建 Network 或节点失败0 → 1

一些较早的用法错误路径仍退出 1(同样是非零,脚本照样能判断),没有为了统一成 2 而改动。anet hub status 是状态查询,Hub 没运行时仍退出 0。

报错与密钥 ​

  • 出错时 anet 打印一句说明和下一步要敲的命令,不打印堆栈。要看堆栈:ANET_DEBUG=1 anet …。
  • 以错误码为消息的致命错误仍是 [anet] FATAL: Error: <CODE> 这一行,方便脚本从日志里取码。
  • anet 不在输出里打印完整密钥:anet config、anet config json、anet node start、anet doctor 显示的 token 都是 utok_…ab12 这种「前缀…末 4 位」;报错里出现的 token、Bearer 头和 URL 里的 token= 参数同样打码。
  • anet node create --env KEY=… 和 anet node migrate-token-to-envref 把密钥写进 .anet/nodes/<node>/.env(权限 600、已加入 gitignore),只打印打码后的值和一条从该文件读取的 export 命令。
  • 例外:anet token create 和 anet hub admin reset-user 的用途就是发出新凭据,只显示这一次。

配置位置与环境变量 ​

路径内容
~/.anet/config.json当前 Hub、用户 token 和 Network
.anet/nodes/<node>/config.json节点配置
~/.commhub/commhub.db默认 Hub SQLite 数据库
~/.anet/server/admin-utok.jsonHub 主机的本地管理员恢复 token

常见环境变量:

变量作用
COMMHUB_URLHub URL
COMMHUB_ALIAS节点 alias
COMMHUB_TOKEN认证 token;节点配置中的 token 优先级更高
COMMHUB_AUTH_TOKENlegacy Hub master-token 兼容入口;新部署使用用户和节点 token
ANET_CODEX_RESUME_TIMEOUT_MSanet node start --copresence 恢复 Codex 会话的超时(整数毫秒,最大 900000);未设置时从 300 秒起,按 rollout 每开始 1 GiB 增加 120 秒,最高 15 分钟;超时会报告实际等待时间和 rollout 大小

Codex 共存启动会在旧进程停止后先创建私有恢复点;备份失败时默认拒绝启动,并清掉半成品。只有操作员明确接受无法安全回滚时,才可使用 --skip-recovery-backup 跳过;命令会打印醒目的风险警告,且不会把旧恢复点冒充成这次启动的新备份。 | ANTHROPIC_BASE_URL | Anthropic 兼容模型端点 | | ANTHROPIC_AUTH_TOKEN | 第三方 Anthropic 兼容端点凭据 | | ANTHROPIC_API_KEY | Anthropic 官方端点凭据 |

Secret 建议使用 envRef,不要把 token 或模型密钥直接提交到配置仓库。详见 安全设计。

延伸阅读 ​

Powered by Sleep2AGI

下载客户端