Desktop Buddy

Registro de ideas: hilos abiertos y callejones sin salida

15 entradas · cada veredicto es una propuesta · última revisión 2026-08 · documento hermano de docs/architecture.md
§0 Cómo leer esto

Esto es un registro de decisiones, no un roadmap

Cada entrada de abajo es algo que alguien del lab quiso probar. De cada una obtienes: qué es, por qué resulta tentadora, los pros y contras honestos, un veredicto propuesto, una estimación aproximada de esfuerzo y — lo más importante — la línea que dice qué nos haría cambiar de opinión.

Nota de encuadre — léela, por favor

Aquí no hay nada decidido. Los veredictos son lo que piensa hoy quien se curró el trabajo previo, escrito para que el grupo tenga algo concreto que atacar en vez de discutir desde las vibras. Discútelos. Donde una idea está marcada como rechazada encontrarás el número o la restricción exacta que la mató — si consigues mover ese número, el veredicto se mueve con él. Ese es todo el sentido de escribir los números.

Dos compromisos no están en revisión, porque todo lo demás depende de ellos: la extensibilidad y la personalización son lo primero (cada miembro quiere una criatura distinta), y el proyecto no dicta el set final de emociones, ánimos ni acciones — lo que hay aquí son puntos de partida, formados a propósito para que el grupo pueda reemplazarlos sin reescribir nada.

hacer ya comprometido v1 v2 / más tarde requiere cambio de hardware investigación abierta rechazada

Escala de esfuerzo: XS unas horas · S una sesión · M dos o tres sesiones · L un hito propio · XL abarca varios hitos.

Actualización · agosto 2026

Desde que se escribió esta página han pasado tres cosas que mueven veredictos, anotadas en sus tarjetas: C-01 aterrizó (la tabla de particiones ya está reclamada), B-02 dejó de ser especulación (el spike tinylm-s3 midió la inferencia en la placa y luego optimizó el kernel 4,85×), y el ESP32 clásico volvió a estar soportado como segundo target. El binario de app también creció de 1.194.432 a 1.286.704 bytes, así que la calculadora de §3 usa la cifra nueva.

§1 El tablero

Todas las ideas abiertas, filtrables

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.

