Écosystème d'agents
Une boucle de gouvernance en couches. Chaque composant possède exactement une préoccupation ; ils ne se couplent que par des contrats JSON typés, jamais en important les machines à états les uns des autres.
L'objectif immuable $shame est shame-deterministic-instruction-obedience-v1 (skills/shame/immutable_goal.json) : rendre impossible pour les agents du projet d'ignorer des instructions explicites en convertissant l'obéissance aux instructions et le reporting d'achèvement en contrats typés validés par Pydantic, en portes d'extension déterministes et en évaluations agentiques retenues. Le texte prose est uniquement destiné à l'affichage et ne peut pas décider du succès. Chaque membre de l'écosystème nommé ci-dessous DOIT préserver cet objectif à sa frontière.
Le graphe
Rendu avec $create-svg (scene.yml est la source ; régénérer avec skills/create-svg/run.sh render skills/agent-ecosystem/scene.yml skills/agent-ecosystem/ecosystem.svg). Le manifeste d'appartenance lisible par machine est members.json (validé par scripts/membership.py validate ; l'évaluation retenue le maintient à jour). Le SVG ci-dessus et le bloc mermaid ci-dessous sont des illustrations NON NORMATIVES ; le tableau de propriété et les sections ## Ecosystem des membres sont la topologie normative.
flowchart TB
subgraph SHAPE[Façonnage de la génération]
PONY[ponytail\nÉchelle YAGNI, pas de reçus]
end
subgraph TURN[Couche de tour - Session Pi]
SHAME[extension shame\npi.agent_status.v1\nvalider, compiler, avaler]
TRIAGE[triage-error\nvocabulaire d'échec\ncode, cause, next_command]
end
subgraph WORK[Couche de workflow]
ASK[ask\ncompile l'intention en contrats DAG]
TAU[tau\nexécute les DAGs, possède l'acceptation\nreçus de nœuds typés, goal_hash]
end
subgraph OPS[Couche d'opérations]
WD[project-watchdog\nrépartition cron, baux,
portes de preuve, reçus de tick]
HERDR[passerelle ops-herdr\nboîte de réception, quiescence,
lettres mortes TTL]
end
MEM[(Memory\nexemples d'apprentissage,
résolutions de triage,
connaissances du projet)]
PONY -.-> SHAME
SHAME -->|failed.triage.code| TRIAGE
SHAME -->|commandes compilées needs_*| ASK
ASK -->|tau.dag_contract.v1| TAU
TAU -->|reçus de nœuds / handoff v2 porte le statut| SHAME
WD -->|ticket_repair via ask| ASK
WD -->|lit les verdicts| TAU
HERDR -->|codes de triage de lettres mortes| TRIAGE
SHAME -->|exemples étiquetés| MEM
TRIAGE -->|codes créés| MEM
TAU -->|export post-exécution des mauvais reçus de nœuds| MEM
Tableau de propriété
| Composant | Possède | Émet | Consomme | DOIT pour l'objectif immuable $shame |
|---|---|---|---|---|
| agents du projet | obéissance aux instructions à la frontière du tour | rapports pi.agent_status.v1 | instructions de l'opérateur, résultats d'outils, reçus | DOIT reporter le travail gardé comme données de statut typées, utiliser continuing.not_done[].next_command pour le travail inachevé exécutable par l'agent, et ne jamais traiter la prose/les commits/l'opinion du relecteur comme une preuve d'achèvement. |
| triage-error | vocabulaire d'échec (failure_codes.json) | {code, cause, next_command} | texte d'erreur brut de n'importe quelle couche | DOIT faire correspondre un signal brut à un code de catalogue ou créé ; les étiquettes terminales vagues ne peuvent pas devenir des décisions valides. |
| shame | statut de tour (pi.agent_status.v1) et shame.immutable_goal.v1 | objets de statut, objectif immuable, exemples d'apprentissage | codes de triage, étiquettes humaines | DOIT garder la vérité du statut validée par Pydantic, prose-affichage-seulement, et évaluée par porte. |
| extension lazy-report-shame-shame-shame | application de message_end de Pi | paquets de rejet, statut rendu, commandes de suivi | JSON de statut final, registres de continuation | DOIT rejeter le JSON de statut manquant/invalide, supprimer la prose de statut générée par le modèle, rendre à partir de données validées, et mettre en file d'attente les commandes de continuation/escalade compilées. |
| status-json-check.mjs | extraction du statut final et invocation du validateur | résultat du vérificateur avec objet de statut validé | texte de l'assistant | DOIT ne pas décider de la validité du statut avec des regex, des en-têtes de prose, du markdown, du HTML ou un jugement LLM. |
| agent_status_schema.py | légalité du statut Pydantic | passage/échec d'analyse | JSON de statut final | DOIT rendre les états de statut invalides irreprésentables avec extra=forbid, les charges utiles d'état typées, les codes de triage canoniques, et not_done uniquement sur continuing. |
| compile-status-command.mjs | compilation typée statut-vers-commande | commande de suivi exacte ou pas de commande | objet de statut validé par Pydantic | DOIT compiler les charges utiles continuing/needs_* mécaniquement et compiler les états terminaux/humains en aucune commande automatique. |
| agentic-evals | preuve de régression retenue | rapports de préparation | fixtures et commandes | DOIT échouer si la politique de statut par regex/prose revient ou si les invariants du statut Pydantic sont affaiblis. |
| ask | compilation intention-vers-DAG | tau.dag_contract.v1, paquets de récupération | charges utiles d'escalade de statut | DOIT consommer les charges utiles typées needs_* au lieu de la prose d'escalade informelle. |
| tau | exécution et acceptation du DAG | reçus de nœuds, tau.agent_handoff.v1/v2, hachages d'objectifs | contrats DAG, objets de statut intégrés | DOIT posséder les hachages d'objectifs immuables et les reçus d'acceptation typés ; la prose du relecteur ne peut pas remplacer l'acceptation. |
| project-watchdog | répartition planifiée | reçus de tick, portes de preuve, verrous, registres de continuation | tickets GitHub, verdicts tau | DOIT exposer le travail ouvert lisible par machine afin que done puisse échouer pendant que les tickets/portes/prochaines étapes restent non résolus. |
| ops-herdr | transport inter-sessions | enregistrements de boîte de réception, lettres mortes | codes de triage | DOIT transporter les échecs/états inter-sessions comme des enregistrements typés de boîte de réception ou de lettres mortes avec des codes de triage. |
| ponytail | minimalisme de génération | commentaires de dette ponytail: (pas de reçus) | rien du monde des reçus | DOIT ne pas outrepasser les exigences de statut, de reçu, de preuve ou d'évaluation. |
| Memory | rappel | réponses de lecture de stockage/rappel (pas de reçus d'enveloppe ; les rappels sont des observations, jamais enveloppés) | tout ce qui est durable | DOIT stocker les exemples de honte, les résolutions de triage et les connaissances du projet avec lecture ; les rappels sont des observations, pas des reçus d'achèvement. |
| agent-ecosystem | propriété des composants et frontières de reçus | validation pi.receipt_envelope.v1 | charges utiles de frontière | DOIT publier la carte de propriété et exiger le wrapping d'enveloppe aux frontières changeant l'autorité. |
| goal-helper | forme d'objectif centrée sur la preuve | invite/checklist d'objectif immuable | texte d'objectif humain | DOIT lier le succès à la preuve principale, aux critères d'achèvement, à la portée autorisée, à la dérive interdite, au budget de réessai et à la condition d'arrêt. |
pi.receipt_envelope.v1 - l'enveloppe de frontière
Enveloppez une charge utile dans l'enveloppe UNIQUEMENT aux frontières changeant l'autorité : envoi, transfert, acceptation, escalade, fermeture, échec durable. Les objets internes restent non enveloppés (décision YAGNI examinée : pas de bus d'événements universel, pas d'enveloppe sur chaque artefact).
{
"schema": "pi.receipt_envelope.v1",
"receipt_id": "stable-id",
"payload_schema": "pi.agent_status.v1",
"producer": "shame",
"emitted_at": "RFC3339",
"goal_hash": "sha256:<64hex> (optionnel)",
"parent_refs": [
{"receipt_id": "id", "expected_schema": "s", "expected_producer": "p", "digest": "sha256:<64hex> (optionnel)"}
],
"triage_code": "code de catalogue ou créé (optionnel)",
"payload": {}
}
Validez avec :
skills/agent-ecosystem/run.sh validate <envelope.json>
echo '{...}' | skills/agent-ecosystem/run.sh validate -
Règles appliquées par scripts/receipt_envelope.py (Pydantic, extra=forbid) :
triage_code, lorsqu'il est présent, doit être un code de catalogue triage-error ou un code créé*_unclassified_<8hex>- même règle quepi.agent_status.v1.failure.goal_hashetparent_refs[].digestdoivent êtresha256:+ 64 hex minuscules.parent_refsnécessitentgoal_hash: une arête de preuve sans objectif partagé n'est pas fiable et échoue à la validation.- Pydantic prouve UNIQUEMENT la STRUCTURE. La RÉSOLUTION de référence est une étape distincte côté consommateur avec quatre vérifications obligatoires : le reçu référencé existe ; son schéma est égal à
expected_schema; son producteur est égal àexpected_producer; etresolved_parent.goal_hash == envelope.goal_hash(un hachage présent n'est pas un objectif partagé tant qu'il n'est pas comparé). La vérification du condensé s'applique lorsquedigestest défini. Une enveloppe structurellement valide n'est pas encore une enveloppe de confiance. payload.schemaest REQUIS dans chaque charge utile enveloppée et doit être égal àpayload_schemade l'enveloppe ; une charge utile anonyme échoue à la validation.- Les modifications d'ensemble de champs sur tout schéma
extra=forbidsont cassantes par construction ; elles nécessitent une nouvelle version de schéma, jamais une modification sur place.
Conventions de champs JSON partagés
Les champs ci-dessous sont la surface partagée réelle. Un composant « partage » un champ lorsqu'il émet ou valide le même nom, la même forme et la même sémantique que le propriétaire.
| Champ | Forme | Propriétaire | Partagé par |
|---|---|---|---|
schema | id versionné, p. ex. pi.agent_status.v1 | chaque propriétaire de schéma | chaque objet de contrat ; les incréments de version sont additifs ou nouveau-nom |
code (triage) | entrée de catalogue ou <prefix>_unclassified_<8hex> | triage-error | shame failure.triage.code, enveloppe triage_code, lettres mortes herdr, paquets de récupération ask |
cause / next_command | chaîne simple / commande exécutable exacte | triage-error | chaque consommateur d'une classification de triage ; next_command est également le champ de continuation de shame continuing |
goal_hash | sha256: + 64 hex minuscules | tau (paquet d'objectif immuable) | statut shame (optionnel), enveloppe (optionnel), chaque reçu de nœud tau |
verified[] | paires {command, result} | shame | preuve partout où un objet de statut est intégré |
proof[] | chemins/URLs/IDs concrets ; les chemins locaux dans pi.agent_status.v1 doivent exister avant que done ne passe | shame | objets de statut ; les portes de preuve watchdog nomment les mêmes artefacts |
parent_refs[] | {receipt_id, expected_schema, expected_producer, digest?} | enveloppe agent-ecosystem | preuve d'escalade (remplace les chemins ad hoc dans needs_webgpt) |
producer / receipt_id / emitted_at | chaîne / id stable / RFC3339 | enveloppe agent-ecosystem | tout reçu enveloppé à la frontière |
payload_schema | id versionné ; doit être égal à payload.schema lorsque la charge utile en déclare un | enveloppe agent-ecosystem | tout reçu enveloppé à la frontière |
| verdicts terminaux | PASS FAIL BLOCKED NEEDS_ATTENTION | tau | ask rejoint, portes de preuve watchdog, moniteurs de flux |
recoverable / not_this | bool / liste d'exclusion | catalogue triage-error | consommateurs décidant de réessayer vs escalader |
Conventions de triage-error (normatives ici, implémentées là-bas)
- Un signal brut correspond à UN
{code, cause, next_command}; un code générique à une frontière de couche est un bug, pas une classification. - Les entrées du catalogue vivent dans
skills/triage-error/failure_codes.jsonavec{code, layer, match[], cause, next_command, recoverable, not_this[]}. La correspondance est déterministe : la normalisation est exactement" ".join(text.lower().split())(minuscules, tous les espaces blancs réduits en espaces simples, extrémités coupées) ; une entrée correspond lorsque L'UN de ses jetonsmatch[](également en minuscules) est une sous-chaîne du signal normalisé ; lorsque--layerest donné, les entrées avec unlayerdifférent sont ignorées ; la PREMIÈRE entrée correspondante dans l'ordre du fichier gagne. Jamais de regex, jamais de jugement LLM. Interdits comme classifications terminales (ce sont des symptômes, pas des causes, et doivent être re-triés à partir du signal sous-jacent) :NEEDS_ATTENTION,BLOCKED,browser_handler_timeout,unknown_error,generic_failure, et tout mot de verdict terminal nu. - Les signaux non correspondants créent
<layer-ou-inconnu>_unclassified_<8hex>où les 8 caractères hex sont les 8 premiers du sha256 du texte du signal normalisé, de sorte que le même signal crée toujours le même code. La création ouvre la boucle ticket + agentic-eval + mémoire. Seuil de récurrence : la DEUXIÈME observation du même code créé déclenche une promotion ou un alias. Représentation d'alias : une cartealiasesde premier niveau dans le fichier du catalogue mappe code créé -> code canonique ; parce que la création est déterministe sur le signal normalisé, un signal récurrent re-crée le même code et le classificateur le résout à travers la carte vers l'entrée canonique (enregistrée commealiased_from) ; le code créé n'est jamais une deuxième identité canonique. Les effets secondaires ticket/eval/mémoire sont idempotents par code créé (clé par la chaîne de code). - Chaque composant de l'écosystème qui nomme un échec utilise un code de catalogue ou créé. Les validateurs Pydantic (schéma de statut, enveloppe) l'appliquent au moment de l'analyse, de sorte qu'une étiquette ambiguë ne peut pas exister dans un objet valide.
Décisions de conception (issues de la revue externe)
- La rigueur s'applique aux DÉCISIONS, pas aux observations. Gardez les preuves brutes permissives ; gardez les résultats acceptés stricts. Une observation typée
unknownest légale ; une décision ambiguë ne l'est pas. - Les codes créés
*_unclassified_*ont un cycle de vie provisoire : promouvoir au catalogue ou créer un alias vers un code existant lorsqu'ils reviennent ; ne les laissez jamais proliférer. - Les modifications de schéma sont additives ; les changements cassants de forme obtiennent une nouvelle version (modèle
tau.agent_handoff.v2), jamais de modifications sur place. - Ne construisez pas : un bus d'événements de gouvernance universel ; des reçus pour les commentaires ponytail, les rappels Memory, ou les nouvelles tentatives internes.
Appartenance
Une compétence ou une extension rejoint l'écosystème en ajoutant une section ## Ecosystem à son SKILL.md nommant : quels schémas elle produit, lesquels elle consomme, et quels événements de frontière elle enveloppe dans l'enveloppe. Membres actuels : shame, triage-error, tau, ask, project-watchdog, ops-herdr. Ponytail est adjacent par conception.