Esta es la referencia compacta de [Scripting y automatización](/docs/scripting).
Nombra la superficie pública que un script humano o un LLM puede citar
con precisión.

## Verbos CLI

El binario `paneflow` intercepta estos verbos y sale antes de iniciar
la GUI. Los verbos desconocidos salen con código de uso `2` en vez de
lanzar la app silenciosamente.

| Verbo | Método principal o motor | ¿Escribe en paneles? | Uso |
| --- | --- | --- | --- |
| `ls [--human]` | `surface.list` | No | Lista paneles en el espacio de trabajo activo |
| `read <target>` | `surface.read` | No | Lee el scrollback de un panel |
| `search <target> <pattern>` | `surface.search` | No | Busca en el scrollback de un panel |
| `ps [--json]` | `fleet.list` | No | Lista agentes detectados entre espacios de trabajo |
| `status <target> [--json]` | `surface.status` | No | Lee el estado de agente de un panel |
| `new` | `workspace.create` | No | Crea un espacio de trabajo |
| `select <index>` | `workspace.select` | No | Selecciona un espacio de trabajo |
| `split <h\|v>` | `surface.split` | No | Divide un panel |
| `focus <target>` | `surface.focus` | No | Enfoca un panel y su espacio de trabajo |
| `send <target> <text>` | `surface.send_text` | Gate | Prepara o envía texto |
| `key <target> <keystroke>` | `surface.send_keystroke` | Gate | Envía una tecla que no somete |
| `wait --match <sel>` | `surface.read`, `events.subscribe` | No | Bloquea hasta pattern, idle o ambos |
| `watch [--surface <sel>] [--type <event>]` | `events.subscribe` | No | Emite eventos de ciclo de vida y superficie |
| `up <file>` | Motor de spec workspace | Solo prellenado | Crea un workspace declarativo |
| `flow run <file>` | Motor flow | Gate para pasos que envían | Ejecuta un DAG multiagente local |

Alias aceptados por la CLI: `list_panes` apunta a `ls`, `read_pane` a
`read` y `search_pane` a `search`.

## Selectores

| Selector | Ejemplo | Notas |
| --- | --- | --- |
| Id numérico | `paneflow read 42` | Coincide exactamente con `surface_id` |
| Nombre | `paneflow status backend` | Mejor selector para scripts duraderos |
| `cmdline:<substr>` | `paneflow read cmdline:vite` | argv foreground completo en Linux, nombre de ejecutable en macOS y Windows |
| `cwd:<path>` | `paneflow read cwd:/home/me/api` | Coincide con el directorio de trabajo del panel |

Un selector que no coincide con nada o coincide con varios paneles sale
con código `3`, salvo comandos que aceptan explícitamente múltiples
coincidencias como `send --broadcast`, `wait --any` y `wait --all`.

## Códigos de salida

| Código | Significado |
| --- | --- |
| `0` | Éxito |
| `1` | Fallo runtime: instancia inaccesible, panel cerrado, gate rechazado o error de handler |
| `2` | Error de uso CLI |
| `3` | Objetivo no encontrado o ambiguo |
| `4` | Timeout de `wait` o timeout de ready en flow |

## Gates de escritura

La lectura está permitida por defecto. Las escrituras se separan por
capacidad:

| Operación | Gate |
| --- | --- |
| `send` sin `--submit` | `PANEFLOW_IPC_SCRIPTING=1` o `ai_unrestricted` |
| `send --submit` | `PANEFLOW_IPC_SCRIPTING=1` o `ai_unrestricted` |
| `key` | `PANEFLOW_IPC_SCRIPTING=1` |
| Paso flow con `submit = true` | Capacidad scripting reportada por `system.capabilities` |

`send` no añade carriage return salvo que `--submit` esté presente.
`key` rechaza teclas que someten como `enter`, `ctrl-m` y `ctrl-j`. Un
payload único de `surface.send_text` está limitado a 64 KiB.

Claves de configuración relevantes:

