## Le problème qui attend la plupart des constructeurs

Si vous exécutez un agent sur un magasin, l'attribution est triviale. Vous savez qui a écrit chaque ligne. Vous avez écrit à l'agent.

Au moment où vous exécutez deux, trois, cinq agents sur la même instance de Neotoma, [l'image change](/posts/when-agents-share-state-everything-breaks). Chaque agent écrit des observations, des relations, des sources, des interprétations. Le magasin accumule l’état de chacun d’eux. Si l’un de ces agents commence à écrire des données erronées, des résumés subtilement erronés, des dates périmées, des relations mal attribuées, la seule façon de déterminer à quels enregistrements faire confiance est de raisonner sur l’agent qui les a écrits.

Sans attribution par ligne, vos options en cas de problème sont difficiles : effacer le magasin et réingérer, ou laisser les mauvaises lignes et vivre avec la dérive. Les deux s’aggravent à mesure que le magasin s’agrandit.

Ce problème devient plus aigu pour quiconque expédie un produit piloté par un agent. Les dossiers de vos clients sont rédigés par une flotte : vos propres agents, des agents tiers intégrés via MCP, peut-être un plugin installé par quelqu'un la semaine dernière. Lorsqu'un client demande « qui a écrit ceci sur mon compte et sous quelle autorité ? », il faut répondre à cette question à partir des données, et non à partir d'un exercice de corrélation entre les journaux du serveur et les transcriptions de conversations.

J'exécute des agents sur Cursor, Claude Code, Codex et ChatGPT, écrivant tous sur une seule instance Neotoma. J'ai écrit sur [ce que fait réellement cette pile](/posts/what-my-agentic-stack-actually-does). L'intégration AAuth de Neotoma est ce qui comble l'écart pour ma pile et pour tous ceux qui la construisent : chaque agent apporte sa propre clé, et le magasin peut rester digne de confiance à mesure que la flotte se développe.

## Pourquoi AAuth

La couche d'attribution est construite sur [AAuth](https://www.aauth.dev/), un protocole ouvert qui donne à chaque client HTTP sa propre identité cryptographique. Pas de pré-inscription. Aucun secret partagé. Pas de jetons au porteur. Chaque demande est signée avec les signatures de message HTTP [RFC 9421](https://datatracker.ietf.org/doc/html/rfc9421), donc un jeton volé ne vaut rien sans la clé de signature.

J'ai choisi AAuth parce que la personne derrière, Dick Hardt, est un ami et l'un des plus grands experts en identité que je connaisse. Il a édité OAuth 2.0 ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749)), co-écrit OpenID Authentication 2.0 et a été membre fondateur du conseil d'administration de la [OpenID Foundation](https://openid.net/foundation/members/). Il s’agit de la même lignée que la plupart des développeurs rencontrent via les flux de codes d’autorisation et la connexion fédérée. Lorsqu’une personne ayant cet historique démarre un nouveau protocole spécifiquement pour les agents, c’est celui contre lequel il vaut la peine de s’appuyer.

## Ce que chaque écriture contient désormais

[v0.6.0](https://github.com/markmhendrickson/neotoma/releases/tag/v0.6.0) fournit une attribution d'agent par ligne sur chaque surface d'écriture : `/store`, `/observations/create`, `/create_relationship`, `/correct`, `/entities/split`, les outils de magasin MCP et la CLI écrit à la fois sur MCP et HTTP. Chaque observation, relation, source et interprétation marque :

- Un identifiant d'agent vérifié (empreinte numérique de clé publique pour les rédacteurs signés, sujet JWT et émetteur pour les jetons d'agent, nom et version clientInfo comme solution de secours).
- Un niveau de confiance qui classe le degré de preuve de l'identité.
- Le transport par lequel l'écriture est arrivée.

Cinq niveaux couvrent le spectre :

- `hardware` : l'agent a fourni une enveloppe `cnf.attestation` (Apple Secure Enclave, WebAuthn packed ou TPM2) que le serveur a vérifié par rapport aux racines de confiance.
- `operator_attested` : la signature vérifiée et l'opérateur a ajouté l'émetteur ou la paire émetteur-sujet à la liste blanche. L'opérateur se porte garant du processus de l'agent sans exiger d'attestation matérielle.
- `software` : l'agent a signé la requête avec une clé valide, vérifiée par le serveur. C'est là que la plupart des agents atterrissent aujourd'hui, y compris ma propre signature de proxy Cursor avec un ES256 JWK sauvegardé sur fichier.
- `unverified_client` : l'agent s'est déclaré avec un clientInfo reconnaissable mais n'a pas signé.
- « anonyme » : aucune identité.

