Tous les articles

AFPS, le format portable qu'il manquait aux agents IA

MCP transporte les tool calls. A2A transporte les messages. Agent Skills livre des capacités. Rien ne standardisait le package lui-même. D'où AFPS. Voici le trou qu'il comble et les décisions derrière.

Appstrate
standardafpsécosystèmearchitecture

🧱 La couche qui manquait à la stack d’agents 2026

En 2026, l’étagère des standards open‑source pour agents IA a fini par se remplir. MCP définit comment les agents appellent des outils au runtime. A2A définit comment les agents se parlent entre processus. Anthropic Agent Skills définit une capacité réutilisable sous la forme d’un SKILL.md à frontmatter YAML. Trois specs, trois couches : transport, communication, capacité.

Rien là‑dedans ne standardise ce que la plupart des équipes veulent réellement livrer : un package portable qui déclare ce que l’agent doit accomplir, et qui embarque dans un seul artefact déplaçable tout ce qu’il lui faut (prompt, dépendances, schémas d’entrée/sortie, métadonnées d’auth des providers).

C’est ce trou‑là que vient combler AFPS, le Agent Format Packaging Standard. On l’a écrit, publié sous CC‑BY, et cet article explique pourquoi il devait exister et comment les décisions ont été prises.

Avant toute chose, la divulgation qui s’impose. Appstrate a écrit AFPS et bénéficie de son adoption. Ce qui suit est notre lecture : la stack 2026 a un trou en forme de package, et AFPS a la bonne forme pour le combler. Quand un choix est discutable, on le dit. Notre runtime est parmi les premiers à exécuter nativement des packages AFPS, mais le format, lui, est volontairement agnostique.

🎯 Capacité contre objectif : le déplacement qui compte

Chaque standard d’agents existant décrit des capacités : ce qu’un agent sait faire, comment un tool doit être invoqué, à quoi ressemble un skill sur le filesystem. Des primitives utiles. Aucune ne répond à qu’est‑ce que cet agent cherche à accomplir, et qu’est‑ce qu’il lui faut pour y arriver ?

AFPS renverse le cadrage. Le manifest part de l’objectif, un prompt.md qui dit « traite la boîte de réception et résume les demandes de support », puis déclare autour de ce prompt chaque capacité (skills, tools) et chaque connexion (providers avec métadonnées d’auth) dont l’agent dépend. Versionné. Dépendances résolues. Un seul ZIP.

                ┌───────────────────────────────┐
  Goal          │  AFPS Agent                   │  "Summarize support requests"
                │  prompt.md + manifest.json    │
                ├───────────────────────────────┤
  Capability    │  Skills (SKILL.md)            │  "Rewrite in professional tone"
                │  Tools (source + manifest)    │  "Fetch JSON from a URL"
                ├───────────────────────────────┤
  Connection    │  Providers (OAuth2, API key)  │  "Gmail, OpenAI, Slack"
                ├───────────────────────────────┤
  Transport     │  MCP / A2A                    │  Runtime protocols
                └───────────────────────────────┘

AFPS vit sur les deux couches du haut. Les deux du bas sont déjà standardisées. Rien dans AFPS ne concurrence MCP ou A2A : problème différent.

📦 Ce qu’il y a vraiment dans un fichier .afps

Le package minimal viable, c’est deux fichiers dans un ZIP :

// manifest.json
{
  "name": "@my-org/hello-world",
  "version": "1.0.0",
  "type": "agent",
  "schemaVersion": "1.0",
  "displayName": "Hello World",
  "author": "My Org",
  "dependencies": {}
}
<!-- prompt.md -->
Summarize the latest unread emails and list any action items.

Zippe les deux, donne à l’archive l’extension .afps, et tu as un package d’agent valide que n’importe quel runtime compatible AFPS saura exécuter. Les vrais packages déclarent des dépendances et une configuration de providers ; l’exemple complet, dans le repo de la spec, va plus loin. La spec définit quatre types (agent, skill, tool, provider), chacun avec ses fichiers compagnons requis, pour qu’un consommateur puisse dispatcher sur manifest.type et rejeter à peu de frais les archives malformées.