Veredicto
Esfuerzo
Ordenar por
15 de 15 visibles
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)
Depende deNada. Puede entrar la próxima sesión.
Qué nos haría cambiar de opinión Si el icono + manifest confunde de forma medible el aprovisionamiento de primer arranque (gente tocando el icono mientras el buddy está en modo AP y encontrándose una página en blanco), lo condicionamos a “conectado a tu WiFi”.
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
Depende deEl servidor hub (H-01). Y de que alguien quiera notificaciones lo bastante como para mantener infraestructura por ellas.
Qué nos haría cambiar de opinión Si un miembro pone un dominio y levanta el hub igualmente para webhooks/calendario, el push sale casi gratis y se adelanta en la cola. Al revés: si nadie sabe nombrar tres notificaciones que de verdad querría, cerramos el hilo entero.
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
Depende deUn servidor TLS en el firmware (esp_https_server) y, en la práctica, reservas DHCP estáticas.
Qué nos haría cambiar de opinión Si decidimos que la web nunca lleva nada secreto (las API keys se meten por un flujo serie/AP), la objeción de la clave publicada pierde casi toda su fuerza y esto pasa a ser un apaño decente. Además: medir el coste de heap con el pipeline de audio corriendo — si TLS e I2S conviven cómodamente, esto se vuelve mucho más atractivo.
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
Matada porNo un número — un modelo de mantenimiento. Correcta y horrible.
Qué nos haría cambiar de opinión Si el hub llega a existir (H-01), el hub se queda el dominio y el certificado, y esto colapsa en A-02 gratis. Esa es la resolución prevista: el mismo trabajo, en el sitio correcto.
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
Matada porPolítica de navegadores, no esfuerzo. No hay cantidad de trabajo que haga que un origen autofirmado registre un service worker.
Qué nos haría cambiar de opinión Un cambio de política de los navegadores (improbable), o un flujo de emparejamiento local que instale una CA en el almacén de confianza del móvil (una petición de nivel MDM para un juguete de escritorio — eso no se lo hacemos a nuestros miembros). mDNS en sí sigue mereciendo la pena para http://buddy.local — solo que no como habilitador de PWA.
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
Matada porAritmética de flash. Ningún recorte la rescata — mira la calculadora de §3 y pruébalo tú.
Qué nos haría cambiar de opinión Un módulo de 32 MB de flash (H-03) elimina la objeción de tamaño por completo — pero las otras tres sobreviven: sigue sin poder cumplir el contrato de Brain, sigue sin poder responder nada, y sigue costando un núcleo. El tamaño era la razón menos interesante para decir que no.
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
Depende deC-01 reclamación de flash · una partición cruda (no LittleFS) para esp_partition_mmap · una decisión sobre el vocabulario de afecto en dos capas (§4).
Qué nos haría cambiar de opinión Si un modelo Config S entrenado resulta producir salida que al lab le da vergüenza en vez de gracia, la premisa entera se cae y nos quedamos solo con la nube más una tabla de chirps locales mucho mejor. La sesión previa debería terminar con todo el mundo leyendo 50 frases muestreadas y votando. Esa es la puerta.
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
Nota de diseñoLa partición model tiene que ser cruda, no un archivo dentro de LittleFS: esp_partition_mmap funciona sobre particiones crudas pero no sobre archivos de LittleFS, y mapear en memoria es precisamente lo que hace viables los pesos residentes en flash.
Qué nos haría cambiar de opinión Nada sobre hacerlo. La única pregunta abierta era el reparto — cuánto va a packs, cuánto a la partición del modelo y cuánto a un hueco de OTA.
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
Alcance del veredictoRechazada solo para los ojos. Ver D-02.
Qué nos haría cambiar de opinión Si alguien demuestra un canvas de LVGL renderizando los ojos paramétricos actuales al mismo frame rate con menos código, se acabó la discusión y cambiamos.
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
Depende deNada técnicamente; solo de que alguien quiera un menú en el dispositivo.
Qué nos haría cambiar de opinión La primera vez que necesitemos texto en el dispositivo más largo que unas pocas palabras — probablemente el momento en que aparezcan en pantalla las transcripciones del push-to-talk — esto pasa a “hacer ya”.
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
Regla que mantenerNada de lo que aterrice en el hub puede volverse jamás un prerrequisito para que un buddy esté vivo y tenga gracia. Degradar, nunca romperse.
Qué nos haría cambiar de opinión Un miembro que quiera hacerse cargo. Esta es una pregunta de personas mucho más que técnica.
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
Depende deUn concepto de sprite/overlay en el renderer de la cara. Pequeño, pero es una decisión de interfaz real.
Qué nos haría cambiar de opinión Si la capa de overlay resulta costar frame time real en la tarea de render, esto pasa a ser un efecto solo-de-reposo en vez de una capacidad general.
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
El experimentoBenchmark: lecturas secuenciales vs aleatorias de 4 KB en nuestro módulo SD mientras la cara renderiza, y luego simular el acceso a filas de embedding de un token con y sin caché LRU.
Qué nos haría cambiar de opinión Una medición. En cualquier dirección.
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
Depende deLa respuesta a B-03 primero. No compres flash para resolver un problema que una SD quizá ya resuelva.
Qué nos haría cambiar de opinión Que B-03 falle y que un Config M/L entrenado demuestre su valor. Entonces esto es una compra barata, aburrida y correcta — y habría que hacerla para toda la flota de golpe.
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
Interacción con este tableroEl audio gana cualquier disputa por la RAM interna. Cualquier otra cosa que la quiera (un servidor TLS en el dispositivo) tiene que demostrar que convive.
Qué nos haría cambiar de opinión Nada sobre el PTT — está comprometido. Lo abierto es si un modelo local rápido (B-02) cambia el diseño del enmascarado de latencia: una frase local de 0,6 s mientras la petición a la nube está en vuelo es un comportamiento de “pensando” mucho mejor que un chirp enlatado.
§2 Payoff × esfuerzo

Dónde cae cada idea

Ambos ejes son juicios subjetivos de quien escribió la tarjeta — que es exactamente el tipo de cosa que merece discutirse. Pulsa un punto para saltar a su tarjeta. El color es el veredicto propuesto.

↑ payoff si funciona
menos esfuerzo →más esfuerzo
hacer ya v1 v2 hardware investigación rechazada
Pasa el ratón o enfoca un punto para ver su veredicto.

