Cette page est la référence compacte de [Scripting et automatisation](/docs/scripting).
Elle nomme la surface publique qu'un script humain ou un LLM peut citer exactement.

## Verbes CLI

Le binaire `paneflow` intercepte ces verbes et quitte avant le
démarrage de la GUI. Les verbes inconnus sortent avec le code d'usage
`2` au lieu de lancer l'application silencieusement.

| Verbe | Méthode principale ou moteur | Écrit dans les panneaux ? | Usage |
| --- | --- | --- | --- |
| `ls [--human]` | `surface.list` | Non | Liste les panneaux de l'espace de travail actif |
| `read <target>` | `surface.read` | Non | Lit le scrollback d'un panneau |
| `search <target> <pattern>` | `surface.search` | Non | Recherche dans le scrollback d'un panneau |
| `ps [--json]` | `fleet.list` | Non | Liste les agents détectés dans les espaces de travail |
| `status <target> [--json]` | `surface.status` | Non | Lit l'état agent d'un panneau |
| `new` | `workspace.create` | Non | Crée un espace de travail |
| `select <index>` | `workspace.select` | Non | Sélectionne un espace de travail |
| `split <h\|v>` | `surface.split` | Non | Divise un panneau |
| `focus <target>` | `surface.focus` | Non | Focalise un panneau et son espace de travail |
| `send <target> <text>` | `surface.send_text` | Gate | Prépare ou soumet du texte |
| `key <target> <keystroke>` | `surface.send_keystroke` | Gate | Envoie une touche non soumettante |
| `wait --match <sel>` | `surface.read`, `events.subscribe` | Non | Bloque jusqu'à une regex, l'idle ou les deux |
| `watch [--surface <sel>] [--type <event>]` | `events.subscribe` | Non | Streame les événements de cycle de vie et de surface |
| `up <file>` | Moteur de spec workspace | Préremplissage uniquement | Crée un espace de travail déclaratif |
| `flow run <file>` | Moteur flow | Gate pour les étapes qui soumettent | Lance un DAG multi-agent local |

Alias acceptés par le CLI : `list_panes` mappe vers `ls`,
`read_pane` vers `read` et `search_pane` vers `search`.

## Sélecteurs

| Sélecteur | Exemple | Notes |
| --- | --- | --- |
| Id numérique | `paneflow read 42` | Matche exactement `surface_id` |
| Nom | `paneflow status backend` | Meilleur sélecteur pour des scripts durables |
| `cmdline:<substr>` | `paneflow read cmdline:vite` | argv foreground complet sur Linux, nom d'exécutable sur macOS et Windows |
| `cwd:<path>` | `paneflow read cwd:/home/me/api` | Matche le répertoire de travail du panneau |

Un sélecteur qui ne matche rien ou plusieurs panneaux sort avec le
code `3`, sauf pour les commandes qui acceptent explicitement plusieurs
matches comme `send --broadcast`, `wait --any` et `wait --all`.

## Codes de sortie

| Code | Sens |
| --- | --- |
| `0` | Succès |
| `1` | Échec runtime : instance inaccessible, panneau fermé, gate refusé ou erreur handler |
| `2` | Erreur d'usage CLI |
| `3` | Cible introuvable ou ambiguë |
| `4` | Timeout de `wait` ou timeout de ready flow |

## Gates d'écriture

La lecture est autorisée par défaut. Les écritures sont séparées par
capacité :

| Opération | Gate |
| --- | --- |
| `send` sans `--submit` | `PANEFLOW_IPC_SCRIPTING=1` ou `ai_unrestricted` |
| `send --submit` | `PANEFLOW_IPC_SCRIPTING=1` ou `ai_unrestricted` |
| `key` | `PANEFLOW_IPC_SCRIPTING=1` |
| Étape flow avec `submit = true` | Capacité scripting reportée par `system.capabilities` |

`send` n'ajoute pas de carriage return sauf si `--submit` est présent.
`key` rejette les touches qui soumettent comme `enter`, `ctrl-m` et
`ctrl-j`. Un seul payload `surface.send_text` est limité à 64 KiB.

