跳到主要内容

arc service

arc service 管理具名 AFS 后台实例:list、start、stop、restart、status、delete、gc、url、logs。

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]),每个都有自己的 --helpExamples: 块——不再是一条命令带一个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 结构都是真实跑出来的原样。

bash
arc service <verb> [options]

verb 是下面之一:listlsps)、startstoprestartstatusdeletermremove)、gcprune)、urllogslog)。用 --instance <name> / -i 指定实例。省略 --instance 即种子实例 default(home ~,端口 4900)。其它名字由内核分配端口,除非你传 --port

不要 stop / delete 你没启动的种子实例。本页 dump 用的是一次性 registry,没有碰本机 :4900 上的 default

隔离

隔离靠具名实例加 --homeARC_HOME 已退役:CLI 会警告并忽略取值。

bash
export ARC_INSTANCES_DIR=/tmp/arc-svc-docs-514/instances
arc service start --instance docs514b --home /tmp/arc-svc-docs-514/home-b

ARC_SERVICE_PORT 仍在,但只作用于未具名的种子实例。优先用名字,或传 --port

下面 dump 省略了 stderr 上的 splash banner。

子命令

每个子命令都有自己的 --help 和自己的 Examples:(见本页底部的 --help 一节)。arc service <坏动词> 和不带动词的 arc service 都打印下面这张组级列表,不是某个动词自己的。

子命令Alias作用
listlsps列出每个本地实例的状态、端口和 home
start启动一个实例;首次用即创建
stop停下正在跑的实例,保留记录和数据
restart按记录重启实例——不接受重新配置;要改配置用 stopstart
status报告一个实例是否在跑,以及跑在哪个端口
deletermremove删除一个实例:它的记录和数据
gcprune清掉进程已经不在了的注册记录
url打印实例的 base URL(以及它的 blocklet URL)
logslog打印实例的 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全部把结果里的单个字段(例如 urlport)以纯文本打印——不是一种 view,会覆盖 --json/--view。见下面的 --print
--portstart监听端口(0–65535)。0 = 自动分配。省略时:default4900,具名实例用记录里的端口或自动分配
--hoststart绑定地址(localhost0.0.0.0:: 或单播 IP)。默认 localhost
--advertisestart绑定非 loopback 时通过 mDNS 宣告(默认 true--no-advertise 关闭)
--blockletstart要服务的 blocklet 父目录或单个 blocklet 目录(可重复)。记在实例上
--space-rootstartarc space init 建好的 Folder-as-DID-Space。省略则从 --home 派生
--forcedelete先停再删。默认 false
--dry-rundelete打印会删掉什么,不实际删除。默认 false
--yesdelete跳过 TTY 确认提示。默认 false
--followlogs流式输出新写入的行。默认 false

--yaml 已删除,从未真正实现——见 总览

restart 自己的 --help 里没有 start 那组配置 flag——传了会被一条专门的报错拒绝,不是 yargs 通用的「unknown argument」(那条通用路径是真正被删除的 flag,比如 --blocklet-dir,才会撞上的;见已删除与已退役):

bash
$ 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 守卫不一样:

bash
$ 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/--blocklet1。)

状态

状态含义
starting记录已占用,进程还没到 up
up进程在听端口
stoppedstop 退出。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  1

status 的退出码:up0starting / stopped3dead4。非 up 时它照样报上一次的 pid / port / URL,并明确标注(--json 里是 lastKnown,人类视图里是一行 Note:)。

Start、list、status、url

空 registry:

bash
$ export ARC_INSTANCES_DIR=/tmp/arc-svc-docs-514/instances
$ arc service list
NAME          ID                PORT   STATUS   HOME                          SOURCES
(no instances)

启动一个具名实例。端口 61497 是内核分配的,不是 4900

bash
$ 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 HTTP

Build / Exec 来自 daemon 启动时写的 <home>/.afs/daemon.build.json;老 daemon 没有这个 sidecar 时这两行直接不打,不猜。Version / Commit / Checkout 描述的是真正在服务这个实例的那个 binary——见下面的身份字段

--blocklet 记录 blocklet 源(可重复)。同一个 flag 既接受父目录,也接受单个 blocklet 目录:

bash
$ 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)
bash
$ 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  1

