Conseils d'installation et astuces — Linear × CMA webhook bridge
Les choses qui ne sont pas évidentes dans la documentation et qui ont tendance à coûter du temps de débogage.
Modèle mental
Un webhook est « appelle-moi quand quelque chose se produit »
C'est simplement une requête HTTP POST qu'un service envoie à une URL que tu lui as fournie, avec un petit corps JSON décrivant un événement. Tu enregistres l'URL une fois ; le service l'appelle chaque fois que l'événement se déclenche. Pas de polling, pas de connexions ouvertes.
Le bridge est obligatoire (aujourd'hui)
Linear's Agent Platform et CMA ne partagent pas un format de fil ou des identifiants. Quelque chose doit traduire « Linear @mention » → « CMA user.message » à l'entrée, et « CMA idle » → « Linear comment » à la sortie, tout en gardant les deux ensembles de clés. C'est le bridge.
Deux webhooks, un bridge
- Linear → bridge se déclenche sur @mention. Le payload transporte
agentSession.id,organizationIdet le contexte du problème. - Anthropic → bridge se déclenche sur inactivité de session. Le payload transporte uniquement l'ID de session CMA.
Aucun ne transporte d'« URL de rappel ». Aucun ne transporte la sortie de l'agent. Les deux sont simplement des signaux avec des ID.
Le webhook est une sonnette, pas une livraison
Le payload session.status_idled d'Anthropic est volontairement mince — {type, id}. Tu fais toujours un suivi avec sessions.retrieve(id) (pour obtenir les métadonnées) et sessions.events.list(id) (pour obtenir la sortie). Pousse le signal, tire les données. Les tentatives restent bon marché ; les données ne sont jamais obsolètes.
metadata est l'état de routage entier
Quand le bridge crée la session CMA, il définit metadata: {linear_session_id, linear_org_id}. Quand le webhook d'inactivité arrive plus tard avec seulement un ID de session, le bridge récupère la session, relit ces clés et sait exactement où répondre — sans rien stocker dans le bridge lui-même. C'est ce qui le rend sans état.
Pièges
Les webhooks Anthropic sont limités à l'espace de travail
L'endpoint que tu enregistres dans Console reçoit uniquement les événements des sessions dans ce même espace de travail. Si ta ANTHROPIC_API_KEY appartient à l'espace de travail A mais que tu as enregistré l'endpoint dans l'espace de travail B, tu obtiens zéro livraisons, silencieusement. Vérifie la colonne Workspace de ta clé API et assure-toi qu'elle correspond au sélecteur d'espace de travail sur la page Webhooks de la Console.
Un webhook d'espace de travail se déclenche pour chaque session de l'espace de travail
Pas seulement la tienne. Si l'espace de travail Anthropic est partagé avec d'autres agents, scripts ou collègues, chaque session.status_idled dans cet espace de travail atteint ton endpoint. Ton gestionnaire doit filtrer : sessions.retrieve(id) → vérifier tes clés metadata → retourner 204 pour tout ce qui n'est pas le tien. Capture aussi les 404/403 sur sessions.retrieve — les sessions créées sous d'autres clés API dans le même espace de travail ne sont pas lisibles par la tienne.
Corollaires : s'abonne uniquement aux types d'événements dont tu as besoin (session.status_idled, session.status_terminated), pas « Tous les événements » ; et pour la production, envisage un espace de travail Anthropic dédié pour qu'il n'y ait pas de sessions non liées à rejeter.
Les apps Linear OAuth sont réservées aux administrateurs d'espace de travail
Les OAuth apps se trouvent à linear.app/<your-workspace>/settings/api — dans la barre latérale c'est Administration → API, puis la section OAuth Applications. Si tu n'es pas admin de ton espace de travail d'entreprise, crée un espace de travail personnel gratuit pour tester — ça prend deux minutes et tu n'installeras pas un agent expérimental en production.
Lors de la création de l'app, le champ Developer URL est obligatoire mais cosmétique (c'est juste un lien affiché sur l'écran de consentement) — n'importe quelle véritable URL https:// convient.
actor=app est le paramètre OAuth crucial
scope=app:assignable,app:mentionable + actor=app est ce qui crée un app user dans l'espace de travail Linear qui apparaît dans le sélecteur @. Une LINEAR_API_KEY personnelle ne fait pas cela — le bridge doit poster en retour en tant qu'app, via le token OAuth.
Règle des 10 secondes d'accusé de réception de Linear
Le bridge doit poster un certain agentActivity (un {type: "thought"} suffit) dans les 10 secondes suivant la réception du AgentSessionEvent, ou Linear marque la session comme échouée. Fais cela avant de créer la session CMA.
event.id est ta clé d'idempotence
Anthropic réessaye les livraisons échouées avec le même event.id de haut niveau. Déduplique sur celui-ci. Retourne 2xx une fois que tu l'as soit géré soit décidé de l'ignorer — tout le reste déclenche une tentative, et environ 20 défaillances consécutives désactivent automatiquement ton endpoint.
Noms des en-têtes de signature
La documentation dit X-Webhook-Signature ; le fil utilise Webhook-Signature / Webhook-Id / Webhook-Timestamp (spécification Standard Webhooks). Le webhooks.unwrap() du SDK gère cela — ça ne compte que si tu vérifies à la main.
Liste de vérification dev local
ngrok http 3000(oucloudflared tunnel) → note l'URL publique. Tout ce qui suit l'utilise.bun run setup→ copieCLAUDE_AGENT_ID/CLAUDE_ENVIRONMENT_IDdans.env.local.- Linear OAuth app (Administration → API → OAuth Applications → Create new) : Developer URL = n'importe quelle véritable URL
https://(cosmétique) ; callback<url>/oauth/callback; webhook<url>/linear-webhook, events = Agent session events → copie client ID/secret + webhook secret. - Anthropic Console → Webhooks :
<url>/cma-webhook, events =session.status_idled+session.status_terminated→ copiewhsec_.... Même espace de travail que ta clé API. - Remplis
.env.local,bun run dev. - Visite
<url>/oauth/authorize→ approuve → « Agent installé. » - @mentionne-le dans un problème.
Déboguer un silence radio
- « Réflexion en cours… » n'apparaît jamais → le webhook Linear ne t'atteint pas. Vérifie l'URL du webhook de l'app Linear et que ngrok est actif.
- « Réflexion en cours… » apparaît mais aucune réponse → vérifie
curl localhost:4040/api/requests/http(journal des requêtes de ngrok). Si pas de POST à/cma-webhook: décalage d'espace de travail du côté Anthropic, ou endpoint non sauvegardé. Si POST arrive avec 401 : décalage de clé de signature. - La réponse est vide →
sessions.events.listpeut être paginée ; itère si l'agent a produit plusieurs événements.
Notes de production
- Remplace ngrok par un vrai déploiement (Cloudflare Workers, Fly, etc.). Rien d'autre ne change.
- Remplace le Set
seenEventIdsen mémoire par Redis ou une DB pour l'idempotence multi-instances. - Remplace le fichier
.linear-tokens.jsonpar un vrai gestionnaire de secrets. - Restreins l'abonnement aux événements de l'endpoint Anthropic à exactement ce que tu gères.