Abrir una PR
Abrir una PR correctamente es un problema de investigación antes que un problema de git. Un revisor decide en la primera pantalla si el autor conoce el repositorio — la gramática del título, la forma del cuerpo, los asuntos de los commits lo indican — así que el trabajo es: aprender lo que escriben los mantenedores de este repositorio, y luego escribir eso.
Elige la profundidad primero
Exprés es para "solo abrir la PR", "solo enviarlo", "meterlo ya" — y para cualquier cambio lo suficientemente pequeño como para que la investigación cueste más que la revisión que ahorra. Orienta, escribe, envía, entrega la vigilancia. Omite el explorador de estilo y su tarjeta, la calibración de voz y la puerta de prosa. No preguntes si se quiere exprés: la redacción ya lo ha dicho, y confirmarlo es la demora que el usuario estaba evitando.
ccx vcs lane --json
ccx vcs diff
ccx vcs ship --no-watch --pr-title-file "$TITLE" --pr-body-file "$BODY"
El cuerpo sigue diciendo qué cambió y por qué, en la plantilla del repositorio cuando la tiene, y el título sigue coincidiendo con la gramática de las últimas PRs fusionadas — una lectura de gh pr list --state merged --limit 5 --json title, no un explorador. El exprés elimina la investigación, nunca el cuerpo: una PR sin cuerpo es lo único que ningún carril envía.
Completo es el resto de este archivo, y vale su coste en un repositorio que no posees, en un cambio del que hay que persuadir a un mantenedor, o la primera vez que abres una PR en cualquier lugar. En un repositorio ajeno, las pasadas de conformidad y cortesía no son opcionales ni siquiera en exprés — un invitado que las omite desperdicia el viaje de ida y vuelta del mantenedor, no el suyo propio.
Oriéntate
El camino importa aquí: tres comandos cuya salida nombrada utilizan todos los pasos posteriores.
ccx vcs lane --json # carril, rama, tronco, sucio, github.mine, PRs descendentes y cuáles carecen de cuerpo
gh repo view --json isPrivate,owner,viewerPermission,pullRequestTemplates,nameWithOwner,defaultBranchRef
ccx vcs guidelines # CONTRIBUTING, plantilla de PR, código de conducta, configuración de issues — imprime la ruta de la tarjeta
Luego ccx vcs diff para el cambio en sí.
ccx vcs lane informa del carril — no lo elige, y tú tampoco. ccx vcs ship selecciona jj, git o gt en el momento del envío, y un repositorio que el usuario no controla cae silenciosamente del carril gt, así que no escribas nada que asuma un carril antes de que ship informe uno. github.mine es el veredicto de propiedad; la prueba detrás de él y todo lo que depende de mine: false vive en reference/oss.md. Lee la tarjeta que escribió ccx vcs guidelines, luego separa los requisitos estrictos de las preferencias — reference/guidelines.md tiene las pistas, y las alternativas de gh api para un repositorio que no publica nada.
Aprende el estilo de la casa
El estilo de la casa vive en una tarjeta en disco, explorada una vez por repositorio y almacenada en caché:
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pr-cache.sh" status <owner/name> # fresh | stale:<reason> | missing
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pr-cache.sh" path <owner/name> # imprime el directorio de caché
fresh no necesita exploración — lee la tarjeta y continúa. stale o missing → lanza el explorador, una vez por repositorio por ejecución:
Agent(subagent_type: "open-pr:pr-style-scout",
prompt: "repo: <owner/name>\ncache: <dir>\nviewer: <gh login>")
El explorador toma muestras de PRs recientes fusionadas, filtra bots, PRs escritas por IA y — en un repositorio ajeno — las del propio visor, y escribe la tarjeta en el directorio de caché. Devuelve una ruta, un resumen breve y una confianza — lee la tarjeta que escribió, no su narración.
La tarjeta lleva su tamaño de muestra y una confianza por eje, porque los filtros que mantienen la muestra humana también la reducen. La gramática del título y la estructura del cuerpo son convenciones — se mantienen con cualquier tamaño de muestra. El tono de respuesta a la revisión y el registro de la prosa se basan en menos señales: con confidence: low son una inclinación, no una regla, y la plantilla de PR y las directrices tienen más peso. Una convención leída de tres muestras describía esas tres. El diseño de la caché, el esquema de la tarjeta y la caducidad viven en reference/style-cache.md.
Calibra la voz
Cuando el usuario tiene un perfil wlm local, toma prestadas las partes de su voz que sobreviven al cambio de formato:
wlm profile list
wlm -p <profile> stylecard show # -p va antes del subcomando y no es opcional
La tarjeta wlm se creó para prosa de blog de formato largo: la lista de Never y la elección de palabras se transfieren completas, el tono a la mitad de fuerza, la longitud y los abridores no se transfieren en absoluto. La tabla de transferencia completa y la alternativa sin perfil están en reference/voice.md. Cuando la tarjeta del repositorio y la tarjeta de voz no coinciden, gana el repositorio — eres un invitado en su formato.
Repositorios que no controlas
github.mine: false cambia el registro y añade dos pasadas antes de escribir (reference/oss.md):
- El registro de cortesía — directo sobre el cambio, deferente sobre la decisión: los números respaldan las afirmaciones, el mantenedor conserva las decisiones que le corresponden.
- Conformidad con estándares — recorre
ccx vcs diffcontra la tarjeta de directrices y la lista de verificación: alcance, estilo, pruebas, documentación, higiene de commits, tamaño del diff frente a la norma de PRs fusionadas del repositorio. Cada fallo es una corrección, o una frase en el cuerpo que asume la desviación. - Primero el issue — cuando la tarjeta de directrices marca un issue como requisito estricto, busca antes de abrir:
gh issue list --repo <slug> --search "<keywords>" --state all. Sin coincidencia → redacta el issue, luego pon el borrador frente al usuario conAskUserQuestion— abrir como está redactado / editar primero / enlazar un issue existente / saltarse el requisito deliberadamente — y actúa según su elección. Abrir un issue publica bajo el nombre del usuario en el proyecto de otro; redactarlo no.
Escribe
El título, el cuerpo y los asuntos de los commit siguen la tarjeta de estilo con la confianza indicada; la plantilla de PR, cuando existe, es el esqueleto del cuerpo. Un número donde sea que un adjetivo calificaría el cambio: un revisor verifica "40 ms menos de arranque en frío" y descarta "mucho más rápido".
Escribe el cuerpo y el título en archivos, nunca en argumentos de shell — un cuerpo con acentos graves, $ o un bloque de código no sobrevive intacto a una línea de comandos, y un título es rechazado allí por menos (ver Ship):
BODY=$(mktemp)
TITLE=$(mktemp)
El cuerpo es prosa, por lo que pasa por la puerta de la prosa antes de enviarse: slop-cop check "$BODY" --lang=markdown, clasificando las banderas en lugar de aceptarlas todas.
Los mensajes de commit reciben el mismo tratamiento: la tarjeta registra la gramática de los asuntos de este repositorio, su longitud y qué trailers llevan sus propios commits fusionados — iguala esos trailers y ningún otro. En un repositorio cuyo historial no tiene Co-Authored-By: Claude ni Generated with Claude Code, un trailer que anuncia la herramienta es la línea única que hace que una PR cuidadosa se lea como automatizada, y los mantenedores filtran por ella; en un repositorio cuyo historial sí los lleva, mantenerlos es la convención.
Una pila por sesión
El trabajo relacionado de una sesión va en una sola pila encadenada, nunca en hermanos independientes del tronco — incluso cuando los diffs son demostrablemente disjuntos. "Los archivos no se superponen" no es razón para dividir: los hermanos borran el orden de revisión que una cadena establece, y pierden la maquinaria de mitad de pila — un reajuste lleva una enmienda a través de cada rama superior, mientras que los hermanos se reorganizan cada uno por separado. Encadena en orden de dependencia, lo que consume por encima de lo que consume; un carril todavía en vuelo va en la punta, para que las ramas terminadas debajo de él nunca se reorganicen bajo su cambio. Mecánica en reference/stack.md.
Una PR es una unidad de trabajo del tamaño de una funcionalidad. Los seguimientos, correcciones y respuestas a revisiones son commits en la PR abierta, nunca un hijo apilado. Envíalos con ccx vcs ship, añadiendo --amend para fusionarlos en su commit o --tip-only cuando solo ha cambiado la punta de una pila. Apila solo cuando un padre debe aterrizar antes de que otro trabajo pueda proceder, o cuando la revisión necesita la división. Empuja en puntos de control coherentes, nunca por edición, porque cada push reemplaza la compilación en ejecución y vuelve a ejecutar CI y los bots de revisión. Aún así, empuja dentro de la hora, ya que origin es la copia de seguridad.
Envía
La combinación de banderas es importante:
ccx vcs ship --no-watch --pr-title-file "$TITLE" --pr-body-file "$BODY"
Escribe el título en un archivo de una línea junto al archivo del cuerpo y pasa --pr-title-file, nunca un --pr-title en línea. El sandbox Bash de un agente aislado de un árbol de trabajo rechaza cualquier argumento que empareje una comilla con la palabra git o un nombre de shell, como GitHub's ... git, y un título en un archivo nunca llega a la línea de comandos. Ship toma el asunto del commit de ese título y el cuerpo del commit del cuerpo de la PR, por lo que -m solo es necesario para un asunto que difiere del título.
--no-watch porque el vigilante incorporado de ship bloquea hasta que CI concluye — justo cuando estás esperando, mal cuando el vigilante está a punto de ser entregado. Ship posee crear y actualizar PR en cada carril: un gh pr create hecho a mano junto a él produce una PR que el carril gt no puede reconciliar con su propia pila.
En una PR que ya está abierta, ship advierte y mantiene el título y el cuerpo que tiene, por lo que una enmienda no lleva ninguna de las dos banderas, y una PR cuyo texto debería cambiar toma --replace-pr-text.
En el carril gt, un envío puede crear varias PRs, y cada PR en el envío que aún no tiene cuerpo recibe uno. --pr-title-file y --pr-body-file se repiten y se delimitan por rama (--pr-body-file <branch>=<path>; un valor simple se aplica a la punta); ccx vcs lane --json es lo que te dice qué PRs descendentes no tienen cuerpo.
Un rechazo es información, no un reintento: nothing to commit significa que un envío anterior ya lo había aterrizado; ship reproduce un needs_restack de gt por sí mismo. Cuando ship aún se niega porque una rama está fuera de su padre o el tronco se ha movido, ejecuta ccx vcs stack submit (o pasa el rechazo textualmente al propietario de la pila cuando otro carril la posee), luego vuelve a ejecutar ship.
Ship informa de la rama, el número y la URL de la PR, y el sha de la cabeza. La entrega necesita los cuatro.
Entrega el vigilante
Resuelve ${CLAUDE_PLUGIN_ROOT} a su ruta absoluta en el llamador en el momento de la creación y completa poll: con el comando listo para ejecutar. La variable se sustituye en el texto de esta habilidad; el subagente no la recibe. Pasa la frase después de poll: textualmente para que el vigilante pueda armar el script incluso si el arnés omite su definición de agente.
Agent(subagent_type: "open-pr:pr-watcher", run_in_background: true,
name: "pr-watch-<number>",
prompt: "pr: <number>\nurl: <url>\nrepo: <owner/name>\nhead: <sha>\n"
"branch: <branch>\nlane: <gt|jj|git>\ncache: <dir>\nownership: <mine|foreign>\n"
"poll: bash \"<abs plugin root>/scripts/pr-poll.sh\" <owner/name> <number> <cache>/pr/<number>.json\n"
"Ejecuta PR_POLL_WINDOW=40 <poll: command> solo como Bash en primer plano con timeout: 60000, vuelve a ejecutarlo inmediatamente en caso de DONE window-elapsed, y sigue llamando hasta obtener un veredicto final: nunca armes un Monitor ni ejecutes en segundo plano, ya que ninguno activa un subagente, nunca lo envuelvas en un bucle, y nunca sustituyas un bucle de gh pr checks/bk hecho a mano, que no puede ver la llegada de una cola. En caso de DONE ready-to-merge, SendMessage a main antes que cualquier otra cosa.")
Después de la creación, verifica que el script de sondeo haya escrito su archivo de estado:
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pr-watch-armed.sh" "<cache>/pr/<number>.json"
En caso de salida 1, SendMessage al vigilante la misma línea poll: de nuevo y ejecuta la comprobación una segunda vez. Si falla de nuevo, informa al usuario de que el vigilante no está armado. La creación de un agente por sí sola no demuestra que el script se esté ejecutando.
Un vigilante por PR — un segundo en la misma PR anularía al primero. Cada informe excepto evicted termina la vigilancia; SendMessage por nombre la reanuda para la siguiente ronda. Un mensaje evicted: <reason> <detail> llega a mitad de ejecución y el vigilante sigue observando para que el llamador lo vuelva a encolar por etiqueta o en la interfaz de Graphite. Empuja cualquier corrección antes de reencolar; el llamador decide cuándo reencolar.
Después de un informe ready-to-merge: open-pr.on-ready
Un informe ready-to-merge significa que la PR está verde, es fusionable y está aprobada: cada comprobación pasó, cada conjunto de comprobaciones de GitHub Actions en la cabeza se ha completado, mergeable es verdadero, el estado de la cola se leyó limpiamente (nunca QUEUE unknown), y la PR no está encolada ni expulsada en su cabeza actual. Ninguna revisión más reciente del revisor es CHANGES_REQUESTED, y el mergeable_state de REST no es blocked (el estado para una aprobación requerida faltante). Un informe ready-to-merge downstack #<n> es una PR apilada que espera a la PR descendente # (incluso cuando la comprobación de fusionabilidad de Graphite es la única comprobación no terminada en una pila Graphite heredada). La PR en sí está lista, pero aterriza solo con su pila descendente: nombra # en la pregunta y encola la pila, nunca esta PR sola.
Lee el CLAUDE.md del usuario para una de estas líneas exactas:
open-pr.on-ready: offer-open(el valor predeterminado cuando no se establece ninguna línea): en ese mismo turno, pregunta al usuario a través deAskUserQuestionsi desea abrir la página de la PR. Ejecutagh pr view <number> --websolo con un sí.open-pr.on-ready: offer-merge: en ese mismo turno, pregunta "¿fusionar # ahora?" a través deAskUserQuestion. Añade la etiqueta de cola del repositorio solo con un sí.
Nunca etiquetes ni abras basándote solo en el informe. Bajo la habilidad long-running, reenvía el informe al mostrador de aterrizaje; es el dueño de la decisión independientemente de la configuración.
Después de añadir la etiqueta de cola a una PR cuyo vigilante ya informó ready-to-merge, reanuda ese vigilante por nombre para que vigile la cola a través de comprobaciones verdes hasta un aterrizaje o un fallo:
SendMessage(to: "pr-watch-<number>", message: "Etiqueta de cola <label> añadida. Reanuda la vigilancia de la cola en el mismo archivo de estado.")
Su informe llega como una notificación durante la tarea — sigue trabajando hasta que llegue. Cuando informa de un juicio...