脚本参考
Paneflow 自动化的 CLI verb、selector、JSON-RPC method、event frame、config key、workspace spec、flow spec、MCP tool、hook 和退出码。
这是 脚本与自动化 的紧凑参考。它命名了人类 脚本或 LLM 可以精确引用的公共接口。
CLI verb
paneflow 二进制会拦截这些 verb,并在 GUI 启动前退出。未知
verb 会以 usage code 2 退出,而不是静默启动 app。
| Verb | 主要 method 或 engine | 是否写入面板 | 用途 |
|---|---|---|---|
ls [--human] | surface.list | 否 | 列出活动工作区中的面板 |
read <target> | surface.read | 否 | 读取面板 scrollback |
search <target> <pattern> | surface.search | 否 | 搜索面板 scrollback |
ps [--json] | fleet.list | 否 | 列出跨工作区检测到的智能体 |
status <target> [--json] | surface.status | 否 | 读取单个面板的智能体状态 |
new | workspace.create | 否 | 创建工作区 |
select <index> | workspace.select | 否 | 选择工作区 |
split <h|v> | surface.split | 否 | 分割面板 |
focus <target> | surface.focus | 否 | 聚焦面板及其工作区 |
send <target> <text> | surface.send_text | gated | 预填或提交文本 |
key <target> <keystroke> | surface.send_keystroke | gated | 发送一个不会提交的按键 |
wait --match <sel> | surface.read, events.subscribe | 否 | 阻塞到 pattern、idle 或两者都满足 |
watch [--surface <sel>] [--type <event>] | events.subscribe | 否 | 流式输出生命周期和 surface 事件 |
up <file> | Workspace spec engine | 仅预填 | 创建声明式工作区 |
flow run <file> | Flow engine | 提交 step 需要 gate | 运行本地多智能体 DAG |
CLI 接受的 alias:list_panes 映射到 ls,read_pane 映射到
read,search_pane 映射到 search。
Selector
| Selector | 示例 | 说明 |
|---|---|---|
| Numeric id | paneflow read 42 | 精确匹配 surface_id |
| Name | paneflow status backend | 持久脚本的最佳 selector |
cmdline:<substr> | paneflow read cmdline:vite | Linux 上是完整 foreground argv,macOS 和 Windows 上是 executable basename |
cwd:<path> | paneflow read cwd:/home/me/api | 匹配面板工作目录 |
如果 selector 不匹配任何面板,或匹配多个面板,会以 code 3 退
出。但显式接受多匹配的 command 例外,例如 send --broadcast、
wait --any 和 wait --all。
退出码
| Code | 含义 |
|---|---|
0 | 成功 |
1 | Runtime failure:实例不可达、面板关闭、gate 拒绝或 handler error |
2 | CLI usage error |
3 | target not found 或 ambiguous |
4 | wait timeout 或 flow ready timeout |
写入 gate
读取默认允许。写入按 capability 区分:
| Operation | Gate |
|---|---|
send without --submit | PANEFLOW_IPC_SCRIPTING=1 或 ai_unrestricted |
send --submit | PANEFLOW_IPC_SCRIPTING=1 或 ai_unrestricted |
key | PANEFLOW_IPC_SCRIPTING=1 |
Flow step with submit = true | system.capabilities 报告的 scripting capability |
除非存在 --submit,否则 send 不会附加 carriage return。key
会拒绝 enter、ctrl-m 和 ctrl-j 等提交型按键。单个
surface.send_text payload 上限为 64 KiB。
相关 config key:
| Key | Default | 含义 |
|---|---|---|
ai_unrestricted | false | 允许受信任的 AI 自动化在没有 env gate 的情况下提交文本 |
ai_injection_fence | true | 将 surface.read 文本包裹在不可信终端 envelope 中 |
submit_paste_delay_ms | 70 | bracketed paste 与提交 carriage return 之间的基础延迟 |
terminal.env | none | 注入到新终端的环境变量 |
读取字段
paneflow read <target> --json 和原始 surface.read 返回:
| Field | 含义 |
|---|---|
text | scrollback 文本,默认 fenced |
lines | 返回的行数 |
total_lines | 保留的总行数 |
eof | 是否读到了保留缓冲区中最旧的行 |
output_generation | 随面板输出前进的 monotonic counter |
默认值和限制:lines 默认 200,并被 clamp 到 1-4000。offset
从 buffer 末尾开始计算。超出范围的 offset 是 invalid-params error。
JSON-RPC param fenced 默认使用 ai_injection_fence。CLI flag
--raw 会传入 fenced: false。
智能体状态字段
paneflow ps --json 返回 {"agents":[...]}。paneflow status <target> --json 返回一个 status object。
| Field | 含义 |
|---|---|
pid | 智能体 process id,已知时存在 |
tool | 智能体家族,例如 claude、codex、opencode 或 gemini |
state | thinking、waiting_for_input、finished、errored、stalled、idle 或 unknown_running |
hooked | lifecycle hook event 是否已连接 |
reason | 检测原因,包括 no_hook |
surface_id | 面板 id |
surface_name | 面板名称 |
workspace | 工作区 index |
active_tool_name | 智能体内部当前运行的 tool |
message | 等待中的 prompt 或 permission text |
last_result | 可用时的 last turn summary |
waiting_ms | 等待输入的时间 |
idle_ms | 距离观测到的上次 activity 的时间 |
output_generation | status 上的面板输出 counter |
空 fleet 会以 exit code 0 返回 {"agents":[]}。没有 tracked agent
的面板返回 idle state,而不是 error。
Workspace spec
paneflow up <file> 读取 TOML workspace spec。
| Top-level field | Type | Default | Notes |
|---|---|---|---|
name | string | "Workspace" | 工作区标题 |
layout | string | "even_h" | even_h、even_v、main_vertical 或 tiled |
port_base | integer | 3000 | ${port_offset} allocation 的 base |
[[panes]] | array | required | 每个面板一个 entry |
| Pane field | Type | Default | Notes |
|---|---|---|---|
cwd | string | none | expansion 和 canonicalization 后必须存在 |
agent | string | none | 智能体 launcher name,与 command 互斥 |
command | string | none | 原始 command,与 agent 互斥 |
prompt | string | none | 预填到智能体输入中,up 永不提交 |
focus | bool | false | 给此面板初始焦点 |
env | table | none | 合并在 terminal.env 之上;支持 ${port_offset} |
name | string | none | 稳定 selector name |
worktree | string | none | <repo>.worktrees/ 下 managed worktree 的 branch name |
copy_env | bool | true | 将 gitignored .env* file 复制进 worktree |
setup | string | none | launch 前运行的 command |
setup_timeout_secs | integer | 300 | setup timeout |
worktree_teardown | string | "auto" | auto 在关闭时移除干净 worktree;keep 保留 |
${port_offset} 只在 env value 中替换。未知 key 是 error。创建
工作区会先验证 path,再创建面板。
Flow spec
paneflow flow run <file> 读取 TOML flow spec,并在当前 Paneflow
实例上运行。
| Field | Type | Notes |
|---|---|---|
id | string | 必需且唯一的 step id |
needs | array | dependency;在 foreach 上等待所有 instance |
foreach | array | fan-out,每个 item 一个 instance |
pane | inline table | 使用 workspace pane field 创建面板 |
send | inline table | { target, text, submit? };需要 dependency |
ready | table | { pattern, timeout_secs? };regex barrier |
capture | table | { var, lines };在 ready 后捕获 1-500 行 |
submit | bool | 提交 spawned pane prompt;需要 scripting access |
Variables:
| Variable | Scope |
|---|---|
${item} | foreach step:cwd、name、worktree、env、send.target、ready.pattern、prompt 和 text |
${var} | send.text 和 submitting pane.prompt 中的 captured value |
${var.<item>} | 来自 foreach group 的 capture |
runner 会在执行前验证 unknown key、missing dependency、dependency
cycle、invalid regex、undefined capture、pane budget 和 missing
timeout。Ctrl-C 会停止 orchestration loop;已创建的面板会保留
在 Paneflow 中。
JSON-RPC 连接
| Property | Value |
|---|---|
| Linux endpoint | $XDG_RUNTIME_DIR/paneflow/paneflow.sock |
| macOS endpoint | 用户 runtime dir,同名 Paneflow socket |
| Windows endpoint | \\.\pipe\paneflow |
| Framing | Newline-delimited JSON-RPC 2.0 |
| Request model | 除 events.subscribe 外,每个连接一个 request |
| Local trust | 仅同一用户;无网络 listener、无 token、无 TLS |
| Backpressure | 连接上限和 bounded event queue 会返回 structured error 或 dropped frame |
运行时探测 capability:
printf '%s\n' '{"jsonrpc":"2.0","method":"system.capabilities","params":{},"id":1}' \
| nc -U "$PANEFLOW_SOCKET_PATH"JSON-RPC method
| Method | Params | Returns or notes |
|---|---|---|
system.ping | - | liveness check |
system.capabilities | - | {scripting, methods[]} |
system.identify | - | {name, version, protocol} |
workspace.list | - | 带 index 和 title 的工作区 |
workspace.current | - | 活动工作区 |
workspace.create | name?, cwd?, layout? | 创建工作区 |
workspace.select | index | 切换工作区 |
workspace.close | index? | 关闭工作区 |
workspace.up | name, layout, panes[] | up 和 flow root 使用的声明式 spawn |
workspace.restore_layout | layout | 应用 layout tree |
surface.list | - | {surfaces:[{surface_id,name,title,cwd,cmd,workspace}]} |
surface.read | surface_id, lines?, offset?, fenced? | scrollback 和 output_generation |
surface.search | surface_id, pattern, max_matches? | case-insensitive substring match |
surface.rename | surface_id, name | 重命名或清空面板 name |
surface.focus | surface_id | 聚焦面板和工作区 |
surface.status | surface_id | 单个面板的智能体状态 |
surface.send_text | surface_id, text, submit?, paste? | gated PTY text write |
surface.send_keystroke | surface_id, keystroke | env-gated non-submitting keystroke |
surface.split | direction, surface_id?, cwd?, command?, prompt?, env?, name?, managed_worktree? | 分割面板 |
fleet.list | - | read-only fleet snapshot |
events.subscribe | surfaces?, types? | persistent newline-delimited event stream |
ai.session_start | hook payload | lifecycle telemetry |
ai.prompt_submit | hook payload | lifecycle telemetry |
ai.tool_use | hook payload | lifecycle telemetry |
ai.notification | hook payload | lifecycle telemetry |
ai.stop | hook payload | lifecycle telemetry |
ai.exit | hook payload | lifecycle telemetry |
ai.session_end | hook payload | lifecycle telemetry |
结构化失败使用 JSON-RPC error envelope:-32602 invalid params、
-32601 gated method、-32001 permission 和 -32000 backpressure。
部分 legacy validation error 仍会以 result 内的 {"error":"..."}
形式返回;client 应将两种形态都视为 failure。
Event
paneflow watch 和原始 events.subscribe 会发出 newline-delimited
JSON。第一帧确认 subscription。
| Event type | 含义 |
|---|---|
subscribed | subscription acknowledged |
ai.session_start | 智能体 session starts |
ai.prompt_submit | prompt is submitted |
ai.tool_use | 智能体 reports tool use |
ai.notification | 智能体 asks for input or permission |
ai.stop | 智能体 turn stops |
ai.exit | 智能体 process exits |
ai.session_end | 智能体 session closes |
surface_changed | 面板 output_generation advanced |
heartbeat | idle keepalive |
dropped | subscriber lagged and events were shed |
收到 dropped frame 后,用 paneflow ps --json 或 paneflow status <target> --json 重新同步。
MCP 桥接
paneflow-mcp 是基于同一个 Paneflow socket 的只读 stdio MCP server。
| Tool | Params | Returns |
|---|---|---|
list_panes | - | 带有 surface_id、name、title、cwd、cmd、workspace 的面板 |
read_pane | target, lines?, offset? | scrollback text |
search_pane | target, pattern, max_matches? | matching lines |
它没有用于输入、提交、聚焦或分割面板的 tool。返回的终端输出会被 fenced 为不可信数据。
生命周期 hook
paneflow-ai-hook 从 stdin 读取 event JSON,发送一个 JSON-RPC
ai.* frame,然后以 0 退出,这样停止的 Paneflow 实例不会破坏
智能体。这个 hook surface 驱动 status、notification、ps、
status 和 watch。
持久化 paneflow hooks setup 仅限 Claude Code。Codex 使用每次
launch 注入的 shim hook。没有 hook surface 的智能体仍然可以运行,
但其状态可能仅限于 process detection。