Clés de configuration pertinentes :

| Clé | Défaut | Sens |
| --- | --- | --- |
| `ai_unrestricted` | `false` | Autorise une automatisation IA de confiance à soumettre du texte sans gate d'environnement |
| `ai_injection_fence` | `true` | Enveloppe le texte `surface.read` dans une enveloppe terminal non fiable |
| `submit_paste_delay_ms` | `70` | Délai de base entre bracketed paste et le carriage return de soumission |
| `terminal.env` | aucun | Variables d'environnement injectées dans les nouveaux terminaux |

## Champs de lecture

`paneflow read <target> --json` et `surface.read` brut retournent :

| Champ | Sens |
| --- | --- |
| `text` | Texte du scrollback, fenced par défaut |
| `lines` | Nombre de lignes retournées |
| `total_lines` | Nombre total de lignes retenues |
| `eof` | Indique si la lecture a atteint la ligne retenue la plus ancienne |
| `output_generation` | Compteur monotone avancé par la sortie du panneau |

Défauts et limites : `lines` vaut 200 par défaut et est clampé entre
1 et 4000. `offset` part de la fin du buffer. Un offset hors limites
est une erreur invalid-params.

Le paramètre JSON-RPC `fenced` utilise `ai_injection_fence` par défaut.
Le flag CLI `--raw` passe `fenced: false`.

## Champs d'état agent

`paneflow ps --json` retourne `{"agents":[...]}`. `paneflow status
<target> --json` retourne un objet de statut.

| Champ | Sens |
| --- | --- |
| `pid` | Id de processus agent, quand connu |
| `tool` | Famille d'agent comme `claude`, `codex`, `opencode` ou `gemini` |
| `state` | `thinking`, `waiting_for_input`, `finished`, `errored`, `stalled`, `idle` ou `unknown_running` |
| `hooked` | Indique si les événements de hook de cycle de vie sont attachés |
| `reason` | Raison de détection, dont `no_hook` |
| `surface_id` | Id de panneau |
| `surface_name` | Nom de panneau |
| `workspace` | Index d'espace de travail |
| `active_tool_name` | Outil en cours dans l'agent |
| `message` | Prompt ou permission en attente |
| `last_result` | Résumé du dernier tour, quand disponible |
| `waiting_ms` | Temps passé à attendre une entrée |
| `idle_ms` | Temps depuis la dernière activité observée |
| `output_generation` | Compteur de sortie du panneau, sur `status` |

Une flotte vide est `{"agents":[]}` avec le code de sortie `0`. Un
panneau sans agent suivi retourne l'état idle, pas une erreur.

## Spec workspace

`paneflow up <file>` lit une spec workspace TOML.

| Champ top-level | Type | Défaut | Notes |
| --- | --- | --- | --- |
| `name` | string | `"Workspace"` | Titre de l'espace de travail |
| `layout` | string | `"even_h"` | `even_h`, `even_v`, `main_vertical` ou `tiled` |
| `port_base` | integer | `3000` | Base pour l'allocation `${port_offset}` |
| `[[panes]]` | array | requis | Une entrée par panneau |

| Champ de panneau | Type | Défaut | Notes |
| --- | --- | --- | --- |
| `cwd` | string | aucun | Doit exister après expansion et canonicalization |
| `agent` | string | aucun | Nom de launcher agent, mutuellement exclusif avec `command` |
| `command` | string | aucun | Commande brute, mutuellement exclusive avec `agent` |
| `prompt` | string | aucun | Prérempli dans l'entrée d'un agent, jamais soumis par `up` |
| `focus` | bool | `false` | Donne le focus initial à ce panneau |
| `env` | table | aucun | Fusionné par-dessus `terminal.env`, supporte `${port_offset}` |
| `name` | string | aucun | Nom de sélecteur stable |
| `worktree` | string | aucun | Nom de branche pour un worktree géré sous `<repo>.worktrees/` |
| `copy_env` | bool | `true` | Copie les fichiers `.env*` gitignored dans le worktree |
| `setup` | string | aucun | Commande lancée avant le démarrage |
| `setup_timeout_secs` | integer | `300` | Timeout de setup |
| `worktree_teardown` | string | `"auto"` | `auto` supprime les worktrees propres à la fermeture, `keep` les conserve |