status 报得出 start 报过的每一件事——对一个不是你刚起的实例也一样,stdout/stderr 的分法也一样:

bash
$ 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。startstatus 对同一个实例报同一个 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 永远是全的。

bash
$ 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)
bash
$ 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 里:

json
"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 里:

json
"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

bash
$ 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 一样。

bash
$ 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 会先重打已有行再流式输出。

bash
$ arc service stop --instance docs514b
Service stopped: docs514b

stopped 的实例照样报上一次的 pid / port / URL,并且明说这些是历史值(退出码 3):

bash
$ 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 会复用记录。

本页每个代码块都是独立的一次捕获;实例名在不同小节里重复出现(docs514adocs514b)并不意味着一条连续的会话——下面 delete 的四个例子都用全新的一次性名字,正因为这样,它们谁都不是在删一个前面例子已经删掉的名字。

delete 现在对成功有两种输出形态,按 view 分——跟 arc afs delete 一样的分法(ArcBlock/arc#6055):默认(机器、非 TTY)视图是一句光秃秃的 OK <name>——write 的形状——--view human 是一句说清楚删了什么的话。下面两个实例在删除前都是 stopped

bash
$ arc service delete --instance docs514x
OK docs514x

$ arc service delete --instance docs514y --view human
Removed instance "docs514y"

正在跑的实例,delete 不带 --force 会失败——这也是 ArcBlock/arc#6301 前缀修复真正体现出来的地方:本页每一条失败行现在都以 ERROR: 开头,而旧的捕获完全没有前缀:

bash
$ arc service delete --instance docs514z
ERROR: instance "docs514z" is running. stop it first, or use --force

--force 先停再删——上面那条拒绝的 accept-path 对应项,同一个实例,同一个动词:

bash
$ arc service delete --instance docs514z --force --yes
OK docs514z

--dry-run 只预览,不动手,对 stopped 或 running 的实例都能用:

bash
$ 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 会留下:

bash
$ arc service gc
Collected 1 dead instance
  docs514dead
kept 1

$ arc service gc
No dead instances to collect

之后 list 仍有 stoppedup 行;docs514dead 没了。已经没有 dead 时,gc 用一行说明这件事,退出码仍然是 0。另一个完全空的 registry(零个已注册实例,不是上面那个)用来说明 kept 是一个真的数,能数到 0,不是一个空答案——跟下面 --print 那条「渲染出零个字符,不是 falsy」的规则是同一条:

bash
$ arc service gc --json
{
  "removed": [],
  "kept": 0
}

--print

--print <field> 从命令的正常结果里读一个字段,以纯文本写到 stdout,完全绕开 --json/--view。ArcBlock/arc#6301 改了「算没算有值」的判据:以前是falsyfalse0"" 都被当成不存在,打印为空还照样退出 0——和一个真的空答案分不出来);现在是渲染出零个字符false0 分别是五个字符和一个字符,所以是真答案,照样退出 0。查字段用的是 Object.hasOwn,不是 in(后者会走原型链,让 --print __proto__ 答出 {})。

Accept path——一个真实值是布尔 false 的字段照样打印并退出 0(这个实例是用 --no-advertise 起的):

bash
$ arc service status --instance docs514b --print advertise
false

Accept path——一个真实值是数字 0 的字段照样打印并退出 0(空 registry,所以 gckept 计数真的是零):

bash
$ 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)会被拒绝,不是悄悄打印成空:

bash
$ arc service status --instance docs514b --print branch
$ echo $?
1

stderr(banner 已省略):ERROR: field "branch" in result has no value

Reject path——一个结果里根本不存在的字段,报错不一样,退出码一样:

bash
$ arc service status --instance docs514b --print nosuchfield
$ echo $?
1

stderr:ERROR: no field "nosuchfield" in result

--print "" 以前被当成「没给 --print」而落回完整的默认视图——所以 arc service status --print "$FIELD"$FIELD 没设时会打印整个人类视图,而不是报错。现在不会了:空字段名跟别的字段名一样被查,查不到,和上面 nosuchfield 一样被拒绝:

bash
$ arc service status --instance docs514b --print ""
$ echo $?
1

stderr:ERROR: no field "" in result

--json 契约

