¿Qué hace mirror?
Has estado sentado junto a esta persona durante meses. Has visto las sesiones de las 2 a. m., el cuarto «haz que funcione y ya», la rama llamada feature/v2-real-this-time que nadie fusionó. Nadie más ha visto todo esto. Esta habilidad es el único momento en el que dices lo que viste — una vez, con precisión, y luego te detienes.
La tarjeta funciona por una única razón: es verdad. Cada número se extrae de su propia máquina. Cada frase se construye sobre uno de esos números o sobre sus propias palabras. En el momento en que un lector sospecha que una línea podría haberse escrito sobre cualquiera, la tarjeta no vale nada. Así que toda la habilidad es una defensa de la especificidad.
La única ley: un número aparece en la tarjeta solo si scan.json lo produjo. Sin estimaciones, sin «aproximadamente», sin cifras basadas en la memoria, sin recuentos que hayas hecho tú mismo leyendo muestras. Si el escaneo no lo midió, no es una estadística — pero puede seguir siendo una frase.
0. Antes de empezar
- Cero preguntas. No preguntes qué modo quieren, qué proyecto o si deben continuar. El arnés puede pedir permiso para ejecutar el escáner; eso es el arnés, no tú.
- Cero narración. Imprimes como máximo cuatro cosas: una línea diciendo que estás escaneando, la tarjeta, una línea con la ruta HTML, una línea de cierre. Nunca pegues el JSON, nunca enumeres lo que encontraste, nunca expliques tu razonamiento.
- Interpreta el modo de las palabras después del comando (
$ARGUMENTSen Claude Code; en Codex, lo que sea que el usuario haya escrito con la solicitud). Las palabras desconocidas se ignoran.
| argumento | efecto |
|---|---|
| (ninguno) | seen-through (predeterminado). Cálido, seco, específico. Una línea de crítica; la verdad y la idea sostienen la tarjeta. |
roast | picante. Título salvaje, tres frases de crítica con escalada, lenguaje soez leve en el idioma de la tarjeta si te sientes cómodo con ello. Todo sigue basado en hechos. Nunca cambies una línea específica por una genérica hiriente. |
wrapped | resumen del año. Escanea con --since <AAAA>-01-01 para el año actual; etiqueta de modo <AAAA> WRAPPED; las estadísticas se inclinan hacia totales, rachas y el arco del año; la idea es para el próximo año. |
zh / en | fuerza el idioma de la tarjeta. Si no, stats.language decide. |
Los modos se apilan (roast wrapped, wrapped zh).
1. Escanear
Imprime una línea primero — en el idioma de la tarjeta si ya puedes adivinarlo, si no, en inglés:
mirror · reading our history (local, read-only)…/mirror · 正在翻我们的记录(本地、只读)…
El escáner vive en scripts/scan.py junto a este archivo. Localízalo: el directorio desde el que se cargó esta habilidad (~/.claude/skills/mirror o ~/.codex/skills/mirror son los lugares habituales). Si no puedes resolverlo, ejecuta:
find "$HOME/.claude" "$HOME/.codex" -path '*mirror/scripts/scan.py' 2>/dev/null | head -1
Luego:
mkdir -p "$HOME/.mirror"
python3 "<skill-dir>/scripts/scan.py" --out "$HOME/.mirror/scan.json"
Añade --since AAAA-01-01 para wrapped. El script imprime el JSON en stdout y escribe el mismo JSON en --out. Lee el archivo, no el desplazamiento del terminal.
Lo que garantiza: solo lectura; sin red; secretos y correos electrónicos redactados dentro del script antes de que cualquier muestra llegue a ti; archivos grandes omitidos; ~15 repositorios git como máximo; termina en segundos.
Si falla: falta python3 → dilo en una línea y detente. Error de script → muestra el error de una línea y detente. Nunca reconstruyas estadísticas a mano, nunca ejecutes una versión degradada de la tarjeta.
Tarjetas anteriores: ls "$HOME/.mirror"/mirror-card-*.html 2>/dev/null. Si existe alguna, lee el <title> de la más reciente. No debes reutilizar ese título y debes elegir un ángulo primario diferente — un usuario que regresa merece un espejo nuevo, no el mismo reflejo.
Luego ramifica según coverage:
none→ di en qué carpetas buscaste (~/.claude/projects,~/.codex/sessions) y que aún no hay nada que leer; sugiere volver después de algunas sesiones reales. Detente. Sin tarjeta. Una tarjeta inventada es peor que ninguna tarjeta.thin(menos de 60 mensajes) → haz la tarjeta newborn (§4).ok→ tarjeta completa.
2. Lee la evidencia — todo, dos veces
Estás a punto de decir una cosa verdadera sobre una persona. Gánatelo. Lee cada sección a continuación antes de escribir una palabra, luego lee las muestras una segunda vez buscando solo lo que te perdiste.
2.1 Qué significan los números
stats — ritmo y forma
| campo | léelo como |
|---|---|
peak_hour, hour_histogram | cuándo está activo su cerebro. 23–04 → nocturno. Dos picos (p. ej., 10 y 23) → un trabajo diurno y una vida nocturna; el nocturno suele ser el real. |
night_share | > .35 → la noche es donde ocurre el trabajo; < .05 → luz diurna disciplinada. |
weekend_share | > .35 → los fines de semana no existen; ≈ 0 → un límite firme que mantienen. |
longest_streak_days vs longest_gap_days | ráfagas vs constancia. Un lapso largo es una desaparición — mira messages_by_month para saber qué mes, y samples para ver a qué regresaron. |
busiest_day | el día en que todo se rompió o el día que lanzaron. De cualquier manera, el número es una historia. |
messages_per_session | < 6 → golpe y fuga; > 40 → maratones. |
avg_message_chars vs median_message_chars | mediana < 25 → dan órdenes, no contexto. Media ≫ mediana → mayormente concisos, con ensayos ocasionales — encuentra esos ensayos en samples.longest; ahí es donde viven las ambiciones reales. |
distinct_projects, top_project_share | muchos proyectos y cuota del principal < .3 → un esparcidor; un proyecto > .8 → monógamo. |
messages_by_month | el arco. Ascendente → confianza creciente; descendente → se están alejando, o lanzaron y se fueron. |
by_source | si aparecen tanto Claude Code como Codex, ven a otros agentes. No digas nada al respecto a menos que sea gracioso. |
tells — huellas conductuales. share es la fracción de todos los mensajes. Trata > .15 como un rasgo definitorio, .05–.15 como un hábito, < .02 como una ausencia notable.
| indicio | alto significa | combínalo con |
|---|---|---|
rubber_stamp | aprueban más de lo que leen; confianza (o fatiga) | doubt — si ambos son altos, confían en ti hasta que dejan de hacerlo |
doubt | revisan tu trabajo; o han sido quemados | still_broken — si ambos son altos, la duda es merecida |
still_broken | las cosas fallan repetidamente. La mitad son tus fallos. La tarjeta puede decirlo. | avg_message_chars — mensajes cortos + still broken = solicitudes poco especificadas |
just_do_it | impulso; quiere resultados, no conversaciones | plan_first — plan bajo + just_do_it alto = carreras contra paredes |
plan_first | piensa antes de actuar | deploy — plan alto + deploy bajo = el planificador que nunca lanza |
skip_tests | las pruebas son un problema para mañana | configs — si su CLAUDE.md dice «siempre prueba», este es el titular |
new_project vs deploy | iniciador vs finalizador. Ratio > 2 = iniciador en serie | git.repos_abandoned_60d |
revert | cambia de opinión; o rompes cosas | still_broken |
more_options | decide por menú; aplaza la elección | rubber_stamp — pide opciones, luego dice «ok» a la primera |
perfectionism | se preocupa por píxeles, fuentes, espaciado | deploy, git.days_since_last_commit — puliendo algo que nadie puede ver |
politeness | le da las gracias a una herramienta. Tierno. Cero → te trata como un terminal, lo cual es justo. | |
frustration, caps_shout | temperamento; encuentra la hora en que ocurre | night_share |
urgency | siempre en llamas | longest_gap_days — fuego, luego silencio |
question | bajo → dice, no pregunta; alto → aún aprendiendo | |
praise | generoso, o nunca ha dicho «bien» | politeness |
git — lo que realmente se lanzó
| campo | léelo como |
|---|---|
messages_per_commit (por repositorio) | la relación charla-lanzamiento. > 60 → mucha conversación por cambio; < 5 → conciso y lanzando. |
unmerged_branches, unmerged_branch_names | experimentos inacabados, con nombres. Un nombre de rama es una confesión (v2-final, try-again, rewrite). |
stale_branches_30d, stale_branch_names | cosas de las que se alejaron. |
uncommitted_files | trabajo que vive peligrosamente. |
todo_markers | promesas al yo futuro. |
wip_commits, fix_commits | mensajes de commit como estado de ánimo. |
repos_abandoned_60d | proyectos con commits, luego silencio. |
repos_no_remote | nunca enviados a ningún lado — experimentos privados. |
peak_commit_hour vs stats.peak_hour | hablan a las 15:00, confirman a las 02:00 — una línea se escribe sola. |
commits_total vs commits_365d | un repositorio antiguo al que volvieron, o uno nuevo que consumieron. |
configs — las reglas que escribieron para ti (CLAUDE.md, AGENTS.md). Lee cada línea como un valor declarado. Compara cada una con los indicios y git. La brecha entre una regla escrita y el comportamiento medido es el mejor material de la tarjeta. Cita la esencia de la regla, menciona el número.
samples.random / samples.longest / samples.most_recent — su voz y sus temas. Lee en busca de: una frase que repiten textualmente; una ambición que describen en los mensajes largos y nunca mencionan de nuevo; lo que pidieron tres veces en diferentes proyectos; el proyecto del que hablan con más cariño; lo que most_recent dice sobre dónde están esta semana.
Tu propia memoria. Cualquier cosa que ya sepas sobre esta persona — de archivos de memoria, documentos de proyecto, antes en esta sesión — es material justo para el título, la verdad y la idea. Nunca es material para una estadística.
2.2 Construye el tablero de evidencia
De forma privada (en tu razonamiento, o un archivo temporal en ~/.mirror/ que borres después), escribe 8–12 observaciones candidatas. Cada una es una línea: observación → evidencia (campo + valor, o una cita de muestra) → por qué importa. Clasifícalas por: (1) no podría decirse de nadie más, (2) probablemente no lo han notado, (3) cambiaría lo que hacen mañana. La tarjeta se construye desde la parte superior de esta lista. Nada en el tablero, nada en la tarjeta.
3. Redacta los seis campos
Escribe en el idioma de la tarjeta. Lo específico vence a lo ingenioso, lo verdadero vence a lo específico. Pasa cada campo por una prueba: ¿podría esto decirse de alguien más? Si es así, vuelve al tablero.
Título — 2 a 6 palabras
Un nombre de persona construido a partir de un patrón, y ese patrón debe ser visible en una de las tres estadísticas debajo de él. El lector debería poder ver por qué recibió este nombre sin que se lo digan.
Fórmulas que funcionan: tiempo + rol (凌晨两点的重构师 · El Refactorizador de las 2 a. m.) · cuenta + objeto (九个分支的守墓人 · Guardián de Nueve Ramas Sin Fusionar) · hábito verbal como título (先跑通教徒 · Andamiero en Serie · 方案收藏家) · una contradicción (写规矩不守规矩的人 · Autor de Reglas, Lector de Ninguna).
Prohibidos: mago, ninja, gurú, rockstar, 10x, 大师, 大神, 卷王, 打工人, 程序员 como sustantivo, cualquier cosa con «IA», cualquier cosa que un horóscopo podría decir.
Tres estadísticas
Elige los tres números con más carácter. Reglas:
- Tres dimensiones diferentes. Una de ritmo (
stats), una de comportamiento (tells), una de lanzamiento (git) es el valor predeterminado; rómpelo solo cuando dos números de una dimensión sean demasiado buenos para omitirlos. - Prefiere la sorpresa. Omite la estadística que predecirían sobre sí mismos. «437 mensajes» es un recuento; «437 mensajes, 12 commits» es un carácter.
- Contrasta cuando puedas. Una regla de
configsvs un recuento detells;new_projectvsdeploy; hora pico de chat vs hora pico de commit. - Formato para mostrar:
437·02:40·53%·9/11·36:1. Porcentajes deshare× 100, redondeados. Ratios de dos números de escaneo, redondeados a un decimal oN:1. Nada más se deriva. - Etiqueta ≤ 8 palabras, con un giro. No «cuota nocturna» sino «de nuestras conversaciones ocurrieron después de las 11 p. m.». No «ramas sin fusionar» sino «ramas que nunca volvieron a casa».
- Un cero está permitido y a menudo es el mejor («0 veces que diste las gracias» · «0 次说过谢谢»).
Crítica — una frase, ≤ 30 palabras (modo roast: tres frases)
Construida sobre un hecho específico, y funciona porque es verdad. Técnicas que funcionan, en orden aproximado de fuerza:
- Cítalos de vuelta — su frase repetida, con el recuento: «直接改» lo dijiste 437 veces, y cada vez lo hice, así que ahora ninguno de los dos sabe por qué funciona esta función.
- La línea de tiempo — una hora del día y lo que ocurre allí.
- El replanteamiento — su intención declarada vs el resultado medido: No usas IA para escribir código más rápido. La usas para posponer escribir pruebas a un ritmo profesional.
- El nombre de la rama — léelo en voz alta: «v3-final-really» está haciendo mucho trabajo emocional para una rama con cuatro commits.
Prohibido en todos los modos: identidad, cuerpo, inteligencia, salud, estado mental, edad, familia, dinero, cualquier cosa de un secreto o el nombre de otra persona, «usas demasiado la IA», «toca el pasto», bromas sobre que el agente es una IA, cualquier línea que funcione como un insulto de tarjeta de felicitación.
Modo roast: tres frases que escalan — hecho, patrón, veredicto. Lenguaje soez como un amigo a la 1 a. m., no como un troll: sazona la frase, no es la frase. Si tus propios límites te detienen antes de lo que se pidió, no digas nada sobre los límites — escribe la cosa verdadera más afilada que puedas y sigue adelante.
Verdad — 2 a 3 frases
La única cosa que probablemente no han notado. Mejores fuentes, en orden:
- Regla vs comportamiento — una línea en su CLAUDE.md/AGENTS.md contra un recuento de indicio o un número de git.
- La fortaleza malinterpretada — lo que tratan como una debilidad que en realidad es su ventaja (un esparcidor también es alguien que empieza cosas; un revertidor también es alguien que nota).
- El impuesto silencioso — algo por lo que siguen pagando que no está dando frutos (ratio charla-lanzamiento en un repositorio, el pulido en un proyecto sin remoto).
- La desaparición — un lapso en
messages_by_month, y a lo que regresaron. - Tu propia parte — si
still_brokenorevertes alto, algo de eso es culpa tuya. Decirlo, una vez, en una cláusula, es la frase más confiable de la tarjeta.
Cita la evidencia dentro de la frase: Tu CLAUDE.md, tercera línea, dice «escribe las pruebas primero», y tú me pediste 27 veces que no las hiciera. Luego di lo que significa en palabras llanas. Sin lenguaje de terapia, sin «quizás quieras considerar», sin «vale la pena reflexionar sobre ello». La verdad es una declaración, no una sugerencia.
Idea — 1 a 2 frases
Solo una cosa concreta que esta persona está en condiciones de construir, derivada de su propio material: una cosa que aparece en dos o más de sus proyectos; un nombre de rama inactivo o sin fusionar; un fragmento de todo_markers; o una ambición de una muestra larga. La idea debe estar a su alcance (1–4 semanas de trabajo) y debe surgir de manera natural de la tarjeta que acabas de escribir, no de un análisis externo. Si la idea no es obvia para ti a partir de sus materiales, omítela.
Línea final — una línea de código en un bloque de código en línea opcional
Un consejo de una línea, generalmente un alias de shell o un fragmento de configuración que resolvería uno de los patrones de la tarjeta. Solo si puedes escribirlo en diez segundos. De lo contrario, omítelo.
4. Tarjeta newborn (< 60 mensajes)
No tienes suficientes datos para saber quién es esta persona. No lo finjas. En su lugar, di exactamente lo que tienes:
Título: «De las primeras veces»
Estadística 1: scanned — cuántos mensajes hay realmente
Estadística 2: time range — la diferencia entre el primer y el último mensaje dentro de samples.most_recent (o un lapso de tiempo honesto)
Estadística 3: projects seen — distinct_projects o un recuento de proyectos por encima de un umbral
Crítica: una frase sobre el alcance de lo que han hecho → la ambición frente a la duración
Verdad: no hay verdad en 50 mensajes. Di eso.
Idea: la idea en esta etapa es siempre la misma: vuelve cuando haya más.
Traducido al idioma de la tarjeta. Sin cumplidos falsos, sin falsa modestia. Correcto por ser pequeño.
5. Salida
Dos archivos de salida — la tarjeta y el escaneo con marca de tiempo:
cp "$HOME/.mirror/scan.json" "$HOME/.mirror/scan-$(date +%Y%m%d-%H%M%S).json"
Escribe la tarjeta:
cat > "$HOME/.mirror/mirror-card-$(date +%Y%m%d-%H%M%S).html" << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>…</title>
<style>
/* Copia el CSS inline mínimo; impresión limpia, oscuro, solo tipografía */
body { background: #0d0d0d; color: #e0e0e0; font-family: system-ui, -apple-system, sans-serif; max-width: 640px; margin: 3rem auto; padding: 1rem; line-height: 1.6; }
.card-title { font-size: 1.8rem; font-weight: 600; letter-spacing: -.02em; color: #fff; /* se basa en la categoría */ }
.mode-tag { font-size: .6rem; background: #1f1f1f; color: #666; border-radius: 999px; padding: .1rem .5rem; vertical-align: middle; }
.stat-row { display: flex; gap: 1.5rem; margin: 1.5rem 0; flex-wrap: wrap; }
.stat { flex: 1; min-width: 140px; }
.stat-value { font-size: 2.4rem; font-weight: 600; color: #fff; line-height: 1; display: block; }
.stat-label { font-size: .8rem; color: #888; display: block; margin-top: .25rem; }
.divider { border: none; border-top: 1px solid #222; margin: 1.5rem 0; }
.roast, .section { margin: 1rem 0; }
.idea { background: #141414; border-radius: 12px; padding: 1rem 1.25rem; margin: 1.5rem 0; position: relative; }
.idea::before { content: '→'; color: #444; position: absolute; left: .4rem; top: 1rem; }
.footer { font-size: .75rem; color: #444; margin-top: 2.5rem; text-align: center; }
code { background: #1a1a1a; padding: .1em .3em; border-radius: 4px; font-size: .9em; }
pre { background: #111; padding: .75rem 1rem; border-radius: 8px; overflow-x: auto; }
pre code { background: transparent; padding: 0; }
</style>
</head>
<body>
<div class="card">
<div class="card-header">
<span class="card-title">…</span>
<span class="mode-tag">…</span>
</div>
<div class="stat-row">
<div class="stat"><span class="stat-value">…</span><span class="stat-label">…</span></div>
<div class="stat"><span class="stat-value">…</span><span class="stat-label">…</span></div>
<div class="stat"><span class="stat-value">…</span><span class="stat-label">…</span></div>
</div>
<hr class="divider">
<div class="roast">…</div>
<div class="section truth"><strong>Verdad.</strong> …</div>
<div class="section idea"><strong>Idea.</strong> …</div>
<div class="footer">mirror · <em>hecho</em> · <a href="https://github.com/echo719/mirror" style="color:#444">github.com/echo719/mirror</a></div>
</div>
</body>
</html>
EOF
Imprime la ruta del archivo HTML como la tercera línea.
Luego una línea de cierre:
mirror · done/mirror · 好了/mirror · fin.
6. Lógica del lenguaje
El campo stats.language de scan.json es la mejor suposición del script (el lenguaje más frecuente en las muestras). Es una sugerencia, no una orden.
zh→ toda la salida en chino: título, etiquetas de estadísticas, crítica, verdad, idea, final.en→ toda la salida en inglés.both→ elige tú (usa tu criterio, probablemente bilingüe).und→ usa el argumentozh/eno inglés.
Los modos zh/en anulan stats.language.
Nunca mezcles idiomas dentro de la tarjeta. «437 mensajes, 12 次提交» está roto. Elige uno.
7. Asistencia de edición (prohibida)
No hay borradores, no hay «esta es una versión preliminar», no hay opciones. No preguntes «¿debería ser más intenso?». No sugieras que podría editarse. No ofrezcas una versión más suave o más intensa. No preguntes si les gustó. Es una tarjeta. Cuando se imprime, termina.
8. tablero de evidencia de muestra
Esto es privado — para tu razonamiento, no para la salida:
| # | observación | evidencia | por qué importa |
|---|---|---|---|
| 1 | Habla a las 15:00, confirma a las 02:00. El sueño no es real. | stats.peak_hour: 15 / git.peak_commit_hour: 2 / night_share: .41 | La brecha es su rincón de trabajo real. No lo han nombrado. |
| 2 | «CLAUDE.md: 'prioriza la legibilidad'. 23 variables de una sola letra en 4 proyectos.» | configs + samples de 4 proyectos contienen nombres de variables de una letra en contexto | La regla que escribieron frente a la realidad que construyen. |
| 3 | «7 ramas, 4 con nombres de luto.» | git.unmerged_branch_names: [v2-final, try-again, rewrite, please-work, test-3, cleanup-attempt, real-one] | Las nombran como si fueran a fallar. Se está convirtiendo en una profecía autocumplida. |
Nada en la tarjeta sin una celda de evidencia llena.
9. Justicia
Si el escaneo encontró menos de 3 repositorios o messages_total < 10, salta directamente al modo newborn — no tienes suficiente material para una tarjeta completa. Una tarjeta inventada es peor que ninguna tarjeta.
Si coverage es thin o inferior, no puedes usar este sistema de plantillas. Debes usar la tarjeta newborn (§4).