这是 [脚本与自动化](/docs/scripting) 的紧凑参考。它命名了人类
脚本或 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：

```bash
printf '%s\
' '{"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。

## 相关

- [脚本指南](/docs/scripting)
- [Conductor](/docs/conductor)
- [配置 schema](/docs/configuration/schema)