| Clave | Valor por defecto | Significado |
| --- | --- | --- |
| `ai_unrestricted` | `false` | Permite a automatizaciones de IA confiables enviar texto sin el gate de entorno |
| `ai_injection_fence` | `true` | Envuelve el texto de `surface.read` en una envoltura de terminal no confiable |
| `submit_paste_delay_ms` | `70` | Retardo base entre bracketed paste y el carriage return de envío |
| `terminal.env` | ninguno | Variables de entorno inyectadas en nuevos terminales |

## Campos de lectura

`paneflow read <target> --json` y `surface.read` crudo devuelven:

| Campo | Significado |
| --- | --- |
| `text` | Texto de scrollback, fenced por defecto |
| `lines` | Número de líneas devueltas |
| `total_lines` | Total de líneas retenidas |
| `eof` | Si la lectura llegó a la línea retenida más antigua |
| `output_generation` | Contador monótono avanzado por la salida del panel |

Valores por defecto y límites: `lines` vale 200 por defecto y se
limita a 1-4000. `offset` parte del final del buffer. Un offset fuera
de rango es un error invalid-params.

El parámetro JSON-RPC `fenced` usa `ai_injection_fence` por defecto.
El flag CLI `--raw` pasa `fenced: false`.

## Campos de estado de agente

`paneflow ps --json` devuelve `{"agents":[...]}`. `paneflow status
<target> --json` devuelve un objeto de estado.

| Campo | Significado |
| --- | --- |
| `pid` | Id de proceso del agente, si se conoce |
| `tool` | Familia de agente como `claude`, `codex`, `opencode` o `gemini` |
| `state` | `thinking`, `waiting_for_input`, `finished`, `errored`, `stalled`, `idle` o `unknown_running` |
| `hooked` | Si los eventos de hook de ciclo de vida están conectados |
| `reason` | Razón de detección, incluido `no_hook` |
| `surface_id` | Id del panel |
| `surface_name` | Nombre del panel |
| `workspace` | Índice del espacio de trabajo |
| `active_tool_name` | Herramienta que se está ejecutando dentro del agente |
| `message` | Prompt o texto de permiso en espera |
| `last_result` | Resumen del último turno, si está disponible |
| `waiting_ms` | Tiempo pasado esperando input |
| `idle_ms` | Tiempo desde la última actividad observada |
| `output_generation` | Contador de salida del panel, en `status` |

Una flota vacía es `{"agents":[]}` con código de salida `0`. Un panel
sin agente rastreado devuelve estado idle, no un error.

## Spec workspace

`paneflow up <file>` lee una spec workspace TOML.

| Campo top-level | Tipo | Valor por defecto | Notas |
| --- | --- | --- | --- |
| `name` | string | `"Workspace"` | Título del espacio de trabajo |
| `layout` | string | `"even_h"` | `even_h`, `even_v`, `main_vertical` o `tiled` |
| `port_base` | integer | `3000` | Base para la asignación `${port_offset}` |
| `[[panes]]` | array | requerido | Una entrada por panel |

| Campo de panel | Tipo | Valor por defecto | Notas |
| --- | --- | --- | --- |
| `cwd` | string | ninguno | Debe existir tras expansión y canonicalization |
| `agent` | string | ninguno | Nombre de launcher de agente, mutuamente exclusivo con `command` |
| `command` | string | ninguno | Comando crudo, mutuamente exclusivo con `agent` |
| `prompt` | string | ninguno | Prellenado en la entrada de un agente, nunca enviado por `up` |
| `focus` | bool | `false` | Da foco inicial a este panel |
| `env` | table | ninguno | Se fusiona sobre `terminal.env`; soporta `${port_offset}` |
| `name` | string | ninguno | Nombre selector estable |
| `worktree` | string | ninguno | Nombre de rama para un worktree gestionado bajo `<repo>.worktrees/` |
| `copy_env` | bool | `true` | Copia archivos `.env*` ignorados por git al worktree |
| `setup` | string | ninguno | Comando ejecutado antes del lanzamiento |
| `setup_timeout_secs` | integer | `300` | Timeout de setup |
| `worktree_teardown` | string | `"auto"` | `auto` elimina worktrees limpios al cerrar; `keep` los conserva |

