Ouvrir une PR
Ouvrir une PR correctement est un problème de recherche avant d'être un problème git. Un relecteur décide dans le premier écran si l'auteur connaît le dépôt — la grammaire du titre, la forme du corps, les sujets des commits le signalent — donc le travail est : apprendre ce que les mainteneurs de ce dépôt écrivent, puis écrire cela.
Choisissez d'abord la profondeur
Express est pour « ouvrir juste la PR », « juste livrer », « faire entrer ça » — et pour tout changement assez petit pour que la recherche coûte plus que la relecture qu'elle économiserait. Orienter, écrire, expédier, confier la surveillance. Ignorer l'explorateur de style et sa carte, le calibrage vocal et la passerelle de prose. Ne demandez pas si l'express est souhaité : la formulation l'a déjà dit, et le confirmer est le délai que l'utilisateur voulait éviter.
ccx vcs lane --json
ccx vcs diff
ccx vcs ship --no-watch --pr-title-file "$TITLE" --pr-body-file "$BODY"
Le corps dit toujours ce qui a changé et pourquoi, dans le modèle du dépôt s'il en a un, et le titre correspond encore à la grammaire des dernières PR fusionnées — une lecture gh pr list --state merged --limit 5 --json title, pas une exploration. Express abandonne la recherche, jamais le corps : une PR sans corps est la seule chose qu'aucune lane n'expédie.
Complet est le reste de ce fichier, et il mérite son coût sur un dépôt que vous ne possédez pas, sur un changement dont un mainteneur doit être convaincu, ou la première fois que vous ouvrez une PR quelque part. Sur un dépôt étranger, les passes de conformité et de politesse ne sont pas optionnelles même en express — un invité qui les saute gaspille l'aller-retour du mainteneur, pas le sien.
S'orienter
Le chemin compte ici : trois commandes dont la sortie nommée est référencée par tout ce qui suit.
ccx vcs lane --json # lane, branche, tronc, dirty, github.mine, PRs downstack et lesquelles manquent de corps
gh repo view --json isPrivate,owner,viewerPermission,pullRequestTemplates,nameWithOwner,defaultBranchRef
ccx vcs guidelines # CONTRIBUTING, modèle PR, code de conduite, config issue — affiche le chemin de la carte
Puis ccx vcs diff pour le changement lui-même.
ccx vcs lane rapporte la lane — elle ne la choisit pas, et vous non plus. ccx vcs ship sélectionne jj, git ou gt au moment de l'expédition, et un dépôt que l'utilisateur ne contrôle pas tombe silencieusement de la lane gt, donc n'écrivez rien qui suppose une lane avant que ship n'en rapporte une. github.mine est le verdict de propriété ; le test derrière et tout ce qui dépend de mine : false vit dans reference/oss.md. Lisez la carte que ccx vcs guidelines a écrite, puis séparez les exigences strictes des préférences — reference/guidelines.md contient les indices, et les alternatives gh api pour un dépôt qui ne publie rien.
Apprendre le style maison
Le style maison vit dans une carte sur disque, explorée une fois par dépôt et mise en cache :
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pr-cache.sh" status <owner/name> # fresh | stale:<raison> | missing
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pr-cache.sh" path <owner/name> # affiche le répertoire cache
fresh n'a besoin d'aucune exploration — lisez la carte et passez à la suite. stale ou missing → déclenchez l'explorateur, une fois par dépôt par exécution :
Agent(subagent_type : "open-pr:pr-style-scout",
prompt : "repo : <owner/name>\ncache : <dir>\nviewer : <gh login>")
L'explorateur échantillonne les PR fusionnées récentes, filtre les bots, les PR écrites par IA et — sur un dépôt étranger — celles du visionneur lui-même, et écrit la carte dans le répertoire cache. Il renvoie un chemin, un résumé court et une confiance — lisez la carte qu'il a écrite, pas sa narration.
La carte porte sa taille d'échantillon et une confiance par axe, car les filtres qui gardent l'échantillon humain le réduisent aussi. La grammaire du titre et la structure du corps sont des conventions — elles tiennent à toute taille d'échantillon. Le ton de réponse à la relecture et le registre de prose reposent sur moins de signaux : à confidence : low ils sont une tendance, pas une règle, et le modèle PR et les directives pèsent plus lourd. Une convention lue sur trois échantillons les décrit tous les trois. La disposition du cache, le schéma de la carte et la fraîcheur vivent dans reference/style-cache.md.
Calibrer la voix
Quand l'utilisateur a un profil wlm local, empruntez les parties de sa voix qui survivent au changement de format :
wlm profile list
wlm -p <profile> stylecard show # -p vient avant la sous-commande et n'est pas optionnel
La carte wlm a été construite pour une prose de blog longue : la liste Jamais et le choix des mots se transfèrent entièrement, le ton à moitié, la longueur et les ouvertures pas du tout. Le tableau de transfert complet et le repli sans profil sont dans reference/voice.md. Là où la carte du dépôt et la carte vocale divergent, le dépôt gagne — vous êtes un invité dans son format.
Dépôts que vous ne contrôlez pas
github.mine : false change le registre et ajoute deux passes avant d'écrire (reference/oss.md) :
- Le registre de politesse — direct sur le changement, déférent sur la décision : les chiffres portent les affirmations, le mainteneur garde les décisions qui sont les siennes.
- Conformité aux normes — parcourez
ccx vcs diffpar rapport à la carte de directives et à la liste de contrôle : périmètre, style, tests, documentation, hygiène des commits, taille du diff par rapport à la norme des PR fusionnées du dépôt. Chaque manquement est une correction, ou une phrase dans le corps reconnaissant l'écart. - Issue-first — quand la carte de directives marque une issue comme une exigence stricte, cherchez avant d'ouvrir :
gh issue list --repo <slug> --search "<keywords>" --state all. Pas de correspondance → rédigez l'issue, puis présentez le brouillon à l'utilisateur avecAskUserQuestion— ouvrir tel quel / éditer d'abord / lier une issue existante / ignorer l'exigence délibérément — et agissez selon son choix. Ouvrir une issue publie sous le nom de l'utilisateur sur le projet de quelqu'un d'autre ; la rédiger ne le fait pas.
Écrire
Le titre, le corps et les sujets de commit suivent la carte de style à la confiance déclarée ; le modèle PR, s'il existe, est le squelette du corps. Un nombre partout où un adjectif qualifierait autrement le changement : un relecteur vérifie « 40 ms de moins au démarrage à froid » et ignore « beaucoup plus rapide ».
Écrivez le corps et le titre dans des fichiers, jamais dans des arguments shell — un corps avec des backticks, $, ou une barrière de code ne survit pas intact à une ligne de commande, et un titre y est refusé pour moins (voir Expédier) :
BODY=$(mktemp)
TITLE=$(mktemp)
Le corps est de la prose, donc il passe la barrière de prose avant d'être expédié : slop-cop check "$BODY" --lang=markdown, en triant les drapeaux plutôt qu'en les acceptant tous.
Les messages de commit reçoivent le même traitement : la carte enregistre la grammaire des sujets de ce dépôt, sa longueur, et quels trailers les commits fusionnés de ce dépôt portent — correspondance avec ces trailers et aucun autre. Sur un dépôt dont l'historique n'a pas de Co-Authored-By : Claude ou Generated with Claude Code, un trailer annonçant l'outillage est la seule ligne qui fait passer une PR soignée pour automatisée, et les mainteneurs filtrent dessus ; sur un dépôt dont l'historique les porte, les garder est la convention.
Une pile par session
Un travail connexe d'une session va dans une pile chaînée, jamais des branches sœurs indépendantes du tronc — même si les diffs sont prouvablement disjoints. « Les fichiers ne se chevauchent pas » n'est pas une raison pour diviser : des sœurs effacent l'ordre de relecture qu'une chaîne énonce, et perdent la mécanique de milieu de pile — un restack porte un amendement à travers chaque branche au-dessus, alors que les sœurs rebasent seules chacune. Chaînez dans l'ordre des dépendances, ce qui consomme au-dessus de ce qu'il consomme ; une lane encore en vol va à la pointe, pour que les branches finies en dessous ne soient jamais rebasées sous son agitation. Mécanique dans reference/stack.md.
Une PR est une unité de travail de la taille d'une fonctionnalité. Les suivis, corrections et
réponses aux relectures sont des commits sur la PR ouverte, jamais un enfant empilé. Expédiez-les avec
ccx vcs ship, en ajoutant --amend pour les fondre dans son commit ou --tip-only
quand seule la pointe d'une pile a changé. Empilez seulement quand un parent doit atterrir avant
que d'autres travaux puissent continuer, ou quand la relecture a besoin de la division. Poussez à des
points de contrôle cohérents, jamais par édition, car chaque poussée remplace la
construction en cours et relance les CI et les bots de relecture. Poussez quand même dans l'heure,
car l'origine est la sauvegarde.
Expédier
La combinaison de drapeaux est importante :
ccx vcs ship --no-watch --pr-title-file "$TITLE" --pr-body-file "$BODY"
Écrivez le titre dans un fichier d'une ligne à côté du fichier corps et passez --pr-title-file, jamais un --pr-title en ligne. Le bac à sable Bash d'un agent isolé dans un worktree refuse tout argument qui associe un guillemet au mot git ou à un nom de shell, comme GitHub's ... git, et un titre dans un fichier n'atteint jamais la ligne de commande. Ship prend le sujet du commit de ce titre et le corps du commit du corps de la PR, donc -m n'est nécessaire que pour un sujet qui diffère du titre.
--no-watch car la surveillance intégrée de ship bloque jusqu'à ce que CI conclue — juste au moment où vous attendez, mauvais quand la surveillance va être confiée. Ship possède la création-et-mise-à-jour de PR dans chaque lane : un gh pr create fait à la main à côté produit une PR que la lane gt ne peut pas réconcilier avec sa propre pile.
Sur une PR déjà ouverte, ship prévient et garde le titre et le corps qu'elle a, donc un amendement ne porte aucun drapeau, et une PR dont le texte doit changer prend --replace-pr-text.
Sur la lane gt, une soumission peut créer plusieurs PR, et chaque PR dans la soumission qui n'a pas encore de corps en reçoit un. --pr-title-file et --pr-body-file se répètent et sont cadrés par branche (--pr-body-file <branche>=<chemin> ; une valeur nue s'applique à la pointe) ; ccx vcs lane --json vous dit quelles PR downstack sont sans corps.
Un refus est une information, pas une nouvelle tentative : nothing to commit signifie qu'une expédition précédente a déjà atterri cela ; ship rejoue un needs_restack de gt lui-même. Quand ship refuse toujours parce qu'une branche est en dehors de son parent ou que le tronc a bougé, exécutez ccx vcs stack submit (ou passez le refus textuellement au propriétaire de la pile quand une autre lane la possède), puis relancez ship.
Ship rapporte la branche, le numéro et l'URL de la PR, et le sha de tête. La transmission a besoin des quatre.
Confier la surveillance
Résolvez ${CLAUDE_PLUGIN_ROOT} en son chemin absolu dans l'appelant au moment
de la création et remplissez poll : avec la commande prête à exécuter. La variable est
substituée dans le texte de cette compétence ; le sous-agent ne la reçoit pas. Passez la
phrase après poll : textuellement pour que l'observateur puisse armer le script même si
le harnais omet sa définition d'agent.
Agent(subagent_type : "open-pr:pr-watcher", run_in_background : true,
name : "pr-watch-<num>",
prompt : "pr : <num>\nurl : <url>\nrepo : <owner/name>\nhead : <sha>\n"
"branch : <branche>\nlane : <gt|jj|git>\ncache : <dir>\nownership : <mine|foreign>\n"
"poll : bash \"<chemin absolu plugin>/scripts/pr-poll.sh\" <owner/name> <num> <cache>/pr/<num>.json\n"
"Exécutez PR_POLL_WINDOW=40 <poll : commande> seul comme Bash de premier plan avec timeout : 60000, relancez-le immédiatement sur DONE window-elapsed, et continuez d'appeler jusqu'à un verdict final : n'armez jamais un Monitor et ne mettez jamais l'appel en arrière-plan, car aucun ne réveille un sous-agent, ne l'enveloppez jamais dans une boucle, et ne substituez jamais une boucle gh pr checks/bk faite main, qui ne peut pas voir un atterrissage de file. Sur DONE ready-to-merge, SendMessage main avant toute autre chose.")
Après la création, vérifiez que le script de scrutation a écrit son fichier d'état :
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pr-watch-armed.sh" "<cache>/pr/<num>.json"
Sur sortie 1, SendMessage à l'observateur la même ligne poll : et exécutez
la vérification une deuxième fois. Si elle échoue à nouveau, signalez à l'utilisateur que la
surveillance n'est pas armée. Une création d'agent seule ne prouve pas que le script tourne.
Un observateur par PR — un deuxième sur la même PR pousserait le premier. Chaque rapport sauf evicted termine la surveillance ; SendMessage par nom la reprend pour le prochain tour. Un message evicted : <raison> <détail> arrive en cours d'exécution et l'observateur continue de surveiller pour que l'appelant le remette en file par étiquette ou dans l'UI de Graphite. Poussez toute correction avant de remettre en file ; l'appelant décide quand remettre en file.
Après un rapport ready-to-merge : open-pr.on-ready
Un rapport ready-to-merge signifie que la PR est verte, fusionnable et approuvée :
chaque vérification passée, chaque suite de vérifications GitHub Actions sur la tête s'est
terminée, mergeable est vrai, l'état de la file a été lu proprement (jamais
QUEUE unknown), et la PR n'est ni en file ni évincée sur sa tête actuelle.
Aucun dernier avis du relecteur n'est CHANGES_REQUESTED, et REST mergeable_state
n'est pas blocked (l'état pour une approbation requise manquante). Un
rapport ready-to-merge downstack #<n> est une PR empilée attendant la PR downstack
# (y compris quand la vérification de fusionnabilité de Graphite est la seule vérification inachevée
sur une pile Graphite héritée). La PR elle-même est prête, mais elle n'atterrit qu'avec
sa downstack : nommez # dans la question et mettez la pile en file, jamais
cette PR seule.
Lisez le CLAUDE.md de l'utilisateur pour une de ces lignes exactes :
open-pr.on-ready : offer-open(le défaut quand aucune ligne n'est définie) : dans ce même tour, demandez à l'utilisateur viaAskUserQuestions'il veut ouvrir la page de la PR. Exécutezgh pr view <num> --webseulement sur un oui.open-pr.on-ready : offer-merge: dans ce même tour, demandez « fusionner # maintenant ? » viaAskUserQuestion. Ajoutez l'étiquette de file du dépôt seulement sur un oui.
N'étiquetez ni n'ouvrez jamais sur le seul rapport. Sous la compétence
long-running, transmettez le rapport au bureau d'atterrissage ; il possède la décision quel que
soit le réglage.
Après avoir ajouté l'étiquette de file à une PR dont l'observateur a déjà signalé ready-to-merge, reprenez cet observateur par nom pour qu'il surveille la file à travers les vérifications vertes jusqu'à un atterrissage ou un échec :
SendMessage(to : "pr-watch-<num>", message : "Étiquette de file <étiquette> ajoutée. Reprenez la surveillance de la file sur le même fichier d'état.")
Son rapport arrive comme une notification en cours de tâche — continuez de travailler jusqu'à ce qu'il arrive. Quand il rapporte un jugement…
… [tronqué pour la traduction]