`${port_offset}` ne se substitue que dans les valeurs `env`. Les clés
inconnues sont des erreurs. La création d'espace de travail valide les
chemins avant de créer les panneaux.

## Spec flow

`paneflow flow run <file>` lit une spec flow TOML et l'exécute contre
l'instance Paneflow courante.

| Champ | Type | Notes |
| --- | --- | --- |
| `id` | string | Id d'étape requis et unique |
| `needs` | array | Dépendances ; sur `foreach`, attend toutes les instances |
| `foreach` | array | Fan-out, une instance par item |
| `pane` | inline table | Spawn un panneau avec les champs de panneau workspace |
| `send` | inline table | `{ target, text, submit? }`, exige une dépendance |
| `ready` | table | `{ pattern, timeout_secs? }`, barrière regex |
| `capture` | table | `{ var, lines }`, capture 1 à 500 lignes après `ready` |
| `submit` | bool | Soumet un prompt de panneau spawné, exige un accès scripting |

Variables :

| Variable | Portée |
| --- | --- |
| `${item}` | Étapes `foreach` : `cwd`, `name`, `worktree`, `env`, `send.target`, `ready.pattern`, prompts et textes |
| `${var}` | Valeurs capturées dans `send.text` et `pane.prompt` soumis |
| `${var.<item>}` | Captures d'un groupe `foreach` |

Le runner valide les clés inconnues, dépendances manquantes, cycles de
dépendances, regex invalides, captures indéfinies, budget de panneaux
et timeouts manquants avant exécution. `Ctrl-C` arrête la boucle
d'orchestration ; les panneaux créés restent dans Paneflow.

## Connexion JSON-RPC

| Propriété | Valeur |
| --- | --- |
| Endpoint Linux | `$XDG_RUNTIME_DIR/paneflow/paneflow.sock` |
| Endpoint macOS | Répertoire runtime utilisateur, même nom de socket Paneflow |
| Endpoint Windows | `\\.\pipe\paneflow` |
| Framing | JSON-RPC 2.0 délimité par lignes |
| Modèle de requête | Une requête par connexion, sauf `events.subscribe` |
| Confiance locale | Même utilisateur uniquement ; pas de listener réseau, pas de token, pas de TLS |
| Backpressure | Cap de connexions et files d'événements bornées retournent des erreurs structurées ou des frames `dropped` |

Sondez les capacités au runtime :

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

## Méthodes JSON-RPC

