arc service 管理具名 AFS 后台实例。arc afs、MCP 桥接、以及 blocklet 服务,都依赖一个正在运行的实例。
对照版本:arc 2.0.0-beta.48,commit 5a5316bde(main,2026-09-10)——不是发布出去的那个同版本号二进制;同一个 2.0.0-beta.48 曾同时对应两份不同的构建,所以本页钉的是 commit,不是 semver。arc service 现在是九个真子命令(arc service <verb> [options]),每个都有自己的 --help 和 Examples: 块——不再是一条命令带一个positional action choice 列表。--json 拒绝路径在 ArcBlock/arc#5205 之后重测过(error 对象在 stdout——下面 --json 契约 再次纠正这一点);delete 在 ArcBlock/arc#5279 之后成为主动词名(rm/remove 现在是 alias);子命令化和每条失败行统一的 ERROR: 前缀都来自 ArcBlock/arc#6301。实例名 positional 在 ArcBlock/arc#5713 退役:指定实例的唯一写法是 --instance / -i。复制 dump 前先跑 arc --version;动词和 flag 仍可能变。下面的 --help 是英文(LC_ALL=C)——ArcBlock/arc#5244 之后,帮助/报错文本永远是英文,不随你系统的 locale 变化。
下面的实例名、home 路径和端口都简化成易读的 docs514a / /tmp/arc-svc-docs-514/... 形式;报错文本、字段名、退出码和 JSON 结构都是真实跑出来的原样。
arc service <verb> [options]verb 是下面之一:list(ls、ps)、start、stop、restart、status、delete(rm、remove)、gc(prune)、url、logs(log)。用 --instance <name> / -i 指定实例。省略 --instance 即种子实例 default(home ~,端口 4900)。其它名字由内核分配端口,除非你传 --port。
不要 stop / delete 你没启动的种子实例。本页 dump 用的是一次性 registry,没有碰本机 :4900 上的 default。
隔离
隔离靠具名实例加 --home。ARC_HOME 已退役:CLI 会警告并忽略取值。
export ARC_INSTANCES_DIR=/tmp/arc-svc-docs-514/instances
arc service start --instance docs514b --home /tmp/arc-svc-docs-514/home-bARC_SERVICE_PORT 仍在,但只作用于未具名的种子实例。优先用名字,或传 --port。
下面 dump 省略了 stderr 上的 splash banner。
子命令
每个子命令都有自己的 --help 和自己的 Examples:(见本页底部的 --help 一节)。arc service <坏动词> 和不带动词的 arc service 都打印下面这张组级列表,不是某个动词自己的。
| 子命令 | Alias | 作用 |
|---|---|---|
list | ls、ps | 列出每个本地实例的状态、端口和 home |
start | 启动一个实例;首次用即创建 | |
stop | 停下正在跑的实例,保留记录和数据 | |
restart | 按记录重启实例——不接受重新配置;要改配置用 stop 再 start | |
status | 报告一个实例是否在跑,以及跑在哪个端口 | |
delete | rm、remove | 删除一个实例:它的记录和数据 |
gc | prune | 清掉进程已经不在了的注册记录 |
url | 打印实例的 base URL(以及它的 blocklet URL) | |
logs | log | 打印实例的 daemon 日志 |
Flags
每个子命令都接受共享的全局 flag——--json、--view、--home、--instance / -i、--print——外加它自己的额外 flag:
| Flag | 子命令 | 含义 |
|---|---|---|
-i、--instance | 全部 | 这条命令作用在哪个本地 ARC 实例。省略即 default。指定实例的唯一写法 |
--home | 全部 | 实例根。用于 start(创建)、arc did init。在 restart 上它是拿来跟记录里的 home 做一致性核对的,不是新配置——一致就是 no-op,指向别的路径会被拒绝(见 失败路径) |
--print | 全部 | 把结果里的单个字段(例如 url、port)以纯文本打印——不是一种 view,会覆盖 --json/--view。见下面的 --print |
--port | start | 监听端口(0–65535)。0 = 自动分配。省略时:default 用 4900,具名实例用记录里的端口或自动分配 |
--host | start | 绑定地址(localhost、0.0.0.0、:: 或单播 IP)。默认 localhost |
--advertise | start | 绑定非 loopback 时通过 mDNS 宣告(默认 true;--no-advertise 关闭) |
--blocklet | start | 要服务的 blocklet 父目录或单个 blocklet 目录(可重复)。记在实例上 |
--space-root | start | 用 arc space init 建好的 Folder-as-DID-Space。省略则从 --home 派生 |
--force | delete | 先停再删。默认 false |
--dry-run | delete | 打印会删掉什么,不实际删除。默认 false |
--yes | delete | 跳过 TTY 确认提示。默认 false |
--follow | logs | 流式输出新写入的行。默认 false |
--yaml 已删除,从未真正实现——见 总览。
restart 自己的 --help 里没有 start 那组配置 flag——传了会被一条专门的报错拒绝,不是 yargs 通用的「unknown argument」(那条通用路径是真正被删除的 flag,比如 --blocklet-dir,才会撞上的;见已删除与已退役):
$ arc service restart --instance docs514a --port 4910
ERROR: restart does not reconfigure. use `stop` then `start` to change --port--home 是唯一的例外:它是全局 flag,所以 restart --home <和记录一致的路径> 会静默成功(no-op),只有指向不同路径才会被拒绝——报错和退出码都跟上面的配置 flag 守卫不一样:
$ arc service restart --instance docs514a --home /tmp/somewhere-else
ERROR: --instance "docs514a" and --home "/tmp/somewhere-else" name different instances (instance "docs514a" is registered at "/tmp/arc-svc-docs-514/home-a")(退出码 5,而 --port/--host/--advertise/--space-root/--blocklet 是 1。)
状态
| 状态 | 含义 |
|---|---|
starting | 记录已占用,进程还没到 up |
up | 进程在听端口 |
stopped | 经 stop 退出。start / restart 会复用这条记录 |
dead | 进程没经过干净 stop 就没了。gc 只清这种 |
list 对每个非 up 的行都显示记录里的端口,并加 * 后缀标注这是最后已知值而非实时值(stopped/dead 都会加);只有完全没有记录过端口时(一个从没到过 up 的实例)才显示 -:
NAME ID PORT STATUS HOME SOURCES
docs514a b719db414c5cc62 61497* stopped /tmp/arc-svc-docs-514/home-a 1status 的退出码:up 是 0,starting / stopped 是 3,dead 是 4。非 up 时它照样报上一次的 pid / port / URL,并明确标注(--json 里是 lastKnown,人类视图里是一行 Note:)。
Start、list、status、url
空 registry:
$ export ARC_INSTANCES_DIR=/tmp/arc-svc-docs-514/instances
$ arc service list
NAME ID PORT STATUS HOME SOURCES
(no instances)启动一个具名实例。端口 61497 是内核分配的,不是 4900:
$ arc service start --instance docs514a --home /tmp/arc-svc-docs-514/home-a
Instance: docs514a
ID: b719db414c5cc624
Status: up
PID: 95665
Port: 61497
URL: http://127.0.0.1:61497
Home: /tmp/arc-svc-docs-514/home-a
Space: /tmp/arc-svc-docs-514/home-a/.afs/spaces
Sources: -
Version: 2.0.0-beta.48
Commit: 5a5316bde
Checkout: /tmp/arc-svc-docs-514/project
Host: localhost
Started: 2026-09-10T01:52:25.130Z (up 2s)进度、日志路径、build id、endpoints 走 stderr。实例记录走 stdout——这次捕获的 stderr(banner 已省略):
Starting AFS service...
AFS Service started
Log: /tmp/arc-svc-docs-514/home-a/.afs/daemon.log
Build: 2.0.0-beta.48+5a5316bde (debug)
Exec: /path/to/arc/runtimes/node/dist/cli.mjs
Endpoints:
http://127.0.0.1:61497/ AUP Web Client
http://127.0.0.1:61497/explorer Explorer UI
http://127.0.0.1:61497/ws WebSocket (Explorer)
http://127.0.0.1:61497/afs/* REST API
http://127.0.0.1:61497/mcp MCP Streamable HTTPBuild / Exec 来自 daemon 启动时写的 <home>/.afs/daemon.build.json;老 daemon 没有这个 sidecar 时这两行直接不打,不猜。Version / Commit / Checkout 描述的是真正在服务这个实例的那个 binary——见下面的身份字段。
用 --blocklet 记录 blocklet 源(可重复)。同一个 flag 既接受父目录,也接受单个 blocklet 目录:
$ arc service start --instance docs514b --home /tmp/arc-svc-docs-514/home-b \
--blocklet /path/to/arc/blocklets/afs-preview-fixture --host 127.0.0.1 --no-advertise
Instance: docs514b
ID: b719db414c5cc625
Status: up
PID: 95666
Port: 61498
URL: http://127.0.0.1:61498
Home: /tmp/arc-svc-docs-514/home-b
Space: /tmp/arc-svc-docs-514/home-b/.afs/spaces
Sources: /path/to/arc/blocklets/afs-preview-fixture
Version: 2.0.0-beta.48
Commit: 5a5316bde
Checkout: /tmp/arc-svc-docs-514/project
Host: 127.0.0.1
Started: 2026-09-10T01:49:56.435Z (up 7s)这次的 stderr 在被省略的 banner 和 AFS Service started 之间多了一行 Extra blocklet dirs:,Endpoints: 之后多了一个 Blocklet: 块:
Starting AFS service...
Extra blocklet dirs: /path/to/arc/blocklets/afs-preview-fixture
AFS Service started
Log: /tmp/arc-svc-docs-514/home-b/.afs/daemon.log
Build: 2.0.0-beta.48+5a5316bde (debug)
Exec: /path/to/arc/runtimes/node/dist/cli.mjs
Endpoints:
http://127.0.0.1:61498/ AUP Web Client
http://127.0.0.1:61498/explorer Explorer UI
http://127.0.0.1:61498/ws WebSocket (Explorer)
http://127.0.0.1:61498/afs/* REST API
http://127.0.0.1:61498/mcp MCP Streamable HTTP
Blocklet: afs-preview-fixture
http://afs-preview-fixture.localhost:61498/
http://localhost:61498/?blocklet=afs-preview-fixture (Safari / universal)$ arc service list
NAME ID PORT STATUS HOME SOURCES
docs514a b719db414c5cc624 61497 up /tmp/arc-svc-docs-514/home-a 0
docs514b b719db414c5cc625 61498 up /tmp/arc-svc-docs-514/home-b 1status 报得出 start 报过的每一件事——对一个不是你刚起的实例也一样,stdout/stderr 的分法也一样:
$ arc service status --instance docs514b
Instance: docs514b
ID: b719db414c5cc625
Status: up
PID: 95666
Port: 61498
URL: http://127.0.0.1:61498
Home: /tmp/arc-svc-docs-514/home-b
Space: /tmp/arc-svc-docs-514/home-b/.afs/spaces
Sources: /path/to/arc/blocklets/afs-preview-fixture
Version: 2.0.0-beta.48
Commit: 5a5316bde
Checkout: /tmp/arc-svc-docs-514/project
Host: 127.0.0.1
Started: 2026-09-10T01:49:56.435Z (up 3m)日志路径、build id、endpoints、blocklet URL,以及(非 loopback 绑定时的)LAN 诊断走 stderr;记录走 stdout。start 和 status 对同一个实例报同一个 URL——两边都用注册表里的 http://127.0.0.1:<port> 形式。加 --json 时 stderr 的这些块不打,全部作为数据出现在 payload 里。
如果这台机器的 project root 里有很多 blocklet,status 只展开你用 --blocklet 点名的那些,其余只报个数——这是对着一个完整的 dev checkout 跑出来的真实数字,不是编的:
Blocklets: 51 route(s) served — 50 not expanded; `arc service url` or --json lists them all--json 里的 urls.blocklets 永远是全的。
$ arc service url --instance docs514b
http://127.0.0.1:61498/stderr(banner 已省略),和 start 同一套打印机:
Blocklet: afs-preview-fixture
http://afs-preview-fixture.localhost:61498/
http://localhost:61498/?blocklet=afs-preview-fixture (Safari / universal)$ arc service url --instance docs514b --print url
http://127.0.0.1:61498--print url 只把实例 URL 写到 stdout(这次捕获没有尾斜杠),退出码 0。$(arc service url --instance NAME) 仍是这一行。Agent 要 blocklet 地址用 --json 里的 Host URL(http://afs-preview-fixture.localhost:…)。?blocklet= 是 Safari 兜底,挂不上 /blocklets/<name> 的 RPC。
身份字段
Version / Commit / Branch / Sha / Checkout 描述的是服务这个实例的那个 binary,不是你敲的那个 arc。daemon 在启动时算好并写进自己的注册表行,所以在任何 shell 里 status 出来的值,和 curl http://127.0.0.1:<port>/.well-known/arc/instance 一致。
对 up 的实例,status 会直接问 daemon,答案放在 live 里:
"live": {
"ok": true,
"url": "http://127.0.0.1:61498/.well-known/arc/instance",
"record": { "version": "2.0.0-beta.48", "commit": "5a5316bde", "pid": 95666, "port": 61498, "blocklets": 1 }
}注册表行和 daemon 不一致时——arc upgrade 就是这种情况,它在进程不重启的前提下换掉 binary——两个值都报,不一致的字段列在 drift 里:
"drift": [{ "field": "version", "registry": "2.0.0-beta.48", "live": "2.0.0-beta.49" }]这个探针是尽力而为。如果进程还活着但 loopback 上一时没人应答——这条是从一个被 SIGSTOP 暂停的 daemon 上抓到的,所以措辞是超时而不是拒绝连接——status 会退回纯注册表视图并说明原因,退出码不变:
Live: unreachable (The operation was aborted due to timeout) — registry values only(进程彻底没了而不只是暂时无应答时报的是 dead——见状态——这种情况根本不做探针。)
Restart、logs、stop、delete、gc
restart 复用记录,不接受新的 --port:
$ arc service restart --instance docs514b
Instance: docs514b
ID: b719db414c5cc625
Status: up
PID: 95700
Port: 61498
URL: http://127.0.0.1:61498
Home: /tmp/arc-svc-docs-514/home-b
Space: /tmp/arc-svc-docs-514/home-b/.afs/spaces
Sources: /path/to/arc/blocklets/afs-preview-fixture
Version: 2.0.0-beta.48
Commit: 5a5316bde
Checkout: /tmp/arc-svc-docs-514/project
Host: 127.0.0.1
Started: 2026-09-10T01:58:00.472Z (up 3s)stderr 打的是 AFS Service restarted(不是 started),其它跟上面 start 的 stderr 一样。
$ arc service logs --instance docs514b
{"ts":"2026-09-10T01:58:01.683Z","level":"info","service":"arc-node","ns":"node:boot","message":"boot vault-ready +652ms"}
{"ts":"2026-09-10T01:58:01.686Z","level":"info","service":"arc-node","ns":"node:boot","message":"boot did-space-ready +656ms"}
{"ts":"2026-09-10T01:58:02.235Z","level":"info","service":"arc-node","ns":"node:boot","message":"[code-agents] recover ok: claimed=0 marked=0 orphaned=0 deferred=0 locksScanned=0 locksReclaimed=0"}后面的 boot 行省略。--follow 会先重打已有行再流式输出。
$ arc service stop --instance docs514b
Service stopped: docs514bstopped 的实例照样报上一次的 pid / port / URL,并且明说这些是历史值(退出码 3):
$ arc service status --instance docs514b
Instance: docs514b
ID: b719db414c5cc625
Status: stopped
PID: 95700
Port: 61498
URL: http://127.0.0.1:61498
Home: /tmp/arc-svc-docs-514/home-b
Space: /tmp/arc-svc-docs-514/home-b/.afs/spaces
Sources: /path/to/arc/blocklets/afs-preview-fixture
Version: 2.0.0-beta.48
Commit: 5a5316bde
Checkout: /tmp/arc-svc-docs-514/project
Host: 127.0.0.1
Started: 2026-09-10T01:58:00.472Z
Note: PID / Port / URL above are the LAST KNOWN values from this instance's previous run, not a live process.--json 里同一件事是 "lastKnown": true,并且没有 live 键——stopped 实例不做探针。list 对 PORT 打 <port>*(见状态)。同名再 start 会复用记录。
本页每个代码块都是独立的一次捕获;实例名在不同小节里重复出现(docs514a、docs514b)并不意味着一条连续的会话——下面 delete 的四个例子都用全新的一次性名字,正因为这样,它们谁都不是在删一个前面例子已经删掉的名字。
delete 现在对成功有两种输出形态,按 view 分——跟 arc afs delete 一样的分法(ArcBlock/arc#6055):默认(机器、非 TTY)视图是一句光秃秃的 OK <name>——write 的形状——--view human 是一句说清楚删了什么的话。下面两个实例在删除前都是 stopped:
$ arc service delete --instance docs514x
OK docs514x
$ arc service delete --instance docs514y --view human
Removed instance "docs514y"正在跑的实例,delete 不带 --force 会失败——这也是 ArcBlock/arc#6301 前缀修复真正体现出来的地方:本页每一条失败行现在都以 ERROR: 开头,而旧的捕获完全没有前缀:
$ arc service delete --instance docs514z
ERROR: instance "docs514z" is running. stop it first, or use --force--force 先停再删——上面那条拒绝的 accept-path 对应项,同一个实例,同一个动词:
$ arc service delete --instance docs514z --force --yes
OK docs514z--dry-run 只预览,不动手,对 stopped 或 running 的实例都能用:
$ arc service delete --instance docs514w --dry-run
Would delete instance docs514w at /tmp/arc-svc-docs-514/home-w (dry-run)
$ arc service delete --instance docs514w --dry-run --json
{
"name": "docs514w",
"removed": false,
"home": "/tmp/arc-svc-docs-514/home-w",
"dryRun": true,
"homeRemoved": true
}homeRemoved 这里的意思是「一次真正的运行会删掉这个 home 目录」,不是说已经删了——同一个对象上的 removed: false / dryRun: true 已经说明了这一点;把这三个字段放在一起读,别只看 homeRemoved。
--yes 跳过交互式 TTY 确认。实际上这在真终端之外几乎不起作用:确认本来就是只在 TTY 里才问的设计(interactive 要求 stdin 和 stdout 都是真 TTY),所以 agent、管道、测试——包括产出本页这些 dump 的那些调用——都不会看到那个提示,加不加 --yes 都一样。给一个可能有一天会在终端里跑的脚本加上它仍然是对的。
gc 只收集 dead(进程没走 stop 就没了)。stopped 会留下:
$ arc service gc
Collected 1 dead instance
docs514dead
kept 1
$ arc service gc
No dead instances to collect之后 list 仍有 stopped 和 up 行;docs514dead 没了。已经没有 dead 时,gc 用一行说明这件事,退出码仍然是 0。另一个完全空的 registry(零个已注册实例,不是上面那个)用来说明 kept 是一个真的数,能数到 0,不是一个空答案——跟下面 --print 那条「渲染出零个字符,不是 falsy」的规则是同一条:
$ arc service gc --json
{
"removed": [],
"kept": 0
}--print
--print <field> 从命令的正常结果里读一个字段,以纯文本写到 stdout,完全绕开 --json/--view。ArcBlock/arc#6301 改了「算没算有值」的判据:以前是falsy(false、0、"" 都被当成不存在,打印为空还照样退出 0——和一个真的空答案分不出来);现在是渲染出零个字符。false 和 0 分别是五个字符和一个字符,所以是真答案,照样退出 0。查字段用的是 Object.hasOwn,不是 in(后者会走原型链,让 --print __proto__ 答出 {})。
Accept path——一个真实值是布尔 false 的字段照样打印并退出 0(这个实例是用 --no-advertise 起的):
$ arc service status --instance docs514b --print advertise
falseAccept path——一个真实值是数字 0 的字段照样打印并退出 0(空 registry,所以 gc 的 kept 计数真的是零):
$ arc service gc --print kept
0(同一条规则也覆盖 0 的端口;那个具体情形没法从一次真实绑定里跑出来——OS 从来不会真的把端口分配成 0——所以 CLI 自己的正控单测直接对一个合成的 { port: 0 } 对象跑:runtimes/node/test/daemon/service-print-contract.test.ts:135。)
Reject path——一个存在但没有值的字段(没有 .git 的 checkout 上的 branch / sha / commit)会被拒绝,不是悄悄打印成空:
$ arc service status --instance docs514b --print branch
$ echo $?
1stderr(banner 已省略):ERROR: field "branch" in result has no value
Reject path——一个结果里根本不存在的字段,报错不一样,退出码一样:
$ arc service status --instance docs514b --print nosuchfield
$ echo $?
1stderr:ERROR: no field "nosuchfield" in result
--print "" 以前被当成「没给 --print」而落回完整的默认视图——所以 arc service status --print "$FIELD" 在 $FIELD 没设时会打印整个人类视图,而不是报错。现在不会了:空字段名跟别的字段名一样被查,查不到,和上面 nosuchfield 一样被拒绝:
$ arc service status --instance docs514b --print ""
$ echo $?
1stderr:ERROR: no field "" in result
--json 契约
只有成功时 JSON 才在 stdout。拒绝时 stdout 永远是空的(0 字节)——每一条失败都是,不是「有些是」。 这纠正了本页早先的一个说法,那时写着拒绝路径会把 { "error": "…" } 放到 stdout 上;对 arc service 来说那从来都不是真的,ArcBlock/arc#6301 的修复说明也确认修完之后的契约明确是它九个拒绝场景里「stdout 0 字节」。报错文本走 stderr,带 ERROR: 前缀,进程以非零码退出。
两种不同的拒绝都落到同一个「stdout 0 字节」形状上——值得放在一起看,因为它们走的是不同的代码路径:
$ arc service status --instance no-such-xyz --json
$ echo $?
1stderr:ERROR: no instance named "no-such-xyz". `arc service list` shows 2——这条根本没走到动作自己的 executor,实例解析这一步就先失败了。
$ arc service delete --instance docs514b --json
$ echo $?
1stderr:ERROR: instance "docs514b" is running. stop it first, or use --force——这条是在 delete 自己的 executor 里跑的,executor 在成功解析出实例之后才决定失败。
两条路径同一个形状:stdout 空,stderr 带 ERROR: 前缀,退出码非零。--json 对这些都没有影响——它只改变一次成功的运行本来会打印什么。
成功时,JSON 是人类视图的超集。 终端打出来的每一条 URL / 主机名 / 路径都在 payload 里——logFile、endpoints、blockletUrls、lan、build——agent 永远不需要去刮 stderr。
$ arc service status --instance docs514b --json
{
"name": "docs514b",
"id": "b719db414c5cc625",
"status": "up",
"port": 61498,
"url": "http://127.0.0.1:61498",
"home": "/tmp/arc-svc-docs-514/home-b",
"spaceRoot": "/tmp/arc-svc-docs-514/home-b/.afs/spaces",
"blocklets": [
"/path/to/arc/blocklets/afs-preview-fixture"
],
"pid": 95666,
"version": "2.0.0-beta.48",
"commit": "5a5316bde",
"branch": null,
"sha": null,
"checkout": "/tmp/arc-svc-docs-514/project",
"startedAt": "2026-09-10T01:49:56.435Z",
"urls": {
"ui": "http://127.0.0.1:61498/",
"blocklets": {
"afs-preview-fixture": "http://127.0.0.1:61498/?blocklet=afs-preview-fixture"
}
},
"host": "127.0.0.1",
"advertise": false,
"uptime": "3s",
"logFile": "/tmp/arc-svc-docs-514/home-b/.afs/daemon.log",
"endpoints": [
{ "url": "http://127.0.0.1:61498/", "label": "AUP Web Client" },
{ "url": "http://127.0.0.1:61498/explorer", "label": "Explorer UI" },
{ "url": "http://127.0.0.1:61498/ws", "label": "WebSocket (Explorer)" },
{ "url": "http://127.0.0.1:61498/afs/*", "label": "REST API" },
{ "url": "http://127.0.0.1:61498/mcp", "label": "MCP Streamable HTTP" }
],
"blockletUrls": {
"afs-preview-fixture": [
{ "url": "http://afs-preview-fixture.localhost:61498/", "label": "" },
{ "url": "http://localhost:61498/?blocklet=afs-preview-fixture", "label": "(Safari / universal)" }
]
},
"build": {
"id": "2.0.0-beta.48+5a5316bde (debug)",
"exec": "/path/to/arc/runtimes/node/dist/cli.mjs"
},
"live": {
"ok": true,
"url": "http://127.0.0.1:61498/.well-known/arc/instance",
"record": {
"version": "2.0.0-beta.48",
"commit": "5a5316bde",
"branch": null,
"sha": null,
"checkout": "/tmp/arc-svc-docs-514/project",
"pid": 95666,
"port": 61498,
"blocklets": 1
}
}
}字段分组:前十个键是实例记录;version … urls 来自注册表行;logFile … build 是人类视图打过的那些;live / drift 是对活 daemon 的对账。实例绑在非 loopback 地址上时会多一个 lan,整块 LAN 诊断在它的 lines 里。
list 只报记录类字段,不带「打印过的事实」那几个——它每行不打 banner,也不做探针。注意这里 sha 有值(一个真的 git checkout),而上面单实例的例子里是 null(一个没有 .git 的 checkout)——两个都是真的,来自两次不同的运行:
$ arc service list --json
{
"instances": [
{
"name": "docs514a",
"id": "b719db414c5cc624",
"status": "up",
"port": 61497,
"url": "http://127.0.0.1:61497",
"home": "/tmp/arc-svc-docs-514/home-a",
"spaceRoot": "/tmp/arc-svc-docs-514/home-a/.afs/spaces",
"blocklets": [],
"pid": 95665,
"version": "2.0.0-beta.48",
"commit": "5a5316bde",
"branch": null,
"sha": "5a5316bdece751ee90416382b3ad851e565afa22",
"checkout": "/tmp/arc-svc-docs-514/project",
"startedAt": "2026-09-10T01:49:44.207Z",
"urls": { "ui": "http://127.0.0.1:61497/", "blocklets": {} },
"host": "localhost",
"advertise": true,
"uptime": "5s"
}
]
}list 每行的 version 就是那个实例真正在跑的 binary——一眼能看出哪些实例没被 upgrade 覆盖到。
$ arc service stop --instance docs514b --json
{
"name": "docs514b",
"id": "b719db414c5cc625",
"stopped": true,
"pid": 95700
}
$ arc service delete --instance docs514b --json
{
"name": "docs514b",
"removed": true,
"home": "/tmp/arc-svc-docs-514/home-b"
}--view json 和 --json 是同一个通道。
logs 是流,拒绝 --json——跟其它拒绝一样的「stdout 0 字节 / stderr 报错」形状:
$ arc service logs --instance docs514a --json
$ echo $?
1stderr:ERROR: logs is a stream and does not support --json
yargs 级错误(未知动词、缺必填参数)同样即使加了 --json 也不打 JSON——它们根本没走到 --json 会起作用的地方,而是把子命令的 help 打到 stderr(见失败路径)。
失败路径
对已经 up 的实例再 start(退出码 1)。提示语现在会点名你启动时用的那个 --home,不只是光秃秃的动词——因为 restart 在 start 时传了 --home 的情况下也需要它:
$ arc service start --instance docs514b --home /tmp/arc-svc-docs-514/home-b
ERROR: instance "docs514b" is already running
pid 95666, port 61498, started 39s ago
use `arc service restart --instance docs514b --home /tmp/arc-svc-docs-514/home-b` or pick another namerestart --port(以及别的纯配置 flag——具体哪几个、为什么 --home不一样,见Flags)(退出码 1):
$ arc service restart --instance docs514b --port 4910
ERROR: restart does not reconfigure. use `stop` then `start` to change --port--space-root 必须已经是 DID Space:
$ arc service start --instance docs514c --home /tmp/arc-svc-docs-514/home-c \
--space-root /tmp/arc-svc-docs-514/not-a-space
ERROR: /tmp/arc-svc-docs-514/not-a-space is not a DID Space. create it with `arc space init`未知动词(退出码 5)。yargs 把它当成「positional 不够/不对」处理,把这个组的 --help(下面 --help 一节有全文)打到 stderr,两者一起只加一次前缀:
$ arc service foo
ERROR: Invalid values:
Argument: action, Given: "foo", Choices: list, start, stop, restart, status, delete, gc, url, logs
arc service
Manage AFS background service
Commands:
arc service list List every local instance with its status, port and home
[aliases: ls, ps]
...不带动词的裸 arc service 是同一个机制,原因不同(退出码 5):
$ arc service
ERROR: Not enough non-option arguments: got 0, need at least 1
arc service
...多出来的 positional 实例名(动词后面直接跟一个名字,没有 --instance)在每个动词上都会被拒绝,包括 list / gc——同一个机制,这次打的是子命令自己的 --help(退出码 5):
$ arc service status somename
ERROR: positional instance name was removed; use `--instance <name>` / `-i`
arc service status
Report whether an instance is running, and on which port
...已删除与已退役
这些以前写进文档,现在没了:
| 旧写法 | 现在 |
|---|---|
arc service <action> [op] [dir] [options] | arc service <verb> [options] |
arc service <action> [name] | arc service <verb> --instance <name> / -i |
--blocklet-dir | --blocklet(父目录或单个目录) |
--save | 自动记在实例上 |
ARC_BLOCKLET_DIR | 已删除。传 --blocklet |
arc service blocklet-dir add/list | 已删除 |
arc service restart --port 4900 | restart 拒绝配置 flag |
ARC_HOME | 已退役。 警告并忽略 |
真正被删除的 flag 不再有专门的报错——现在会撞上 yargs 自己的「未知参数」处理,它会给一个「Did you mean?」建议,并倾泻子命令的 --help:
$ arc service start --instance docs514a --home /tmp/arc-svc-docs-514/home-a --blocklet-dir /tmp/nope
ERROR: Unknown arguments: blocklet-dir, blockletDir
Did you mean?
--blocklet
arc service start
...
$ arc service start --instance docs514a --home /tmp/arc-svc-docs-514/home-a --save
ERROR: Unknown argument: save
arc service start
...ARC_HOME 不受子命令化影响——警告照样打,照样在 banner 之前独占一行,而且不带 ERROR: 前缀(它是个 warning,不是 fail(),ArcBlock/arc#6301 的统一没碰它):
$ ARC_HOME=/tmp/retired-home arc service list
warning: ARC_HOME is ignored; instance root comes from the service name and --home, not env--help
组级的 --help——未知动词打出来的也是这个(见失败路径):
arc service
Manage AFS background service
Commands:
arc service list List every local instance with its status, port and home
[aliases: ls, ps]
arc service start Start an instance, creating it on first use
arc service stop Stop a running instance, keeping its record and data
arc service restart Restart an instance from its recorded config (does not
reconfigure — stop then start for that)
arc service status Report whether an instance is running, and on which port
arc service delete Delete an instance: its record and its data [aliases: rm,
remove]
arc service gc Drop registry records whose process is gone [aliases:
prune]
arc service url Print an instance's base URL (and its blocklets')
arc service logs Print an instance's daemon log [aliases: log]
Options:
--json Output in JSON format [boolean]
--view Output view format (json is equivalent to --json). llm is
accepted globally; commands without an llm renderer fail
closed (declare ⇒ execute; arc#6037). [string] [choices:
"default", "llm", "human", "json"] [default: "default"]
--home Instance root — to pick which instance, use --instance. Used
by `arc service start` (create) and `arc did init` (identity).
In `--standalone`, sets DID Space and configDir; mounts come
from a cwd-walk of `.afs-config/config.toml`, not from --home.
[string]
-i, --instance Named local ARC instance this command operates against (see
`arc service list`). Omit for the default instance. [string]
--print Print one result field (e.g. url, port) as plain text — not a
view; overrides --json/--view [string]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Examples:
arc service list
Show every local instance
arc service start -i alice
Start (or create) named instance alice
arc service status -i alice
Is alice running, and on which port?
arc service logs -i alice
Print alice's recent daemon logs
arc service stop -i alice
Stop alice without deleting it
arc service delete -i alice --dry-run
Preview deleting instance alice without removing it九个子命令里挑两个自己的 --help——start(flag 最多的)和 delete(带一组三个破坏性动词专属 flag 的)——看看其它七个跟的是什么样子:
arc service start
Start an instance, creating it on first use
Options:
--json Output in JSON format [boolean]
--view Output view format (json is equivalent to --json). llm is
accepted globally; commands without an llm renderer fail
closed (declare ⇒ execute; arc#6037). [string] [choices:
"default", "llm", "human", "json"] [default: "default"]
--home Instance root — to pick which instance, use --instance. Used
by `arc service start` (create) and `arc did init`
(identity). In `--standalone`, sets DID Space and configDir;
mounts come from a cwd-walk of `.afs-config/config.toml`,
not from --home. [string]
-i, --instance Named local ARC instance this command operates against (see
`arc service list`). Omit for the default instance. [string]
--print Print one result field (e.g. url, port) as plain text — not
a view; overrides --json/--view [string]
--port Port to listen on (0-65535). 0 = auto-assign. Omit: default
uses 4900; named instances use the recorded port or
auto-assign [number]
--host Bind address (localhost, 0.0.0.0, ::, or a unicast IP)
[string] [default: "localhost"]
--advertise Advertise this instance over mDNS when bind is non-loopback
(use --no-advertise to disable) [boolean] [default: true]
--blocklet Blocklet-parent or single-blocklet dir to serve
(repeatable). Recorded on the instance. [array]
--space-root Folder-as-DID-Space created with `arc space init` (omit to
derive from home) [string]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Examples:
arc service start -i alice
Start (or create) named instance alice
arc service delete
Delete an instance: its record and its data
Options:
--json Output in JSON format [boolean]
--view Output view format (json is equivalent to --json). llm is
accepted globally; commands without an llm renderer fail
closed (declare ⇒ execute; arc#6037). [string] [choices:
"default", "llm", "human", "json"] [default: "default"]
--home Instance root — to pick which instance, use --instance. Used
by `arc service start` (create) and `arc did init` (identity).
In `--standalone`, sets DID Space and configDir; mounts come
from a cwd-walk of `.afs-config/config.toml`, not from --home.
[string]
-i, --instance Named local ARC instance this command operates against (see
`arc service list`). Omit for the default instance. [string]
--print Print one result field (e.g. url, port) as plain text — not a
view; overrides --json/--view [string]
--force Stop a running instance before deleting it [boolean] [default:
false]
--dry-run Print what would be removed without deleting it [boolean]
[default: false]
--yes Skip the TTY confirmation prompt [boolean] [default: false]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Examples:
arc service delete -i alice --dry-run
Preview deleting instance alice without removing it其余七个(stop、restart、status、gc、url、logs,再加组自己的 list)跟上面 start/delete 长得一样,少的是本页Flags表里已经限定给 start/delete/logs 的那些——logs 只多一个 --follow。
--json、--view、--home、--instance / -i 都是全局选项(只声明一次,作用于每一条 arc 命令)。--home 是实例根;要指定作用在哪个实例,用 --instance。见 总览。