`${port_offset}` solo se sustituye dentro de valores `env`. Las claves
desconocidas son errores. La creación de workspace valida rutas antes
de crear paneles.

## Spec flow

`paneflow flow run <file>` lee una spec flow TOML y la ejecuta contra
la instancia Paneflow actual.

| Campo | Tipo | Notas |
| --- | --- | --- |
| `id` | string | Id de paso requerido y único |
| `needs` | array | Dependencias; en `foreach`, espera todas las instancias |
| `foreach` | array | Fan-out, una instancia por item |
| `pane` | inline table | Crea un panel usando campos de panel workspace |
| `send` | inline table | `{ target, text, submit? }`; requiere una dependencia |
| `ready` | table | `{ pattern, timeout_secs? }`; barrera regex |
| `capture` | table | `{ var, lines }`; captura 1-500 líneas después de `ready` |
| `submit` | bool | Envía el prompt de un panel creado; requiere acceso scripting |

Variables:

| Variable | Alcance |
| --- | --- |
| `${item}` | Pasos `foreach`: `cwd`, `name`, `worktree`, `env`, `send.target`, `ready.pattern`, prompts y textos |
| `${var}` | Valores capturados dentro de `send.text` y `pane.prompt` que se envía |
| `${var.<item>}` | Capturas de un grupo `foreach` |

El runner valida claves desconocidas, dependencias faltantes, ciclos de
dependencias, regex inválidas, capturas indefinidas, presupuesto de
paneles y timeouts faltantes antes de ejecutar. `Ctrl-C` detiene el
bucle de orquestación; los paneles creados permanecen en Paneflow.

## Conexión JSON-RPC

| Propiedad | Valor |
| --- | --- |
| Endpoint Linux | `$XDG_RUNTIME_DIR/paneflow/paneflow.sock` |
| Endpoint macOS | Directorio runtime del usuario, mismo nombre de socket Paneflow |
| Endpoint Windows | `\\.\pipe\paneflow` |
| Framing | JSON-RPC 2.0 delimitado por líneas |
| Modelo de petición | Una petición por conexión, salvo `events.subscribe` |
| Confianza local | Mismo usuario únicamente; sin listener de red, sin token, sin TLS |
| Backpressure | Límite de conexiones y colas de eventos acotadas devuelven errores estructurados o frames `dropped` |

Sondea capacidades en runtime:

```bash
printf '%s\
' '{"jsonrpc":"2.0","method":"system.capabilities","params":{},"id":1}' \
  | nc -U "$PANEFLOW_SOCKET_PATH"
```

## Métodos JSON-RPC