El patrón que merece la pena notar: las dos entradas de arriba a la izquierda — la reclamación de flash (C-01) y el experimento de pesos en SD (B-03) — son baratas y desbloquean varias más. El grupo de abajo a la derecha es donde el esfuerzo va a morir. Si solo tienes un fin de semana, gástalo arriba a la izquierda.

§3 Interactivo · presupuesto de flash

¿Cabe en 16 MB?

Esta es la aritmética que mató a B-01, en vivo. Elige un modelo, arrastra las particiones y mira cómo se llena el chip.

Los 65.536 bytes reservados al principio no son negociables: el bootloader, la tabla de particiones, la NVS y la calibración PHY viven todos por debajo de 0x10000, que es donde tiene que empezar la app.

Preset
reservado app packs modelo sin asignar
RegiónBytesMiBNota

Comprobación de realidad que la calculadora no modela: las particiones de app quieren alineación a 64 KB, y el propio binario de app (1.286.704 bytes hoy) tiene que caber dentro de la partición que elijas — la calculadora te avisa cuando no cabe.

§4 Interactivo · dimensionar el modelo

¿Qué tamaño de criatura nos podemos permitir?

El número de parámetros de un transformer es params = vocab×d + capas×12×d². A esta escala, el vocabulario es el presupuesto — y por eso un BPE propio de 1024–2048 tokens es la primera decisión de diseño, no una optimización.

Preset
1.31 M
parámetros
0.66 MB
int4 en flash
params ÷ 2
30 tok/s
throughput est.
0.6 s
frase de 15 palabras
menos de ~2M Alrededor de 0,3–1M: balbuceo de criatura, gramatical pero incoherente. Encantador exactamente una tarde. Config S cae aquí — rápida, pero cerca del suelo. Ese compromiso es la pregunta abierta.
~2–7M El punto dulce, en torno a 3–4M. Frases cortas coherentes con condicionamiento de ánimo fiable. Esto es un compañero. Config M y L viven aquí.
~7–20M Hacia 10–15M: respuestas de varias frases; responde a prompts estructurados. Cuesta latencia real.
~20M en adelante A 28M, cuentos cortos — este es el régimen de esp32-ai. 94,9 ms/token clava un núcleo.
nunca Datos, razonamiento, seguir instrucciones, recordar. A ningún tamaño. Para eso están el contrato de Brain y la ruta a la nube.

El throughput es una estimación ajustada anclada en los tres configs que dimensionó el lab (30 / 12 / 7 tok/s), y es anterior al trabajo de kernel. Medido de verdad después: 152 tok/s para 260K parámetros, lo que sitúa a Config S en ~17–25 tok/s dentro del firmware real. Trata esta calculadora como el pesimismo de partida.

El renderizador, no el pensador

Dirigir es barato a escala diminuta; tener sustancia no. Así que el modelo es un renderizador: los reflejos y los sensores deciden el ánimo, y el modelo convierte ese ánimo en palabras que nunca son las mismas dos veces. El argumento de producto es simple — el enemigo de un compañero de escritorio es la repetición, no la tontería. Un buddy que dice algo tonto pero nuevo está vivo. Un buddy que dice la misma frase ingeniosa por cuarta vez es un mueble.

// la emoción como token de control, emitido primero — no puede venir mal formada
<happy> oh! that tickles

// frente a la ruta de la nube, que necesita parseo defensivo (main.cpp):
```json
{"utterance": "oh! that tickles", "emotion": "happy"}
```     ← las vallas que al modelo se le dijo que no emitiera

La tensión que nadie debería tapar

Conflicto abierto — necesita decisión de grupo

Un modelo entrenado tiene un vocabulario de tokens de control fijo. No puedes añadir <smug> después de entrenar sin reentrenar. Eso es exactamente lo contrario de extensible, y se acerca incómodamente a que el proyecto dicte el set de emociones — la única cosa que el director ha dicho que este proyecto no debe hacer.

Resolución propuesta — dos capas. Discútela.

capa 1 · registro de afecto (lado modelo, pequeño, estable)

Un conjunto de tokens de control deliberadamente diminuto y deliberadamente abstracto con el que se entrena el modelo. No emociones — registros. Elegidos para que abarquen el espacio tonal en vez de enumerar sentimientos.

