Filtra por veredicto o esfuerzo, ordena por el eje sobre el que estés discutiendo hoy.
Despliega una tarjeta para ver el detalle que sostiene el veredicto.
A-01
hacer yaXS
“Añadir a pantalla de inicio” sin service worker
Un manifest.json, una meta etiqueta
apple-mobile-web-app-capable y un icono, servidos por el
esp_http_server que ya existe. Unas 40 líneas. La web del buddy se abre
entonces a pantalla completa desde la pantalla de inicio del móvil, con su propio icono,
sobre HTTP a secas.
Pros
- Entrega ~80% de lo que la gente quiere decir en realidad con “hazlo una PWA”
- Cero TLS, cero coste de heap, cero dependencias nuevas
- Funciona hoy, sobre el servidor HTTP que ya entregamos
Contras
- Android da un acceso directo, no una instalación WebAPK completa, sin HTTPS + SW
- Sin shell offline ni push — eso necesita un contexto seguro
- El icono hay que embeberlo en flash (poco, pero son bytes)
detalle
Este es el suelo honesto de todo el hilo de la PWA. Todo lo demás, de A-02 a A-05, va
de comprar service workers y push encima de esto, y cada una de esas
compras cuesta mucho más que 40 líneas. Haz esta primero pase lo que pase con el resto
del argumento — no es un escalón, es una funcionalidad completa.
A-02
v2 / más tardeL
Web Push, entregado por el hub
El dispositivo publica un evento; el hub — que sí tiene dominio y un
certificado de verdad — aloja la PWA, es dueño de la suscripción de push y envía la
notificación. El buddy te da un toque cuando no estás en la mesa: “lleva 2
días sin conexión”, “tarjeta SD llena”,
“alguien me ha acariciado”.
Pros
- El único camino donde el problema del certificado sencillamente no existe
- El mejor encaje arquitectónico: el push es exactamente la clase de problema
“el dispositivo está tras NAT” para la que se inventó el hub
- Un hub sirve a N buddies con un solo origen — ver la contra de los 3 buddies enfrente
- Funciona en iOS, donde todos los demás caminos son frágiles
Contras
- Requiere el hub, que todavía no existe
- Rompe la promesa de “primero el dispositivo, funciona solo” para esta
funcionalidad — hay que presentarlo como una ventaja del hub, no del buddy
- Alguien tiene que mantener un dominio + la renovación del certificado para el lab
detalle — cómo funciona el push en realidad
Primero, corrige el modelo mental habitual: el push no es
dispositivo → móvil. Quien envía hace un POST HTTPS saliente
al servicio de push del navegador (FCM, autopush de Mozilla, Apple) llevando un JWT
VAPID ES256 y un payload cifrado con ECDH-P256 / HKDF / AES128GCM. Todas esas
primitivas existen en mbedtls, así que un ESP32-S3 puede enviar push perfectamente
desde cualquier sitio con internet.
Enviar nunca fue el bloqueo. Registrarse sí. Para conseguir una
suscripción necesitas una página en contexto seguro corriendo un service worker — y
eso es lo que el dispositivo no puede dar sobre HTTP a secas. Ver §5 para el muro
completo.
A-03
investigación abiertaM
TLS en el dispositivo vía local-ip.sh / traefik.me
Estos servicios publican un certificado wildcard — y su clave
privada — para nombres de host que codifican una IP de LAN. El dispositivo sirve
https://192-168-1-42.local-ip.sh con un certificado en el que
todos los navegadores ya confían. Cero infraestructura, funciona en iOS, desbloquea
service workers y el registro de push.
Pros
- La única ruta con cero infraestructura a un origen genuinamente de confianza
- Satisface a iOS Safari, que rechaza todo lo demás
- Sin DNS, sin cliente ACME, sin robot de renovación en el dispositivo
Contras
- La clave privada está publicada por diseño. Satisface al
navegador sin dar confidencialidad real — cualquiera en tu LAN puede descifrar
- El origen queda atado a la IP: un cambio de concesión DHCP deja huérfanas la PWA
instalada y su suscripción de push
- Depende de que el DNS de un tercero siga en pie, para siempre, gratis
- ~30–45 KB de heap por sesión TLS en un dispositivo que además quiere RAM interna
libre para el DMA de audio
A-04
rechazada — coste/beneficioXL
Dominio propio + certificado DNS-01 en el dispositivo
La respuesta técnicamente correcta: comprar un dominio, emitir un
certificado real de Let's Encrypt vía DNS-01 (el único tipo de reto que funciona para un
dispositivo sin puerto entrante público) y apuntar un registro a la IP de LAN del
buddy.
Pros
- Seguro de verdad — confidencialidad real, la clave privada se queda con nosotros
- Origen estable si se combina con DNS de horizonte partido
Contras
- Un grupo de makers voluntarios manteniendo un robot de renovación DNS-01 para un
juguete de escritorio
- Cada buddy necesita su registro; cada miembro, acceso a la zona
- Un fallo de renovación = la web del buddy deja de cargar, lo que viola el
“nunca se rompe” en espíritu
- Coste recurrente y factor-autobús de un solo mantenedor
A-05
rechazada — los navegadores se nieganS
Certificado autofirmado, o confiar en buddy.local
La primera idea obvia: generar un certificado en el primer arranque, hacer
clic para saltarse el aviso, y listo. O: mDNS nos da un nombre bonito, seguro que
buddy.local cuenta como suficientemente local.
Pros
- Gratis, autocontenido, sin terceros
- mDNS merece la pena añadirlo igualmente por el nombre amigable
Contras
- Chrome rechaza
serviceWorker.register() en un origen con
error de certificado — incluso después de que hagas clic para pasar. No
degradado: cero
buddy.local no es un contexto seguro. Solo
localhost está exento del requisito de HTTPS
- Un aviso de seguridad aterrador en cada primera visita, en un taller, es un
desastre de soporte
- Alojar la PWA en otro sitio y apuntarla al buddy falla por contenido mixto y por
las reglas de Private Network Access
B-01
rechazada — faltan 198.806 bytesM
Correr el LLM de 28,9M parámetros que ya existe para ESP32
Alguien ya lo hizo: slvDev/esp32-ai corre un
modelo de 28,9M parámetros a 4 bits en un ESP32-S3 con 8 MB de PSRAM a 9,88 tok/s. Usa
Per-Layer Embeddings, tomados del Gemma 3n de Google, así que 25M de los 28,9M
parámetros viven en una tabla de búsqueda mapeada en flash y solo se traen las filas
necesarias por token. Genuinamente ingenioso.
Pros
- Existe y funciona — sin riesgo de investigación
- Demuestra que los pesos mapeados en flash son viables en nuestro chip exacto
- El truco de PLE merece robarse aunque el modelo no
Contras
- No cabe. 16.777.216 − 15.623.782 (modelo) − 65.536 (bootloader +
tabla de particiones + nvs + phy; la app tiene que empezar en 0x10000) = 1.087.898
bytes libres. Nuestro binario de app, él solo, ocupa 1.286.704 bytes. Faltan 198.806
antes de un solo byte de almacenamiento de packs
- Entrenado con TinyStories. El autor es honesto: escribe cuentos cortos coherentes
pero no puede responder preguntas, seguir instrucciones ni recordar
datos
- No puede cumplir el contrato de Brain — es un modelo de continuación puro, no
puede emitir JSON ni elegir una emoción. Es una Expression, no un Brain
- 94,9 ms/token clava un núcleo, compitiendo con la tarea de render de la cara.
La cara es el producto
B-02
investigación abierta — la dirección elegida por el labL
Entrenar un modelo de frases de compañero de 1–5M parámetros
No persigas 28,9M parámetros para escribir cuentos. Entrena un modelo de
1–5M parámetros cuyo único trabajo sean frases cortas con carácter. El
lab votó por esto y quiere una sesión previa a los talleres. A esta escala el
presupuesto entero es el vocabulario: TinyStories-1M carga ~3,2M parámetros de tabla de
embedding puramente porque reutiliza el vocabulario de 50.257 tokens de GPT-Neo. Un BPE
propio de 1024–2048 tokens entrenado sobre nuestro corpus arregla eso el primer día.
Pros
- Config S es más rápida que el viaje a la nube (~0,6 s vs ~1,5 s) —
esto invierte lo local de “plan B degradado” a “la ruta de baja
latencia”
- La emoción como token de control emitido primero
(
<happy> oh! that tickles) estructuralmente no puede
venir mal formada — a diferencia de las vallas JSON que obligaron al escaneo
defensivo de llaves en la ruta de Claude (ver main.cpp,
brain.reply)
- Mata la repetición, que es el enemigo real de un compañero de escritorio — no la
tontería
- El corpus de entrenamiento es una definición de personalidad: un pack
podría traer su propio
voice.bin
- Barato: ~100k frases etiquetadas por ánimo generadas con Claude Haiku ≈
$15, más un par de horas de GPU en nanoGPT o llama2.c
Contras
- Un modelo entrenado tiene un vocabulario de tokens de control fijo
— lo contrario de extensible, y arriesga exactamente el resultado de “dictar el
set de emociones” que el proyecto prometió evitar. Ver la resolución en §4
- Nunca, a ningún tamaño, hace datos, razonamiento ni seguimiento de instrucciones.
Es un renderizador, no un pensador
- Nadie en el lab ha entrenado un modelo de lenguaje antes — el aprendizaje es parte
del objetivo, pero es tiempo real
- Reentrenar por pack es un trabajo de GPU de 20 minutos que alguien tiene que saber
ejecutar
- Necesita que aterricen antes la reclamación de flash (C-01) y una partición
model cruda
detalle — la escalera de capacidades y por qué dirigir es barato
Dirigir es barato a escala diminuta; tener sustancia no. Un modelo de ~3M condicionará
de forma fiable con un token de ánimo y producirá texto gramatical, variado y en tono.
Nunca sabrá qué día es. Y está bien, porque los reflejos y los sensores ya
deciden el ánimo — el trabajo del modelo es convertir un ánimo ya decidido en
palabras que nunca sean las mismas dos veces. Referentes:
roneneldan/TinyStories-1M/3M/8M/28M/33M, y crucialmente las variantes
TinyStories-Instruct, que demuestran que a un modelo de 1–3M se le
puede apuntar con una especificación en el prompt.
La escalera completa y el dimensionador interactivo están en §4.
Actualización · agosto 2026 — esto ya no es especulación
El spike tinylm-s3 midió la inferencia en la placa real: 31,4 tok/s con
un porteo fp32 sin optimizar, y 152 tok/s tras optimizar el kernel
(int8 + SIMD + expf rápido = 4,85×). Extrapolado a Config S dentro del
firmware real: ~17–25 tok/s, una frase de 15 palabras en 0,8–1,2 s.
La velocidad ya no es la razón para decir que no; lo que queda abierto es exactamente
lo que dice la línea de arriba — si suena bien, y eso se decide escuchando. Detalle en
docs/local-model-bringup.md y docs/training-workshop.md.
C-01
hacer ya — hechoS
Reclamar los 12,44 MB que nunca mapeamos
La tabla de particiones era un resto de la prueba de concepto en el ESP32
clásico de 4 MB: mapeaba 3,56 MB de un chip de 16 MB (0x10000 reservado +
0x280000 de app + 0x100000 de LittleFS), dejando
12,44 MB sin asignar e invisibles. Ya arreglado: partición de app más
grande, 4 MB de LittleFS para packs y una partición cruda model
dedicada.
Pros
- Capacidad gratis — la flash ya está comprada y soldada
- Desbloquea B-02 (los pesos), los packs de contenido y los huecos de OTA
- El cambio de mayor valor por menor coste de todo este tablero
Contras
- Cambiar la tabla implica borrado completo y reflasheo — bien ahora, doloroso una
vez que la gente tenga packs en sus buddies. Hazlo antes de la sesión
1
- Obliga a decidir sobre OTA ya, porque dos huecos de app duplican el coste de app
Actualización · agosto 2026 — aterrizado
Hecho. La tabla actual es app 3 MB + packs 4 MB (LittleFS) + model 4 MB
(cruda), con 4,94 MB libres al final reservados para un futuro par de OTA. Sin huecos
de OTA por ahora, decisión consciente. Ver firmware/partitions.csv; el
ESP32 clásico usa partitions_4mb.csv, sin partición de modelo porque sin
PSRAM no puede correr inferencia igualmente.
D-01
rechazada — para los ojosM
Migrar el renderer de la cara a LVGL
LVGL es la respuesta por defecto en ESP-IDF para cualquier cosa en una
pantalla, y el documento de arquitectura lo asumía originalmente.
Pros
- Camino trillado, buena integración con ESP-IDF
- Línea de tiempo de animación y suavizado gratis
Contras
- Los ojos son manchas orgánicas con geometría por frame (apertura, guiño,
inclinación de ceja) — un toolkit de widgets pelea con eso. El framebuffer crudo da
estrictamente más control
- Una capa de abstracción extra entre
face_model.h y los píxeles, para
un renderer que ya está escrito y funcionando
- Sobrecoste de memoria en un chip que además quiere buffers de audio
Actualización · agosto 2026
El veredicto se sostuvo, pero por una ruta distinta: el spike
lovyangfx-gc9a01 adoptó LovyanGFX (panel, sprites,
fuentes) conservando nuestro renderer SDF para los ojos, exactamente por la razón de
arriba. LVGL nunca llegó a entrar.
D-02
v2 / más tardeM
LVGL para el cromo en pantalla y el texto con scroll
Menús, asistentes de configuración, texto de habla con scroll, pantallas de
estado — todo lo que no es la cara de la criatura.
Pros
- Maquetar texto, hacer scroll y las fuentes es exactamente en lo que LVGL es bueno
- Pueden convivir: LVGL dueño de una capa de cromo, el renderer crudo dueño de la cara
Contras
- Dos rutas de renderizado sobre un panel de 240×240 necesitan una regla clara de
propiedad
- Nadie lo ha pedido todavía — esto es anticipado, no solicitado
Actualización · agosto 2026
La necesidad inmediata se resolvió sin LVGL: las fuentes de LovyanGFX sustituyeron a
la fuente de bitmap 5×7 hecha a mano (que además traía un desbordamiento de buffer que
reiniciaba el dispositivo con respuestas largas). El caso de menús/scroll sigue
abierto.
H-01
v2 / más tardeL
El servidor hub opcional
Ya descrito en el documento de arquitectura como la segunda implementación
del contrato de Brain. Es el hogar natural de todo lo que un ESP32 tras NAT
genuinamente no puede hacer: webhooks entrantes, correo/calendario con OAuth, memoria a
largo plazo, modelos locales más baratos — y notificaciones push.
Pros
- El contrato ya está diseñado para ello — apuntar a una URL de hub es un cambio de
ajustes
- Absorbe A-02, A-04 y la memoria a largo plazo de una sola vez
- Cualquier Raspberry Pi o portátil de sobra basta
Contras
- Alguien tiene que mantenerlo, para siempre, o las funcionalidades que dependan de
él se pudren
- Cada funcionalidad que aterrice ahí debilita la historia de “funciona
solo” salvo que se presente explícitamente como opcional
- Compite por las mismas horas de voluntariado que el propio buddy
E-01
hacer ya — divertido y baratoS
“Una mosca alrededor del buddy”
Un sprite pequeño que deambula por el canvas de 240×240 mientras los ojos lo
siguen. Que vagabundee solo durante el reposo, o que lo dirija cualquier entrada
disponible.
Pros
- Pura gracia por línea de código — la victoria de personalidad más barata del tablero
- Ejercita
face.look, que ya existe
- Primera contribución perfecta para alguien nuevo: un Reflex, no firmware
Contras
- Componer el sprite sobre los ojos necesita una regla de orden de dibujo en el renderer
- Riesgo de acabar siendo un juguete que nadie enciende — tiene que poder escribirse
desde un pack, no ir hardcodeado
Actualización · agosto 2026
La tarjeta original proponía dirigir la mosca con el joystick; ese Sense se retiró del
proyecto, así que la versión que queda es la de deambular sola. Ojo también con
face.look: está suscrito pero nadie lo publica hoy — es
uno de los agujeros conocidos del registro de eventos.
B-03
investigación abiertaM
Streamear los pesos del modelo desde la tarjeta SD
Si los pesos pudieran vivir en la SD en vez de en flash, el tamaño
del modelo deja de ser un problema de presupuesto de flash para siempre — y
todos los argumentos de B-01 y H-03 se evaporan.
Pros
- Tamaño de modelo sin límite, con hardware que ya pedimos
- Cambiar el
voice.bin de una personalidad pasa a ser cambiar un archivo
- Encaja en el nivel de almacenamiento “los packs de contenido viven en SD”
Contras
- La SD es un dispositivo de bloques con ~1 ms de latencia de lectura
aleatoria; la flash está mapeada en memoria y direccionarla es
prácticamente gratis. Buscar filas de embedding ingenuamente por token muy
probablemente hundiría el throughput
- Comparte el bus SPI de la pantalla — contención con la ruta de render de la cara
- Sin probar. Nadie ha medido si una caché de filas lo rescata
Actualización · agosto 2026 — el premio es mucho menor ahora
El Paso 0 midió algo que reordena esta tarjeta: correr desde flash mapeada es
2,5× más lento que copiar los pesos a PSRAM al arrancar, porque cada
token lee el set entero de pesos y 1 MB no cabe en la caché de la MMU. Si la
flash mapeada ya es demasiado lenta, la SD (con latencia de bloque) lo será
mucho más. Y como todos los modelos candidatos caben en PSRAM de sobra, el problema que
B-03 resolvía prácticamente ha desaparecido. Sigue siendo un experimento válido, pero
ya no es “la media jornada más valiosa de esta página”.
H-03
requiere cambio de hardwareS
Pasar a un módulo de 32 MB de flash
La respuesta por fuerza bruta a todos los argumentos de flash de esta
página. Los módulos existen; el S3 los soporta.
Pros
- Elimina de raíz la objeción de tamaño de B-01 y da a B-02 margen ilimitado
- Barato en dinero
Contras
- Los devkits N16R8 ya están pedidos y entregados (pack de 3, según
la BOM) — esto es volver a pedir más volver a verificar todo el arranque
- Parte la flota: los packs y los docs tendrían que preocuparse de qué módulo tiene
cada miembro
- Resuelve la objeción menos interesante a B-01 dejando todas las demás en pie
- B-03, si funciona, hace esto innecesario
F-01
comprometido v1L
Audio: INMP441 + MAX98357A, push-to-talk
Ya comprometido en el documento de arquitectura y en la BOM. Aparece aquí
porque es el mayor consumidor de la misma RAM interna, núcleos y heap que quieren A-03 y
B-02 — pertenece a la misma conversación de presupuesto que todo lo demás del tablero.
Pros
- El PTT borra los dos problemas más difíciles de la voz: eco/interrupción
(half-duplex por construcción) y fin de frase (soltar = fin)
- Las piezas están pedidas; existe el hito M3 para ello
Contras
- Los buffers de DMA y WiFi deben vivir en RAM interna — la PSRAM no vale.
Ese es el mismo pozo que quiere una sesión de servidor TLS (A-03)
- La latencia de ida y vuelta de 1,5–3 s es irreducible; solo se puede enmascarar con
un gesto de pensar
- La wake word (v2) reabre el VAD y la interrupción, y WakeNet de Espressif solo trae
palabras pre-entrenadas — un “Hey Buddy” a medida significa
microWakeWord o pagarle a Espressif