| Método | Params | Retorno o notas |
| --- | --- | --- |
| `system.ping` | - | Check de vida |
| `system.capabilities` | - | `{scripting, methods[]}` |
| `system.identify` | - | `{name, version, protocol}` |
| `workspace.list` | - | Espacios de trabajo con índices y títulos |
| `workspace.current` | - | Espacio de trabajo activo |
| `workspace.create` | `name?`, `cwd?`, `layout?` | Crea un espacio de trabajo |
| `workspace.select` | `index` | Cambia de espacio de trabajo |
| `workspace.close` | `index?` | Cierra un espacio de trabajo |
| `workspace.up` | `name`, `layout`, `panes[]` | Spawn declarativo usado por `up` y raíces flow |
| `workspace.restore_layout` | `layout` | Aplica un árbol layout |
| `surface.list` | - | `{surfaces:[{surface_id,name,title,cwd,cmd,workspace}]}` |
| `surface.read` | `surface_id`, `lines?`, `offset?`, `fenced?` | Scrollback y `output_generation` |
| `surface.search` | `surface_id`, `pattern`, `max_matches?` | Coincidencias substring case-insensitive |
| `surface.rename` | `surface_id`, `name` | Renombra o borra el nombre de un panel |
| `surface.focus` | `surface_id` | Enfoca panel y espacio de trabajo |
| `surface.status` | `surface_id` | Estado de agente para un panel |
| `surface.send_text` | `surface_id`, `text`, `submit?`, `paste?` | Escritura de texto PTY con gate |
| `surface.send_keystroke` | `surface_id`, `keystroke` | Tecla no submit gated por env |
| `surface.split` | `direction`, `surface_id?`, `cwd?`, `command?`, `prompt?`, `env?`, `name?`, `managed_worktree?` | Divide un panel |
| `fleet.list` | - | Snapshot read-only de la flota |
| `events.subscribe` | `surfaces?`, `types?` | Stream persistente de eventos delimitado por líneas |
| `ai.session_start` | payload hook | Telemetría de ciclo de vida |
| `ai.prompt_submit` | payload hook | Telemetría de ciclo de vida |
| `ai.tool_use` | payload hook | Telemetría de ciclo de vida |
| `ai.notification` | payload hook | Telemetría de ciclo de vida |
| `ai.stop` | payload hook | Telemetría de ciclo de vida |
| `ai.exit` | payload hook | Telemetría de ciclo de vida |
| `ai.session_end` | payload hook | Telemetría de ciclo de vida |

Los fallos estructurados usan envolturas JSON-RPC `error`: `-32602`
invalid params, `-32601` gated method, `-32001` permission y `-32000`
backpressure. Algunos errores de validación legacy aún llegan como
`{"error":"..."}` dentro de `result`; los clientes deben tratar ambas
formas como fallos.

## Eventos

`paneflow watch` y `events.subscribe` crudo emiten JSON delimitado por
líneas. El primer frame confirma la suscripción.

| Tipo de evento | Significado |
| --- | --- |
| `subscribed` | Suscripción confirmada |
| `ai.session_start` | La sesión de agente empieza |
| `ai.prompt_submit` | Se envía un prompt |
| `ai.tool_use` | El agente reporta uso de herramienta |
| `ai.notification` | El agente pide input o permiso |
| `ai.stop` | El turno del agente se detiene |
| `ai.exit` | El proceso del agente sale |
| `ai.session_end` | La sesión de agente se cierra |
| `surface_changed` | El `output_generation` del panel avanzó |
| `heartbeat` | Keepalive idle |
| `dropped` | El subscriber se retrasó y se descartaron eventos |

Después de un frame `dropped`, resincroniza con `paneflow ps --json` o
`paneflow status <target> --json`.

## Puente MCP

`paneflow-mcp` es un servidor MCP stdio read-only sobre el mismo socket
Paneflow.

| Herramienta | Params | Retorno |
| --- | --- | --- |
| `list_panes` | - | Paneles con `surface_id`, `name`, `title`, `cwd`, `cmd`, `workspace` |
| `read_pane` | `target`, `lines?`, `offset?` | Texto de scrollback |
| `search_pane` | `target`, `pattern`, `max_matches?` | Líneas coincidentes |

No tiene herramienta para escribir, enviar, enfocar o dividir paneles.
La salida de terminal devuelta está fenced como datos no confiables.

## Hooks de ciclo de vida

`paneflow-ai-hook` lee JSON de evento en stdin, publica un frame
JSON-RPC `ai.*` y sale con `0` para que una instancia Paneflow detenida
no rompa el agente. La superficie de hooks alimenta estado,
notificaciones, `ps`, `status` y `watch`.

`paneflow hooks setup` persistente está limitado a Claude Code. Codex
usa hooks de shim por lanzamiento. Los agentes sin superficie de hooks
siguen ejecutándose, pero su estado puede limitarse a detección de
proceso.

## Relacionado

- [Guía de scripting](/docs/scripting)
- [Conductor](/docs/conductor)
- [Esquema de configuración](/docs/configuration/schema)