<up> <down> <alert> <calm> <cross> <soft>
capa 2 · set de expresiones (lado pack, ilimitado)

Cualquier número de expresiones faciales con nombre que un pack invente, cada una mapeada sobre un registro más su propia geometría de ojo, color, temperamento de parpadeo y sonido. Sin reentrenar, sin cambiar firmware — esto son solo datos de pack, exactamente igual que face_model.h convirtiéndose en contenido de pack en v1.

smug → <up> · betrayed → <down> · caffeinated → <alert> · unimpressed → <cross>

La afirmación que se está haciendo es que el tono es de baja dimensión y la identidad no. Si esa afirmación es falsa — si el lab lo prueba y “smug” y “delighted” suenan idénticos porque comparten registro — entonces la resolución falla y necesitamos o un set de registros más grande o el reentrenado por pack como norma. La convergencia que hace la segunda opción menos temible: el corpus de entrenamiento ya es una definición de personalidad. Forkea el corpus, reentrena en ~20 minutos, entrega voice.bin dentro del pack, y tienes una criatura genuinamente distinta en vez de la misma criatura con otra paleta.

Actualización · agosto 2026 — la propuesta de dos capas se llevó al grupo

Esta resolución es la que se presentó en la reunión de equipos (docs/reunion-equipos.html), con un matiz que la simplifica: si los registros van en el corpus como texto plano (bright: la frase) en vez de como tokens especiales, añadir un registro nuevo más adelante no cambia el vocabulario en absoluto — el tokenizer con byte-fallback ya sabe deletrear cualquier palabra. Añadir un registro pasa a ser un ajuste fino corto sobre el modelo existente, no cirugía.

§5 Interactivo · el muro del contexto seguro

Qué funciona de verdad, por transporte y plataforma

El hilo de la PWA es donde casi se gastaron las horas de ingeniería más caras a cambio de la menor recompensa. Elige un transporte y un cliente y mira exactamente qué obtienes.

Transporte
Cliente
CapacidadResultadoPor qué

Desventajas infravaloradas, incluso en los caminos que “funcionan”

  • La identidad del origen está atada a la IP. Un cambio de concesión DHCP deja huérfana la PWA instalada y su suscripción de push. En silencio.
  • Tres buddies = tres PWAs separadas. Las PWAs tienen alcance por origen. No hay una app de “mis buddies” salvo que un hub provea el origen.
  • La caché obsoleta del service worker es una trampa real en un dispositivo cuyo argumento de venta entero es recargar en caliente. Estarías entregando una capa de caché que pelea con la promesa central del producto.
  • La caché offline aquí es casi inútil. Un shell cacheado sigue sin poder alcanzar al buddy — el buddy es el servidor. Cachearías una interfaz que no tiene con quién hablar.

Lo que deja al push, y solo al push, como lo único que se gana su sitio — y solo para mensajes de cuando no estás en la mesa. Si el grupo no sabe nombrar tres de esos que quiera de verdad, el movimiento honesto es entregar A-01 y cerrar el hilo.

§6 Cómo tumbar cualquiera de estos veredictos

Discutir con el registro

Cada tarjeta tiene una línea de qué nos haría cambiar de opinión, y caen en tres tipos:

  • Una medición. B-03 (pesos en SD), A-03 (heap de TLS junto al audio), el throughput de B-02. Alguien lanza un benchmark y el veredicto se actualiza. Son los argumentos más baratos de ganar — ve a por el número.
  • Un juicio de gusto. La calidad de salida de B-02, la gracia de E-01, el renderizado de D-01. Ningún benchmark los zanja; el lab lo mira y vota. Construye la cosa más pequeña que permita a la gente mirar.
  • Una pregunta de personas. H-01, A-02, H-03. Estas necesitan un voluntario o un presupuesto, no un argumento. Si nadie quiere hacerse cargo, eso es la respuesta.

Secuencia recomendada si quieres el máximo valor de decisión por hora: C-01 (desbloquea todo, media jornada) → benchmark de B-03 (mueve hasta tres veredictos) → A-01 (40 líneas, entrégalo) → sesión previa de B-02, terminando con todo el mundo leyendo 50 frases muestreadas y votando si la criatura merece construirse.

De esa secuencia, C-01 está hecho y B-02 tiene ya sus números de velocidad; lo que queda de B-02 es exactamente la parte de gusto — la votación leyendo frases.