Estos son los prompts que funcionaron, los resultados que fallaron y las correcciones manuales que permitieron terminar el producto.
Usé Claude Code para crear la estructura de una extensión desde cero durante un fin de semana. Este fue el proceso.
El punto de partida
El proyecto era una extensión que mide el tiempo en distintos sitios y muestra un resumen diario en un popup. Algo parecido a una versión sencilla de Amethyst.
Las herramientas: Claude Code en la terminal, Vite, TypeScript y CRXJS, como en la guía de configuración.
Quería comprobar hasta dónde podía avanzar la IA antes de tener que intervenir.
Lo que Claude Code hizo bien
La estructura inicial del proyecto
Primer prompt, traducido aquí al español:
«Crea una extensión de Chrome con Manifest V3, TypeScript y Vite con CRXJS. Debe tener un popup, un service worker y un script de contenido. Configura la estructura, tsconfig y Vite».
Generó en un intento el manifiesto, la configuración y los archivos de entrada. CRXJS estaba bien conectado y el manifiesto usaba los campos de MV3.
Mi estimación del tiempo ahorrado fue de unos veinte minutos.
Los mensajes con tipos
«Añade mensajes tipados entre el popup y el worker usando uniones discriminadas. GET_STATS devuelve estadísticas diarias; RESET_STATS borra los datos de hoy».
Produjo el patrón de la guía de mensajes: unión discriminada, wrapper genérico y listener con return true para responder de forma asíncrona.
Hasta añadió comprobaciones de chrome.runtime.lastError. Me sorprendió.
El esquema de almacenamiento
«Crea un wrapper tipado de chrome.storage.local para el seguimiento por sitio. Esquema: siteStats, mapa de dominio a segundos; currentSession, sitio e inicio; dailyReset, fecha del último reinicio».
La salida era clara, con funciones genéricas y tipos inferidos, similar al enfoque de almacenamiento tipado.
Lo que tuve que corregir
El momento de iniciar el script de contenido
El código envolvía la inicialización en DOMContentLoaded. Los scripts declarados con el run_at predeterminado, document_idle, pueden ejecutarse cuando ese evento ya pasó. El envoltorio era innecesario y hacía poco fiable el inicio.
Corrección: ejecutar la inicialización directamente en ese contexto.
El ciclo de vida del service worker
Guardó el temporizador en un setInterval. Eso no mantiene vivo un worker de MV3.
Corrección: usar chrome.alarms con intervalos de un minuto y persistir el inicio de sesión. En cada alarma calculo el tiempo transcurrido, como explica la nota de almacenamiento.
Detectar la pérdida de foco
chrome.tabs.onActivated no basta para saber si el usuario se fue a otra aplicación. Chrome no activa otra pestaña al perder el foco de la ventana.
Corrección: añadir chrome.windows.onFocusChanged para pausar el seguimiento cuando corresponda.
El estilo del popup
El CSS era genérico, sin un espaciado coherente ni cuidado del ancho de 380 píxeles que había elegido. Funcionaba, pero tuve que rehacerlo.
Corrección: reescribir los estilos, lo que me llevó unos treinta minutos.
Los prompts que ayudaron
Pedir una arquitectura concreta: «Usa uniones discriminadas» orienta mejor que «añade mensajes».
Recordar las restricciones de MV3: mencionar que el worker termina al quedar inactivo ayuda a evitar temporizadores en memoria como única fuente de estado.
Pedir errores concretos: solicitar el manejo del caso en que falta el script de contenido produjo un try/catch alrededor de chrome.tabs.sendMessage.
Avanzar por funciones: estructura, mensajes, almacenamiento e interfaz, por separado, funcionó mejor que pedirlo todo de una vez.
Los prompts que no bastaron
«Haz que se vea bien». Los criterios vagos producen estilos genéricos. Definir tipografía, ancho, radios y colores da una referencia revisable.
«Contempla todos los casos límite». El foco de ventana, las páginas chrome:// y el cierre del popup aparecieron al probar. La frase no sustituye esas pruebas.
Máquinas de estados complejas. La transición «inactivo → registrando → pausado → registrando» parecía correcta, pero tenía fallos sutiles de tiempo. Necesitaba verificación manual.
Mi balance del trabajo
| Área | Parte generada por IA | Mi corrección |
|---|---|---|
| Estructura inicial | 100 % | Ninguna relevante |
| Manifiesto | 95 % | Ajustes de permisos |
| Tipos de mensajes | 100 % | Ninguna relevante |
| Wrapper de almacenamiento | 90 % | Migraciones |
| Lógica de segundo plano | 60 % | Temporizador, ciclo de vida y foco |
| Script de contenido | 80 % | Momento de inicio |
| Interfaz y CSS | 30 % | Reescritura completa |
| Pruebas | 0 % | Verificación manual |
Son estimaciones de ese proyecto. La IA hizo alrededor del 60 % del código; yo escribí o rehice el resto. Ese resto concentró las decisiones difíciles.
Qué aprendí del proceso
Claude Code me ayudó con estructuras repetitivas, tipos y patrones conocidos. Necesitó más revisión en el comportamiento específico del navegador, el diseño visual y los casos que solo aparecen al probar.
El proceso que me funcionó:
- Dejar que genere la estructura y los patrones.
- Revisar cada archivo y entenderlo, usando la arquitectura de MV3 como referencia.
- Probar pronto en el navegador.
- Corregir los huecos.
Pude terminar en un fin de semana porque ya conocía la arquitectura de extensiones. Si hubiera empezado desde cero, algunos fallos me habrían parecido código correcto.
Por dónde seguir
- Lee cómo construí ResistGate para ver el recorrido de un producto completo.
- Prepara la publicación con la guía de la Chrome Web Store.
Esta nota forma parte de la serie Extensiones de Chrome: de cero a producto, donde explico lo que aprendí construyendo ResistGate y Amethyst, desde el primer popup hasta la publicación.
Un pequeño voto de confianza
¿Valió la pena leer esta nota?