只有成功时 JSON 才在 stdout。拒绝时 stdout 永远是空的(0 字节)——每一条失败都是,不是「有些是」。 这纠正了本页早先的一个说法,那时写着拒绝路径会把 { "error": "…" } 放到 stdout 上;对 arc service 来说那从来都不是真的,ArcBlock/arc#6301 的修复说明也确认修完之后的契约明确是它九个拒绝场景里「stdout 0 字节」。报错文本走 stderr,带 ERROR: 前缀,进程以非零码退出。

两种不同的拒绝都落到同一个「stdout 0 字节」形状上——值得放在一起看,因为它们走的是不同的代码路径:

bash
$ arc service status --instance no-such-xyz --json
$ echo $?
1

stderr:ERROR: no instance named "no-such-xyz". `arc service list` shows 2——这条根本没走到动作自己的 executor,实例解析这一步就先失败了。

bash
$ arc service delete --instance docs514b --json
$ echo $?
1

stderr:ERROR: instance "docs514b" is running. stop it first, or use --force——这条是在 delete 自己的 executor 里跑的,executor 在成功解析出实例之后才决定失败。

两条路径同一个形状:stdout 空,stderr 带 ERROR: 前缀,退出码非零。--json 对这些都没有影响——它只改变一次成功的运行本来会打印什么。

成功时,JSON 是人类视图的超集。 终端打出来的每一条 URL / 主机名 / 路径都在 payload 里——logFileendpointsblockletUrlslanbuild——agent 永远不需要去刮 stderr。

bash
$ 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
    }
  }
}

字段分组:前十个键是实例记录;versionurls 来自注册表行;logFilebuild 是人类视图打过的那些;live / drift 是对活 daemon 的对账。实例绑在非 loopback 地址上时会多一个 lan,整块 LAN 诊断在它的 lines 里。

list 只报记录类字段,不带「打印过的事实」那几个——它每行不打 banner,也不做探针。注意这里 sha 有值(一个真的 git checkout),而上面单实例的例子里是 null(一个没有 .git 的 checkout)——两个都是真的,来自两次不同的运行:

bash
$ 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 覆盖到。

bash
$ 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 报错」形状:

bash
$ arc service logs --instance docs514a --json
$ echo $?
1

stderr:ERROR: logs is a stream and does not support --json

yargs 级错误(未知动词、缺必填参数)同样即使加了 --json 也不打 JSON——它们根本没走到 --json 会起作用的地方,而是把子命令的 help 打到 stderr(见失败路径)。

失败路径

对已经 up 的实例再 start(退出码 1)。提示语现在会点名你启动时用的那个 --home,不只是光秃秃的动词——因为 restartstart 时传了 --home 的情况下也需要它:

bash
$ 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 name

restart --port(以及别的纯配置 flag——具体哪几个、为什么 --home不一样,见Flags)(退出码 1):

bash
$ arc service restart --instance docs514b --port 4910
ERROR: restart does not reconfigure. use `stop` then `start` to change --port

--space-root 必须已经是 DID Space:

bash
$ 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,两者一起只加一次前缀:

bash
$ 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):

bash
$ arc service
ERROR: Not enough non-option arguments: got 0, need at least 1

arc service
...

多出来的 positional 实例名(动词后面直接跟一个名字,没有 --instance)在每个动词上都会被拒绝,包括 list / gc——同一个机制,这次打的是子命令自己--help(退出码 5):

bash
$ 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 4900restart 拒绝配置 flag
ARC_HOME已退役。 警告并忽略

真正被删除的 flag 不再有专门的报错——现在会撞上 yargs 自己的「未知参数」处理,它会给一个「Did you mean?」建议,并倾泻子命令的 --help

bash
$ 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 的统一没碰它):

bash
$ 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——未知动词打出来的也是这个(见失败路径):

text
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 的)——看看其它七个跟的是什么样子:

text
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

其余七个(stoprestartstatusgcurllogs,再加组自己的 list)跟上面 start/delete 长得一样,少的是本页Flags表里已经限定给 start/delete/logs 的那些——logs 只多一个 --follow

--json--view--home--instance / -i 都是全局选项(只声明一次,作用于每一条 arc 命令)。--home 是实例根;要指定作用在哪个实例,用 --instance。见 总览