CPN Org — Essaim d'agents
Distribuer une tâche sur un cluster d'agents via le protocole A2A Hermes
(https://hermes-agent.nousresearch.com/docs/user-guide/messaging/a2a). Router
chaque unité par la capacité requise, la machine cible et la pression ressource
live du runner.
Ce skill est un routeur, pas un transport. Il décide quoi va où ; A2A et
delegate_task font la livraison. Il ne les remplace pas.
When to Use
- Une tâche se fragmente en unités exigeant des capacités différentes (modèle,
outil, permission) ou des machines différentes (GPU vs CPU, isolé vs partagé).
- Le runner est sous pression ressource et les unités doivent être réparties,
pas empilées.
When NOT to Use
- Quelques PR sœurs dans un dépôt →
cpn-async (workspaces jj, pas de cluster).
- Une unité, une machine →
cpn-stack ; ne pas lancer d'essaim pour une unité.
Procedure
Activer A2A sur chaque hôte qui exécutera une unité. Dans config.yaml :
gateway.platforms.a2a.enabled: true et un port via extra.port ; lister
les pairs sous a2a_agents. Puis hermes tools enable a2a sur chaque hôte.
Entrant : Agent Card à GET /.well-known/agent-card.json et JSON-RPC 2.0 à
POST / (SendMessage, SendStreamingMessage sur SSE, GetTask,
ListTasks, CancelTask, SubscribeToTask, plus CRUD de notifications
push). Les tâches s'injectent dans la session gateway live (même
agent/mémoire/outils), clé par contextId pour le multi-tour.
Énumérer les unités avec leurs exigences — tag de capacité (modèle /
outil / permission), machine cible, poids ressource approximatif
(cpu/mem/io). Enregistrer la liste dans l'issue liée avant d'envoyer.
Sonder la pression runner avant d'assigner. Lire la charge live des
machines candidates ; une unité dont le poids dépasse la marge d'un hôte doit
bouger ou attendre. Ne jamais co-localiser deux unités lourdes sur un runner
chargé. Re-sonder avant chaque (ré)envoi, pas une fois au début.
Router chaque unité par correspondance de capacité → adéquation ressource
→ hôte éligible le moins chargé. L'hôte cible doit être A2A-appelable
(vérifier sa carte avec a2a_discover(url)). Remplacer l'hôte par défaut
uniquement avec une raison explicite
(# ponytail: placement manuel — <raison>).
Envoyer sur A2A. Fan une tâche vers chaque pair annonçant une capacité
avec a2a_orchestrate(capability, message, mode?) — modes all (toutes les
réponses), first (premier succès), best (réponse réussie la plus longue ;
un fan-out tout-erreur rapporte les échecs au lieu d'en choisir un). Pour une
unité ciblée unique, a2a_call(agent, message, context_id?) (multi-tour via
context_id) ; a2a_history(context_id, limit?) rappelle un échange
précédent. Le parent re-vérifie la gate de chaque enfant via terminal avant
de faire confiance à l'agrégat — les rapports d'enfants ne sont pas des
preuves.
Réconcilier. Collecter les résultats, remonter un enfant bloqué comme
rapport BLOCKED: avec preuve, et ne merger que les unités passées.
Pitfalls
- Router uniquement par capacité en ignorant la pression live empile les unités
lourdes sur un runner chaud — mesurer la marge, puis placer.
- Traiter le « done » auto-déclaré d'un enfant comme vérifié — re-exécuter sa
gate dans le parent avant de promouvoir.
- Lancer un essaim pour une unité —
cpn-stack est l'outil plus petit et
correct.
- A2A non authentifié ne lie que
127.0.0.1. Distant : bearer token et
A2A_HOST. A2A_PEER_TOKENS="name:token,…" définit l'identité par pair. Le
texte entrant est filtré contre l'injection et ne peut pas atteindre les
commandes slash opérateur ; les réponses en forme d'identifiants sont masquées
; chaque échange est journalisé dans ~/.hermes/a2a_audit.jsonl. Plafond de
tours par contexte (A2A_MAX_PINGPONG_TURNS, défaut 5) arrête le ping-pong
agent↔agent. Stdlib uniquement — pas de a2a-sdk.
Verification
curl --fail --silent --show-error http://<hôte>:9900/.well-known/agent-card.json
# après envoi : chaque unité a un hôte + tag de capacité enregistrés
# pression : re-sonder les hôtes candidats avant chaque (ré)envoi
# réconcilier : gh issue view <N> --repo cloud-pi-native/console
Utiliser a2a_discover pour valider la carte d'agent ; curl est un remplacement
rapide quand l'outillage A2A est indisponible.
A2A API (Hermes Agent-to-Agent, v1.0)
L'essaim roule sur l'outillage a2a Hermes / serveur JSON-RPC entrant. Activer
dans config.yaml (gateway.platforms.a2a.enabled: true, port entrant via
extra.port ; pairs sous a2a_agents), puis hermes tools enable a2a.
Sortant (appeler d'autres agents) :
a2a_discover(url) — récupère + résume la carte d'agent d'un pair.
a2a_call(agent, message, context_id?) — envoie une tâche, reçoit la réponse
; multi-tour via context_id.
a2a_list() — pairs configurés, conversations sauvegardées, métriques.
a2a_history(context_id, limit?) — rappelle une conversation A2A passée.
a2a_orchestrate(capability, message, mode?) — fan une tâche vers chaque pair
annonçant une capacité. Modes : all (toutes les réponses), first (premier
succès), best (réponse réussie la plus longue ; un fan-out tout-erreur
rapporte les échecs au lieu d'en choisir un).
Entrant (être appelable) : sert la carte d'agent v1.0 à
GET /.well-known/agent-card.json et JSON-RPC 2.0 à POST / — méthodes
canoniques SendMessage, SendStreamingMessage (SSE), GetTask, ListTasks,
CancelTask, SubscribeToTask, plus CRUD de notifications push. Les tâches
s'injectent dans la session gateway live, clé par contextId pour le
multi-tour.
Sécurité : pas de token ⇒ liaison 127.0.0.1 seulement (distant : bearer
token et A2A_HOST) ; A2A_PEER_TOKENS="name:token,…" donne l'identité par
pair ; le texte entrant est filtré contre l'injection et ne peut pas atteindre
les commandes slash opérateur ; les réponses en forme d'identifiants sont
masquées ; chaque échange est journalisé dans ~/.hermes/a2a_audit.jsonl ;
plafond de tours par contexte (A2A_MAX_PINGPONG_TURNS, défaut 5) arrête le
ping-pong agent↔agent. Stdlib uniquement — pas de a2a-sdk.
Test rapide (depuis un autre agent / machine) :
curl http://your-host:9900/.well-known/agent-card.json
curl -X POST http://your-host:9900/ -H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{"jsonrpc":"2.0","id":1,"method":"SendMessage",
"params":{"message":{"messageId":"m1","role":"ROLE_USER",
"parts":[{"text":"What tools do you have?"}]}}}'
See also
cpn-async — flux parallèles in-repo quand aucun cluster d'agents n'est
nécessaire.
cpn-stack — isolation d'une unité (l'outil plus petit pour un flux unique).
cpn-dev-workflow — boucle complète ; gate de validation d'hypothèses AVANT
tout fan-out.
1---2name: cpn-swarm3description: À utiliser quand vous distribuez une tâche cloud-pi-native sur un cluster d'agents via A2A — routage par capacité, machine et pression runner.4license: Apache-2.05---67# CPN Org — Essaim d'agents89Distribuer une tâche sur un cluster d'agents via le protocole A2A Hermes10(<https://hermes-agent.nousresearch.com/docs/user-guide/messaging/a2a>). Router11chaque unité par la capacité requise, la machine cible et la pression ressource12live du runner.1314Ce skill est un routeur, pas un transport. Il décide _quoi va où_ ; A2A et15`delegate_task` font la livraison. Il ne les remplace pas.1617## When to Use1819- Une tâche se fragmente en unités exigeant des capacités différentes (modèle,20 outil, permission) ou des machines différentes (GPU vs CPU, isolé vs partagé).21- Le runner est sous pression ressource et les unités doivent être réparties,22 pas empilées.2324## When NOT to Use2526- Quelques PR sœurs dans un dépôt → `cpn-async` (workspaces jj, pas de cluster).27- Une unité, une machine → `cpn-stack` ; ne pas lancer d'essaim pour une unité.2829## Procedure30311. **Activer A2A sur chaque hôte** qui exécutera une unité. Dans `config.yaml` :32 `gateway.platforms.a2a.enabled: true` et un port via `extra.port` ; lister33 les pairs sous `a2a_agents`. Puis `hermes tools enable a2a` sur chaque hôte.34 Entrant : Agent Card à `GET /.well-known/agent-card.json` et JSON-RPC 2.0 à35 `POST /` (`SendMessage`, `SendStreamingMessage` sur SSE, `GetTask`,36 `ListTasks`, `CancelTask`, `SubscribeToTask`, plus CRUD de notifications37 push). Les tâches s'injectent dans la session gateway live (même38 agent/mémoire/outils), clé par `contextId` pour le multi-tour.39402. **Énumérer les unités** avec leurs exigences — tag de capacité (modèle /41 outil / permission), machine cible, poids ressource approximatif42 (cpu/mem/io). Enregistrer la liste dans l'issue liée avant d'envoyer.43443. **Sonder la pression runner** avant d'assigner. Lire la charge live des45 machines candidates ; une unité dont le poids dépasse la marge d'un hôte doit46 bouger ou attendre. Ne jamais co-localiser deux unités lourdes sur un runner47 chargé. Re-sonder avant chaque (ré)envoi, pas une fois au début.48494. **Router chaque unité** par correspondance de capacité → adéquation ressource50 → hôte éligible le moins chargé. L'hôte cible doit être A2A-appelable51 (vérifier sa carte avec `a2a_discover(url)`). Remplacer l'hôte par défaut52 uniquement avec une raison explicite53 (`# ponytail: placement manuel — <raison>`).54555. **Envoyer sur A2A.** Fan une tâche vers chaque pair annonçant une capacité56 avec `a2a_orchestrate(capability, message, mode?)` — modes `all` (toutes les57 réponses), `first` (premier succès), `best` (réponse réussie la plus longue ;58 un fan-out tout-erreur rapporte les échecs au lieu d'en choisir un). Pour une59 unité ciblée unique, `a2a_call(agent, message, context_id?)` (multi-tour via60 `context_id`) ; `a2a_history(context_id, limit?)` rappelle un échange61 précédent. Le parent re-vérifie la gate de chaque enfant via `terminal` avant62 de faire confiance à l'agrégat — les rapports d'enfants ne sont pas des63 preuves.64656. **Réconcilier.** Collecter les résultats, remonter un enfant bloqué comme66 rapport `BLOCKED:` avec preuve, et ne merger que les unités passées.6768## Pitfalls6970- Router uniquement par capacité en ignorant la pression live empile les unités71 lourdes sur un runner chaud — mesurer la marge, puis placer.72- Traiter le « done » auto-déclaré d'un enfant comme vérifié — re-exécuter sa73 gate dans le parent avant de promouvoir.74- Lancer un essaim pour une unité — `cpn-stack` est l'outil plus petit et75 correct.76- A2A non authentifié ne lie que `127.0.0.1`. Distant : bearer token _et_77 `A2A_HOST`. `A2A_PEER_TOKENS="name:token,…"` définit l'identité par pair. Le78 texte entrant est filtré contre l'injection et ne peut pas atteindre les79 commandes slash opérateur ; les réponses en forme d'identifiants sont masquées80 ; chaque échange est journalisé dans `~/.hermes/a2a_audit.jsonl`. Plafond de81 tours par contexte (`A2A_MAX_PINGPONG_TURNS`, défaut 5) arrête le ping-pong82 agent↔agent. Stdlib uniquement — pas de `a2a-sdk`.8384## Verification8586```bash87curl --fail --silent --show-error http://<hôte>:9900/.well-known/agent-card.json88# après envoi : chaque unité a un hôte + tag de capacité enregistrés89# pression : re-sonder les hôtes candidats avant chaque (ré)envoi90# réconcilier : gh issue view <N> --repo cloud-pi-native/console91```9293Utiliser `a2a_discover` pour valider la carte d'agent ; curl est un remplacement94rapide quand l'outillage A2A est indisponible.9596## A2A API (Hermes Agent-to-Agent, v1.0)9798L'essaim roule sur l'outillage `a2a` Hermes / serveur JSON-RPC entrant. Activer99dans `config.yaml` (`gateway.platforms.a2a.enabled: true`, port entrant via100`extra.port` ; pairs sous `a2a_agents`), puis `hermes tools enable a2a`.101102**Sortant (appeler d'autres agents) :**103104- `a2a_discover(url)` — récupère + résume la carte d'agent d'un pair.105- `a2a_call(agent, message, context_id?)` — envoie une tâche, reçoit la réponse106 ; multi-tour via `context_id`.107- `a2a_list()` — pairs configurés, conversations sauvegardées, métriques.108- `a2a_history(context_id, limit?)` — rappelle une conversation A2A passée.109- `a2a_orchestrate(capability, message, mode?)` — fan une tâche vers chaque pair110 annonçant une capacité. Modes : `all` (toutes les réponses), `first` (premier111 succès), `best` (réponse réussie la plus longue ; un fan-out tout-erreur112 rapporte les échecs au lieu d'en choisir un).113114**Entrant (être appelable) :** sert la carte d'agent v1.0 à115`GET /.well-known/agent-card.json` et JSON-RPC 2.0 à `POST /` — méthodes116canoniques `SendMessage`, `SendStreamingMessage` (SSE), `GetTask`, `ListTasks`,117`CancelTask`, `SubscribeToTask`, plus CRUD de notifications push. Les tâches118s'injectent dans la session gateway live, clé par `contextId` pour le119multi-tour.120121**Sécurité :** pas de token ⇒ liaison `127.0.0.1` seulement (distant : bearer122token _et_ `A2A_HOST`) ; `A2A_PEER_TOKENS="name:token,…"` donne l'identité par123pair ; le texte entrant est filtré contre l'injection et ne peut pas atteindre124les commandes slash opérateur ; les réponses en forme d'identifiants sont125masquées ; chaque échange est journalisé dans `~/.hermes/a2a_audit.jsonl` ;126plafond de tours par contexte (`A2A_MAX_PINGPONG_TURNS`, défaut 5) arrête le127ping-pong agent↔agent. Stdlib uniquement — pas de `a2a-sdk`.128129**Test rapide (depuis un autre agent / machine) :**130131```bash132curl http://your-host:9900/.well-known/agent-card.json133curl -X POST http://your-host:9900/ -H 'Content-Type: application/json' \134 -H 'Authorization: Bearer <token>' \135 -d '{"jsonrpc":"2.0","id":1,"method":"SendMessage",136 "params":{"message":{"messageId":"m1","role":"ROLE_USER",137 "parts":[{"text":"What tools do you have?"}]}}}'138```139140## See also141142- `cpn-async` — flux parallèles in-repo quand aucun cluster d'agents n'est143 nécessaire.144- `cpn-stack` — isolation d'une unité (l'outil plus petit pour un flux unique).145- `cpn-dev-workflow` — boucle complète ; gate de validation d'hypothèses AVANT146 tout fan-out.