Le résultat : vous pouvez consulter n'importe quelle ligne de votre magasin et répondre "quel agent a écrit ceci" en guise de lecture par rapport à des données de première classe.

## Grants au lieu des fichiers de configuration

Au début du cycle v0.6.0, les fonctionnalités ont été chargées à partir de fichiers JSON variables d'environnement. Cela fonctionnait pour un ensemble statique d'agents, mais s'arrêtait au moment où vous souhaitiez suspendre un agent sans redémarrer le serveur.

Maintenant : chaque `agent_grant` est une entité Neotoma de première classe. Il correspond à une identité AAuth (par sujet, émetteur, empreinte numérique ou une combinaison), comporte des entrées de capacité définies par opération et type d'entité, et a un cycle de vie : « actif », « suspendu », « révoqué ». Le middleware d'admission résout une identité AAuth vérifiée en son octroi correspondant à chaque demande, marque l'utilisateur et les capacités de l'octroi sur le contexte de la demande, et l'application en aval vérifie chaque opération par rapport à l'octroi.

Les subventions sont gérées via l'interface utilisateur de l'inspecteur, l'API REST (`POST /agents/grants`, `PATCH`, suspendre, révoquer, restaurer), ou migrées une fois depuis l'ancienne configuration d'environnement via `neotoma agents Grants Import`. Les variables d'environnement héritées (`NEOTOMA_AGENT_CAPABILITIES_*`) provoquent un échec au démarrage si elles sont toujours définies, avec une erreur structurée pointant vers la commande de migration.

La suspension d'une subvention est instantanée. La demande suivante de l'agent échoue à l'admission. La restauration est également instantanée. Pas de redémarrage du serveur, pas de rechargement de la configuration.

Pour toute personne exécutant un produit avec des agents en contact direct avec les clients, cela signifie que la réponse aux incidents passe du « redémarrage du service avec une nouvelle configuration » à la « suspension d'une autorisation et enquête ». Le rayon d'action d'un agent qui se comporte mal est limité aux opérations qui l'autorisent.

## Contrôle en amont de l'identité

Chaque agent peut désormais demander à Neotoma, avant de produire des données, s'il est reconnu comme rédacteur de confiance.

Trois points d'entrée équivalents :

- `GET /session` sur HTTP.
- `get_session_identity` comme outil MCP.
- `session d'authentification neotoma` sur la CLI.

Chacun renvoie le niveau de confiance résolu, le statut d'octroi (admis ou non, avec raison), la politique d'écriture anonyme et un booléen `eligible_for_trusted_writes`. La réponse comprend un bloc de diagnostic expliquant comment le niveau a été résolu. Un nouvel agent échoue bruyamment au démarrage de la session au lieu d'écrire des lignes anonymes jusqu'à ce que quelqu'un le remarque.

Les instructions MCP fournies indiquent à chaque agent connecté d'exécuter cette vérification avant d'activer les écritures.

## Où j'exécute ceci

Trois agents de service distincts dans ma pile écrivent aujourd'hui à Neotoma sous AAuth.

**Procureur MCP Cursor.** Chaque requête MCP de Cursor passe par un proxy de signature (`mcp_identity_proxy.py`) qui injecte une signature RFC 9421 avec un jeton d'agent `aa-agent+jwt`. Neotoma vérifie la signature, résout l'identité (`sub=cursor@markmhendrickson.com`, `iss=https://markmhendrickson.com`), correspond à `agent_grant` et admet l'écriture à `tier=software`. Le proxy exécute également un contrôle en amont de la session au démarrage et peut échouer si le serveur signale un niveau anonyme.

**Pipeline de commentaires.** Un relais Netlify sur « agent.neotoma.io » transmet les rapports de bogues de l'agent à Neotoma via un tunnel [Cloudflare Access](https://www.cloudflare.com/zero-trust/) signé AAuth. Son octroi s'étend uniquement aux opérations `neotoma_feedback`.

