Registro de cambios del producto
Un correo recurrente que informa a los usuarios qué cambió en el producto, redactado de forma natural, enviado de forma segura y luego reutilizado para publicaciones en redes sociales. El correo es la fuente de verdad para cada edición; todos los demás canales se derivan de él.
Cómo funciona este skill
- Pregunta una vez, al inicio. En la primera ejecución (o cuando falta configuración o un valor necesario está en blanco), haz las preguntas de configuración en un lote corto, escribe
config.yamly continúa sin más preguntas. - Luego lo hace todo. En
autonomy.mode: autonomous(el valor por defecto) seleccionas los elementos, redactas, revisas, te autocorriges, tomas capturas de pantalla, envías una prueba, lees la prueba de vuelta, construyes la audiencia, haces un ensayo general, envías a todos, verificas, obtienes las cancelaciones de suscripción, escribes y publicas las publicaciones sociales, y archivas. Sin paso de aprobación. Cada acción externa pasa primero por un filtro de autoevaluación. - El dinero es la única aprobación. Todo lo que cueste dinero espera la confirmación explícita del usuario en el chat, en todos los modos: un envío que supere la cuota incluida del plan del proveedor (
provider.monthly_quota), mejorar el plan del proveedor, comprar un dominio, herramientas o licencias de pago (por ejemplo, una licencia Remotion de empresa de pago). Nada más necesita una confirmación. - Las paradas forzosas no son aprobaciones. Detienen esa acción. Termina todo lo demás que sea seguro, luego informa. Consulta Paradas forzosas.
- Informa al final. Un resumen: el asunto y el texto completo que se envió, los conteos (en cola, enviados, fallidos, excluidos, cancelados), una muestra de entrega, el resultado de la lectura de la prueba, cada publicación con su enlace, todo lo omitido y por qué.
- El modo
reviewmantiene los antiguos pasos de aprobación por acción. Consulta Modo de revisión.
Todos los scripts se ejecutan en modo de ensayo por defecto. Los envíos reales necesitan indicadores explícitos (--send, --yes-send-to-everyone, --yes-send-broadcast). En modo autónomo, los pasas tú mismo, y solo después de que el filtro de autoevaluación correspondiente sea exitoso. Nunca envíes correos ad hoc fuera de los scripts, porque los scripts son los que garantizan el cumplimiento de las cancelaciones.
Paso 0: cargar la configuración
- Busca
config.yamlen la raíz del proyecto actual, luego en la carpeta de este skill (o$CHANGELOG_CONFIG). - Si no hay ninguno, copia
config.example.yamlaconfig.yamlen la raíz del proyecto y pregunta, en un solo mensaje:- nombre del producto, sitio web, URL del panel y de la documentación
- nombre y cargo del remitente, dirección de origen, dirección de respuesta
- destinatarios de prueba (nombres y direcciones)
- proveedor: el ID de audiencia de Resend, la variable de entorno que contiene la clave API y, si lo saben, los correos mensuales incluidos en el plan (
provider.monthly_quota, opcional) - modo de cancelación (
broadcastoown_endpoint) - alojamiento de imágenes: dónde van las capturas de pantalla y su URL base pública
- opcional: cadencia, color de enlace de la marca y cómo publicar en cada canal social (
social.post_via) No adivines ninguno. Escribe las respuestas enconfig.yaml, luego continúa.
- Cualquier valor que aún sea un marcador de posición en MAYÚSCULAS o una dirección
tuproducto.ejemplocuenta como faltante. - Lee
autonomy.mode(por defectoautonomous),voice.notesyvoice.banned_phrases. La configuración de voz anula los valores predeterminados en las referencias. - Los secretos nunca van en la configuración ni en el chat. Las claves API y la clave secreta de firma de cancelación residen en variables de entorno.
Las ediciones posteriores no preguntan nada. La única pregunta opcional es "¿Hay algo enviado fuera de git esta vez (precios, asociaciones, documentación)?" Si el usuario no está presente, sáltate la pregunta y trabaja a partir de git y las notas de la versión.
Paso 1: seleccionar qué incluir
Lee primero references/voice-and-format.md.
- Busca la última edición en
paths.issues_dir(carpetas con nombreNNN-YYYY-MM-DD-slug). La más reciente es la plantilla para la siguiente. - Reúne candidatos desde esa fecha:
git log --since=<fecha> --no-merges --oneline, solicitudes de extracción fusionadas, notas de la versión y cualquier cosa que el usuario haya mencionado. - Conserva solo los cambios visibles para el usuario. De 3 a 5 elementos, ordenados por utilidad para el lector. Empieza con el cambio más útil, el que la mayoría de los lectores puede usar hoy.
- Verifica cada afirmación contra el producto y el sitio web en vivo. Nunca inventes una característica, un número o una fecha. Si no se puede verificar una afirmación, elimina el elemento.
- Escribe la lista y el orden en el
NOTES.mdde la edición y continúa.
Paso 2: redactar el correo
Crea paths.issues_dir/NNN-YYYY-MM-DD-slug/ y escribe:
subject.txt: centrado en el beneficio y primero en el producto ("Ahora puedes exportar informes a Hojas de cálculo"). Nunca "Registro de cambios #N".email.html: a partir de templates/email.html (o la última edición), completando cada marcador[[...]]con la configuración y el contenido.email.txt: las mismas palabras en texto plano con URL desnudas.
Mantén {{NAME}} y {{UNSUB_URL}} como marcadores de posición literales; los scripts de envío los completan por destinatario.
Reglas principales (detalle en la referencia):
Hola {{NAME}},, luego la línea de apertura de la configuración, y luego directamente al elemento principal.- Cada elemento: qué cambió, luego por qué importa, en oraciones fluidas. Sin viñetas etiquetadas.
- Oraciones cortas, palabras sencillas, "ahora puedes" en lugar de "hemos creado".
- Como máximo un énfasis en negrita por párrafo.
- Como máximo una captura de pantalla por elemento; el elemento principal siempre tiene una, y enlaza a la característica.
- HTML con estilo mínimo: contenedor de 600px, fuente del sistema, estilos en línea, sin botones ni pancartas.
- Sin "emocionados de anunciar" y el resto de la lista prohibida. Sin guiones largos o cortos si
voice.no_dashesestá activado. - P.S. opcional informal ("Por cierto, ...").
- Cierre de la configuración. La línea de cancelación es la última línea, pequeña y atenuada.
Paso 3: capturas de pantalla
Sigue references/screenshots.md: prepara un estado real en una cuenta de demostración (sin datos de clientes), captura al 2x con Playwright, recorta al panel, nombra los archivos <issue>-<slug>.png, aloja en paths.image_base_url y confirma que cada URL devuelve 200 antes de cualquier envío masivo.
Paso 4: lint y autoevaluación (filtro 1: copia)
python3 scripts/lint_email.py ISSUE_DIR --check-links
Corrige cada fallo, luego revisa esta lista de verificación. Corrige y vuelve a ejecutar hasta que cada casilla pase.
-
lint_email.py --check-linkssale con 0. - Leído de principio a fin como un cliente ocupado: el cambio más útil está claro en 5 segundos.
- Cada elemento es algo que un usuario puede ver o usar hoy.
- Cada afirmación, número y enlace coincide con el producto y el sitio en vivo.
- Nada suena a comunicado de prensa; suena como si hablara el remitente.
- Asunto de menos de 60 caracteres, centrado en el beneficio, sin "Registro de cambios #N".
- Cada imagen tiene texto alternativo y su URL alojada devuelve 200 (o se implementará antes del Paso 7).
Paso 5: envío de prueba y lectura de vuelta (filtro 2: copia entregada)
python3 scripts/send_test.py ISSUE_DIR --send # solo a test_recipients, prefijo [TEST]
python3 scripts/send_test.py ISSUE_DIR --readback # un minuto después
Las copias de prueba van solo a test_recipients e incrustan imágenes en línea si aún no están implementadas. --readback obtiene cada mensaje entregado de la API del proveedor y verifica el último evento, el asunto, el saludo renderizado y la línea de cancelación, y que no haya sobrevivido ningún marcador de posición. También lee el HTML devuelto tú mismo una vez. Si algo no está bien, corrígelo, vuelve a hacer lint y vuelve a probar.
En modo own_endpoint, abre el enlace de cancelación de la copia de prueba, confirma que la exclusión se registró y luego vuelve a suscribir la dirección de prueba.
Paso 6: construir la audiencia
Detalle completo en references/sending.md.
- Construye
ISSUE_DIR/audience.jsonlde nuevo desde la base de datos del usuario ({"email", "name"}por línea). Nunca reutilices una lista antigua. - Construye
ISSUE_DIR/unsubs.txtdesde la tabla de exclusiones. En modo broadcast, primero ejecutapython3 scripts/broadcast_unsubs.py --out <issues_dir>/unsubs.txty cópialo. - Las cuentas de fundadores, prueba y demostración están en
excludede la configuración; reciben copias de prueba en su lugar.
Paso 7: enviar a todos (filtro 3: audiencia)
Elige la ruta de unsubscribe.mode. Ejecuta primero el ensayo general y verifica los conteos.
Modo broadcast (el proveedor aloja la cancelación):
python3 scripts/broadcast_sync.py ISSUE_DIR/audience.jsonl # plan
python3 scripts/broadcast_sync.py ISSUE_DIR/audience.jsonl --apply # inserta o actualiza contactos
python3 scripts/broadcast_create.py ISSUE_DIR --create # solo borrador
python3 scripts/broadcast_create.py --send BROADCAST_ID # muestra el conteo de destinatarios, se niega
python3 scripts/broadcast_create.py --send BROADCAST_ID --yes-send-broadcast
Modo propio endpoint (enlaces firmados a tu propia página):
python3 scripts/blast.py ISSUE_DIR # ensayo con conteos
python3 scripts/blast.py ISSUE_DIR --send --yes-send-to-everyone
Lista de verificación de audiencia, todo debe pasar antes del indicador de envío:
- Los filtros 1 y 2 pasaron en esta misma copia (nada cambió desde la lectura de vuelta).
- La lista de exclusiones se obtuvo o construyó en esta ejecución y no está vacía si el producto ha tenido alguna vez una cancelación.
- Los conteos del ensayo general tienen sentido: en cola es cercano a usuarios menos exclusiones menos cancelados; sin saltos sorpresa respecto al
NOTES.mdde la última edición. - Modo broadcast:
broadcast_sync.pyno reportó contactos obsoletos inesperados. - Cada URL de imagen alojada devuelve 200.
- Cuota: si
provider.monthly_quotaestá configurado, pasa--sent-this-month N(suma los conteos de enviados en losNOTES.mdde las ediciones de este mes más otro correo en el mismo plan si se conoce). Si el script dice que el envío superaría la cuota, detente y pregunta al usuario; pasa--yes-over-quotasolo después de su confirmación explícita.
El envío uno por uno es reanudable: si se detiene, vuelve a ejecutar el mismo comando y omite las direcciones ya enviadas.
Paso 8: verificar y sincronizar
- Uno por uno:
python3 scripts/verify_delivery.py ISSUE_DIR --sample 40. Transmisiones:GET /broadcasts/{id}a través de la API del proveedor o el panel. - Obtén las exclusiones después de un día (
broadcast_unsubs.py). Si el usuario mantiene las exclusiones en su propia base de datos y tienes acceso de escritura, impórtalas; de lo contrario, indícalo en el informe.
Paso 9: publicaciones sociales
Escribe a partir del correo final, siguiendo references/social.md:
- X: tweet de gancho que comienza con
social.hook_prefix, nombra cada elemento, sin enlace, la captura de pantalla más potente. Luego un tweet numerado por elemento con su enlace y captura de pantalla. Además, un tweet de cotización personal de una línea para un fundador. - LinkedIn: una publicación, primera línea de gancho, un párrafo corto por elemento, texto plano, galería de imágenes.
- Comunidad (Discord o Slack): línea de apertura, una línea por elemento con un enlace desnudo, el enlace del hilo una vez activo.
De 4 a 5 elementos como máximo, sin avisos de política, las afirmaciones coinciden con el sitio en vivo. Ejecuta las mismas comprobaciones de frases prohibidas y guiones en social.md (lint_email.py lo lee). Luego, para cada canal con una herramienta en social.post_via, publícalo tú mismo y registra la URL de la publicación. Para canales sin herramienta, entrega al usuario el texto final y las imágenes. El tweet de cotización del fundador es desde una cuenta personal, así que entrégaselo a menos que se haya configurado una herramienta para esa cuenta.
Paso 10: video (opcional, solo a solicitud)
Si el usuario lo pide, sigue references/video.md: un reel de movimiento de 15 a 25 segundos a partir de las capturas de pantalla de la edición, sin diapositiva de título, titular grande por elemento, las capturas de pantalla dominan, cierre con la URL del producto. Remotion necesita una licencia de empresa de pago por encima de cierto tamaño de equipo; esa es una pregunta de dinero para el usuario.
Paso 11: archivar e informar
En la carpeta de la edición, conserva: subject.txt, email.html, email.txt, las capturas de pantalla, social.md, test_results.jsonl y un NOTES.md con la lista de elementos, la fecha de envío, la ruta utilizada, el tamaño de la audiencia, los conteos de enviados y fallidos, el ID de la transmisión, las URLs de las publicaciones y las cancelaciones después de un día. Si el producto tiene una página web pública de registro de cambios (product.changelog_page) y su fuente está en este repositorio, agrega también la edición allí. Cuando el usuario corrija la voz o el formato, agrega la lección a voice.notes en la configuración para que la próxima edición comience desde ahí. Luego envía el resumen descrito al principio.
Paradas forzosas
Detén esa acción, termina todo lo demás que sea seguro e informa qué se detuvo y por qué. Nunca evites una parada.
- Fallos de lint que no puedes corregir.
- Un enlace o imagen rota que no puedes corregir (aún no es 200 después de implementarlo o corregirlo).
- La lectura de vuelta de la prueba falla y no puedes encontrar la causa.
- El filtrado de exclusiones falla: no se puede obtener o construir la lista de exclusiones, la consulta de audiencia da error, o un script se niega debido a
unsubs.txt. Nunca envíes sin ella. - Errores del proveedor por encima del umbral durante el envío (
blast.pysale con 2 enprovider.max_failuresoprovider.max_failure_rate). Informa el error; el envío masivo es reanudable una vez corregido. - Un envío que superaría la cuota, una mejora de plan o cualquier otro gasto: pregunta al usuario (regla del dinero).
- Solicitudes de inicio de sesión, 2FA o reautenticación, CAPTCHAs, advertencias de la plataforma o límites de velocidad en una herramienta de publicación, formularios de pago o facturación.
- Cualquier cosa que rompa las leyes de cancelación o antispam (falta de línea de cancelación, reinscripción de alguien que se dio de baja).
- Una afirmación que no puedas verificar. Elimínala en lugar de adivinarla.
Modo de revisión
Con autonomy.mode: review, los tres filtros también necesitan la aprobación del usuario:
- Filtro de borrador. Muestra el asunto, el correo y la lista de elementos en el chat. No se envía nada hasta que el usuario apruebe la copia.
- Filtro de prueba. Envía solo a
test_recipients. El usuario lo lee en una bandeja de entrada real y dice "adelante" o da correcciones. - Filtro de envío masivo. Muestra los conteos del ensayo general (en cola, excluidos, cancelados). Envía a todos solo cuando el usuario diga que sí a ese envío específico en el chat. Un sí a un paso anterior no es un sí a este.
Las publicaciones sociales se muestran antes de publicarlas, y la lista de elementos se propone antes de escribir. Nunca pases un indicador de envío antes del filtro correspondiente.
Responder a "¿cuántos suscriptores?"
Suscriptores = usuarios menos cancelaciones. Cuenta las cancelaciones de la tabla de cancelaciones del usuario o unsubs.txt (en modo broadcast, ejecuta primero broadcast_unsubs.py). Proporciona también la tasa de cancelación de la última edición.
Archivos
config.example.yaml: cada valor específico de la empresa, másautonomy,provider.monthly_quotaysocial.post_via.templates/email.html,templates/email.txt: el diseño inicial.scripts/:lint_email.py,send_test.py(con--readback),
…
[truncado para la traducción]