| Méthode | Params | Retour ou notes |
| --- | --- | --- |
| `system.ping` | - | Check de vivacité |
| `system.capabilities` | - | `{scripting, methods[]}` |
| `system.identify` | - | `{name, version, protocol}` |
| `workspace.list` | - | Espaces de travail avec indexes et titres |
| `workspace.current` | - | Espace de travail actif |
| `workspace.create` | `name?`, `cwd?`, `layout?` | Crée un espace de travail |
| `workspace.select` | `index` | Change d'espace de travail |
| `workspace.close` | `index?` | Ferme un espace de travail |
| `workspace.up` | `name`, `layout`, `panes[]` | Spawn déclaratif utilisé par `up` et les racines flow |
| `workspace.restore_layout` | `layout` | Applique un arbre layout |
| `surface.list` | - | `{surfaces:[{surface_id,name,title,cwd,cmd,workspace}]}` |
| `surface.read` | `surface_id`, `lines?`, `offset?`, `fenced?` | Scrollback et `output_generation` |
| `surface.search` | `surface_id`, `pattern`, `max_matches?` | Matches substring case-insensitive |
| `surface.rename` | `surface_id`, `name` | Renomme ou efface le nom d'un panneau |
| `surface.focus` | `surface_id` | Focalise le panneau et l'espace de travail |
| `surface.status` | `surface_id` | État agent pour un panneau |
| `surface.send_text` | `surface_id`, `text`, `submit?`, `paste?` | Écriture PTY gate |
| `surface.send_keystroke` | `surface_id`, `keystroke` | Touche non soumettante gate par env |
| `surface.split` | `direction`, `surface_id?`, `cwd?`, `command?`, `prompt?`, `env?`, `name?`, `managed_worktree?` | Divise un panneau |
| `fleet.list` | - | Snapshot read-only de la flotte |
| `events.subscribe` | `surfaces?`, `types?` | Stream d'événements persistant délimité par lignes |
| `ai.session_start` | payload hook | Télémétrie de cycle de vie |
| `ai.prompt_submit` | payload hook | Télémétrie de cycle de vie |
| `ai.tool_use` | payload hook | Télémétrie de cycle de vie |
| `ai.notification` | payload hook | Télémétrie de cycle de vie |
| `ai.stop` | payload hook | Télémétrie de cycle de vie |
| `ai.exit` | payload hook | Télémétrie de cycle de vie |
| `ai.session_end` | payload hook | Télémétrie de cycle de vie |

Les échecs structurés utilisent des enveloppes JSON-RPC `error` :
`-32602` invalid params, `-32601` méthode gate, `-32001` permission et
`-32000` backpressure. Certaines erreurs de validation legacy arrivent
encore comme `{"error":"..."}` dans `result` ; les clients doivent
traiter les deux formes comme des échecs.

## Événements

`paneflow watch` et `events.subscribe` brut émettent du JSON délimité
par lignes. La première frame accuse réception de l'abonnement.

| Type d'événement | Sens |
| --- | --- |
| `subscribed` | Abonnement confirmé |
| `ai.session_start` | La session agent démarre |
| `ai.prompt_submit` | Un prompt est soumis |
| `ai.tool_use` | L'agent reporte l'usage d'un outil |
| `ai.notification` | L'agent demande une entrée ou une permission |
| `ai.stop` | Le tour agent s'arrête |
| `ai.exit` | Le processus agent sort |
| `ai.session_end` | La session agent se ferme |
| `surface_changed` | Le `output_generation` du panneau a avancé |
| `heartbeat` | Keepalive idle |
| `dropped` | Le subscriber a pris du retard et des événements ont été supprimés |

Après une frame `dropped`, resynchronisez avec `paneflow ps --json` ou
`paneflow status <target> --json`.

## Pont MCP

`paneflow-mcp` est un serveur MCP stdio read-only au-dessus du même
socket Paneflow.

| Outil | Params | Retour |
| --- | --- | --- |
| `list_panes` | - | Panneaux avec `surface_id`, `name`, `title`, `cwd`, `cmd`, `workspace` |
| `read_pane` | `target`, `lines?`, `offset?` | Texte de scrollback |
| `search_pane` | `target`, `pattern`, `max_matches?` | Lignes correspondantes |

Il n'a aucun outil pour taper, soumettre, focaliser ou diviser des
panneaux. La sortie terminal retournée est fenced comme donnée non
fiable.

## Hooks de cycle de vie

`paneflow-ai-hook` lit le JSON d'événement sur stdin, poste une frame
JSON-RPC `ai.*`, puis sort avec `0` afin qu'une instance Paneflow
arrêtée ne casse pas l'agent. Cette surface de hook alimente le statut,
les notifications, `ps`, `status` et `watch`.

`paneflow hooks setup` persistant est limité à Claude Code. Codex
utilise des hooks de shim par lancement. Les agents sans surface de
hook fonctionnent quand même, mais leur état peut être limité à la
détection de processus.

## Liens associés

- [Guide scripting](/docs/scripting)
- [Conductor](/docs/conductor)
- [Schéma de configuration](/docs/configuration/schema)