Pega cualquier cosa. devtools averigua qué es y te la desenreda paso a paso.
Un JWT, un base64, un timestamp Unix, un JSON ilegible, una URL llena de parámetros. Lo pegas en un único campo y devtools detecta qué es, aplica la transformación que toca y vuelve a detectar sobre el resultado, encadenando pasos hasta llegar a algo legible.
entrada cruda cadena de pasos salida
┌──────────────┐ ┌──────────────────────────────────────┐ ┌──────────────┐
│ "ZXlKaGJHY2 │───►│ 1 base64 ──decode──► eyJhbGci… │───►│ JSON │
│ iOiJIUzI1N │ │ 2 jwt ──decode──► {"alg":…} │ │ formateado │
│ iJ9…" │ │ 3 json ──format──► { … } │ │ + exp legible│
└──────────────┘ └──────────────────────────────────────┘ └──────────────┘
cada paso es reversible, inspeccionable y se puede desviar a otra transformación
El cuello de botella de un devtools no es la transformación, es la elección: decodificar base64 es trivial, lo que cuesta es acertar con la pestaña correcta entre veinte. Las suites que ya existen tratan cada utilidad como una isla — copias la salida de una y la pegas en la siguiente. Aquí no eliges nada: pegas, y la cadena se construye sola.
No es un catálogo de utilidades. Es una sola cosa: detectar → transformar → volver a detectar → mostrar la cadena entera.
Y la dirección inversa —«componer»— ya está aquí, en /compose. La misma
cadena recorrida al revés: escribes un valor y le vas poniendo capas que eliges tú
(json.minify, base64.encode, url.encode, hash.sha256, jwt.sign) hasta
el resultado que vas a pegar en un curl. Corre entera en tu navegador: ni el
texto ni el secreto de firma salen de tu máquina — componer no dispara una sola
petición de red. Con cuenta, el historial guarda solo la receta (los pasos),
nunca los valores ni el secreto.
Y una receta se comparte con un enlace. El botón «Copiar enlace» de /compose
te da una URL (/compose?r=…) que lleva solo los pasos —nunca tu valor ni tu
secreto, que ni siquiera viajan en ella—; quien la abre ve la cadena precargada y
mete lo suyo. El enlace trae además una vista previa con los pasos para cuando lo
pegas en Slack o en un PR.
devtools procesa en el servidor lo que le pegas. No lo uses con secretos de producción vivos.
Dicho eso, el producto está construido para no convertirse en un pasivo:
- El historial guarda una vista previa truncada a 120 caracteres, el tipo detectado y la lista de transformaciones. Cuánto se redacta depende del tipo: de un JWT solo sobrevive la cabecera (ni payload ni firma); de un JSON, las claves sin sus valores; de un base64, solo su longitud; de una URL, el dominio. El resto —texto, hashes, UUIDs y timestamps— se guarda tal cual: son opacos o son justo lo útil de ver, pero si pegas un token de 64 hex, se guarda entero.
- Además, antes de guardar se barre el texto buscando JWTs en cualquier
posición, aunque la entrada no se haya detectado como JWT: una petición HTTP
pegada entera desde el panel Network, una cookie (
access_token=…), un parámetro de URL (?id_token=…) o un cuerpo de formulario. De cada uno que encuentra quedan la cabecera y nada más. Qué cuenta como «encontrar»: que alguna parte del token descodifique a un JSON con el campoalg, que es como se reconoce un JWT. Lo que no cumpla eso —algo con pinta de JWT que no lo sea, o un token opaco como 64 hex osk-live-…— se guarda entero. Es una red ancha, no una garantía absoluta. - El input crudo tampoco se loguea: los logs registran tipo, longitud en bytes, número de pasos y duración.
- Consecuencia honesta: «reabrir» una entrada del historial te devuelve la cadena, no el dato. Para copiar valores hay que volver a pegarlo.
La herramienta funciona sin cuenta. Registrarse solo desbloquea el historial.
50 de 50 tareas cerradas (100 %).
| Fase | Qué entrega | Estado |
|---|---|---|
| F0 · Fundaciones | Monorepo con pnpm gate verde, Postgres en Docker, migración inicial aplicada y auth email+contraseña operable en el navegador: registrarse, entrar, y que la sesión sobreviva a un refresh |
✅ Completa |
| TD · Design system | /design-system muestra tokens y componentes fieles a Claude Design, lint de adherencia activo y skill frontend actualizada — se ejecuta tras T0.1, antes de continuar F0 |
✅ Completa |
| F1 · El motor y el campo | Pegas un JWT (o un base64, o un timestamp) en / y ves la cadena desenredada paso a paso, con las alternativas de detección a un clic y el desvío de cualquier paso |
✅ Completa |
| F2 · El historial | Con cuenta iniciada, lo que analizas aparece en /history con la vista previa redactada; se puede reabrir y borrar. Sin cuenta, / sigue funcionando igual |
✅ Completa |
| F3 · Producción | https://devtools.carlosvillu.dev sirve la app con TLS válido, el recorrido completo funciona en producción y el backup diario produce un dump restaurable |
✅ Completa |
| F4 · Post-v1 | Pegar una petición HTTP entera en / no deja el payload del JWT en la BD: la redacción del preview deja de depender de que el detector acierte con el tipo |
✅ Completa |
| F5 · La landing | / es una landing estilo Google (wordmark + campo + badges + footer); pegar o Enter salta a /analyze, que es la experiencia de análisis de hoy. El input viaja por sessionStorage, nunca por la URL. El header de / refleja la sesión (email + salir, o «Entrar»); la portada trae og:image para compartir en redes |
✅ Completa |
| F6 · Componer | La pantalla de trabajo tiene dos direcciones: /analyze decodifica (hoy) y /compose compone — escribes un valor, encadenas transformaciones que TÚ eliges (json.minify, base64.encode, url.encode, hash.sha256, jwt.sign…) y copias el resultado listo para compartir. El motor de composición corre en el navegador: ni el texto fuente ni el secreto de firma salen de la máquina. Con cuenta, el historial guarda la receta (los pasos), nunca los valores |
✅ Completa |
| F7 · Compartir la receta | Una composición se comparte con un enlace (/compose?r=…) que lleva solo la receta —nunca el fuente ni el secreto—; quien lo abre ve los pasos precargados y mete su propio valor. El servidor genera una imagen OG con los pasos para que el enlace tenga preview rico. Fiel a la privacidad: se comparte la receta, no el dato (D11, O9) |
✅ Completa |
Las fases y sus tareas viven en planning.md; el producto
completo, en PRD.md. La tabla de arriba se genera desde el planning
con pnpm readme:status y el gate la verifica: la portada de este repo no puede
mentir sobre en qué punto está el desarrollo.
Stack: pnpm workspaces + TypeScript · apps/web (Next.js App Router +
Tailwind v4) · packages/core (el motor de detección y cadena, con Zod) ·
packages/db (Postgres + Drizzle) · Vitest + Playwright · Base UI/shadcn · pino.
El corazón es packages/core: los detectores, las transformaciones y el motor de
encadenado son lógica pura y total — sin I/O, sin excepciones y con el reloj
inyectado como parámetro. Misma entrada y mismo now producen la misma cadena
byte a byte, que es lo que permite testearlo con golden files.
pnpm install
cp .env.example .env # Postgres para docker compose
cp apps/web/.env.example apps/web/.env # DATABASE_URL para la web (Next lee el .env de apps/web, no el de la raíz)
docker compose -f docker-compose.dev.yml up -d
pnpm dev # aplica las migraciones al arrancarSon dos ficheros .env a propósito, y es la trampa que más se olvida: docker
compose lee el de la raíz y Next el de apps/web. Las migraciones se aplican
solas al arrancar la web; pnpm db:migrate existe aparte para operarlas a mano
(necesita DATABASE_URL en el entorno).
devtools es, declaradamente, un banco de pruebas de un arnés de desarrollo
autónomo: el código lo escribe tarea a tarea un bucle de agentes de Claude Code
gobernado por la skill dev-loop, y cada tarea se cierra con evidencia
verificable en docs/verifications/<ID>/. El producto es real y funciona; el
objetivo declarado es ejercitar el proceso.
Las reglas que lo gobiernan están en CLAUDE.md: una tarea por
ciclo con contexto fresco, quien implementa no se evalúa a sí mismo, ninguna
tarea se marca hecha sin evidencia con veredicto PASS, y prohibido debilitar
tests para ponerse en verde.
AGPL-3.0 — Copyright (C) 2026 Carlos Villuendas.
Si despliegas una versión modificada de devtools y la ofreces por red, la AGPL te obliga a ofrecer también su código fuente a quienes la usen.