**[Darkmesh](https://github.com/markmhendrickson/darkmesh) écriture d'intro chaude.** Mon [fork Darkmesh](https://github.com/markmhendrickson/darkmesh/blob/main/docs/neotoma_integration.md) ([context](/posts/the-substrate-plancast-needed)) enregistre une intro chaude révélée dans Neotoma avec Signatures RFC 9421 et un jeton « aa-agent+jwt ». Chaque révélation atterrit avec l'agent_sub, l'agent_iss et l'empreinte numérique du nœud, limités par une subvention par nœud.

Les tests conjoints Darkmesh ont prouvé l’application sous une forme contradictoire. Un deuxième agent simulé d'un nœud homologue a tenté d'écrire un « warm_intro_reveal » sans ce type d'entité dans son attribution. Neotoma a rejeté l'écriture. Les écritures du nœud autorisé se sont déroulées sans changement.

Suivant sur la feuille de route : l'[agent public sur markmhendrickson.com](https://markmhendrickson.com/agent/) encapsule une instance de Neotoma comme mémoire et ne sert aujourd'hui que les entités que j'ai explicitement marquées publiques. Je prévois d'ajouter des lectures contrôlées par AAuth afin que les visiteurs autorisés puissent interroger des types d'entités non publiques spécifiques. Même mécanisme d’identité signée plus octroi, appliqué au chemin de lecture.

## Mise à niveau à l'échelle de la flotte

Neotoma envoie ses instructions MCP canoniques du serveur à chaque client connecté à chaque poignée de main. Dans la version 0.6.0, ces instructions codifient désormais le contrôle en amont de l'attribution, le balisage « observation_source », les bords de provenance des réponses citées, un groupe d'affichage « Ambigu (N) » pour les avertissements de fusion heuristique et une boucle structurée de soumission de commentaires.

Lorsque j'ai mis à niveau mon serveur, mes hooks Cursor, Claude Code, Codex et OpenCode ont tous adopté les nouveaux comportements. Aucune version côté client. Aucune migration par outil. Une bosse de serveur, cinq agents mis à jour. Pour toute personne exécutant des flottes client, le même modèle s'applique : mettez à niveau l'instance Neotoma et chaque agent connecté récupère les nouvelles valeurs par défaut sans déploiement client.

## La surface d'audit

Pour les constructeurs de produits sur les marchés réglementés, la question complémentaire d'un client est rarement "votre système s'en est-il souvenu". Il s'agit de "qui l'a écrit et pouvez-vous prouver qu'il était autorisé".

Après la version 0.6.0, il s'agit d'une lecture par rapport à des données de première classe :

- `GET /agents` énumère chaque identité d'agent que le serveur a vue.
- `GET /agents/{key}` renvoie la vue détaillée par agent.
- Audits `GET /agents/{key}/records` qui enregistrent un agent donné créé.
- `GET /agents/grants` répertorie toutes les subventions, leurs capacités et leur statut de cycle de vie.

Si vous proposez des fonctionnalités agentiques à des clients des secteurs verticaux de la santé, de la finance, du droit ou des entreprises, c'est la surface que vos clients finiront par exiger.

## Comment l'allumer

```bash
keygen d'authentification neotoma --alg ES256
exemple de signe d'authentification de néotome
session d'authentification du néotome
```

Créez une subvention pour la nouvelle identité via l'inspecteur ou l'API REST, en adaptant les capacités aux opérations dont votre agent a besoin. Si vous effectuez une mise à niveau à partir de l'ancien modèle env-config, exécutez une fois « neotoma agents grants import --owner-user-id <your_user_id> », puis supprimez les anciennes variables.

Pour la signature programmatique, [`@aauth/local-keys`](https://www.aauth.dev/) ou une bibliothèque AAuth équivalente signe les requêtes avec les signatures de message HTTP RFC 9421 plus un jeton `aa-agent+jwt`. Neotoma vérifie la signature sur les octets bruts signés par le client.

Les écritures sans AAuth fonctionnent toujours. Ils atterrissent dans le niveau « anonyme ». Les constructeurs qui souhaitent des échecs majeurs peuvent inverser `NEOTOMA_AAUTH_STRICT=1` et ajouter des sujets spécifiques à `NEOTOMA_STRICT_AAUTH_SUBS`.

## Également expédié

La v0.6.0 n'est pas seulement AAuth. La même version propose une répartition des entités pour les enregistrements trop fusionnés, l'exportation d'instantanés de flotte plus des outils de dérive, des conversations multi-agents de première classe via « conversation_message » et « sender_kind », et un périmètre d'API resserré. Le supplément complet se trouve dans [les notes de version v0.6.0](https://github.com/markmhendrickson/neotoma/releases/tag/v0.6.0).

## Installer et mettre à niveau

```bash
npm install -g neotoma@[0.6.0](https://github.com/markmhendrickson/neotoma/releases/tag/v0.6.0)
initialisation du néotome
keygen d'authentification de néotome
session d'authentification du néotome
```

La mise à niveau du serveur vous donne le nouvel estampillage d'attribution et l'actualisation des instructions MCP lors de la prochaine prise de contact client. Aucune installation côté client requise pour les agents déjà connectés via MCP.

Installation complète : [neotoma.io/install](https://neotoma.io/install). Dépôt : [github.com/markmhendrickson/neotoma](https://github.com/markmhendrickson/neotoma). Notes de version : [v0.6.0](https://github.com/markmhendrickson/neotoma/releases/tag/v0.6.0).