L’extension est une convention, pas une exigence stricte. La spec §2.5 est explicite : les consommateurs DOIVENT accepter les ZIP quelle que soit l’extension. On a choisi .afps parce que les humains et les OS tirent profit d’un signal stable qui dit « ceci est un package d’agent, pas une archive au hasard ».

🔐 Les morceaux difficiles : identité, versioning, résolution de dépendances

Un skill livré comme SKILL.md est utile, mais seul il ressemble plus à un copier‑coller qu’à une dépendance. Pour partager des skills entre tenants, équipes ou organisations sans collision ni cassure silencieuse, trois choses doivent être verrouillées. Le manifest AFPS les verrouille, parce qu’on ne voyait pas comment un runtime multi‑tenant pouvait s’en passer.

1. Identité scopée. Chaque package AFPS porte un nom scopé qui matche une regex stricte (^@[a-z0-9]([a-z0-9-]*[a-z0-9])?\/[a-z0-9]([a-z0-9-]*[a-z0-9])?$). Pas de majuscules, pas d’underscores, doit commencer et finir alphanumérique. Même forme que les scopes npm, pour la même raison : les registries peuvent faire respecter la possession du scope et rejeter les typosquats.

2. Versioning sémantique. Agents, skills, tools et providers sont livrés en MAJOR.MINOR.PATCH. Le champ schemaVersion est séparé et n’utilise que MAJOR.MINOR : il épingle la forme du manifest, pas le comportement. Les suivre indépendamment laisse le runtime faire évoluer son validateur et l’écosystème faire évoluer le contenu des packages sans qu’ils se marchent dessus.

3. Dépendances typées. dependencies.{providers, skills, tools} : trois maps, chacune d’un nom scopé vers une plage semver.

"dependencies": {
  "skills":    { "@example/rewrite-tone": "^1.0.0" },
  "tools":     { "@example/fetch-json":   "^1.0.0" },
  "providers": { "@example/gmail":        "^1.0.0" }
},
"providersConfiguration": {
  "@example/gmail": { "scopes": ["gmail.readonly", "gmail.send"] }
}

La séparation entre dependencies.providers et providersConfiguration, c’est là que l’expérience opérationnelle se voit. Un package provider déclare ce qu’il peut faire (endpoints, mode d’auth, scopes supportés). Un agent consommateur déclare ce qu’il veut (le sous‑ensemble de scopes qu’il utilise vraiment). Deux agents peuvent dépendre du même @example/gmail à la même version et demander des enveloppes de scopes totalement différentes, sans forker le package provider. C’est exactement le découpage qu’il faut à un runtime multi‑tenant qui veut un jour faire tourner côte à côte des agents d’équipes différentes.

🤝 Compatible avec ce qui existe déjà

La façon facile de pondre une nouvelle spec, c’est de tout redéfinir. La façon plus dure, celle qu’AFPS prend, c’est de composer avec les standards existants plutôt que de les remplacer.

  • MCP. AFPS est muet sur le transport des tool calls. Selon la spec §1.2.1, un runtime peut choisir d’exposer des tools AFPS via MCP. Rien n’empêche un consommateur de faire tourner des packages AFPS et de parler MCP aux clients externes.
  • Agent Skills. Les skills AFPS en sont un sur‑ensemble strict. Un répertoire Agent Skills valide devient un skill AFPS dès que tu ajoutes un manifest.json à côté du SKILL.md. Le vocabulaire du frontmatter (name, description, license, allowed-tools, et le reste) est préservé tel quel. AFPS ajoute identité, versioning et graphe de dépendances : les trois choses qu’Agent Skills laisse explicitement de côté.
  • A2A. Les protocoles inter‑agents opèrent sous la couche package. AFPS réserve les champs préfixés x- pour que les métadonnées A2A puissent vivre dans un manifest sans attendre que la spec les ratifie.

Si un package adopte AFPS aujourd’hui et que l’écosystème continue de se standardiser autour, rien ne l’oblige à casser demain. Les points d’extension sont là par design.

🔓 Pourquoi on l’a publié au lieu de le garder interne

C’est le choix où le trade‑off mérite d’être explicite.

