Transport de socket RPC
Le daemon expose une interface JSON-RPC 2.0 via un flux IPC local, un socket de domaine Unix sous Unix et un tube nommé (named pipe) sous Windows. Il s’agit du transport principal pour les clients locaux comme zerocode. La passerelle HTTP/WS demeure pour les webhooks, le tableau de bord web et les consommateurs REST distants.
Résolution de point de terminaison
Chaque répertoire de données dispose de son propre point de terminaison, de sorte que plusieurs instances de démon sur la même machine n’entrent pas en collision. Le répertoire de données est dérivé du répertoire de configuration (--config-dir / ZEROCLAW_CONFIG_DIR, ou ZEROCLAW_DATA_DIR).
| OS | Point de terminaison par défaut |
|---|---|
| Linux | <data_dir>/daemon.sock (socket de domaine Unix) |
| macOS | <data_dir>/daemon.sock (socket de domaine Unix) |
| Windows | \\.\pipe\zeroclaw-<hash> où <hash> est dérivé de data_dir |
Remplacez par la variable d’environnement ZEROCLAW_SOCKET sur l’une ou l’autre plateforme :
sh
export ZEROCLAW_SOCKET=/tmp/my-zeroclaw.sock
zeroclaw daemon
PowerShell
$env:ZEROCLAW_SOCKET = '\\.\pipe\my-zeroclaw'
zeroclaw daemon
Protocole de communication
NDJSON (JSON délimité par des sauts de ligne). Chaque ligne est un message JSON-RPC 2.0 complet. Aucun cadrage HTTP, aucun préfixe de longueur. Le cadrage est identique sur toutes les plateformes ; les canaux nommés transportent le même flux d’octets que les sockets Unix.
{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":1},"id":1}\n
{"jsonrpc":"2.0","result":{"protocolVersion":1,"serverVersion":"0.8.5"},"id":1}\n
Établissement de connexion
Le premier appel RPC doit être initialize. Le démon rejette toutes les autres méthodes jusqu’à ce que initialize réussisse. Une incompatibilité de version du protocole produit une erreur structurée avec le code -32011.
{
"jsonrpc": "2.0",
« méthode »: "initialiser",
"paramètres": {
"protocolVersion": 1
},
"id": 1
}
Le point de terminaison ne nécessite pas de jeton d’appairage. Le contrôle d’accès est géré par le système d’exploitation :
- Unix : le socket est
0o600, le répertoire parent est0o700. - Windows : l’ACL du canal nommé est par défaut définie sur l’utilisateur créateur et
SYSTEM.
Méthodes
| Méthode | Direction | Description |
|---|---|---|
initialize | client -> daemon | Authentifiez-vous et négociez la version du protocole |
session/new | client -> daemon | Créer une session d’agent (nécessite agentAlias ; cwd et sessionId sont facultatifs ; keep_siblings, également facultatif, désactive l’éviction des sessions sœurs inactives du même mode pour les clients gérant eux-mêmes le cycle de vie de leurs sessions sœurs) |
session/close | client -> daemon | Fermer et nettoyer une session |
session/prompt | client -> daemon | Exécuter un tour (diffusé via les notifications session/update) |
session/cancel | client -> daemon | Annuler un tour en cours |
status | client -> daemon | Version du serveur, version du protocole, liste des sessions actives |
session/update | démon -> client | Notification en streaming pendant un tour (fragments de texte, appels d’outils, approbations) |
elicitation/create | démon -> client | Demander une saisie interactive pour les flux ask-user et poll |
Requêtes bidirectionnelles
Chaque partie peut envoyer une requête sur le socket établi. Le récepteur doit répondre avec le même id et exactement l’un de result ou error. Chaque pair utilise sa propre séquence zc-out-<number> pour les requêtes sortantes ; le préfixe ne constitue pas un espace de noms globalement unique. La corrélation reste directionnelle : chaque pair ne met en correspondance les réponses qu’avec sa propre table des requêtes en attente ; le même ID textuel peut donc être en vol indépendamment dans des directions opposées.
{"jsonrpc":"2.0",« méthode »:"elicitation/create","paramètres":{"message":"Continuer ?"},"id":zc-out-0}
{"jsonrpc":"2.0","résultat":{action:"accepter","contenu":{"réponse":"oui"}},"id":zc-out-0}
Une réponse explicite "result": null est une réussite et résout tout de même l’appelant en attente. Un objet error le résout comme un échec. Si le pair ne répond pas, l’opération ask-user ou poll à l’origine conserve son comportement actuel en matière de délai d’attente.
Chaque trame doit être un objet JSON avec "jsonrpc": "2.0". Les requêtes doivent contenir une chaîne de caractères method ; si params est présent, il doit être un objet ou un tableau. Les réponses doivent contenir un id de type chaîne, numérique ou null, ainsi qu’exactement un membre de réponse. Un JSON non valide produit -32700 (erreur d’analyse). Une enveloppe mal formée de type requête produit -32600 (requête non valide), en utilisant son identifiant de requête valide lorsqu’il est possible de le récupérer. Une enveloppe mal formée de type réponse est consignée sans le contenu de la trame et ignorée sans réponse, car renvoyer son identifiant pourrait faire aboutir une requête sans rapport dans la direction opposée. Les enveloppes dont la direction est ambiguë utilisent id: null. Les identifiants de réponse valides mais inconnus sont également consignés et ignorés plutôt que de recevoir une réponse, ce qui empêche les boucles de réponses.
Activer le streaming
session/prompt retourne le résultat final lorsque le tour se termine. Pendant l’exécution, le démon envoie des notifications session/update avec des événements incrémentaux :
{"jsonrpc":"2.0",« méthode »:"session/mise à jour","paramètres":{"sessionId":"...","type":agent_message_chunk,« texte »:Bonjour}}
{"jsonrpc":"2.0",« méthode »:"session/mise à jour","paramètres":{"sessionId":"...","type":"tool_call",toolCallId:tc_1,« nom »:bash,rawInput:{...}}}
{"jsonrpc":"2.0",« méthode »:"session/mise à jour","paramètres":{"sessionId":"...","type":"résultat_de_l'outil",toolCallId:tc_1,« nom »:bash,rawOutput:"..."}}
Types d’événements : agent_message_chunk, agent_thought_chunk, tool_call, tool_result, approval_request.
Mode éphémère
zeroclaw daemon --ephemeral suit les clients connectés et s’arrête automatiquement lorsque le dernier se déconnecte (après un délai de grâce de 1 seconde). Une reconnexion pendant le délai de grâce annule l’arrêt. Le daemon ne se terminera pas tant qu’au moins un client ne s’est pas connecté.
Les démons démarrés sans --ephemeral ignorent le nombre de clients et s’exécutent jusqu’à leur arrêt explicite.
Sécurité
- Répertoire du socket Unix :
0o700(propriétaire uniquement) - Fichier de socket Unix :
0o600(propriétaire uniquement) - Canal nommé Windows : l’ACL par défaut accorde l’accès à l’utilisateur créateur et à
SYSTEM SO_PEERCREDsous Linux fournit le PID et l’UID du processus de connexion pour la journalisation d’audit ; Windows enregistrepipe:localcomme étiquette du pair
Test rapide
Démarrez le daemon dans un terminal :
sh
zeroclaw daemon
Dans un second terminal sous Unix, connectez-vous avec socat :
sh
socat READLINE UNIX-CONNECT:~/.zeroclaw/data/daemon.sock
Collez les lignes une par une :
{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":1},"id":1}
{"jsonrpc":"2.0","method":"status","params":{},"id":2}
Sous Windows, utilisez n’importe quel client de canal nommé (PowerShell [System.IO.Pipes.NamedPipeClientStream], nc via WSL, ou exécutez simplement zerocode).
Composants internes
La couche de répartition se trouve dans crates/zeroclaw-runtime/src/rpc/ :
| Fichier | Rôle |
|---|---|
transport.rs | Trait RpcTransport |
turn.rs | execute_turn() exécuteur de tour partagé |
session.rs | RpcSession, SessionStore |
dispatch.rs | Routage de méthode RpcDispatcher |
local.rs | LocalTransport + écouteur (socket Unix / canal nommé Windows) |
wss.rs | WSS (WebSocket Secure) transport + accepteur TLS |
attachments.rs | Traitement des téléchargements de fichiers, déduplication, génération de marqueurs |
Le trait RpcTransport est conçu de sorte que des transports supplémentaires (vsock, IPC personnalisé) s’intègrent sans toucher à la logique de dispatch ou de session. Le module local.rs encapsule les primitives Unix et Windows derrière une seule structure LocalTransport à l’aide de tokio::io::split, de sorte que la boucle de lecture/écriture soit partagée entre les deux plateformes.