On aurait pu garder AFPS comme convention privée à l’intérieur du runtime Appstrate. Plus rapide à itérer, pas de coût de gouvernance, pas de risque qu’un concurrent livre mieux. L’inconvénient, lui, est immédiat : chaque agent écrit pour notre runtime serait verrouillé, chaque client intégrerait ce lock‑in à sa décision d’adoption, et chaque partenaire d’intégration devrait reverse‑engineer nos manifests.

L’alternative, c’est ce qu’on a fait : publier la spec sous CC‑BY 4.0, mettre en place une gouvernance indépendante avec un processus de changement, et laisser n’importe quel runtime l’implémenter. Le pari est simple. On préfère perdre un client au profit d’un concurrent qui parle aussi AFPS que le garder piégé dans un format qu’il ne peut pas exporter. Des agents portables, c’est mieux pour l’écosystème, et un écosystème d’agents portables, c’est un meilleur endroit pour vendre un runtime qu’un patchwork de formats propriétaires.

C’est aussi pour ça que le périmètre de la spec est volontairement étroit. AFPS ne définit ni protocole de registry, ni schéma de signature, ni API de runtime. Specs séparées, à écrire, qui travailleront avec AFPS plutôt que de se faire absorber par lui.

🧭 Ce que ça débloque

Avec AFPS en place, une poignée de patterns deviennent possibles que la stack 2026 ne supporte pas aujourd’hui sans vendor lock‑in :

  • Portabilité cross‑runtime. Une équipe écrit un agent contre un runtime, exporte un .afps, le fait tourner sur un autre. Pas de réécriture, pas de manifest reverse‑engineered, pas d’« export vers notre format ».
  • Marketplaces à dépendances résolues. Un skill ou un tool peut être publié une fois, référencé par nom scopé, consommé par des agents d’équipes différentes, à la manière des packages npm, avec plages semver et vérifications d’intégrité façon lockfile (la spec §8.5 recommande les hashes SRI).
  • Agents auditables. Le manifest déclare chaque capacité, chaque provider et chaque scope OAuth requis dans un seul fichier. Les workflows de revue, les contrôles de conformité et l’outillage supply‑chain peuvent travailler dessus sans faire tourner l’agent.
  • Composition agent‑à‑agent au niveau package. Un agent peut déclarer un autre agent comme dépendance, comme un skill déclare un tool. Ce n’est pas un protocole A2A complet, juste de la réutilisation compositionnelle, mais c’est la fondation sur laquelle des interactions style A2A peuvent se construire.

Que tout ça arrive dépend de l’adoption, pas du fait qu’on l’ait écrit. La spec existe. La suite, c’est d’autres runtimes, d’autres outils, d’autres packages. Ou bien rien, et AFPS reste une convention interne soigneusement documentée à une URL publique.

🛠 La suite

Côté spec, les priorités sont étroites. Un protocole de registry est le trou évident : une façon de publier et résoudre des packages par nom scopé sans faire tourner un miroir maison. La signature en est une autre. CC‑BY c’est bien, mais c’est la provenance cryptographique que la sécurité supply‑chain réclame vraiment. Deux chantiers adjacents, que la gouvernance AFPS est pensée pour accueillir sans faire bouger la spec principale en dessous.

Côté Appstrate, le boulot consiste à prouver que faire tourner nativement des packages AFPS (comme processus isolés, multi‑tenant, derrière un vrai runtime, avec les credentials gérés hors de l’agent et l’infrastructure des agents contrôlée par l’opérateur) est un meilleur défaut que l’alternative propriétaire. Si la preuve tient, AFPS devient facile à adopter. Sinon, aucune spec écrite n’y changera rien.

Trois choses à faire :

  1. Lis la spec : ~40 pages de markdown. Le primer est la version courte.
  2. Essaie Appstrate : auto‑héberge avec curl -fsSL https://get.appstrate.dev | bash, ou fais‑le tourner sur notre infra.
  3. Ouvre une issue ou une proposition de changement. La gouvernance est pensée pour absorber les retours du terrain, surtout venant des équipes qui font tourner des agents multi‑tenant aujourd’hui.

Et si tu as construit un runtime d’agents et que tu n’es pas d’accord avec ce qui précède, on préfère largement le savoir.