Plan maestro de cambios — de cero al MVP (hito v0.1)
Directiva 2026-11-01:
release-automatica-mainautomatiza cada push a main con CI verde, sin PR manual de release. Sustituye ese gesto deversion-que-propone-ci; firmas, Android y preparación para 1.0 siguen teniendo sus propias changes. La versión se estampa solo en el build.
Backlog ordenado de propuestas de cambio que llevan a Meltemi desde el repositorio vacío hasta el hito v0.1 de Fase 1 (meltemi.md §10). Este documento es el mapa; cada change escribe sus cuatro artefactos (proposal, design, specs, tasks) inmediatamente antes de implementarse — nunca durante, y nunca se implementa nada que no esté aquí o en una change aprobada. Producto de la auditoría de planificación del 2026-07-11 (5 lentes, 64 hallazgos).
Cierre del bootstrap (2026-07-18): la etapa OpenSpec queda cerrada. El motor de specs de fase 1 hospeda la verdad viva del proyecto en
.meltemi/specs/y el histórico en.meltemi/changes/archive/(migrados con verificación del motor,migracion-openspec-a-meltemi); el método del proyecto son los comandos de Meltemi sobre.meltemi/. El árbolopenspec/se conserva como histórico consultable hasta el retiro físico confirmado por el mantenedor (D3 de la migración).Desviación aprobada por el mantenedor (2026-07-16, ampliada el mismo día): el backlog está completamente materializado — las 19 changes restantes existen en
openspec/changes/con sus cuatro artefactos (proposal, design, specs EARS, tasks), listas para/opsx:applyen el orden declarado. Disciplina que lo hace sostenible: (1) los deltas decli-contractson acumulativos — cada uno asume archivadas las changes anteriores del orden; alterar el orden exige revisar esos deltas; (2) los designs de las changes profundas marcan sus decisiones como provisionales y se revalidan obligatoriamente al llegar al frente de la cola (en especialciclo-sdd-autoria,orquestacion-worktreesycomando-implement, la change de integración); (3) los hallazgos de QA y la deuda registrada están absorbidos en las specs correspondientes (H1/H4/H5 →proxy-permisos; H6 →documentacion-inicial).
Estado de “listo para programar”
Sección titulada «Estado de “listo para programar”»| Prerequisito | Estado |
|---|---|
| Documento fundacional (meltemi.md v1.0) | ✅ Ratificado 2026-07-11 |
Constitución + rumbo (.meltemi/) |
✅ Ratificados 2026-07-11 |
| Change de Fase 0 completa (4 artefactos + enmiendas de auditoría) | ✅ |
Proyección de contexto raíz (AGENTS.md/CLAUDE.md) |
✅ |
| Research de integración de agentes persistido | ✅ docs/research/integracion-agentes.md |
| Plan maestro de cambios | ✅ Este documento |
| Ratificación humana (Guillermo) de meltemi.md, constitución y rumbo | ✅ 2026-07-11 |
| Registros operativos (org GitHub, org npm, dominio, crates) | 🟡 org GitHub y npm hechas (askenaz-dev); meltemi.dev servido por Cloudflare desde el 2026-10-21 (el sitio es de meltemi-web; GitHub Pages de este repositorio, apagado el 2026-10-26); v0.1.0 publicada (2026-07-26, 10 assets firmados); crates por reservar (verificados libres el 2026-07-27) |
Fase 0 (en curso)
Sección titulada «Fase 0 (en curso)»| # | Change | Alcance | Depende de |
|---|---|---|---|
| 0 | ✅ fase-0-fundacion |
Constitución ratificada, contrato proto/, esqueleto meltemid, sesión ACP e2e, /propose mínimo |
— |
Fase 1 — backlog ordenado (MVP)
Sección titulada «Fase 1 — backlog ordenado (MVP)»Ola 1 — método y fundamentos (arranca al cerrar Fase 0):
| # | Change | Alcance | Depende de |
|---|---|---|---|
| 1 | ✅ enmiendas-fundacionales-v1 |
Vía rápida: ratifica el bootstrap en dos etapas (excepción a §9.3), actualiza §0 a la marca V2, asigna fase a §6.12 (métricas), aclara telemetría post-v1, añade plataforma primaria de desarrollo | 0 |
| 2 | ✅ formato-artefactos-meltemi |
Esquema canónico de .meltemi/: nombres de artefactos, cabeceras de delta, canon EARS (política bilingüe: estructura en inglés vs prosa en español — resolver la contradicción §5.1/práctica), front-matter de rumbo |
0 |
| 3 | ✅ motor-specs-artefactos |
Parseo y validación de la estructura .meltemi/ completa (constitución, rumbo, specs, changes, archive) |
2 |
| 4 | ✅ motor-ears-deltas |
Validación EARS en vivo, parseo/aplicación de deltas; la detección semántica de contradicciones/huecos quedó explícitamente diferida a una change futura | 3 |
| 4b | ✅ enmienda-edicion-movil |
Vía rápida (2026-07-15): cerca de la edición utilitaria in situ (spec edit-surface) y alcance del compañero móvil monitorear/aprobar/dirigir vía túnel SSH (spec mobile-companion); meltemi.md v1.2 → v1.3 (ratificación pendiente) |
1 |
Ola 2 — superficies (en paralelo con Ola 1 tras el #0):
| # | Change | Alcance | Depende de |
|---|---|---|---|
| 5 | ✅ cli-contrato |
Gramática de subcomandos, regla de despacho CLI↔TUI, códigos de salida, --json, disciplina stdout/stderr; mapeo comando↔RPC junto a proto/ |
0 |
| 6 | ✅ tui-nucleo-ux |
Arquitectura de información de la TUI (paneles, navegación), estados vacíos y onboarding de primer uso, accesibilidad terminal (no-solo-color, NO_COLOR, fallback ASCII) | 5 |
| 7 | catalogo-flota |
Registro público ACP + detección local de binarios; nivel de integración, permisos y estatus por agente | 0 |
| 8 | sesiones-reanudables |
Reanudar sesión ACP, recuperación tras caída, inspección/navegación de sesiones | 0 |
Ola 3 — capa de agentes completa:
| # | Change | Alcance | Depende de |
|---|---|---|---|
| 9 | proxy-permisos |
Motor de reglas permitir/preguntar/denegar + UX de la bandeja (cola de peticiones concurrentes, creación de reglas in situ, mitigación de fatiga de aprobación, auditoría) | 7 |
| 10 | niveles-integracion-conformidad |
Niveles 2 (adaptadores), 3 (headless JSON) y 4 (artefactos); suite de conformidad por nivel con criterios pasa/no-pasa | 7 |
| 11 | proyeccion-contexto |
Compilación constitución+rumbo+spec activa → AGENTS.md y variantes; bloques gestionados que nunca sobrescriben contenido del usuario | 3 |
| 12 | gestion-contexto-repo |
Mapa del repositorio, referencias @archivo/@carpeta en prompts |
11 |
| 13 | mcp-passthrough |
Declaración de servidores MCP e inyección a agentes compatibles; higiene §8.7 | 7 |
Ola 4 — el ciclo SDD completo:
| # | Change | Alcance | Depende de |
|---|---|---|---|
| 14 | ciclo-sdd-autoria |
/constitution, /explore, /propose completo (requirements EARS + design + deltas + tasks con gates humanos), /plan; modo dual spec-full/fast-forward con criterio escrito de proporcionalidad |
4, 6 |
| 15 | revision-specs-ux |
La obsesión (§4.9): render de diff de deltas en terminal, presentación de contradicciones, checklist interactiva de /review, comentario→instrucción al agente |
14 |
| 16 | orquestacion-worktrees |
Worktrees aislados, N agentes × M tareas, carreras, merge asistido lado a lado | 8 |
| 17 | checkpoints-rollback |
Checkpoint automático pre-tarea, reversión granular, alcance honesto (qué NO se revierte) enganchado a la clasificación del proxy | 16 |
| 18 | git-commit-por-tarea |
Commit atómico con trailer de trazabilidad hasta el requisito EARS; convención de mensajes | 16 |
| 19 | comandos-verify-archive |
/verify (checklist por requisito + tests vinculados a criterios) y /archive (fusión de deltas en la verdad viva) |
4, 18 |
| 20 | comando-implement |
/implement: despliegue de agentes sobre tasks.md en modo planificar/actuar con checkpoints |
14, 9, 16, 17, 18 |
Ola 5 — salida al mundo (antes de que el repo sea público / del hito v0.1):
| # | Change | Alcance | Depende de |
|---|---|---|---|
| 21 | gobernanza-comunidad |
GOVERNANCE.md, CONTRIBUTING.md (contribución vía specs), CODE_OF_CONDUCT.md, SECURITY.md, texto del CLA acotado (§9.3) + tooling de firma, plantillas .github/ |
— (antes de público) |
| 22 | documentacion-inicial |
README raíz, quickstart, esqueleto de docs/ y tooling de documentación | 6 |
| 23 | distribucion-releases |
Versionado, firmado y custodia de claves, empaquetado por plataforma, instalador de una línea | 6 |
| 24 | migracion-openspec-a-meltemi |
El dogfooding definitivo: las specs vivas del propio proyecto migran a .meltemi/ |
19 |
| 25 | hito-v01-aceptacion |
El escenario del hito como spec ejecutable: una feature de idea a código en terminal con dos agentes de proveedores distintos en paralelo | todo lo anterior |
Orden de abordaje declarado (2026-07-16)
Sección titulada «Orden de abordaje declarado (2026-07-16)»Secuencia canónica de las 19 changes restantes (todas con proposal pre-redactada). Satisface el grafo de dependencias y prioriza: completar la capa de agentes con gobierno de permisos, luego el contexto, luego el ciclo SDD, luego el paralelismo, y al final la salida al mundo. Nada queda por fuera.
| Orden | Change | Por qué aquí |
|---|---|---|
| 1º | catalogo-flota |
Desbloquea #9/#10/#13; sin flota no hay orquesta |
| 2º | proxy-permisos |
Agentes reales exigen gobierno real; corrige H1 (QA) y la deuda del contador de pendientes |
| 3º | proyeccion-contexto |
Cierra la proyección manual de AGENTS.md; vehículo del nivel 4; independiente |
| 4º | niveles-integracion-conformidad |
Cubre el mercado completo (niveles 2/3/4), con la proyección ya disponible |
| 5º | mcp-passthrough |
Los agentes llegan con sus herramientas; capa de agentes completa |
| 6º | sesiones-reanudables |
Robustez e histórico; puerta del paralelismo (#16) |
| 7º | gestion-contexto-repo |
Mapa y @refs para dirigir agentes antes de la autoría pesada |
| 8º | ciclo-sdd-autoria |
El corazón del método — llega con flota, permisos y contexto ya operativos |
| 9º | revision-specs-ux |
La obsesión (§4.9): sin revisión placentera, el método muere |
| 10º | orquestacion-worktrees |
N agentes × M tareas sin pisarse; carreras |
| 11º | checkpoints-rollback |
Autonomía solo con deshacer barato y honesto |
| 12º | git-commit-por-tarea |
Trazabilidad línea→requisito (constitución §8) |
| 13º | comandos-verify-archive |
Cierra los verbos del ciclo; el motor ya demostró la fusión |
| 14º | comando-implement |
La composición de todo (requiere 2º, 8º, 10º, 11º, 12º ya hechas) |
| 15º | gobernanza-comunidad |
Antes de abrir el repositorio al mundo |
| 16º | documentacion-inicial |
El quickstart ya describe un producto real, no una promesa |
| 17º | distribucion-releases |
Empaquetado, firmado, instalador; materializa reserva de crates y alias mel |
| 18º | migracion-openspec-a-meltemi |
El dogfooding definitivo: se retira la herramienta prestada |
| 19º | hito-v01-aceptacion |
El hito como spec ejecutable; la meta de v0.1 |
Paralelizable sin romper el orden: 15º–16º (documentos, sin código) pueden avanzar en cualquier momento por una sesión aparte; 3º puede adelantarse en paralelo tras 1º. El orden canónico es el de la tabla; toda desviación se anota aquí.
Documentos transversales (se crean durante Fase 1, referenciados por las changes)
Sección titulada «Documentos transversales (se crean durante Fase 1, referenciados por las changes)»docs/plataformas.md— matriz de soporte: SO mínimos, arquitecturas, webviews (antes de #23).docs/presupuestos-rendimiento.md— los números de §12 traducidos a criterios EARS y gates de CI (antes de #6).docs/paridad-nucleo.md— matriz viva capacidad → RPC → TUI → GUI; toda change que añada un RPC la actualiza (desde #5).docs/operaciones/checklist-lanzamiento.md— registros y activos (ver pendientes del arquitecto).
Fase 2 (v1.0) — abierta el 2026-07-20
Sección titulada «Fase 2 (v1.0) — abierta el 2026-07-20»Archivadas el 2026-07-25 (183 escenarios verificados, 64 requisitos revisados uno por uno, deltas plegados a la verdad viva):
| Change | Qué dejó en la verdad viva |
|---|---|
gui-tauri-paridad |
desktop/ Tauri 2 + Svelte 5, crate compartido core/meltemi-client, matriz de paridad como gate de CI, política de concurrencia humano↔agente (worktree/apply-edit + human_edit + nota al siguiente turno), LSP BYO, instaladores con gate < 15 MB; creó docs/ux/design-system.md y docs/paridad-nucleo.md |
gui-clase-mundial |
Shell de tres zonas con la densidad del design system, identidad de entidades, drawer, superficie de Ajustes, paleta con difusa/grupos/formularios tipados, la sesión como acción primaria, guarda de trabajo sin guardar |
flota-deteccion-guia |
Detección en dos capas (CLI oficial + adaptador) con estado compuesto, remedio por capa con su comando exacto, estatus legal sin maquillaje y docs/agentes.md verificada contra el registro |
multiproyecto-suscripciones |
Registro de proyectos (project/list), agente y suscripción en los metadatos de sesión, árbol Proyecto→Sesiones en la GUI, agrupación y ámbito conmutable en la TUI |
analitica-consumo-local |
analytics/usage: actividad plegada de los registros locales, tokens solo donde la salida oficial los reporta, frontera medido/no-reportado con motivo estable y declaración de honestidad junto a las cifras |
sitio-web-producto |
site/ estático (sin JS, sin orígenes externos), descargas a la última release firmada con nombres estables, tokens derivados del cliente y lint del sitio como gate |
tablero-de-carrera |
Archivada el 2026-08-08. La carrera visible: procedencia por calle en worktree/diff (fuente, suscripción, nivel, sesión, commit y base propia, todo aditivo), el despacho asentando registro de primera clase, el tablero de la GUI (calles lado a lado, acciones con confirmación, merge por archivo) y el del shell (glifo+palabra con gemelos ASCII, despacho sin congelar el bucle); docs/qa/2026-08-07-tablero-de-carrera-smoke.md |
Pendientes de Fase 2: motor-propio-byok (propuesta redactada, activa) ·
lanzador-conversacional (abierta 2026-07-27, implementada y verificada
106/106; no archiva hasta la ratificación de la enmienda) ·
adaptadores-propios-acp (abierta 2026-07-27, implementada 24/24 con
conformidad real anclada; espera la decisión del mantenedor sobre enviar con
Codex en nivel 0) ·
texto-intacto-al-agente (abierta 2026-07-31, vía rápida: el prompt se
doble-codifica y el agente recibe acentos rotos; verify limpio, lista para
archivar) ·
avisos-de-escritorio (abierta 2026-07-31, del comparativo de mercado: nada
avisa al escritorio cuando un permiso espera) ·
primer-arranque-del-home (abierta 2026-07-31, vía rápida, del mismo
comparativo) ·
artefactos-de-cada-push (abierta 2026-08-05, vía rápida: el build de cada
push a main descargable como artefacto de la ejecución, jamás como release) ·
vincular-suscripciones (abierta 2026-08-08, planificada: el pedido
fundacional — vincular N suscripciones por proveedor desde cualquier
superficie, con la variable de contexto como dato del registro) ·
barra-de-estado-agentica (abierta 2026-08-09, vía rápida candidata: la
barra de estado existente aprende a decir el bucle agéntico; primer hallazgo
capturado de la auditoría de intuitividad) ·
harness-global-y-por-agente (abierta 2026-08-09: el harness de agentes —
rules/skills/agents/hooks por ámbitos global → por-agente → proyecto,
formatos FDH reutilizados, vista efectiva ×3; fase 1 = pilar Rules + vista) ·
sesion-que-espera (abierta 2026-08-09: el borde del turno aprende a esperar
— la sesión vive entre mensajes, como Claude Code/Codex) ·
pensamiento-a-la-vista (abierta 2026-08-09, vía rápida candidata: destapar
el pensamiento que la cadena ya transporta — GUI expandido en vivo, TUI
conversacional) ·
modos-de-autonomia (abierta 2026-08-09: Manual/Semi/Autónomo como posturas
por sesión sobre el proxy; Bypass rechazado por §3 de entrada) ·
modelo-y-esfuerzo-por-sesion (abierta 2026-08-09: modelo y esfuerzo como
strings opacos por sesión y por perfil — la palanca de cuotas) ·
registro-agentes-en-superficie · menu-nativo-aplicacion · sandbox-propio ·
hooks-eventos · plugins-skills-sdk · i18n-superficies ·
metricas-sdd-locales · lsp-superficie-revision.
(pulido-pre-anuncio, la vía rápida del acabado pre-anuncio, quedó archivada
el 2026-07-27.) Las 39 changes abiertas el 2026-09-24 tras el comparativo
con Orca tienen su propio orden de abordaje más abajo («Orden de abordaje
tras el comparativo con Orca»); su fuente es
docs/research/comparativo-orca-2026-09-24.md.
Orden de abordaje de las changes activas — declarado el 2026-08-09
Sección titulada «Orden de abordaje de las changes activas — declarado el 2026-08-09»Diecisiete changes activas tras tres tandas del mismo día: la conversacional
(titulo-de-sesion, piel-de-pestanas, compositor-que-trabaja,
redirigir-turno, preguntas-del-agente), la del explore de intuitividad y
harness (barra-de-estado-agentica, harness-global-y-por-agente) y la de
la revisión del mantenedor con referencias visuales (sesion-que-espera,
pensamiento-a-la-vista, modos-de-autonomia,
modelo-y-esfuerzo-por-sesion). Criterios, en orden: cerrar el trabajo a
medio camino antes de abrir más; dependencias declaradas
(preguntas-del-agente exige redirigir-turno; sesion-que-espera toca el
mismo borde del turno que redirigir-turno y van adyacentes); el bucle
diario del mantenedor antes que las apuestas grandes; y lo bloqueado por
eventos externos no gasta turno. Toda desviación se anota aquí.
| Orden | Change | Estado (motor) | Por qué aquí |
|---|---|---|---|
| — | lanzador-conversacional |
52/52, verify 106/106 | Espera solo la firma v1.5 (pendiente 1c del arquitecto, gate de archivo); no es trabajo de agente |
| 1º | ✅ artefactos-de-cada-push |
7/7, verify 9/9 | Verificada en runner real con el artefacto descargado y abierto. Espera review |
| 2º | ✅ piel-de-pestanas |
8/8 verify, smoke hecho | «El manejo de tabs está feo»: la anatomía de Chrome. Espera review |
| 3º | ✅ titulo-de-sesion |
13/13, 11/11 verify, smoke hecho | Las pestañas nombran el trabajo, no un hash. Espera review |
| 4º | ✅ compositor-que-trabaja |
7/7, verify 5/5, smoke hecho | El anillo de trabajo y ■ Detener donde se escribe. Espera review, que además ratifica la enmienda del design system |
| 5º | 🔸 pensamiento-a-la-vista |
3/4, verify 6/6 | La misma experiencia que el 4º: la luz dice «trabajo», el transcript lo muestra — destapar el pensamiento ya transportado (GUI) y el pliegue conversacional de la TUI |
| 6º | barra-de-estado-agentica |
proposal | El cromo ambiental: proyecto, change+gate, sesiones por estado, tokens con frontera honesta |
| ☆ | Auditoría de intuitividad | sesión dedicada, no change | Tras la tanda visual (2º–6º): barrido CDP sistemático → informe en docs/qa/ + la siguiente tanda; correrla antes re-hallaría lo ya capturado |
| 7º | primer-arranque-del-home |
proposal | Vía rápida chica del comparativo: el chip advierte proactivamente; onboarding listo antes de cualquier anuncio |
| 8º | avisos-de-escritorio |
proposal | La atención cuando la app no tiene foco; preguntas-del-agente la da por presente en su experiencia |
| 9º | redirigir-turno |
implementada (12/12, verify 9/9) | El verbo del medio (interrumpir y relevar, atómico en el daemon); prerrequisito declarado del 11º; paridad ×3 servida en la change |
| 10º | sesion-que-espera |
implementada (verify 19/19) | El chat que no muere: el borde del turno espera en vez de cerrar — mismo código que el 9º, adyacentes para no reabrirlo dos veces; la evidencia que eventos-para-tardios dejó pedida |
| 11º | preguntas-del-agente |
proposal | La corona del bucle conversacional: AskUserQuestion contestada donde se escribe; depende del 9º y aprovecha el 8º |
| 12º | modos-de-autonomia |
proposal | Manual/Semi/Autónomo como posturas por sesión sobre el proxy existente; Bypass rechazado por §3 de entrada |
| 13º | modelo-y-esfuerzo-por-sesion |
implementada (verify 14/14) | La palanca de cuotas: modelo y esfuerzo opacos por sesión y por perfil. Hallazgo de cierre: los adaptadores propios no anuncian opciones de sesión porque ningún proveedor pineado enumera modelos, así que la vía en vivo queda cableada, probada con el mock y disponible para cualquier agente ACP que sí anuncie (design D9) |
| 14º | ✅ harness-global-y-por-agente |
implementada (25/25, verify 15/15) | La apuesta estratégica: fase 1 (Rules + vista efectiva) con design por delante; spec-full. Espera review |
| 15º | motor-propio-byok |
proposal | La mayor de fase 2; entra tras el harness (la directiva más reciente manda) y con su rename terminológico ya hecho |
| ⏳ | procedencia-de-release |
tasks 6/8, verify 6/6 | Sus 2 tareas dependen de eventos externos — una corrida real disparada por tag (próxima release) y la clave pública que entrega el mantenedor — se cierra cuando ocurran, sin gastar turno |
Estado al 2026-08-16: hechas 1º–4º y 8º–10º (esperan review); la 5ª solo espera su smoke. Cinco changes del orden siguen con proposal y nada más (11º–15º), y la auditoría ☆ no ha corrido.
Lo que 9º y 10º cerraron juntas —adyacentes a propósito, sobre el mismo borde del turno— es el bucle conversacional del daemon: se puede interrumpir un turno y relevarlo, y la sesión ya no muere al terminarlo. El 10º trajo además la evidencia que
eventos-para-tardiosdejó pedida para desacoplar un RPC que bloquea el turno entero, y la trajo con su prueba: sin el desacople la espera es imposible, porque la petición que posee la sesión nunca respondería.Paralelizable sin romper el orden: 2º, 4º, 5º y 6º son solo
desktop/ui(el 5º suma el render de la TUI) y pueden avanzar mientras 3º toca daemon+proto, commiteando por tarea (aviso de concurrencia del 2026-07-26). La auditoría ☆ corre en sesión aparte con la app viva. Las changes nombradas sin abrir no cuentan aquí:registro-agentes-en-superficie,menu-nativo-aplicacion,sandbox-propio,hooks-eventos,plugins-skills-sdk,i18n-superficies,metricas-sdd-locales,lsp-superficie-revision,harness-skills,harness-hooks,harness-subagentes,ruteo-declarativo-de-perfiles, el.rpmde Fedora/RHEL y la extensión ACP de usage.
Orden de abordaje tras el comparativo con Orca — declarado el 2026-09-24
Sección titulada «Orden de abordaje tras el comparativo con Orca — declarado el 2026-09-24»Fuente: docs/research/comparativo-orca-2026-09-24.md — 23 agentes
verificando siete dimensiones contra el árbol y contra onorca.dev, más una
prueba integrada real en Windows con Claude Code 2.1.280, Codex y
OpenCode sobre un daemon aislado de main @ 4bc8e9e. Sesenta brechas
verificadas se cubren con 39 changes (todas con proposal.md, en
.meltemi/changes/; design/specs/tasks just-in-time al llegar al frente de
la cola). Ninguna exige enmendar la constitución; dos traen enmiendas de
rumbo/§11 con ratificación como gate.
Criterios, en orden: (1) lo que la prueba integrada rompió se arregla antes que cualquier feature; (2) confianza ejecutable antes de anunciar (procedencia cerrada, corrida publicada); (3) el estado vivo antes que cualquier animación de trabajo, porque sin él la animación miente; (4) el remoto se construye de adentro hacia afuera (cliente → máquinas → lectura → aviso → móvil); (5) lo bloqueado por eventos externos —ratificaciones, ollama, clave pública— no gasta turno. Toda desviación se anota aquí.
Consolidación de nombres: el informe nombra changes chicas que aquí se
funden por compartir archivos y capability. arranque-solo-en-endpoint-propio
tunel-resiliente+acceso-remoto-documentado→acceso-remoto-afinado;estados-de-carga+pulso-de-la-tui+senal-de-vida-del-turno+ventana-hasta-el-primer-frame+vocabulario-de-movimiento→senales-de-vida;canales-de-comunidad+cadencia-y-changelog+quickstart-sin-cargo(+ FAQ y privacidad) →antes-de-anunciar;pestanas-que-vuelven+bandeja-de-avisos+la-sesion-dice-su-rama(+ exportar sesión) →escritorio-que-recuerda;paleta-que-encuentra+buscar-en-las-sesiones+markdown-que-se-lee+previsualizar-binarios→buscar-y-leer;abrir-pr-con+abrir-terminal-aqui(+ enmienda de rumbo) →abrir-con-lo-tuyo;distribucion-gestores-paquetes+avisos-de-version→distribucion-y-actualizacion;perfil-con-entornose absorbe enguia-modelos-localesporque[[fleet.profile]].envya existe.
Tanda 1 — confianza ejecutable (≤ 2 semanas)
Sección titulada «Tanda 1 — confianza ejecutable (≤ 2 semanas)»| Orden | Change | Vía | Brechas | Por qué aquí | Depende de |
|---|---|---|---|---|---|
| 1º | ✅ codex-al-dia |
completa · implementada (17/17, verify 40/40) | AI-1 | Codex no arranca con ninguna versión (0.77: modelo de cuenta; 0.156: user agent que el adaptador no lee). Cerrada: re-anclada a 0.156.1 con compuerta estricta verificada, y la corrida real del 2026-09-25 le re-otorgó el nivel 2 | — |
| 2º | ✅ turno-vacio-es-error |
completa (el código de salida 15 modifica la taxonomía viva) · implementada (10/10, verify 29/29) |
AI-11 | un turno sin mensajes ni herramientas se reportó como éxito. Cerrada: el daemon mide cada turno y escribe turn_empty salvo que un humano lo detuviera; cinco respuestas llevan emptyTurn; el CLI sale con 15; GUI, TUI y la analítica lo muestran |
— |
| 3º | ✅ aprobador-en-el-cli |
completa · implementada (7/7, verify 21/21) | AI-12 | el CLI denegaba todo permiso: con Claude Code solo servía para charlar. Cerrada: en un terminal pregunta con las opciones del agente y lo que envió (completado con la tool_call de la sesión, sin texto crudo del agente); recordar escribe la regla más específica o no se ofrece; sin terminal, el rechazo del agente y un aviso que nombra las reglas; Ctrl+C cancela primero (el log dice interrupted) y sale con 13; el terminal siempre sale del modo crudo |
— |
| 4º | ✅ modelo-por-opcion-anunciada |
completa · implementada (10/10, verify 27/27) | LM-3, LM-6 | --model rehusado a un agente que anuncia modelos; el model del perfil se pierde en propose/dispatch/implement. Cerrada: cada palanca va por la bandera que declara su entrada del registro (levers: Codex modelo y esfuerzo, Claude Code modelo) o por la opción que el agente anuncia, fijada y confirmada antes del primer prompt (la última respuesta decide, el modo no se mueve, espera acotada [sessions] lever-wait y cancelable); si no, se rehúsa sin prompt como lever_refused y el 2007 con sus datos, acotados y escapados en las tres superficies; el perfil rige en todo verbo antes de sus efectos (propose ya no deja andamio); el histórico dice lo que rigió y nunca lo rehusado |
— |
| 5º | ✅ usage-desde-acp |
completa (la revisión adversarial mostró dos MODIFIED: la frontera entre medido y no reportado, y el evento de uso de session-history) · implementada (8/8, verify 16/16) |
LM-7 | usage_update está en el log y usage dice «no reportado». Cerrada: la contabilidad lee el contexto y el costo que el agente reporta por ACP como cifras suyas, aparte de los tokens —por conversación del agente (implement abre una por tarea), una sola vez aunque la conversación se reanude, sumadas por moneda y nunca convertidas—; los tokens de esas sesiones quedan ausentes con el motivo «el protocolo transportó contexto y costo, no consumo»; la CLI y la vista Uso lo muestran rotulado como del agente. Hallazgos corregidos: el plegado perdía binario y nivel de las sesiones con modelo declarado, y una prueba de control remoto corría contra la cancelación previa al primer prompt de la 4º |
— |
| 6º | ✅ guia-modelos-locales |
rápida · implementada y archivada (5/5, verify 6/6; 2026-10-24) | LM-1/2/5/8, P5 | la única vía funcional (OpenCode) sin escribir; corrige «Aider funciona hoy». Cerrada: docs/local-models.md con tres recetas (ollama, LiteLLM, OpenRouter) verificadas en forma con OpenCode 1.18.32 el 2026-09-25, cada una con su perfil, y un lint que rehúsa claves en claro; la receta 1 pasó por Meltemi: el perfil llega, --model anunciado se confirma antes del primer prompt y uno no anunciado se rehúsa sin prompt (confirma en vivo la vía anunciada de la 4º); la pierna local queda escrita y pendiente en docs/conformidad-manual.md; Aider deja de prometerse; el README y el LEEME enlazan sin nombrar productos, y el requisito de la página de agentes del sitio pasó a meltemi-web (agents-page-own-model). Hallazgo anotado aparte: un ${VAR} dentro de un texto más largo se resuelve en silencio a vacío |
ollama en la máquina del mantenedor (pierna local) |
| 7º | ✅ verbos-del-agent-boss |
completa (watch y log son flujos —un registro por línea— y eso es una excepción declarada a las dos reglas de formato: dos MODIFIED) · implementada (10/10, verify 29/29) |
MOB-5, C-F | aprobar, seguir y cancelar por SSH sin TUI; la CLI como herramienta de agentes. Cerrada: seis verbos sobre cinco métodos que ya existían —permissions, approve, deny, watch, log, cancel—, sin RPC nuevo; se decide con lo que el agente ofreció para esa petición (la aprobación de una vez cuando es una sola, su rechazo o cancelar, --option de la clase del verbo) y una petición por vez, nunca en bloque; una petición que ya no espera sale con 12, una sesión desconocida con 11; watch declara su interés antes de mirar y no sobrevive a su sesión (su cierre, o una consulta de vida cada 2 s) ni a su daemon (10); el texto del agente viaja como escapes de JSON; la receta «aprobar desde el teléfono, hoy» sin túnel en docs/acceso-remoto.md, probada con el binario sin TTY. Hallazgo corregido: los tests de espera de config.rs compartían directorio temporal y se lo borraban en paralelo (carrera traída por la 4º). Hallazgos anotados aparte: harness --agent rehusado por la gramática, y una sesión aparcada que se cancela cierra con completed |
— |
| 8º | ✅ acceso-remoto-afinado |
completa (que un endpoint explícito no arranque un daemon estrecha dos requisitos vigentes: dos MODIFIED) · implementada (7/7, verify 15/15) | R3, R9, R4, MOB-6, R-V1 | un endpoint caído arranca un daemon equivocado; túnel sin latido; Windows servido sin guía. Cerrada: un cliente arranca el daemon solo en el endpoint propio del usuario o con MELTEMI_START_HERE=1, y cualquier otro que no responde se rehúsa al instante nombrando el túnel —medido: el release de main levantaba un daemon en un endpoint ajeno; el nuevo rehúsa en 34 ms—; el arranque bajo demanda, que nunca tuvo prueba, la tiene con el meltemid real (arranca, se reutiliza, se apaga); el túnel lleva latido y ExitOnForwardFailure, --exec corre exactamente lo impreso y un túnel que muere sale con 10; docs/acceso-remoto.md gana el PC Windows servido, el teléfono de hoy (verbos, TUI por ssh -t, campana) y las esperas con sus valores; docs/plataformas.md deja de contradecir al helper; el smoke declara pendientes, con lo que falta, la GUI/TUI sobre un socket reenviado (un host macOS/Linux) y el tramo sshd de Windows (instalar el servidor) |
host macOS/Linux y OpenSSH Server en Windows (tramos pendientes del smoke) |
| 9º | ✅ corrida-integrada |
rápida (dos requisitos ADDED) · implementada (6/6, verify 6/6) | AI-2, AI-V1, P9 | la matriz agente × verbo × superficie con informe fechado; el informe de aceptación v0.1. Cerrada: scripts/smoke-agents.ps1 (y su gemelo .sh) corre aislado por las cinco variables los mismos siete verbos contra cada CLI listo y escribe el informe; corrida contra Claude Code 2.1.280, OpenCode 1.18.32 y Codex 0.156.1 (docs/qa/2026-09-26-corrida-integrada.md); el hito v0.1 con dos proveedores reales, los seis criterios aprobados y cinco desviaciones declaradas (docs/qa/2026-09-26-hito-v01-aceptacion.md, enlazado desde docs/hito-v01.md); Claude Code 2.1.280 verificado en nivel 2 por conformance_real. Hallazgos, cada uno con su change: OpenCode edita sin pedir permiso (el proxy no lo gobierna); una regla por ruta no casa con los adaptadores de nivel 2 (adaptadores-con-rawinput); session/log no encuentra el registro de una sesión de worktree; los worktrees de tarea no se excluyen del git del árbol principal; Codex no se reanuda (codex-reanudar-y-mcp); los adaptadores no reportan uso (extension-acp-usage) |
ollama para la pierna local; el .sh en macOS/Linux |
| 10º | ✅ senales-de-vida |
completa · implementada (10/10, verify 21/21; aterrizada el 2026-10-24, un mes después de terminarse) | VIS-3/4/5/6/7/9 | esqueletos, cronómetro, spinner de la TUI, ventana al primer frame, vocabulario de movimiento | — (solo cliente) |
| 11º | comandos-del-agente |
rápida | D2, AI-7 | el / del agente, anunciado y hoy descartado |
— |
| 12º | arrastrar-referencias |
rápida | D3 (texto) | soltar archivos como @ruta |
— |
| 13º | antes-de-anunciar |
rápida | P2, P3, P6, P-V1 | canales, CHANGELOG (con el formato que lee meltemi-release notes), quickstart sin cargo, FAQ (la página de privacidad es de meltemi-web: change ide-privacy-statements, que es el gate del anuncio, no de los artefactos) |
release-con-el-push (0.2.0 publicada y verificada con gh attestation verify) |
| 12º bis | ✅ release-con-el-push |
completa · implementada y archivada (2026-10-24, verify 41/41; la 7.3, apagar Pages, cerrada el 2026-10-26) (enmienda y cierre de procedencia-de-release; REMOVED de «Publicación del sitio con la release» y de product-site en este repositorio) |
P1, P4 (web) | decisión del mantenedor del 2026-10-23: la release nace de un push a main que cambia la versión, sin paso manual; la firma es la atestación del workflow (se retira minisign y la clave que nunca llegó al árbol); el pipeline avisa a meltemi-web al publicar; site/ y el job de Pages se retiran (tarea 7.4 de delivery en meltemi-web). Primera release por este camino: 0.2.0. Va antes de 13º porque es su gate nuevo |
el push de los 177 commits locales con sus gates verdes; github.tf de meltemi-web adopta el repositorio del IDE |
| 12º ter | ✅ grabador-de-avisos-sin-carrera |
rápida, sin deltas (solo un fixture de test) · implementada (4/4) | — | el test del aviso de prueba fallaba en el CI de Windows en dos de las tres corridas en que llegó a ejecutarse: dos avisos seguidos corren dos cmd.exe a la vez, y el >> del grabador .cmd no comparte el archivo, así que se perdía una línea. Cerrada: el grabador toma un candado con mkdir y un test determinista vigila el candado; bajo carga, 12 de 480 corridas rojas antes y 0 de 480 después |
— |
| 12º quater | ✅ seguir-y-cancelar-sin-carrera |
rápida, sin deltas (solo un test) · implementada (4/4) | — | following_reading_and_cancelling_end_to_end fallaba a ratos en Windows por dos preguntas tempranas: si la sesión cancelada ya había salido del registro, cuando el daemon publica el cierre antes de darla de baja; y si watch ya escuchaba cuando el agente pidió permiso, cuando watch solo emite desde su suscripción. Cerrada: espera acotada de la baja, y primer turno callado, watch suscrito y entonces la instrucción; bajo carga, 14 de 480 corridas rojas antes y 0 de 480 después |
— |
Paralelizable: 10º–12º son solo desktop/ui/tui y avanzan mientras 1º–5º
tocan daemon, adaptadores y proto/; 6º, 8º y 13º son documentación y
scripts. Lo que 1º–5º cierran es la deuda que la prueba del 2026-09-24
encontró en una tarde.
Nacidas de la revisión de aprobador-en-el-cli (2026-09-25), con propuesta
escrita y sin turno en este orden hasta que el mantenedor lo asigne:
adaptadores-con-rawinput (los adaptadores propios mandan el comando y la ruta
en la petición: el aprobador los muestra y las reglas precisas gobiernan a
Claude y a Codex), regla-precisa-en-la-bandeja (la bandeja de la TUI propone
hoy la herramienta sola, más amplia que el requisito vivo; la cola gana comando
y ruta, y las tres superficies proponen la misma regla) y
auditar-reglas-y-procedencia (crear una regla queda en el log,
permission/decide dice si no pudo escribirla, y la denegación de un cliente
sin terminal deja de parecer la tecla de una persona).
Nacida de modelo-por-opcion-anunciada (2026-09-25), con propuesta escrita
y sin turno: selector-de-modelo-que-sabe (recordar lo que cada agente anunció,
por agente y perfil, acotado y con escritura atómica, para que el selector lo
ofrezca y avise antes de abrir; la revisión adversarial la sacó del alcance
porque su clave, sus cotas y su contenido publicado —§9— merecen diseño propio).
Desviación declarada al implementar: el contrato de worktree/dispatch llevaba
model y effort que el daemon ignoraba en silencio; ahora rigen (design D5).
Hallazgo anotado para una change aparte: el mismo dispatch ignora el mode
que su schema y el formulario de la GUI ofrecen.
Tanda 2 — estado vivo, transcript rico, remoto usable (1–2 meses)
Sección titulada «Tanda 2 — estado vivo, transcript rico, remoto usable (1–2 meses)»| Orden | Change | Vía | Brechas | Por qué aquí | Depende de |
|---|---|---|---|---|---|
| 14º | ✅ estado-en-vivo |
completa | VIS-1 | session/state a todo cliente; «0 working» con un agente trabajando · implementada (11/11, verify 12/12). Cerrada: la notificación afirma el estado entero de una sesión y no un cambio, así que aplicarla dos veces o en cualquier orden converge — sin números de secuencia, y la foto que una conexión recibe al iniciar puede correr contra la primera transición sin perderla. Canal propio en el hub, sin la regla de delivers: toda conexión iniciada recibe toda transición, porque filtrar por origen era el defecto. El rezago lo ve el daemon, no el cliente, así que el daemon lo repara reenviando la foto entera (el canal de eventos solo lo registra en su log, y por eso sus huecos son mudos). Anuncia el registro, no los doce sitios de llamada. Dos hallazgos del camino: los flujos de un solo turno finalizan quitando la sesión del registro, no marcándola terminada, así que sin anuncio en esa salida un segundo cliente quedaba congelado en «esperando instrucción» para siempre —lo encontró el e2e de dos clientes—; y session/list arma sus filas desde el índice en disco, así que una sesión registrada a mano no aparece en la lista. Medición de la tormenta: 5 clientes × 20 sesiones × 4 transiciones = 400 afirmaciones en 0,32 s sin que nadie se rezague, contra un canal de 1024, así que «sin coalescencia hasta que algo la pida» tiene una cifra detrás. La GUI no tocó ningún componente: los cuatro indicadores derivan de un array y basta mantenerlo vivo. El ticker de la TUI deja de pedir la lista y se queda con los relojes |
— |
| 15º | herramientas-a-la-vista |
completa | D1, VIS-2, AI-4, D9, VIS-8 | filas de herramienta con resultado, diff ACP, subagentes, calles vivas | 10º, 14º |
| 16º | ✅ via-ssh-del-cliente |
completa | MOB-8, R1 | el cliente lanza ssh pc meltemi bridge y habla por su stdio; Windows servido por fin · implementada (8/8, verify 9/9). Cerrada: un endpoint exec:<comando> lanza ese comando y habla el protocolo por su stdio, sin shell en medio —un segundo intérprete es una expansión que nadie pidió y la forma en la que se cuelan los huérfanos— y dentro de un ámbito de proceso, así que un cliente que se cierra o muere no deja un ssh vivo. El comando se lee del entorno o de la configuración de usuario y jamás de un repositorio: un endpoint puede nombrar un comando, y un repositorio capaz de fijarlo ejecutaría algo en tu máquina por el hecho de abrirlo. Tres hallazgos del camino: (1) con MELTEMI_START_HERE=1 un endpoint exec: sí habría arrancado un daemon local, agujero cerrado con guarda explícita; (2) el lector del peer descartaba el error del transporte y fallaba con «connection closed» a secas, así que todo el diagnóstico construido para un comando que muere no llegaba al usuario —ahora la razón se propaga, y sirve a cualquier transporte—; (3) el endpoint se quita del entorno del hijo, o un comando que ejecute meltemi marcaría contra sí mismo. Se declaran además las features de tokio que el crate ya usaba por unificación, con lo que cargo build -p meltemi-client a solas compila por primera vez. Lo que Meltemi no hace, escrito: no añade opciones al comando, no gestiona claves ni passphrases, y no da terminal — de donde se sigue que la primera conexión a un host nuevo falla, con su remedio de una vez en un terminal |
8º |
| 17º | ✅ maquinas-remotas |
completa (MODIFIED en remote-access) |
R2, R10, MOB-7, R8 | lista de máquinas con nombre, chip, prueba de conexión | 16º; identidad-propia para presencia · implementada (7/7, verify 16/16). Cerrada: la lista es [[client.machines]] de ámbito usuario únicamente —un endpoint puede nombrar un comando, así que un repositorio capaz de fijarlo ejecutaría algo en tu máquina por el hecho de abrirlo— y sin material de claves: identity-file, passphrase, port y user rehúsan la máquina entera con el sitio donde ese dato vive, ruidoso a propósito, porque ignorarlo dejaría a alguien creyendo que su clave está en uso sin ver por qué no pasa nada. Cambiar de máquina es reconectar: el endpoint deja de ser constante capturada y pasa a variable del bucle en las dos superficies, con dos sitios que lo atienden —en conexión viva se suelta en vez de drenar, porque lo que está en vuelo es de la máquina que se deja; durante el backoff corta la espera, porque hacer cumplir el castigo de la mala suerte de la anterior es el cliente penalizando al usuario por su propio calendario—. De paso, el terminal gana algo que ya hacía falta: backoff_or_stop descartaba todo comando que llegara durante la espera, así que listar máquinas ahora funciona estando desconectado, que es cuando más se quiere. Probar abre, saluda y cierra, sin pasar por bootstrap: probar no debe poder arrancar nada ni por accidente, y una máquina apagada falla. La presencia se cruza con la malla por nombre y no se inventa cuando no cruza; se lee al abrir la lista y jamás de fondo. Cero RPC y cero cambios en el daemon, que no sabe que existen otras máquinas. Dos hallazgos: la guarda de trabajo sin guardar se hereda como prop desde App en vez de reimplementarse, y reusar la clase CSS machines hizo que el test vivo de identidad-propia —«ninguna fila de máquina de la malla es accionable»— rebanara la lista nueva, que sí tiene botones a propósito: las dos listas no deben compartir selector |
| 18º | lectura-por-el-daemon |
completa | R7 | editor, búsqueda y ajustes leen el disco del daemon, acotados | 16º |
| 19º | ✅ aviso-de-espera-opt-in |
completa | MOB-3, R6 | el push que la spec permite: comando del usuario, contenido mínimo publicado · implementada (7/7, verify 8/8). Cerrada: [notices] on-waiting de ámbito usuario únicamente, apagado por defecto, ejecutado por el cliente conectado y jamás por el daemon. El contrato del contenido queda publicado en docs/acceso-remoto.md con la change, como §9 exige: cinco variables —clase de espera, sesión, máquina, instante y cuenta— y ninguna ruta, nombre de proyecto ni texto de petición, con la razón escrita (el destino es un servicio que el usuario opera pero no siempre solo). Dos añadidos sobre lo propuesto, con su justificación: la cuenta, sin la cual un aviso no dice si vuelves por una cosa o por siete, y un piso de treinta segundos, porque seis notificaciones seguidas es cómo se aprende a silenciar un canal. Se lanza y se suelta, con tope de diez segundos dentro de un ámbito de proceso, así que un comando que no responde no bloquea la interfaz. El emisor vive fuera del bucle de reconexión en las dos superficies, o un daemon que cae y vuelve reiniciaría el piso. El ensayo ignora el piso y no lo gasta. Hallazgo colateral: tres e2e de e2e_agente_por_sesion fallan de forma intermitente bajo la carga de la suite completa y pasan en aislamiento y en la segunda corrida; no los toca esta change y quedan anotados como fragilidad a investigar |
14º; archivar avisos-de-escritorio ✅ |
| 20º | flota-ampliada |
rápida | AI-3, AI-9 (L1) | de 10 a ~18 agentes nivel 1 verificados vendor por vendor | 9º (para medirlos) |
| 21º | codex-reanudar-y-mcp |
completa | AI-8 | Codex reanuda hilos y recibe MCP por el cable | 1º |
| 22º | mcp-stdio-passthrough |
rápida | AI-V1 | stdio es el piso de ACP y hoy se omite | — |
| 23º | extension-acp-usage |
completa | LM-7, AI-6 | tokens de Claude Code y Codex por _meta con espacio de nombres |
5º |
| 24º | escritorio-que-recuerda |
rápida | C-C, C-D, D13, D-V1 | pestañas que vuelven, bandeja con historial, rama por sesión, exportar | 14º (avisos) |
| 25º | buscar-y-leer |
completa | D7, D5, C-A | session/search, paleta unificada, Markdown renderizado, imágenes |
18º (imágenes remotas) |
| 26º | anotar-el-diff |
completa | D6 | comentarios por línea devueltos al agente (meltemi.md §6.8) | 15º |
| 27º | abrir-con-lo-tuyo |
completa (enmienda de rumbo) | D11, D12 | «Abrir PR con…» y «Abrir terminal aquí»; terminal como no-objetivo escrito | ratificación del mantenedor |
| 28º | demo-animada-del-sitio |
rápida | P4 | el producto en movimiento: la captura y los medios en docs/media/; el vídeo en /ide/, su CSS y su lint son de meltemi-web (primero site-figures-provenance) |
10º |
| 29º | meltemi-doctor |
rápida | P-V1 | el diagnóstico que costó una tarde, en una pantalla | 1º (rangos de versión) |
| 30º | docs-en-el-sitio |
completa (enmienda §11) | P7 | la política de idioma decidida y el índice de las docs; servirlas en el sitio es antes una decisión de meltemi-web (la 0006), y el generador es suyo | ratificación del mantenedor |
| 31º | distribucion-y-actualizacion |
completa | P8, D-V1 | winget/brew/scoop tras la release atestada; la actualización la hace el gestor; los repos de destino y la página de descargas son de meltemi-web; el tap (propio o homebrew-tap) lo decide el mantenedor |
13º |
Tanda 3 — apuestas grandes
Sección titulada «Tanda 3 — apuestas grandes»| Orden | Change | Vía | Brechas | Por qué aquí | Depende de |
|---|---|---|---|---|---|
| 32º | ✅ companero-movil |
completa | MOB-1/2/4/9 | Android primero, SSH confinado, canal exec → bridge |
identidad-propia, 16º, 17º, 14º, 19º, 7º · en curso (6/8 al 2026-10-02). Los cinco prerrequisitos aterrizados. Lo hecho: el canal SSH confinado al crate móvil —en un teléfono no hay ssh del sistema que lanzar, así que lo habla la app— entregado como Box<dyn AsyncRead + AsyncWrite>, que es exactamente lo que el Stream del cliente ya era: ni una línea de meltemi-client cambia; la clave de la app, generada en el teléfono, con la pública para autorizar y la privada cifrada en reposo, y la frontera dicha con precisión porque la frase cómoda es falsa (el almacén de Android no exporta privadas asimétricas, así que firmar por él exigiría JNI y no está hecho); y las cuatro pantallas, con adoptar tras dos puertas —el diálogo de la superficie y el confirm que el daemon exige— y la frontera de autoría contada: el compañero entero tiene un solo campo de texto. Hallazgo que corrigió el design: russh exige uno de ring o aws-lc-rs y trae el segundo por defecto, al contrario de lo que el design afirmó; la prohibición de deny.toml mordió al añadir la dependencia, antes de compilar nada, y quedó una excepción acotada (ring solo como envoltorio de russh) con la prohibición del otro intacta. Cerrada (8/8, verify 7/7): el APK instala y arranca en el emulador y abre en la pantalla «No tunnel», que dice qué falta y que no haya relés ni puertos es deliberado. APK release arm64: 10,69 MB contra el techo de 25 MB declarado antes de compilar, de los que 9,15 MB son la biblioteca nativa. Dos cosas que solo se supieron haciéndolo: el build de Android falla desde el CLI de npm —el proyecto Gradle registra cómo se invocó el CLI y desde un shim registra node, que no puede arrancar; el mensaje nombra el último recurso probado y no la causa—, remediado con el CLI nativo y anotado en mobile/README.md; y env(safe-area-inset-bottom) sola no bastó, la barra de gestos cruzaba dos etiquetas, así que la navegación lleva max(inset, 16px). El orden de tareas se alteró a propósito para descubrir eso antes de escribir más pantallas |
| 33º | motor-propio-byok |
completa | LM-4 | la cuña BYO-modelo sin depender de OpenCode | 6º, 23º |
| 34º | adjuntos-en-el-compositor |
completa | D3 (imágenes) | bloques de imagen ACP condicionados a la capacidad anunciada | 12º, 25º |
| 35º | panel-dividido |
completa | D4 | dos paneles, sin anidamiento | 24º, 10º |
| 36º | volver-a-este-turno |
completa | D8 | punto de restauración por turno en worktree gestionado | 15º |
| 37º | segunda-ventana |
completa | C-B | una pestaña en el otro monitor | 35º, 24º |
| 38º | demo-guiada |
completa | P3 | meltemi demo con el agente simulado etiquetado |
13º, 10º |
| 39º | runner-nivel-3 (opcional) |
completa | LM-1, AI-9 | solo si Aider u otro CLI headless lo justifica | 6º |
| 40º | sucesion-y-custodia |
rápida | P10 | inventario de claves y segundo custodio | procedencia-de-release cerrada |
La release que prueba un desarrollador — declarada el 2026-10-28
Sección titulada «La release que prueba un desarrollador — declarada el 2026-10-28»Fuente: release-para-un-desarrollador (propuesta abierta el 2026-10-28 tras
revisar el estado del IDE frente a lo que el sitio declara del cliente de
escritorio). No hay spec del escritorio pendiente: lo que hace honesto el «en
desarrollo» del sitio son los instaladores sin firma de plataforma, el
transcript sin filas de herramienta y el smoke 3.2 de
primer-arranque-del-home. La tanda ordena lo ya propuesto para que una
persona —el mantenedor, en su máquina— instale desde los assets, trabaje con
sus agentes y escriba el informe que acompaña a la release. main @ ee0aa7b:
58 changes activas (28 terminadas sin archivar, 1 con una tarea abierta, 29
solo propuesta), 66 archivadas, 36 specs vivas, 53 commits después de la
v0.2.0 sin tocar proto/ ni la gramática del CLI.
| Orden | Change | Vía | Por qué aquí | Depende de |
|---|---|---|---|---|
| 0º | piso-del-aviso-sin-carrera |
rápida, sin deltas (solo un test) | main está en rojo en macOS desde el 2026-10-28: past_the_floor_the_next_wait_is_told_again supone que grabar el primer aviso tarda menos que un piso de 200 ms; el test pasa a medir el tiempo. Una tanda que empieza en rojo no se puede medir |
— |
| 1º | adaptadores-con-rawinput |
rápida | sin rawInput ni locations ninguna regla gobierna a Claude Code ni a Codex y cada petición escala al cliente (86 aprobadas y 32 denegadas a mano en la aceptación del hito); recordar solo funciona con el simulado |
— |
| 2º | archivo-sin-cabeceras-arrastradas |
rápida | split_requirements arrastra la cabecera siguiente del delta; las 28 changes terminadas se archivan con el motor, y el CHANGELOG.md del 3º se genera del archivo |
— |
| 3º | antes-de-anunciar |
rápida | quickstart desde los instaladores, FAQ, plantillas, CHANGELOG.md en el formato que lee meltemi-release notes; su gate se cumplió el 2026-10-24 |
2º (el archivo es el changelog en bruto) |
| 4º | meltemi-doctor |
rápida | la primera pregunta de cualquier problema, en una pantalla; el guion lo usa como primer paso | — |
| 5º | opencode-que-pregunta |
rápida | OpenCode edita sin pedir permiso: se lanza de modo que pida por ACP o la flota lo declara «no gobernado» con palabras | — |
| 6º | registro-de-la-sesion-de-calle |
rápida | session/log no encuentra el registro de una sesión de dispatch; los worktrees de tarea no se excluyen del git del árbol principal |
— |
| 7º | primer-arranque-del-home 3.2 |
tarea abierta | el smoke con flota vacía, que espera un fixture sin candidatos alcanzables | — |
| 8º | release-para-un-desarrollador |
completa | el guion docs/prueba-de-uno.md, el informe en docs/qa/, la regla de docs/release.md y la recomendación de versión (0.3.0); el mantenedor escribe la versión y corre el guion |
0º–7º |
| deseable | herramientas-a-la-vista |
completa | el transcript del escritorio deja de pintar píldoras: lo que el sitio llama «pulir la carcasa». Entra si cabe; no bloquea | 10º, 14º del orden anterior |
| si caben | regla-precisa-en-la-bandeja, auditar-reglas-y-procedencia |
completas | la bandeja propone la misma regla precisa que el aprobador, y crear una regla queda en el log | 1º |
Avance del 2026-10-28. 0º y 1º implementados; 2º implementado y, con su
motor arreglado, archivadas 27 changes en orden de aterrizaje, cada una con
verify completo y un commit propio: barra-de-estado-agentica,
compositor-que-trabaja, modos-de-autonomia, pensamiento-a-la-vista,
piel-de-pestanas, preguntas-del-agente, redirigir-turno,
sesion-que-espera, titulo-de-sesion, harness-global-y-por-agente,
sesiones-en-la-barra, apagado-entero-y-modos, codex-al-dia,
turno-vacio-es-error, aprobador-en-el-cli, modelo-por-opcion-anunciada,
usage-desde-acp, verbos-del-agent-boss, acceso-remoto-afinado,
corrida-integrada, estado-en-vivo, via-ssh-del-cliente,
aviso-de-espera-opt-in, maquinas-remotas, companero-movil,
senales-de-vida, enfasis-con-color y adaptadores-con-rawinput. Antes,
dos barridos: ningún requisito lo modificaban dos changes sin archivar, y un
MODIFIED (maquinas-remotas sobre remote-access) era anterior a una change ya
archivada del mismo requisito, identidad-propia, y se reconcilió devolviéndole
la aserción que había perdido. enfasis-con-color y modos-de-autonomia tenían
un escenario sin enlazar, y se enlazó. No se archiva lanzador-conversacional
(gate de la firma 1c). La verdad viva valida limpia: 37 capabilities (nace
agent-harness) y 93 changes en el histórico. Hallazgo de 2º, corregido: el
daemon que sirvió los primeros archivos estaba compilado antes del arreglo; la
guarda del lote lo detectó en sesion-que-espera (una cabecera arrastrada), se
deshizo ese archivo sin commitear, se reinició el daemon y se rehízo. Los
anteriores no arrastraron nada porque sus deltas no tenían sección tras un
ADDED.
0º piso-del-aviso-sin-carrera, cerrada el 2026-10-28 (2/2, sin deltas):
el test del piso pregunta «dentro» antes de esperar al grabador y mide «fuera»
desde el último aviso. El CI de la PR de la tanda (run 40779160260, 3946a8e)
lo pasó en macOS, donde main estaba en rojo, y en Linux. Se archivó a mano,
como grabador-de-avisos-sin-carrera, porque meltemi archive rehúsa una
change sin deltas.
3º antes-de-anunciar, cerrada el 2026-10-28 (7/7, verify 6/6): plantillas
de error y de pregunta sin issue en blanco, insignias en los dos README,
meltemi-release changelog y un CHANGELOG.md que nace con la 0.1.0 y la
0.2.0, la regla y la cadencia en docs/release.md, el quickstart desde los
instaladores y docs/faq.md. Encender Discussions queda del mantenedor.
4º meltemi-doctor, cerrada el 2026-10-28 (6/6, verify 6/6): el
diagnóstico se compone en meltemi_client::doctor y lo ofrecen el CLI
(meltemi doctor, --json, sale con 14 si algo falla), la paleta de la TUI y
Ajustes del escritorio, con las mismas frases en español e inglés; nunca
arranca un daemon ni ejecuta un agente. La primera corrida real encontró que
el adaptador propio de Codex, que viaja en toda instalación, hacía fallar la
fila de un agente que nadie instaló; corregido. De paso, la vista de flota de
la TUI sin catálogo vuelve a pintar las máquinas, como su comentario
prometía.
5º opencode-que-pregunta, cerrada el 2026-10-28 (4/4, verify 3/3): una
entrada del registro declara launch-env y el daemon lo aplica en toda
resolución de su id —por id, por perfil, como agente del proyecto—, nunca a un
agent.command literal, y por debajo de lo que el usuario fijó en su entorno o
en su perfil. La entrada de OpenCode lanza con OPENCODE_CONFIG_CONTENT en
ask para editar, comandos, red, subagentes y rutas fuera del proyecto; la
guía lo dice con el valor, y que OpenCode así mande sus preguntas por ACP es una
pierna manual pendiente de docs/conformidad-manual.md.
6º registro-de-la-sesion-de-calle, cerrada el 2026-10-28 (3/3, verify
3/3): el daemon sabe por la forma de la ruta a qué proyecto pertenece una calle
(<raíz>/.meltemi/worktrees/<change>/<calle>), y session/log, la búsqueda
de una sesión por raíz y la reanudación leen y escriben bajo la clave de ese
proyecto; la calle sigue siendo la raíz que el índice guarda. El primer
worktree de tarea excluye la raíz gestionada en .git/info/exclude, como ya
hacía el taller. El e2e encontró un tercer hueco de la misma historia: un
despacho termina sin salir del registro vivo, y session/direct lo rehusaba
como «activa pero no dirigible» mientras el daemon viviera; ahora solo rehúsa
una sesión que sigue corriendo.
7º primer-arranque-del-home, cerrada el 2026-10-28 (3.2 hecha, verify
3/3): el smoke sobre el binario (Linux, WebKitGTK, dos registros fixture) midió
el chip y el saludo, y encontró tres defectos que ya se dieron por buenos en
agosto: la flota vacía cambiaba la palabra pero no el tono, la advertencia se
leía «sin agentes …», y el lado Rust del estado de la interfaz tiraba
fleetGreeted y noticesEnabled en cada guardado —el saludo volvía en cada
ventana y apagar los avisos no duraba—. Los tres corregidos y re-medidos, con un
test que falla si el host deja caer un campo que la superficie persiste.
docs/qa/2026-10-28-primer-arranque-del-home-smoke.md. Nombra
pestana-nueva-con-nombre: la miga y la sección «Abiertas» muestran el id
interno __new__ de la pestaña del compositor.
pestana-nueva-con-nombre, cerrada el 2026-10-28 (vía rápida, verify
1/1): nombrada por el smoke de 7º y hecha en la misma tanda, porque es lo
primero que ve quien abre la app. La miga, el título y la sección «Abiertas»
nombran la pestaña del compositor «Nueva sesión», como ya hacía la tira, en vez
de mostrar su id interno __new__.
8º release-para-un-desarrollador, lo del agente cerrado el 2026-10-28
(verify 4/4; no se archiva: su gate es la corrida del mantenedor). El guion
docs/prueba-de-uno.md —once pasos, de los assets de la release a desinstalar,
cada uno con qué haces, qué esperas ver, dónde queda y su desviación conocida,
y la plantilla del informe—, atado al binario por la docs CI. meltemi-release changelog --report abre las notas con el enlace al informe y lo conserva al
reescribir; la regla y el orden están en docs/release.md. Recomendación de
versión: 0.3.0. Lo que queda es del mantenedor (pendiente 8, abajo).
No son gate, y el guion los declara como desviación conocida:
codex-reanudar-y-mcp (Codex no se reanuda), extension-acp-usage (Claude
Code y Codex no reportan uso), los certificados de firma de plataforma y la
pierna local con ollama.
Lo que Meltemi no copia de Orca, y por qué, está en la sección 6 del informe: relé en la nube y push sin túnel (§3), cuentas y uso por API del proveedor (§2/§5), pty sin gobierno, Chromium embebido, GitHub/CI en el daemon, yolo por defecto, telemetría, releases automáticas, JS en el sitio.
Siguen nombradas sin abrir (no cuentan en este orden):
registro-agentes-en-superficie, menu-nativo-aplicacion, sandbox-propio,
hooks-eventos, plugins-skills-sdk, i18n-superficies,
metricas-sdd-locales, lsp-superficie-revision, harness-skills,
harness-hooks, harness-subagentes, ruteo-declarativo-de-perfiles y el
.rpm de Fedora/RHEL. Nombradas el 2026-10-28 por release-para-un-desarrollador,
con su sitio en la tanda de arriba y su propuesta por abrir:
piso-del-aviso-sin-carrera, archivo-sin-cabeceras-arrastradas,
opencode-que-pregunta y registro-de-la-sesion-de-calle.
La entrega sin huecos — propuestas escritas el 2026-10-29
Sección titulada «La entrega sin huecos — propuestas escritas el 2026-10-29»Fuente: entrega-sin-huecos (paraguas). Nace de revisar la tabla de estado de
/ide/ en meltemi.dev contra el repositorio y la release v0.2.0:
- el compañero móvil figura como «Not yet» y está construido: la change está archivada y el APK mide 10,69 MB, pero ningún workflow lo compila para Android ni lo publica;
- el escritorio se publica sin firma de plataforma;
- el SDK no existe, como dice la tabla;
- la versión y el
CHANGELOG.mdlos escribe el mantenedor a mano.
El eje es automatizar: que CI proponga la versión en una PR cuyo merge publica, que construya, firme y publique todo lo que el producto tiene, y que el sitio pinte el estado desde la release.
Decisiones del mantenedor (2026-10-29):
- todo automatizado hasta el merge de la PR de release;
- la política de firma se enmienda: firmas de plataforma bajo custodia escrita, en jobs que no construyen;
- un hito probado sube el minor, ya escrito en
docs/versionado.md, y la próxima es la 0.3.0; - 1.0.0 la propone CI cuando su lista de preparación está en verde; hoy
faltan la firma y la prueba de un desarrollador (
entrega-sin-huecosD3); - una GitHub App, la que el mantenedor ya tiene, para cada token del camino.
Las nueve changes tienen sus cuatro artefactos y validan limpio. Las de
meltemi-web están en openspec/changes/ de ese repositorio.
| Orden | Change | Repositorio | Vía | Por qué aquí | Depende de |
|---|---|---|---|---|---|
| 0º | ide-state-as-it-is |
meltemi-web | rápida | el sitio dice algo falso hoy | — |
| 1º | ide-delivery-infra |
meltemi-web | completa | los entornos release-pr y signing, la App y los secretos de firma en Terraform |
la App instalada |
| 2º | version-que-propone-ci |
IDE | completa | la versión según la política, en una PR de release; el merge publica; el aviso a la web con la App | 1º |
| 3º | estado-que-publica-la-release |
IDE | completa | capabilities.json atestado en cada release |
— |
| 4º | ide-state-from-release |
meltemi-web | completa | la tabla del sitio sale de la release, verificada | 3º en una release |
| 5º | apk-en-la-release |
IDE | completa | el APK compilado en CI con su techo de 25 MB; publicado solo firmado | — |
| 6º | firma-de-plataforma |
IDE | completa | la enmienda; MSI, DMG y APK firmados en jobs aislados y verificados contra identidades fijadas | 1º, 5º, certificados |
| 7º | contrato-publicado |
IDE | rápida | los JSON Schemas del contrato como asset de cada release; el índice completo | — |
| 8º | distribucion-y-actualizacion |
IDE | completa | Homebrew, Scoop y winget como canal de actualización | 6º para el cask |
| deseable | herramientas-a-la-vista |
IDE | completa (ya propuesta) | lo que separa el escritorio de «publicado» | — |
Del mantenedor:
- instalar la App en este repositorio (contenido y PRs) y en meltemi-web (Actions), y cargar su id y su clave en el Terraform;
- el Apple Developer Program, el proveedor de firma de Windows (
firma-de-plataformaD4) y la clave del APK, generada y respaldada; - la decisión del tap y la salida de winget (
distribucion-y-actualizacionD2, D3); - confirmar la lectura de 1.0 (
entrega-sin-huecos3.3); - correr la prueba de un desarrollador, que es lo que convierte la PR de release en la 0.3.0.
motor-propio-byok — propuesta activa desde el 2026-07-25
Sección titulada «motor-propio-byok — propuesta activa desde el 2026-07-25»Nace de tres peticiones del mantenedor: una vía para modelos autohospedados
(ollama y cualquier endpoint OpenAI-compatible), el manifiesto del motor como
concepto de primera clase con un default (el pedido original lo llamaba
«harness»; renombrado el 2026-08-09 — la palabra nombra ahora el harness de
agentes de harness-global-y-por-agente), y una decisión sobre su proyecto
Forge Harnesses. La forma la decidió meltemi.md D6: el motor propio entra a la flota
como un agente ACP de nivel 1 (core/meltemi-engine), pilotado por stdio igual
que cualquier agente externo — misma detección, mismo proxy de permisos, mismos
worktrees y checkpoints, jamás un canal privilegiado. Todo el tráfico de red
vive en el subproceso: meltemid no enlaza pila HTTP/TLS alguna, propiedad
auditable que sostiene §3.
El manifiesto del motor es un TOML v1 (dialecto, base-url, modelo, prompt,
política de herramientas, límites) que el daemon valida y lista, nunca
interpreta; el default va embebido apuntando a http://localhost:11434/v1,
el único que no privilegia a proveedor comercial alguno. Sin modelo alcanzable
rehusa con remedio; nunca degrada en silencio. Las claves BYOK entran solo por
referencia ${VAR}, con el lint de higiene existente.
Decisión sobre Forge Harnesses: se mantiene como proyecto separado, conectado por contrato — este repositorio publica el esquema versionado del manifiesto (JSON Schema + fixtures de conformidad) y Forge produce manifiestos que se prueban contra ellos. Absorberlo sometería un laboratorio de iteración de prompts a la constitución entera (spec-first por cada ajuste, clippy en 3 SO, Apache-2.0 + CLA desde el día uno), no compraría ni un test de integración en CI (que por regla no ejecuta agentes reales ni red) y arrastraría a Meltemi hacia el marketplace que su rumbo explícitamente no es. Si alguna vez se absorbe, entra Apache-2.0 bajo CLA, sin excepciones.
Mientras la change no se implemente, correr un modelo local bajo Meltemi ya es
posible hoy y sin código nuevo por OpenCode (nivel 1), que habla con
endpoints ollama/OpenAI-compatible y con OpenRouter por su propia
configuración: las recetas, verificadas y fechadas, están en
docs/local-models.md (guia-modelos-locales). Aider (nivel 3) no sirve
hoy: el daemon no lanza el nivel 3 —todo verbo lo rehúsa con
level_not_pilotable—, y lo hará solo si runner-nivel-3 llega a existir.
El design system del mantenedor vive en design-system/ y es la fuente visual
normativa (gui-clase-mundial D11).
instaladores-linux-sin-webview — activa desde el 2026-07-25
Sección titulada «instaladores-linux-sin-webview — activa desde el 2026-07-25»El gate de tamaño disparó en Linux la primera vez que llegó a apuntar ahí: el
AppImage pesa 78 678 520 B contra 15 MB. El número no se ensancha porque no es un
número: el design D7 de gui-tauri-paridad dejó escrito que codifica «no
empaquetamos motor de navegador», y meltemi.md §7 rechaza esa vía por su nombre.
La change retira el AppImage, declara libwebkit2gtk-4.1-0 y libgtk-3-0 en el
.deb —que hoy instala limpio y no arranca— y corrige la prosa pública en los
dos idiomas. El hueco queda nombrado: fuera de la familia Debian no hay
instalador gráfico hasta que exista un .rpm, que es change propia porque exige
verificar los nombres de paquete en Fedora/RHEL en vez de adivinarlos.
procedencia-de-release — activa desde el 2026-07-26
Sección titulada «procedencia-de-release — activa desde el 2026-07-26»Nace de una pregunta del mantenedor tras firmar la v0.1.0 a mano: las empresas grandes no firman desde un portátil. Es cierto — usan HSM/KMS con clave no exportable, o firma keyless sin clave de largo plazo; la ceremonia humana firma claves, no releases. Pero la conclusión no es mover la clave a CI: un secreto de Actions es exactamente el caso que SLSA v1.2 prohíbe en lenguaje normativo, y la firma manual es el único paso que una cuenta de GitHub comprometida no puede completar — un atacante empuja un tag, CI construye y atestigua, y la atestación verifica perfectamente porque registra fielmente su commit.
La change deja la firma donde está y añade lo que falta: una atestación de
build sobre el SHA256SUMS publicado, que liga los artefactos al repositorio,
al commit y al workflow. Enmienda además el requisito de custodia para que sus
promesas sean cumplibles — el ancla de confianza vive en el repositorio y no en
la página de release que autentica; el almacenamiento es offline, no
hardware-backed (minisign no tiene HSM ni PKCS#11); y «revocar» queda definido
como publicar clave nueva y repudiar la vieja, porque minisign carece de
mecanismo de revocación.
Deuda declarada al archivar (no se archivó nada fingiendo que estaba
hecho): ✅ la captura de escritorio del sitio está publicada y su procedimiento
es un script (scripts/capture-desktop.ps1, docs/ux/capturas.md); la firma de MSI/DMG sigue pendiente
de infraestructura de certificados; el arranque y la RAM en macOS y Linux se
publican en el QA de la primera release que incluya la GUI.
pulido-pre-anuncio — vía rápida, archivada el 2026-07-27
Sección titulada «pulido-pre-anuncio — vía rápida, archivada el 2026-07-27»Tres defectos de acabado a la vista del anuncio. Uno: siete botones de la
GUI apilan el icono sobre la etiqueta — el skin global de botones no declara
display y el svg de Icon es block, así que todo botón icono+texto sin
regla flex local rompe la línea; la regla global gana inline-flex y las
re-declaraciones locales duplicadas se retiran (la repetición por componente
era la causa raíz). Dos: «Ver la flota (4)» incrusta el atajo de teclado como
falso contador; el atajo ya tiene su afordancia kbd en el sidebar. Tres:
los adapter-install del registro recomiendan instalar desde rutas
muertas — el codex-acp Rust de Zed quedó archivado el 2026-07-22 y los
adaptadores canónicos viven bajo @agentclientprotocol (verificado contra
npm el 2026-07-27, no citado de memoria). Deltas ADDED-only sobre gui-shell
y fleet-catalog; el refresco del registro es puente honesto mientras
adaptadores-propios-acp no aterrice, y el build que acompañe el anuncio se
reconstruye tras el merge.
lanzador-conversacional — abierta el 2026-07-27
Sección titulada «lanzador-conversacional — abierta el 2026-07-27»Nace de la prueba directa del mantenedor: el modal de lanzamiento actual le
pareció «ordinario», y el mockup que siguió fijó la dirección final en tres
directivas. Supersede y absorbe los borradores sesion-conversacional y
gestion-proyectos-en-superficie, que no entran al backlog como changes
propias. Uno: home conversacional — compositor al centro con el contexto
como chips (proyecto, agente, modo); enviar navega hacia adentro de la
sesión, a una vista de conversación con compositor persistente sobre
session/direct, burbujas de turno sobre el log de eventos (el log de
operador sigue a un conmutador: el transcript es la verdad) y tarjetas de
permiso en línea, con estados honestos — «encolada» jamás finge respuesta.
Dos: el modo libre es el default — una sesión nueva es una sesión libre
gobernada sobre el proyecto elegido; Proponer y Explorar son modos opt-in
del mismo compositor. Tres: los proyectos viven en la navegación —
sección persistente con sesiones anidadas, «Abrir carpeta…» en el nav y en
el chip (diálogo nativo vía el plugin oficial de Tauri, dependencia nueva
del cliente justificada §10), acción rápida por proyecto.
El default libre obliga a una honestidad de producto que la propuesta nombra
con sus frases exactas: hoy no existe RPC para iniciar una sesión libre
(session/direct exige sesión existente; propose/sdd/explore son verbos
del método; worktree/dispatch exige change y tarea), y la promesa pública
dice lo contrario — «ninguna línea de código se escribe sin una
especificación revisada» (rumbo de producto y tesis de meltemi.md). La
resolución: la sesión libre queda gobernada siempre (proxy
deny-by-default, aislamiento y checkpoints, log apend-only — §3 no se
negocia) pero no spec-gated; el método pasa de cerrojo a propuesta de
valor por sesión. La redacción de rumbo/product.md y meltemi.md se enmienda
con ratificación del mantenedor como gate; la constitución del propio
repositorio no se toca — el desarrollo de Meltemi sigue spec-first.
Al daemon entran solo los verbos que la dirección genuinamente no tiene: el
arranque de sesión libre (forma final en el design), project/register
(alta validada y canonicalizada) y project/forget (baja solo del
registro, una línea de olvido en el JSONL que el plegado last-wins
resuelve; jamás toca el disco), más el parámetro agent aditivo en el verbo
nuevo y en propose/sdd/explore — resuelto por resolve_fleet_agent, con
error estructurado que lista candidatos detectados en vez del string crudo.
La conversación en sí es composición cliente sobre eventos-para-tardios.
Paridad ×3 (§4): verbos CLI, direct interactivo en la TUI (hoy reservado
en la paleta), render de proyectos, docs/paridad-nucleo.md al día; el
cromo exclusivo de la GUI no tiene deber de paridad, toda capacidad nueva
del daemon sí. Fuera de alcance: menu-nativo-aplicacion y
registro-agentes-en-superficie siguen siendo changes propias (registrar
agentes ≠ seleccionarlos), y el render conversacional del histórico
archivado más allá del conmutador de log queda para futuro con evidencia.
Desenlace (2026-07-31) — implementada y verificada; el archivo espera una
firma. Los nueve bloques de tareas están cerrados, meltemi validate sale
limpio y meltemi verify da 106/106 escenarios, sin una sola marca manual.
Lo que quedó decidido y conviene leer aquí, porque son las cosas que la
propuesta dejó abiertas:
- Nombres finales de los verbos CLI (design D9):
meltemi session <instruction> [project-root] [--agent <id|perfil>]—nostart, que se leería como arrancar el daemon junto astop— ymeltemi projects register|forget <path>, colgados del listado en plural porqueprojectya toma una raíz posicional y habría leídoregistercomo una ruta.--agentse parsea una sola vez enplany se entrega al subcomando, de modo que vale en cualquier posición; un subcomando que no arranca sesión la rehúsa con diagnóstico en vez de tragársela. - El guardián de reversión, que entró en esta change y no en una futura
(design D2):
checkpoint/revertrehúsa todo punto de restauración cuyo árbol no sea un worktree gestionado, con el remedio degit restore --source. Escribir el checkpoint de la sesión libre sin ese guardián habría armado un verbo existente contra el árbol del usuario —reset --hardmásclean -fdsobre trabajo humano sin commitear—; ninguna superficie ofrece ya ese control. - La enmienda de la promesa está aplicada y sin ratificar:
rumbo/product.mdy la tesis de meltemi.md (v1.5) llevan el texto de D5 con su nota de pendiente. Sin la firma del mantenedor esta change no archiva — pendiente 1c del arquitecto, donde además está lo que hay que hacer al firmar. - Una enmienda de spec en marcha (design D12): la vista de aterrizaje de
gui-shellera «Sesiones» en la verdad viva y estaba fijada por un test; se enmendó el requisito, no la implementación, porque el compositor como llegada es la directiva entera de la change. - Documentación:
docs/sesion-libre.md(qué gobierna una sesión sin spec, dónde opera, y por qué el punto de restauración no es una reversión ofrecida) y el smoke visual con 21 medidas endocs/qa/2026-07-31-lanzador-conversacional-smoke.md.
Lo que el smoke encontró y esta change no arregla (rumbo de estructura: lo que surge se anota, no se cuela). Dos merecen decisión antes de archivar:
- El texto no ASCII llega corrupto al agente —
out.push(bytes[i] as char)encore/meltemid/src/repo_map.rs:120convierte cada byte UTF-8 en un code point Latin-1, así que «acción» viaja como «acción» en todo prompt que pasa por la expansión de@. Es anterior a esta change y de gravedad alta: el agente recibe la frase rota, no solo la pantalla. Anotado arriba comotexto-intacto-al-agente. - Olvidar un proyecto con sesiones no quita su nodo del árbol: el daemon lo
saca del listado, pero el cliente lo reconstruye como nodo inferido
(
desktop/ui/src/lib/tree.ts:81) y no distingue los inferidos. Esconderlo dejaría sesiones sin casa en el árbol, que es justo lo que el nodo inferido evita: es decisión de producto, no un arreglo obvio.
Los otros tres (posición en la cola tapada por el aviso de permiso, cierre de
turno como línea neutra tras una tarjeta, y el primer fleet/list saliendo antes
de que el ámbito de proyecto se resuelva) están descritos con su evidencia en el
informe de QA.
adaptadores-propios-acp — abierta el 2026-07-27 (directiva del mantenedor)
Sección titulada «adaptadores-propios-acp — abierta el 2026-07-27 (directiva del mantenedor)»Dos adaptadores ACP propios, en Rust y en este monorepo, para los dos agentes
cuyo nivel 2 depende hoy de adaptadores de terceros: Claude Code y Codex. Esta
change revierte una decisión registrada — niveles-integracion-conformidad
dejó fuera de alcance «Mantener adaptadores propios: se consumen adaptadores
abiertos existentes» — y la reversión se argumenta, no se esconde. El suelo se
movió: Zed archivó su codex-acp en Rust el 2026-07-22 y los adaptadores
canónicos viven ahora en TypeScript bajo la org agentclientprotocol — la
opción Rust upstream murió, y las dos filas adapter-install del registro ya
apuntan a rutas rancias. La zona gris del adaptador de Claude basado en Agent
SDK es permanente: los términos de Anthropic (feb-2026) nombran al SDK como no
autorizado para OAuth de suscripción, y ningún fork lo arregla porque la zona
gris vive en la superficie de auth, no en quién mantiene el adaptador. Y los
adaptadores propios pueden viajar bundled = true en los instaladores —
reutilizando la detección de directorio hermano de motor-propio-byok —
matando el muro de onboarding «adaptador no detectado» que
flota-deteccion-guia diagnosticó.
El adaptador de Claude pilota el binario oficial claude con la sesión que
el usuario ya inició, vía -p --input-format stream-json --output-format stream-json — jamás el Agent SDK, jamás --bare; el flip anunciado de
--bare como default de -p queda pineado como riesgo en el design, no se
descubre después. Los permisos pasan por --permission-prompt-tool (un shim
MCP por stdio que releva al socket existente de meltemid; el daemon no gana
transporte alguno) con hooks PreToolUse como compuerta dura, y las pérdidas
se declaran: AskUserQuestion se auto-deniega en modo no interactivo y el
contrato del prompt-tool está infradocumentado upstream (issue #1175). El
adaptador de Codex lanza el CLI oficial codex en modo app-server —
JSON-RPC NDJSON por stdio, documentado, la misma interfaz que usa la extensión
VS Code del propio proveedor, con esquema por versión vía
generate-json-schema que es historia de conformidad lista — y no el
patrón de embeber codex-core como librería de los adaptadores Rust
archivados, que choca con §2 aunque sea limpio de licencia.
Honestidad legal sin maquillaje: esto no vuelve «sancionado» a Claude —
gris pasa a tolerado-con-nota en el mejor caso, y la nota del registro se
mantiene veraz; Codex sigue tolerado y mejora, porque desaparece la
dependencia de supply chain sobre un proyecto archivado. Anclas: §2 (binarios
oficiales, auth gestionada por el agente — el adaptador jamás toca tokens),
§5 (los adaptadores entran a la flota como cualquier otra entrada), §6
(prueba por escrito: ACP es el estándar del lado Meltemi; del lado proveedor
no hay estándar — stream-json y app-server son la superficie programática
oficial de cada uno), §10 (dependencias confinadas a los crates adaptadores)
y un solo lenguaje de sistemas. Fuera de alcance: forkear los adaptadores TS
y toda vía basada en SDK. Por directiva del mantenedor (2026-07-27: «no
quiero ACP de terceros… construimos los propios»), los adaptadores propios
pasan a ser la capa por defecto del registro, empaquetados bundled en los
instaladores; los de terceros siguen alcanzables por configuración del
usuario, pero dejan de ser la vía recomendada.
texto-intacto-al-agente — abierta el 2026-07-31, vía rápida
Sección titulada «texto-intacto-al-agente — abierta el 2026-07-31, vía rápida»El primero de los cinco hallazgos del smoke conducido del 2026-07-31, y el
único de gravedad alta: el prompt llega al agente con los acentos rotos.
out.push(bytes[i] as char) en expand_refs
(core/meltemid/src/repo_map.rs) recorre el prompt como bytes y convierte
cada byte UTF-8 en su code point Latin-1 homónimo, así que «acción íntegra
ñandú» entra con 20 caracteres y el registro de la sesión guarda 24. No es un
defecto de pintado: lo corrompido es el prompt, y alcanza a todo camino de
prompt del daemon —free_session.rs y propose.rs pasan ambos por la misma
función—, lo que en un proyecto que se escribe en español significa casi toda
frase enviada. Es anterior a lanzador-conversacional; esa change solo lo hizo
visible, porque el compositor volvió al usuario lector de su propia frase.
La corrección copia el tramo literal entre referencias como una sola rebanada
&str en vez de empujar byte a byte, conservando los índices de byte que la
lógica del token necesita para rebanar (design D1). De la misma raíz cuelga el
defecto hermano que la change arregla en el mismo aliento: is_ref_char solo
admitía is_ascii_alphanumeric, así que un archivo acentuado —ordinario en
esta máquina— no se podía referenciar y @informé.md diagnosticaba «no
encontrado» sobre un informe que el usuario nunca escribió; el token pasa a
char con is_alphanumeric, que admite cualquier alfabeto y sigue dejando
que la puntuación española («¿», «—», «…») lo cierre en vez de tragársela
(design D2). Deltas ADDED-only sobre repo-context: dos requisitos que
escriben lo que hasta hoy era conducta accidental — el texto no referenciado
viaja intacto (con @@ literal, que tampoco estaba en la verdad viva) y las
rutas fuera de ASCII se referencian como cualquier otra. Cero dependencias
nuevas y ningún movimiento del contrato proto/. El barrido de as char se
hizo y queda escrito (design D5): un único sitio en código propio, el que esta
change arregla.
tablero-de-carrera — abierta el 2026-07-31
Sección titulada «tablero-de-carrera — abierta el 2026-07-31»Nace de la demostración de aceptación: el daemon corre la carrera
multiproveedor entera — worktrees aislados, despacho con el binario y la
suscripción de cada proveedor, procedencia persistida, commit trazable —
pero ninguna superficie la muestra como carrera, y para verla hubo que
construir un tablero externo desechable. El inventario honesto: la GUI
tiene medio tablero por accidente (el drill-in de revisión compara diffs
de competidores, sin procedencia ni estado ni acciones), el shell anuncia
los diez verbos de carrera como «(reservado)» y no renderiza ninguno, y
debajo hay tres huecos de contrato que ninguna superficie puede rodear:
el despacho no nombra la sesión que abre, el diff por calle calla la
procedencia que el daemon conoce, y las sesiones de despacho ni siquiera
asientan registro en el índice (aparecen reconstruidas, con nivel
mentiroso). La change ensancha el contrato con campos aditivos por calle
(cero ruptura, sin verbo nuevo, la matriz de paridad no cambia de filas),
hace que el despacho asiente registro de primera clase, y abre las dos
superficies: en la GUI el drill-in de revisión evoluciona a tablero
(calles lado a lado con procedencia, acciones con confirmación explícita,
actualización al concluir turnos); en el TUI el verbo race deja de estar
reservado y abre el tablero sin tocar el contrato de dígitos 1–4. Cuatro
deltas ADDED-only (worktree-orchestration, session-history,
gui-shell, tui-shell), doce escenarios, cero dependencias nuevas;
spec-full deliberado — es superficie nueva sobre la feature fundacional,
no un ajuste. Fuera de alcance, por escrito: canal push de worktrees
(sigue diferido en eventos-para-tardios), merge automático o ranking, y
toda vista numerada nueva.
Desenlace (archivada el 2026-08-08). Quince tareas, veintiséis commits,
verify 12/12 enlazado sin una sola marca manual, suite en 858. El design
salió enmendado por la implementación en un punto que importa: daba por hecho
que level, agent_id y profile bastaban para que una calle declarara su
resolución, y no bastan — un id de catálogo y un agente configurado que nombra
un id se ven idénticos en esos campos, así que deducir la fuente habría sido
inventarla; SessionRecord ganó un source opcional que escriben todos los
caminos que ya resolvían por la flota. Dos decisiones de implementación que el
design no anticipó y quedaron escritas: committed es un hecho del árbol (la
cabeza difiere de su base) y no una marca que deje el despacho, de modo que una
calle comiteada a mano cuenta; y cada calle conserva su base, porque dos
calles de una tarea solo la comparten cuando nadie replicó la asignación contra
un HEAD movido. El smoke conducido sobre el binario de release
(docs/qa/2026-08-07-tablero-de-carrera-smoke.md) encontró y corrigió un
defecto que ningún test de cableado podía ver —la nota de vida partía a mitad
de frase pegada al sha y se leía como una oración sobre la base— y dejó anotado
un falso positivo del operador que se repetirá si no se nombra: medir una
superficie nueva con un binario de target/release viejo se parece exactamente
a un bug de la superficie nueva.
vincular-suscripciones — abierta el 2026-08-08
Sección titulada «vincular-suscripciones — abierta el 2026-08-08»El pedido fundacional en palabras del mantenedor: «si tengo dos suscripciones
de Claude y tres de Codex, debo poder vincular esas suscripciones en la
flota». El motor existe y está probado (flota-multiproveedor: perfiles con
overlay de contexto, resolución sin degradar, carrera de dos suscripciones
verificada e2e; el overlay llega al CLI real a través de los adaptadores
propios, que lanzan sin limpiar el entorno), y la verificación empírica del
2026-08-08 sobre la máquina de desarrollo lo cerró: CODEX_HOME=<dir vacío> codex login status responde «Not logged in» mientras el contexto por defecto
responde «Logged in using ChatGPT». Lo que no existe es el vínculo como
experiencia: ninguna superficie crea, deshace ni compone una suscripción —
solo TOML a mano, sabiendo por cuenta propia qué variable redirige cada
proveedor. La change: la variable de contexto y el gesto de login como
datos del registro (jamás un match por proveedor en el código),
subscription/link/unlink con persistencia en un archivo propiedad del
daemon cargado antes que lo manual (lo escrito a mano gana), el login
compuesto y jamás ejecutado (§2: el contexto se crea vacío, no se lee,
no se borra al desvincular), el duplicado de contexto advertido, y las tres
superficies (§4). Cuatro deltas ADDED-only (fleet-catalog, cli-contract,
gui-shell, tui-shell), diecinueve escenarios, cero dependencias nuevas.
Fuera de alcance por escrito: ejecutar o verificar logins, balanceo entre
suscripciones, y migrar los perfiles manuales existentes.
avisos-de-escritorio — abierta el 2026-07-31 (comparativo de mercado)
Sección titulada «avisos-de-escritorio — abierta el 2026-07-31 (comparativo de mercado)»Nace del comparativo conducido por el mantenedor contra Orca (Stably AI, 13
capturas) y de una verificación en código que lo confirmó: espera-humana
enseñó al daemon a esperar al humano, sesion-esperando y
eventos-para-tardios hicieron la espera visible y suscribible — y ninguna
superficie avisa al escritorio; los únicos «notification» del cliente son
mensajes JSON-RPC del bridge, y la TUI no tiene campana. Un permiso puede
esperar minutos con la app detrás de otra ventana, con el turno detenido en
silencio. La change: capability nueva attention-notices — aviso local del SO
desde los clientes (permiso esperando, gate esperando, sesión terminada o
fallida), con regla de foco (al frente, la bandeja de hoy; sin foco, el
aviso), contenido sin texto del turno, permiso del SO pedido en el primer
aviso real y estado denegado con remedio; GUI vía el plugin oficial de
notificaciones de Tauri (el precedente §10 del plugin de diálogo) con «probar
aviso» en Ajustes; TUI con campana/OSC opt-in. El daemon no gana transporte
alguno: los eventos ya existen, esto es el último metro — y el aviso remoto
autohospedado sigue siendo fase 3, jamás del daemon.
primer-arranque-del-home — abierta el 2026-07-31, vía rápida
Sección titulada «primer-arranque-del-home — abierta el 2026-07-31, vía rápida»El residuo chico del mismo comparativo, verificado en Home.svelte: el rehúso
de agente ya guía ejemplarmente (candidatos con estado y remedio dentro del
chip), pero solo después de fallar; la cara del chip dice «agente del
proyecto» en tono neutro aunque no haya un solo lanzable — el chip de
proyecto, al lado, sí advierte cuando falta la carpeta — y la pista del menú
vacío nombra la Flota sin abrirla. Deltas ADDED-only sobre gui-shell: el
chip advierte proactivamente, el menú vacío gana el gesto a la vista de
flota, y la primera llegada con flota poblada muestra «N detectados» una sola
vez. El wizard modal y la checklist persistente del comparativo se rechazan
por escrito: el compositor con chips es el asistente, en su sitio.
Hallazgos del comparativo anotados, no colados (rumbo de estructura):
setup scripts al crear worktrees → su casa es hooks-eventos cuando llegue;
issues de GitHub/Jira/Linear como tareas vía CLIs oficiales (gh/glab con
su propia auth, patrón compatible con §2) → funciones de equipo, fase 3;
automations recurrentes e importar una carpeta con N repos como grupo →
futuro con evidencia; y para el anuncio, un contraste que es mensaje y no
change: ese producto embarca «Yolo / Dangerously skip permissions» marcado
por defecto — exactamente lo que el deny-by-default constitucional de Meltemi
existe para no ser.
artefactos-de-cada-push — abierta el 2026-08-05, vía rápida
Sección titulada «artefactos-de-cada-push — abierta el 2026-08-05, vía rápida»Nace de una petición del mantenedor: «me gustaría que esto sea automático con
cada push (para eso tenemos CICD)» — quiere probar el build del día, y en
particular el DMG de macOS que su máquina Windows no construye. Lo que no
puede automatizarse es la release firmada: procedencia-de-release fijó que la
firma minisign ocurre fuera de CI porque es el único paso que una cuenta de
GitHub comprometida no puede completar, y con immutable releases activado firmar
precede a publicar sin orden alternativo. La change da el escalón intermedio:
.github/workflows/build.yml, un job por plataforma en cada push a main, que
produce los mismos artefactos que el camino de tag y los sube como artefactos de
la ejecución — sin release, sin versión, sin firma y sin insinuar ninguna de las
tres. release.yml no cambia ni una línea, y esa es la decisión central: hacerlo
allí habría hecho que cada publicación del sitio esperara un build de Tauri de
tres plataformas (publish-site declara needs sobre los jobs de empaquetado) y
habría duplicado los gates que ci.yml ya corre sobre el mismo commit. Los tres
presupuestos de tamaño gatean también esta ruta, con test que exige el mismo
valor en los dos archivos; el artefacto se llama meltemi-unsigned-<SO>-<sha> y
caduca a los 7 días; el aviso de «sin firmar» viaja al resumen del run y dentro
del artefacto. Costo dicho sin maquillar —tres jobs caros por push— con dos
diales declarados para bajarlo: el bloque on: y la matriz de plataformas.
Cuatro deltas ADDED sobre release-distribution, cero dependencias nuevas.
Desenlace (2026-08-09) — verificada en runner real. El primer push a
main tras el merge (commit 5b979c5c, 2026-08-06) dejó el run de Build
verde en 15m3s con sus tres artefactos descargables; el de macOS,
abierto y no inferido, trae el DMG normalizado y el tar.gz con los
cuatro binarios —los dos adaptadores propios incluidos— más SHA256SUMS y el
UNSIGNED-BUILD.txt íntegro. Tiempos de pared, el dato con el que se decide
la cadencia: Linux 7m36s · macOS 9m35s · Windows 14m59s. Los tres pasos de
presupuesto cerraron verdes, así que gatean esta ruta de hecho. No se creó
release alguna y releases/latest sigue en la v0.1.0 firmada. Evidencia
completa de los seis puntos en tasks.md 4.2. La segunda corrida (commit
5f01907, mismo día) salió verde en 3m29s / 3m36s / 5m16s: el par
caché fría ~15 min, caché caliente ~5 min es el número real de la
cadencia, un tercio de lo que la propuesta declaró para el caso normal.
Hallazgo del mismo push, ajeno a esta change y ya resuelto por sí solo:
publish-sitederelease.ymlarrancó a los 71 segundos —sin esperar empaquetado alguno, que era la razón entera de no tocar aquel archivo— pero suactions/deploy-pages@v4agotó la espera («Timeout reached, aborting!», 10m9s), y el del run del tagv0.1.1, empujado 18 segundos después, murió con «Deployment cancelled». En el push del 2026-08-09 el mismo job completó con éxito, así que la causa fue la concurrencia por el entorno Pages, no una rotura del pipeline. Queda escrito para que un rojo idéntico no se lea mañana como defecto nuevo. Siguen abiertos, y son del mantenedor porque tocan credenciales y configuración del repositorio: el HTTPS sin provisionar (https_enforced: false) y el borradorv0.1.1sin publicar que dejó aquel run de tag.
Cuatro días sin gate verde, y lo que dejaron pasar (2026-08-09)
Sección titulada «Cuatro días sin gate verde, y lo que dejaron pasar (2026-08-09)»Al empujar la tanda de propuestas de este día, CI salió rojo en las tres
plataformas — y el diagnóstico dejó ver algo más grande que su causa
inmediata. Entre el 2026-08-06 y el 2026-08-09 no corrió ni un solo run de
ci.yml: toda la tanda UX (divisor, pestañas, avisos, flota por
suscripción, piel de Chrome) entró a main sin pasar por los gates, y su
archivado se apoyó en corridas locales. Lo que eso dejó pasar, encontrado y
corregido en el acto:
- Un
ReferenceErrorvivo en el camino de permisos:stores.tsllamaba apushNoticeen los manejadores depermission/requestypermission/timeout, pero el módulo solo la re-exportaba (export { … } from "./notices", que no crea binding local). Un permiso llegado por push reventaba el manejador: sin aviso y sin elrefreshPending()que venía después. Es exactamente el camino queespera-humanaysesion-esperandoconstruyeron. Lo introdujocromo-que-no-estorbaal sacar los avisos a su módulo puro. - Cuatro claves i18n duplicadas (
fleet.level.declaredyfleet.level.verified, en los dos idiomas), deflota-por-suscripcion. MIN_TAB_PXimportado y no usado enTabStrip.svelte, con el96pxduplicado a mano en su CSS — la constante sigue entab-strip.tsypiel-de-pestanasla reconectará.App.sveltecomparabaview === "sessions"sobre un$stateque TypeScript estrechaba al literal"home"desde que el compositor pasó a ser la vista de aterrizaje; anotado como$state<ViewId>para que el estado vuelva a tener el tipo que dice tener.
Y la causa inmediata del rojo: un aviso de seguridad publicado entre ambos
pushes — nanoid <3.3.17 (high, GHSA-2v37-7h3g-55p8) y postcss
(moderate), ambos transitivos de Vite. npm audit fix los subió a 3.3.18 y
8.5.26 sin tocar package.json. Lección de método, no anécdota: el gate
solo protege si corre; conviene mirar que corrió antes de dar una tanda por
cerrada.
salida-que-se-lee — abierta el 2026-08-15, vía rápida
Sección titulada «salida-que-se-lee — abierta el 2026-08-15, vía rápida»El mantenedor puso la salida de OpenSpec junto a la nuestra y la comparación no
admitía discusión: sin resumen (los totales había que sumarlos a ojo), sin
alineación (treinta y seis filas que no se recorren en vertical) y sin color
(activa y archivada, 7/7 y 0/9, se ven igual). Pidió además formatos de
salida al estilo de Kubernetes.
--json era un booleano, y un booleano no admite un tercer formato sin
convertirse en dos que pueden contradecirse: ahora es un enum resuelto una vez,
y --json --yaml se rehúsa por nombre en vez de resolverse por el último flag.
El emisor YAML es propio y la change queda con cero dependencias: serde_yaml
está archivado por su autor desde 2024 —adoptarlo pediría un ignore en
deny.toml elegido a propósito— y YAML 1.2 es superconjunto de JSON, así que
emitir toda cadena entre comillas dobles con el escapado de JSON es válido por
construcción y los casos de borde temidos no llegan a existir.
El color no carga significado: estado es la palabra, progreso son las cifras, la compuerta lo dice en texto, un artefacto ausente es un punto donde iría una letra. El test renderiza dos veces, quita los escapes de la pintada y exige que sean idénticas — de modo que el color no puede empezar a significar algo más adelante sin que la suite lo note. Y sin TTY no se pinta, que es lo que hace el cambio compatible byte a byte para todo script existente y la razón de que ningún requisito vivo necesitara modificarse.
Tres hallazgos de implementación: padear después de pintar alinea los
escapes en vez de las letras (las secuencias ANSI no ocupan ancho); la última
columna no debe padearse (solo produce espacios finales invisibles); y el filtro
de un test atrapaba la línea de resumen junto con las filas. Nota:
docs/qa/2026-08-15-salida-que-se-lee-smoke.md.
Deuda declarada: que el terminal pinte de verdad no se automatizó — capturar la salida la convierte en un pipe, y en un pipe el color se apaga por diseño, así que la medición destruiría lo que mide. Levantar una pseudo-terminal (ConPTY) sería su propia change.
acceso-remoto-en-dos-vias — abierta el 2026-08-09, vía rápida
Sección titulada «acceso-remoto-en-dos-vias — abierta el 2026-08-09, vía rápida»Nace de una exploración con el mantenedor sobre el compañero móvil, y de tres frases suyas: la combinación debe funcionar «en dos vías» (PC o CEL fuera de casa, el trabajo sigue), varios Meltemi en varios equipos con varios teléfonos, e idealmente PC↔móvil directo con el hub como respaldo aceptable.
Dos hallazgos la definen. El agujero con nombre: Windows no podía ser el
extremo servido, porque su endpoint es un named pipe y ninguna forma de
reenvío SSH lo alcanza — toda ruta termina en algo que corre dentro de esa
máquina. Ese último metro era un verbo que faltaba, meltemi bridge, que
conecta el endpoint local con su propio stdio; ssh <pc> meltemi bridge es
entonces un canal JSON-RPC completo en las tres plataformas, y la limitación de
Windows queda arrinconada donde no molesta. El patrón sin dueño: «en dos vías»
se resuelve con una sola regla — nadie recibe conexiones, ambos extremos marcan
hacia afuera a un punto de encuentro del usuario. El túnel inverso reenvía el
puerto TCP del sshd del PC, que el OpenSSH de Windows sí reenvía, así que el
pipe no viaja por ningún túnel.
Todo lo que va más allá del verbo es infraestructura del usuario —bastión, malla WireGuard con plano de control autohospedado, identidad— y por eso se documenta como frontera en vez de implementarse: licencias verificadas, nada entra al workspace, el daemon sigue ciego y el transporte final sigue siendo el SSH del usuario hacia el socket local. Ningún requisito vivo se modifica.
Dos defectos que solo la medición encontró, ambos en la vuelta
daemon→cliente: tokio::io::copy vacía solo al EOF (un protocolo de
petición/respuesta se ahoga esperando un búfer que solo llena la respuesta que
se retiene); y —la causa real— un abrazo mortal del candado de stdout,
porque main retiene io::stdout().lock() durante todo el dispatch y el
candado de Rust es reentrante por hilo, mientras tokio::io::stdout() escribe
desde el pool de bloqueo. El puente escribe ahora por el escritor que el proceso
ya bloqueó. Nota:
docs/qa/2026-08-15-acceso-remoto-en-dos-vias-smoke.md.
Deuda declarada: el tramo sshd → bridge no se ejercitó — el servidor
OpenSSH de Windows está NotPresent en la máquina del mantenedor e instalarlo
exige privilegios y toca su superficie de seguridad. Queda por medir que el
shell por defecto de sshd no altere el flujo de bytes. Notas de fase 3
capturadas para companero-movil: identidad BYO por certificados SSH de vida
corta emitidos por el IdP del usuario, selector multi-máquina como concepto de
la app (cada meltemid sigue siendo de su máquina), y el aviso de espera
autohospedado.
rama-por-change — abierta el 2026-08-16, vía completa
Sección titulada «rama-por-change — abierta el 2026-08-16, vía completa»El mantenedor instauró el flujo con una frase —cada change «en ramas separadas
por change y al terminar […] merge a main»— después de que un git add
amplio arrastrara archivos ajenos tres veces en un día entre sesiones
concurrentes commiteando sobre el mismo árbol. Meltemi ya orquestaba worktrees,
pero en el eje de las carreras (change×tarea×agente); esta change añade el eje
que el flujo necesita: el taller de la change, con su rama de nombre
desnudo y su aterrizaje.
change/workspace es «dame», no «crea»: idempotente con reencuentro declarado,
creado desde la punta de la rama por defecto (detectada, no asumida). La
propiedad la da el registro, no un namespace: la rama homónima ajena se rehúsa
sin tocarse solo en el camino implícito — nombrarla con --branch es
consentir, y --unique acuña un taller con sufijo que jamás colisiona (los dos
flags se excluyen con palabras, como --json --yaml). change/land
previsualiza sin confirm y fusiona --no-ff con él; el conflicto se aborta
al instante y se entrega al git del usuario. Retirar un taller con commits sin
aterrizar exige confirmación que dice cuántos, y la rama nunca se borra.
La raíz gestionada queda excluida por info/exclude, no por el .gitignore
versionado. Paridad §4 pagada por el registro obligatorio; doce escenarios
cubiertos por e2e contra fixtures (uno con rama por defecto trunk).
cromo-que-no-estorba — abierta el 2026-08-08, vía rápida
Sección titulada «cromo-que-no-estorba — abierta el 2026-08-08, vía rápida»Tres frases del mantenedor sobre una captura: el scroll del panel derecho, los
mensajes que «se quedan pegados» y la paleta que no cierra al hacer clic fuera.
El cajón declaraba overflow: auto en los dos ejes con 268 px fijos, así que
una ruta larga sacaba barra horizontal; ahora es un solo eje y el contenido se
parte. Los avisos no caducaban ninguno, lo cual es obligatorio solo para lo
que la spec nombra —un vencimiento «no se descarta en silencio»— y no para un
«enlace creado»: ahora los informativos se retiran a los 6 s y los de
advertencia y error no tienen reloj, probado por ausencia avanzando cien
veces el plazo; apuntar o enfocar detiene la cuenta y salir la reinicia. Y el
velo de la paleta no tenía manejador de clic mientras el del conmutador sí: en
vez de arreglar ese caso, un barrido exige cierre en todos los velos y
encontró otros cuatro. La política de avisos salió a su propio módulo puro,
porque el store no es importable bajo node y una obligación de spec merece un
test que corra. Nota: docs/qa/2026-08-08-cromo-que-no-estorba-smoke.md.
flota-por-suscripcion — abierta el 2026-08-09, vía rápida
Sección titulada «flota-por-suscripcion — abierta el 2026-08-09, vía rápida»El mantenedor dijo que la flota «no permite configurar varios agentes de un
tipo». Lo que veía era cierto; lo que suponía, no: enlazar varias ya funcionaba
y el smoke de la change anterior lo había fotografiado sin buscarlo. Lo que
faltaba era la lectura: una fila de perfil nunca decía de qué agente era,
aunque el contrato lleva underlyingAgent desde flota-multiproveedor y el CLI
ya imprime (profile → claude-code). La superficie que lo decía era la
terminal; la que lo escondía, la gráfica. Ahora cada agente va seguido de sus
suscripciones, cada una diciendo «suscripción de X» como texto —la sangría
solo acompaña—, con el recuento en el agente; una suscripción cuyo agente no
está en el catálogo se lista marcada, con el id que declara, en vez de
desaparecer. De paso se cumple un requisito vivo de integration-levels que la
superficie incumplía: el nivel se dice «declarado» o «verificado» con palabras y
no con un ✓ a secas, que es justo lo que esa spec prohíbe. Nota:
docs/qa/2026-08-09-flota-por-suscripcion-smoke.md.
pestanas-como-chrome — abierta el 2026-08-09
Sección titulada «pestanas-como-chrome — abierta el 2026-08-09»«El sistema de tabs quiero que se parezca al de google chrome», con grupos y
botones < >. La tira envolvía —flex-wrap: wrap— y cinco sesiones ya
producían una segunda fila que empujaba el contenido. Ahora es una sola fila:
las pestañas encogen hasta un mínimo legible y solo entonces la tira se
desplaza, con controles que existen únicamente mientras hay desbordamiento,
medido con ResizeObserver, y que se deshabilitan en su extremo en vez de
esconderse. La pestaña activa se trae a la vista con nearest, sin lo cual las
flechas del patrón ARIA mueven el foco fuera de pantalla. Lo que no se copia
de Chrome es su respuesta al desbordamiento —Chrome encoge hasta el favicon y
nunca desplaza—: el mantenedor pidió las flechas y la petición manda sobre la
referencia. Los grupos llevan nombre y color; el color identifica y el nombre
viaja en el nombre accesible de cada pestaña, plegar declara cuántas guarda y
no cierra ninguna, y si la activa estaba dentro, la actividad sale a una pestaña
visible. Se agrupa por menú y no arrastrando, porque el equivalente accesible
del arrastre es otra conversación. Nota:
docs/qa/2026-08-09-pestanas-como-chrome-smoke.md.
Deuda declarada de esta tanda: las pestañas y sus grupos no se persisten entre arranques (
sidebar-ajustable-y-pestanasD7, heredado); si se persisten, la primera tarea de esa change es medir el arranque con ocho pestañas. Sigue pendiente la auditoría de intuitividad que el mantenedor pidió como barrido completo de la aplicación.
Hallazgo del smoke de
pensamiento-a-la-vista(2026-08-10), anotado y no colado: al reconstruir una conversación desde el log, el turno de una sesión ya terminada no se marca como cerrado. Medido con veinte segundos de espera activa sobre el binario: no se renderiza el indicador de fin de turno y, en consecuencia, el pensamiento queda desplegado en reposo. El log contieneturn_completedy el pliegue tiene su rama para marcarlo (conversation.ts:301-308), así que el defecto está en el camino que reconstruye desde el log, no en el dato ni en la regla nueva — y afecta igual al indicador de fin de turno, que es anterior. Candidata a vía rápida sobregui-shell. Evidencia endocs/qa/2026-08-10-pensamiento-a-la-vista-smoke.md.
Flake conocido (2026-08-09):
with_no_clients_the_constitutional_deny_ fires_after_the_grace(core/meltemid/tests/e2e_permisos.rs:369) falló una vez solo en Windows tras siete runs verdes. No es una regresión: su espera es un sondeo de 200 × 50 ms —diez segundos— a que la sesión llegue aended, y en un runner cargado eso se agota. Reejecutado, pasó. Si reincide, el arreglo no es reintentar sino ensanchar el margen del sondeo, que es lo único que la prueba mide de más: el escenario es la denegación constitucional, no la velocidad del runner.
Hallazgo del smoke de
piel-de-pestanas(2026-08-09), anotado y no colado: el CLI guarda la raíz del proyecto tal como se la escriben.meltemi session "…" .deja sesiones cuyoprojectRootes el literal., mientrasmeltemi projectssí canonicaliza y muestra la ruta absoluta. En la GUI eso produce dos nodos: el proyecto real con 0 sesiones y un nodo inferido llamado.con todas ellas. Con ruta absoluta el árbol es correcto. Es la misma clase de defecto que la tanda del 2026-07-31 cerró por otras puertas («Spell a project’s root the same way whichever door it comes through»), y esta quedó abierta. Candidata a vía rápida; su casa natural esproject-registry. Evidencia endocs/qa/2026-08-09-piel-de-pestanas-smoke.md.
harness-global-y-por-agente — abierta el 2026-08-09, implementada el 2026-09-15
Sección titulada «harness-global-y-por-agente — abierta el 2026-08-09, implementada el 2026-09-15»La directiva del mantenedor: definir una sola vez el comportamiento base y las
tecnologías —«el backend siempre es FastAPI y usa las tools xxx»— y ajustarlo
por agente y por proyecto. La palabra «harness» queda para esto (rules,
skills, agents, hooks); el TOML del motor propio pasa a llamarse manifiesto
del motor (nota terminológica en motor-propio-byok). Fase 1: cuatro
ámbitos con la precedencia vigente (global → global por-agente → proyecto →
proyecto por-agente), pilar Rules con el formato de FDH tal cual
(RULE.md con scope por glob — la fábrica del mantenedor, CLI Go v0.4.1 en
producción, se reutiliza en vez de reinventarse), proyección de las capas
nuevas por el único escritor (meltemi project, bloques gestionados; lo
global del usuario jamás entra a archivos del repo) y la vista efectiva
×3 al estilo git config --show-origin: por agente, qué le aplica y de qué
capa viene cada pieza. Skills, Hooks y Subagentes quedan nombrados como
changes futuras (harness-skills, harness-hooks, harness-subagentes) con
sus pruebas §6 y §2 por delante; los bundles con nombre y la alineación del
lado FDH, también. Capability nueva agent-harness; spec-full deliberado.
Cerrada 25/25, verify 15/15. Tres hallazgos que solo aparecieron al leer
los archivos de verdad. (1) El fixture con los cuatro RULE.md reales de FDH
encontró un defecto anterior a esta change: parse_list partía por cada
coma y el scope real ["**/*.{ts,tsx}"] se rompía en dos globs que nadie
escribió — ningún archivo de rumbo/ podía hallarlo porque ninguno ha llevado
nunca una coma. (2) Verificar los destinos de ámbito usuario produjo dos hechos
que ninguna suposición habría dado: Codex lee AGENTS.override.md en vez de
AGENTS.md cuando el override existe —escribir igual llenaría un archivo que
nadie lee y parecería haber funcionado— y su directorio se mueve con
CODEX_HOME. (3) agents_supported de FDH dice codex y este catálogo dice
codex-cli: los vocabularios no coinciden, así que el campo se conserva,
se muestra y no gobierna nada — quién recibe una regla lo decide el eje
per-agent/<id>/, que usa los ids de este catálogo.
El guardián de «lo global del usuario jamás entra al repositorio» quedó
estructural: la función que compila lo de repositorio no recibe las fuentes
globales, así que no hay parámetro por donde entren. Un if se olvida en la
siguiente refactorización; una firma que no admite el dato, no.
Y el cierre encontró lo suyo: verify dio 14/15 porque el escenario de la CLI
estaba marcado hecho sin test que lo enlazara — el verbo existía y nadie lo
probaba. Documentación en docs/harness.md.
familia-por-titulo — abierta el 2026-09-16, vía rápida
Sección titulada «familia-por-titulo — abierta el 2026-09-16, vía rápida»Defecto en main, no idea nueva: desktop/ui/tests/forms.test.ts llevaba rojo
el gate «every form resolves to a schema of its own family» desde que
rama-por-change añadió change/workspace y change/land.
harness-global-y-por-agente lo encontró al cerrar y lo anotó sin colarlo
(tasks 6.3); esta change lo cobra por la puerta de siempre.
El test no fallaba por un contrato roto sino por una regla que el contrato nunca
tuvo. El generador liga método→schema por el title del schema (claimsMethod,
gen-method-forms.mjs:49–56), no por el nombre del archivo: el nombre es una
etiqueta que viaja al resultado, nunca una llave que se consulte. Y
workspace.schema.json no es una anomalía — es el cuarto miembro de un grupo
que ya tenía tres: implement (sdd/implement), validate (sdd/validate) y
verify-archive (sdd/verify · sdd/verify-mark · sdd/archive) llevan todos el
nombre de sus verbos y no el de su familia, y son exactamente las tres entradas
que sostenían la lista de excepciones del test. Por eso no se renombró nada:
renombrar habría cambiado el contrato para que una heurística de test dejara de
quejarse, y para ser honesto el archivo habría tenido que partirse en dos,
porque aloja landParams tanto como workspaceParams.
Dos hechos que el mensaje del test escondía: change/land fallaba igual —no
existe land.schema.json y el assert cortaba en el primero—, y cuatro de las
siete entradas de la lista son inertes: change, spec, repo-map y commit
ya pasan por file.startsWith(family).
Propuesta futura anotada, no colada (design D3): derivar la lista de los
title del contrato en vez de escribirla a mano, lo que vigilaría la ligadura
real en lugar de la forma de los nombres y haría imposible esta deriva; con ella
desaparecerían solas las cuatro entradas inertes.
compositor-que-trabaja — abierta e implementada el 2026-08-09
Sección titulada «compositor-que-trabaja — abierta e implementada el 2026-08-09»Home.svelte llevaba class:busy desde el día que se escribió y no había
una sola regla que lo pintara. Ahora la tiene: el viento de la marca
recorriendo el borde del compositor mientras un agente trabaja, y ■ Detener
junto al envío, con la misma confirmación y el mismo verbo que el acceso del
encabezado, que se conserva.
Es la primera change que enmienda el sistema de diseño, y lo hace por escrito en vez de contradecirlo: Motion gana la clase «indicador ambiental de trabajo» (uno por vista, bucle lento, solo transform u opacidad, jamás layout, solo mientras un agente trabaja) y la reserva de marca gana una excepción, redactada con su propio tope — «nada más en la superficie puede reclamarla; una segunda cosa vistiendo el degradado convierte a las dos en decoración».
Tres hallazgos del código cambiaron decisiones. El kill-switch global de
movimiento reducido no apaga: acorta duraciones, y habría dejado la luz
pintada y detenida en una posición cualquiera — el smoke lo midió
(display: none y animation: 1e-05s), así que la regla propia está
probada y no argumentada. LIVE incluye waiting_permission, de modo que
reutilizarlo habría encendido la luz justo donde la change quiere apagarla: una
luz girando mientras el agente espera al humano miente sobre quién debe actuar.
Y la acción primaria pintaba el degradado con un literal suelto teniendo
--mel-wind declarado, lo que se corrigió aquí porque escribir la excepción de
marca y dejar el literal sería enmendar la regla y romperla la misma tarde.
Nota: docs/qa/2026-08-09-compositor-que-trabaja-smoke.md, que incluye la
trampa de método que estuvo a punto de convertirse en un falso defecto — un
driver que inyecta nodos contamina toda medición posterior.
titulo-de-sesion — abierta e implementada el 2026-08-09
Sección titulada «titulo-de-sesion — abierta e implementada el 2026-08-09»Nace de lo que el smoke de piel-de-pestanas fotografió sin buscarlo: seis
pestañas diciendo mock a296f430, mock 929240ed, mock 39597c6f — la misma
palabra y ocho caracteres de hex, seis veces. El daemon deriva ahora el nombre
de la frase que abrió la sesión, en local y sin modelo (§5: pedirle a la sesión
de pago del usuario que se nombre gastaría sus tokens y pondría en su log
palabras que no escribió).
Leer el código antes de escribir el design encontró dos trampas que la
propuesta no podía conocer. La primera es la que más habría dolido: el índice
pliega last-wins y merge_into solo copia los campos que enumera; el
registro de cierre no lleva título, así que sin su propia rama el nombre se
habría visto mientras la sesión corría y desaparecido al terminar — un
defecto de datos con el disfraz de uno de pintado. La segunda: la instrucción
existe dos veces, como se escribió y con las referencias @ expandidas; el
título sale de la primera, y se corta por caracteres y jamás por bytes (el pozo
de texto-intacto-al-agente).
Dos decisiones que la propuesta dejaba abiertas quedaron cerradas: una calle de
carrera no recibe título —no nace de una frase— y reanudar conserva el
suyo en vez de re-derivarlo. Y una tercera se enmendó al implementar: los
turnos de autoría SDD tampoco lo reciben, porque a run_turn no llega la frase
del usuario sino un prompt que compone el método; nombrar con texto
generado es el mismo error que nombrar con una referencia expandida.
Cerrada 13/13 tareas, verify 11/11 sin marcas manuales. Los tres escenarios
de orden y ausencia (que el título se tome antes de expandir, que las
rutas sin frase no lo inventen, que el resume herede) se pinean contra el
código que decide, porque un e2e vería el resultado y no el orden; la
confirmación conducida es el smoke, que además midió la regla de ambigüedad en
sus dos sentidos. Nota:
docs/qa/2026-08-09-titulo-de-sesion-smoke.md.
barra-de-estado-agentica — abierta el 2026-08-09, vía rápida candidata
Sección titulada «barra-de-estado-agentica — abierta el 2026-08-09, vía rápida candidata»Primer hallazgo capturado de la auditoría de intuitividad: el mantenedor pidió
«una barra inferior de estado como VS Code e IntelliJ» — y la barra existe
(StatusBar.svelte, especificada en gui-shell), tan escueta que su propio
mantenedor no la registró como tal. La change la hace hablar el idioma del
dominio en vez del de un editor: proyecto activo, change activa con su gate
(gatePending ya viaja en el contrato), sesiones por estado en vez del plano
«N en curso», y consumo de tokens de las sesiones activas donde esté
medido — con la frontera de honestidad de analitica-consumo-local a la
vista, porque ACP no transporta usage (los niveles 1 y 2 leen «no reportado»
hasta la extensión de usage ya nombrada en motor-propio-byok). Segmentos
accionables (clic navega a la vista dueña), prioridad declarada al encoger, y
las mismas verdades nuevas en el chrome de la TUI; el footer de atajos de la
TUI no se toca. Exclusión escrita: Ln/Col, encoding y toda señal de editor que
el rumbo excluye. Deltas ADDED-only sobre gui-shell y tui-shell (más
local-analytics si el design pide la consulta por sesión), cero dependencias
nuevas.
piel-de-pestanas — abierta el 2026-08-09, vía rápida
Sección titulada «piel-de-pestanas — abierta el 2026-08-09, vía rápida»Segunda captura de la auditoría de intuitividad, con la captura de Chrome al
lado: «el manejo de tabs está feo». pestanas-como-chrome entregó la
estructura (una fila, controles medidos, grupos) y la piel quedó en el mínimo.
El diagnóstico tiene cinco causas leídas en el código: la tira no tiene capa
propia de fondo (la activa no tiene de dónde levantarse), la activa se marca
con borde de acento (se lee como input, no como pestaña), cero hover, cada
pestaña carga su propia caja de 1 px con la X siempre visible, y el estado
viaja como palabra repetida en las N pestañas. La change viste la anatomía de
Chrome: capa de tira, activa unida al panel con curvas de unión
(radial-gradient, dentro del presupuesto cross-webview), separadores solo
entre inactivas, hover honesto, X revelada en hover/foco con Delete como
camino de teclado vigente, estado comprimido a glifo con nombre accesible, y
franja de color del grupo por pestaña. Medidas como constantes testeables en
tab-strip.ts. ADDED-only sobre gui-shell; cero daemon, cero paridad.
titulo-de-sesion — abierta el 2026-08-09
Sección titulada «titulo-de-sesion — abierta el 2026-08-09»«Diferenciar qué agente y a qué pertenece»: una pestaña dice hoy
mock-agent 97040fb6 y con seis sesiones del mismo agente la tira es seis
veces la misma palabra. El daemon deriva el título en local al iniciar
(primera línea de la instrucción, truncado honesto) — en el daemon y no en un
cliente, porque un título calculado en la GUI sería feature de una superficie
(§4) y dos clientes no deben mostrar dos títulos para la misma sesión.
sessionInfo gana title opcional (histórico sin migrar, degradación
honesta), session_started lo lleva, el resume lo hereda. La pestaña pasa a
avatar del agente + título, con el proyecto antepuesto solo cuando las
pestañas abiertas cruzan más de un proyecto; la TUI lo adopta en su lista.
Generarlo con modelo queda declarado como futuro opt-in de
motor-propio-byok: inyectar un prompt oculto en la sesión de pago del
usuario gastaría sus tokens en algo que no pidió y pondría en su log palabras
que no escribió. Vía completa; ADDED sobre acp-session, gui-shell,
tui-shell.
compositor-que-trabaja — abierta el 2026-08-09, vía rápida
Sección titulada «compositor-que-trabaja — abierta el 2026-08-09, vía rápida»La referencia del mantenedor es Copilot: una luz que recorre el borde de la
caja mientras se procesa. El gancho existe (class:busy sin CSS que lo use)
y la señal falta donde el usuario va a escribir lo siguiente. El anillo corre
con el degradado de marca (--mel-aegean → --mel-wind: el viento
recorriendo el borde mientras las velas trabajan) por transform: rotate()
sobre conic-gradient recortado — sin @property, sin mask-composite —,
se enciende en el Home al enviar y en el detalle con
state ∈ {starting, active}, y se apaga en waiting_permission:
esperándote no es trabajando. Reduced-motion cae al fallback que el design
system ya prescribe. Trae el ■ Detener al compositor con el mismo
ConfirmDialog (decisión del mantenedor: la confirmación se queda). El gate
único carga la enmienda al sistema de diseño que esto exige por escrito:
Motion gana la clase «indicador ambiental de trabajo» (uno por vista, lento,
jamás layout) y la reserva de marca gana su única excepción. ADDED-only sobre
gui-shell.
redirigir-turno — abierta el 2026-08-09
Sección titulada «redirigir-turno — abierta el 2026-08-09»El gesto que falta entre detener y complementar: el Esc de Claude Code — «no
sigas por ahí; haz esto» sin perder la sesión. No es hueco casual sino
carrera cerrada a propósito: el cancel marca la cola cancelada
(session.rs) para que ninguna instrucción tardía entre a un turno que no
correrá, y el bucle ACP rompe incondicionalmente en Cancelled. Imitar la
interrupción desde un cliente es exactamente esa carrera; la forma correcta
es el verbo atómico: session/direct con interrupt — encolar primero,
señalar después, y un borde de turno que distingue cancel de sesión (rompe,
como hoy) de interrupción nuestra con relevo (drena a Cancelled y despacha
lo encolado). ACP ya es por-turno; los adaptadores propios no se tocan (su
spec ya exige drenar la cancelación con la verdad). Interrumpir en
waiting_permission resuelve la petición como cancelada, registrada; el log
debe distinguir «el agente se detuvo» de «el humano lo interrumpió». GUI:
«Interrumpir y enviar» junto a «Encolar» cuando hay texto; TUI: el mismo
gesto (paridad §4 servida en la change). Mock-agent gana el escenario e2e.
Vía completa; deltas sobre acp-session, gui-shell, tui-shell y el
schema session-direct.
preguntas-del-agente — abierta el 2026-08-09
Sección titulada «preguntas-del-agente — abierta el 2026-08-09»Cuando el agente pregunta con opciones, la pregunta debe contestar-se donde
se escribe, como Claude/Codex/Copilot: listado con la recomendada visible y
una salida de texto libre al final. Lo notable es cuánto existe:
request_permission transporta N opciones con nombre, la bandeja y la
conversación ya las pintan con botones sobre la misma cola. Faltan la
presentación (acople al compositor en waiting_permission, aparición sin
animación de layout — regla dura vigente) y el emisor real: el adaptador de
Claude rehúsa AskUserQuestion como interactive-only con una premisa que
caducó — Meltemi es la interfaz. Sus propios tests prueban que la
pregunta llega por el canal con su tool_use_id y que la respuesta
transporta updatedInput: el cable existe de punta a punta. La change
levanta el rehúso solo para esa herramienta y escribe la excepción al
principio de input-intacto con su fundamento (en AskUserQuestion el input
es el formulario). Texto libre con la verdad de cada protocolo: por el
canal de Claude viaja en updatedInput; por ACP nativo no viaja
(Selected | Cancelled) y el escape es interrumpir-y-relevar — depende de
redirigir-turno. El mock-agent aprende a preguntar para e2e y demos. Vía
completa; ADDED sobre own-adapters y gui-shell.
sesion-que-espera — abierta el 2026-08-09
Sección titulada «sesion-que-espera — abierta el 2026-08-09»El mantenedor lo mostró con una captura: turno terminado, compositor muerto.
La causa, verificada: el borde del turno cierra la cola en cuanto queda vacía
(take_or_close, session.rs:88-101), el crate ACP mata el subproceso al
drop y finalize_ok deregistra — no existe estado «esperando instrucciones»,
y toda la sesión vive dentro de un solo RPC síncrono. Lo que hoy parece
persistencia es auto-resume (sesión nueva encadenada por resumed_from, que
exige loadSession del agente y relanza el proceso por mensaje). La change:
el borde espera en vez de cerrar (proceso vivo, encolar despierta), el
arranque se desacopla del RPC por vía aditiva —la evidencia de uso que
eventos-para-tardios dejó pedida—, política de idle explícita con finalize
honesto (reason: idle, jamás completed fingido), y el estado
«esperando instrucciones» visible en las tres superficies. Comparte borde con
redirigir-turno: van adyacentes en el orden para no reabrir ese código dos
veces. Vía completa; el riesgo nombrado son los subprocesos idle acumulados
(la política es la mitigación y el QA mide el reposo).
pensamiento-a-la-vista — abierta el 2026-08-09, vía rápida candidata
Sección titulada «pensamiento-a-la-vista — abierta el 2026-08-09, vía rápida candidata»«Ver la ejecución y la cadena de pensamiento en vivo como Codex/Claude
Code/Copilot» — y el hallazgo de la auditoría de código: la cadena entera ya
funciona. Los dos adaptadores propios reenvían el pensamiento en streaming
(claude thinking_delta→AgentThoughtChunk con dedup; codex deltas de
reasoning), el daemon reenvía verbatim, y la GUI ya pinta burbujas que crecen
chunk a chunk. Dos eslabones flojos, exactos: el <details> colapsado de la
GUI (SessionDetail.svelte:637-641) —el stream vivo existe pero hay que
expandirlo a mano— y la TUI que reduce todo evento a [id] tipo
(conn.rs:693-705), sin prosa ni pensamiento. La change destapa: expandido
en vivo durante el turno en la GUI, pliegue conversacional en el drill-in de
la TUI (espejo del fold de conversation.ts, con tope y gemelos ASCII), y la
honestidad de nivel 3 dicha (headless no mapea reasoning; sin chunk no hay
sección). Deltas ADDED sobre gui-shell y tui-shell; cero daemon, cero
contrato, cero dependencias.
modos-de-autonomia — abierta el 2026-08-09
Sección titulada «modos-de-autonomia — abierta el 2026-08-09»Pedido directo del mantenedor con la referencia de los productos vecinos
(Manual / Accept edits / Plan / Auto / Bypass): saber por sesión «si pide más
permisos para cada acción o actúa de forma independiente». El hallazgo que la
abarata: el daemon ya compone posturas por sesión (explore corre
deny_all, la autoría SDD allow_all, los interactivos cargan las reglas
del disco; sdd/implement ya lleva autonomous: bool con «never autonomy by
accident») — falta exponerlo. La change: campo mode aditivo que se traduce
a un bundle sintético con ámbito propio, compuesto con las reglas del usuario
en el punto único existente (la precedencia del motor es por ámbito, no por
posición: el design extiende evaluate); Manual = todo pregunta, Semi =
ediciones dentro del worktree pasan (contención por path_prefix;
is_out_of_tree clasifica mando y red, no rutas), Autónomo =
allow amplio salvo lo irreversible/fuera del árbol, que escala en todos los
modos — §3 literal, y el deny sin clientes no se toca. Bypass no
existirá: es frontera constitucional, no deuda. De paso se salda
allow_meltemi_writes() (promete .meltemi/, devuelve allow_all). Chip de
modo visible en las tres superficies y el modo escrito en el log y la
bandeja. Vía completa: la matriz de composición modo×reglas tiene esquinas
que el design enumera y pinea con tests.
modelo-y-esfuerzo-por-sesion — abierta el 2026-08-09
Sección titulada «modelo-y-esfuerzo-por-sesion — abierta el 2026-08-09»La palanca de cuotas que el mantenedor pidió con sus capturas: elegir modelo
y esfuerzo de razonamiento por sesión. Verificado: el app-server de Codex
ya expone model/effort por turno y el adaptador propio los deja
apagados a propósito citando §5; el de Claude no pasa --model pero el punto
de inserción es limpio y ya lee el modelo que el CLI anuncia; los perfiles
solo declaran agente+env; agent_resolved no registra el modelo (solo asoma
por el meta providerModel del adaptador de Claude o por usage_reported de
un nivel 3). Y ACP sí trae el vehículo: el esquema 1.4.0 del crate
pineado define session config options (Model/ThoughtLevel) — la prueba
§6 se endereza y la vía estándar se cablea. La change, gobernada entera por
§5 y §6: model/effort como strings opacos en el contrato que el
núcleo transporta sin interpretar y solo cada adaptador traduce (lo no
soportado se rehúsa con diagnóstico); los perfiles ganan ambos campos
(«perfil = agente + cuenta + modelo», la unidad de administración de cuotas);
chip y picker en el compositor con ficha que muestra solo lo que Meltemi
sabe —sin precios ni créditos, que son negocio de terceros—; cambio a mitad
de sesión donde el proveedor lo soporta, con el aviso honesto de la
referencia («reinicia la caché del proveedor y puede aumentar el costo»); y
agent_resolved gana el modelo efectivo. El ruteo automático «mejor modelo
por tarea» queda rechazado para el core y nombrado como change futura
declarativa (ruteo-declarativo-de-perfiles).
sidebar-ajustable-y-pestanas — abierta el 2026-08-08
Sección titulada «sidebar-ajustable-y-pestanas — abierta el 2026-08-08»Nace de una captura del mantenedor y tres frases: la línea divisoria entre las
opciones y los proyectos «debe poder moverse», el scroll de la sección de
proyectos «se ve fea», y las sesiones «deben ser tabs, de esa forma puedo tener
varios tabs abiertos». Tres cosas de naturaleza distinta y una sola change,
por una razón medible: el divisor fabrica la segunda barra de scroll —darle
alto a nav obliga a overflow-y: auto y la columna de 216 px estrena otra
barra clásica—, así que entregar la primera sin la segunda duplica el defecto
del que trata la segunda.
Lo que la investigación encontró antes de escribir nada: la «línea» no era un
elemento sino un border-top del encabezado PROYECTOS; no existía un solo
pointerdown en toda la superficie de escritorio; no había ningún estilo de
barra de desplazamiento en el repositorio, así que lo que se veía era el
defecto de plataforma; y las sesiones se pisaban porque el shell guardaba un
identificador que cuatro sitios sobrescribían —de ahí que un borrador escrito en
una sesión sobreviviera dentro de otra.
Dos decisiones cargan el peso. Las pestañas van contenidas en la vista
Sesiones y no sobre la región principal, porque las dos formas rivales
modifican el mismo encabezado de requisito que lanzador-conversacional ya
modifica en un delta sin archivar bloqueado en la firma del mantenedor: solo un
delta ADDED puede fusionarse sin pisar texto ajeno. Y los paneles se montan y
se ocultan en vez de desmontarse, que es lo que mantiene vivos transcript,
búsqueda y borrador; el lado del daemon es seguro porque su conjunto de
vigilancias es un HashSet por conexión sin tope, leído y citado, no supuesto.
El smoke conducido sobre el binario encontró cuatro cosas que el código fuente
no podía enseñar, y todas se corrigieron: que scrollbar-width no hereda;
que la barra angosta conserva sus botones de flecha en WebView2 y ninguna
propiedad estándar los quita; que las dos familias de estilo de barra son
excluyentes en Chromium —de ahí las dos ramas @supports—; y que el anillo
de foco del separador parecía un campo de texto vacío. Nota completa en
docs/qa/2026-08-08-sidebar-ajustable-y-pestanas-smoke.md.
Veinte escenarios, tres requisitos ADDED sobre gui-shell, cero dependencias,
cero métodos del contrato, un solo archivo Rust de producto tocado.
Seguimientos nombrados: (1) adoptar TabStrip en el Editor, cuya tira
propia no sigue el patrón ARIA; (2) un tope de líneas del transcript en la GUI
—la TUI ya tiene el suyo— si ocho transcripts montados lo piden; (3) persistir
el conjunto de pestañas al arrancar, cuya primera tarea sería medir el arranque
con ocho.
sesiones-en-la-barra — abierta el 2026-09-06, implementada el 2026-09-15
Sección titulada «sesiones-en-la-barra — abierta el 2026-09-06, implementada el 2026-09-15»Nace de la maqueta de acabado del shell y de cuatro frases del mantenedor: las sesiones «deben aparecer a la izquierda en el menú y diferenciadas por en curso, en pausa, esperando respuesta del usuario, detenido»; «lo que dice lista, no tiene sentido, no sirve para nada»; «al hacerle nueva sesión debe crear el tab y además dejar el cursor en el campo de texto con foco», con «ctrl + enter para enviar o ctrl + shift + enter para encolar mensaje»; y, al mirar la barra otra vez, «no veo dónde la gestión de tabs a la izquierda».
Las cuatro cosas son una sola pregunta —¿quién me necesita?— hecha desde el sitio donde se elige a quién atender. El contrato ya tiene los seis estados y la barra de estado ya los parte en trabajando / esperando / listas; lo que faltaba era usarlos donde se decide. Por eso el árbol gana cubetas dentro de cada proyecto (el proyecto sigue siendo el ámbito, la cubeta es el orden), la barra gana la sección «Abiertas» que es la tira vista de lado, y la pestaña «Lista» desaparece porque duplicaba la entrada Sesiones del menú.
Dos decisiones cargan el peso, y las dos nacieron de la revisión adversarial
antes de escribir código. La primera: el compositor deja de ser una vista y
pasa a ser la pestaña de llegada, que es lo que hace que «nueva sesión»
cree su tab en vez de esconder los que ya hay; eso roza la frase de «Paridad de
vistas y modelo de navegación» que lanzador-conversacional modifica sin
archivar, así que la enmienda de esa frase se declara como deuda con nombre
—la lleva quien archive segunda— en vez de darse por compuesta. La segunda: con
un turno en vuelo, el acorde que despacha releva (interrumpe y envía, la
puerta que redirigir-turno construyó) y el que encola deja la instrucción
detrás; el texto normativo nunca llama «enviar» al primero, de modo que «Enviar
no interrumpe» de conversational-session sigue siendo cierto palabra por
palabra, y el compositor lo dice antes de que se pulse. El mapeo alterno
—Ctrl+Enter encola, Ctrl+Shift+Enter releva— queda anotado en el design para
que la compuerta lo decida.
Deuda declarada: la guardia migration.rs::SUPERSEDED no cubre gui-shell
(la capability nació después de openspec/), así que el renombre del escenario
de la lista se pinea con un test propio; y la tabla de cubetas vive dos veces
—TypeScript y Rust no comparten función—, con un test de paridad que falla si
divergen.
Cerrada 8/8, verify 34/34. Tres cosas que solo aparecieron al implementar.
(1) El design se equivocó en un hecho: daba por existente una guardia que
prohíbe toda palabra de animación en Sidebar.svelte; ese archivo de tests ya
no existe —se fundió en scenarios_shell.rs— y la prohibición solo cubría la
bandeja. La guardia se escribió aquí, que es justo cuando se volvió portante: la
barra pasó a contener la cubeta donde aterriza un permiso, y una fila que se
deslizara sería movimiento bajo el cursor mientras se decide.
(2) Quitar la pestaña «Lista» destapó un fallo de accesibilidad: TabStrip
ponía tabindex=0 solo en la pestaña seleccionada, y con la lista en
pantalla ninguna lo estaría — un tablist sin nada en el orden de tabulación, o
sea sin manera de entrar con el teclado. Ahora el tabindex sigue a un
focusIndex que cae a la primera pestaña cuando no hay selección: ARIA pide
exactamente una pestaña tabulable, nunca que una esté seleccionada.
(3) Dos decisiones que el design no había tomado y que el código obligó a tomar: si la sesión arranca mientras se lee otra pestaña, la pestaña nace igual pero el frente no se mueve (llevarse al usuario sería que la superficie decidiera dónde mira); y el compositor toma el cursor solo mientras es la pestaña al frente, porque su panel queda montado detrás de otra y un campo oculto que roba el foco escribe donde nadie ve.
Y el cierre encontró lo suyo: verify dio 33/34 porque el escenario de las
teclas del terminal se daba por servido sin test que lo enlazara.
El smoke conducido sobre el binario encontró dos cosas más. La primera se
corrigió aquí: a 216 px la cabecera leía «LISTAS PARA TU INSTRU… 1», y la culpa
no era la frase sino el uppercase + letter-spacing heredados de
.sectionTitle — un nombre de cubeta es una frase sobre sus filas, no el título
de una región.
La segunda no se corrige aquí, y es la que importa: muestreando las cabeceras
80 veces alrededor de un turno real, la cubeta Trabajando nunca apareció. En
la misma corrida el daemon respondió queued y el compositor dijo «el turno en
curso sigue intacto» — o sea que había turno en vuelo y el listado de la
superficie no lo sabía. refreshSessions() se llama al conectar, al conmutar de
proyecto y al terminar un envío, nunca durante un turno; y de ese listado
salen tanto el anillo de compositor-que-trabaja como el par de esta change.
Es anterior a esta change —las dos anteriores ya dependían del mismo
listado—, pero esta lo puso donde se ve. Sale a su propia change en vez de
colarse: refrescar durante un turno es conducta sobre un store compartido, roza
la regla de que la barra no anima, y hay que decidir si repregunta el cliente o
empuja el daemon. Nota completa en
docs/qa/2026-09-16-sesiones-en-la-barra-smoke.md.
identidad-propia — abierta el 2026-09-06, implementada el 2026-10-01, vía completa
Sección titulada «identidad-propia — abierta el 2026-09-06, implementada el 2026-10-01, vía completa»Nace de una frase del mantenedor —«lo otro importante, inicio de sesión; sé que para esto hace falta un backend pero puede ser parte de la propuesta»— y de lo que ya había pedido para el móvil: «poder autenticarme en el cel con mi cuenta y ver las máquinas o instancias que están conectadas».
La respuesta empieza por lo que no se hace, porque tres guardianes lo
prohíben a la vez: deny.toml no admite cliente HTTP ni pila TLS en el
workspace, el webview no alcanza ningún origen https y su test lo pinea, y la
constitución §3 mantiene al daemon sin puertos. Un flujo OIDC dentro de Meltemi
rompería los tres, y docs/acceso-remoto.md ya había escrito que «Meltemi con
login» exigiría enmienda fundacional. La maqueta de acabado que dibujaba un
código de dispositivo dentro de la app se corrige por eso.
Lo que sí cabe es la identidad que la malla del usuario ya conoce: Headscale
con su IdP hace el OIDC en el navegador del usuario al enlazar cada equipo, y
el cliente oficial sabe localmente quién es y qué equipos hay. Meltemi lo
lee por ese binario —la misma regla con la que ejecuta git y los
agentes—, compone sin ejecutar jamás el gesto que enlaza un equipo (como
subscription/link compone el login de una suscripción), y lo muestra en sus
tres superficies antes de que el móvil lo enseñe. Cero dependencias nuevas,
deny.toml intacto, «sin cuentas» sigue siendo literalmente cierto.
El único MODIFIED es sobre «El punto de encuentro en dos vías está documentado», que hoy manda que la identidad y el selector de máquinas queden como notas de fase 3: esta change convierte en capacidad la parte de la variante de malla y deja como nota lo que sigue siéndolo (certificados SSH del bastión, el selector que conecta, el aviso de espera).
Deuda declarada: la forma del JSON del cliente de malla no es verificable
desde el repositorio, así que la primera tarea del daemon captura una salida
real redactada como fixture antes de escribir el parser —un campo mal nombrado
daría un parser verde en CI y un rehúso contra el cliente de verdad—. Y el test
tui/tests/docs.rs pinea hoy la nota de fase 3 que la change reescribe: se
reescribe con ella, conservando sus tres marcadores.
Implementada el 2026-10-01 (8/8). La deuda declarada arriba bloqueó la
change cuatro días: en el equipo del mantenedor no hay cliente de malla
instalado, y el design decía por qué no se podía saltar. Se desbloqueó por la vía
más fuerte, no por un atajo: la forma se verificó contra las definiciones de
tipo publicadas del propio cliente, fijadas en v1.102.5
(ipn/ipnstate/ipnstate.go, tailcfg/tailcfg.go), que es de donde el CLI
serializa su JSON. Una captura muestra solo los campos que una máquina pobló
en un estado; el tipo enumera todos con su etiqueta y su regla de presencia —y
delató cuatro trampas que una captura en un equipo sano habría escondido:
Self y CurrentTailnet son nulos sin conexión (justo el caso «sin enlazar»),
LastSeen no lleva omitempty y un par en línea trae el tiempo cero (un parser
ingenuo diría «visto: año 1»), las claves del mapa User son el id en decimal
como cadena mientras el par lo trae como número (buscarlo sin convertir
devuelve un usuario vacío contra el cliente real), y ShareeNode marca el equipo
que otra persona compartió hacia dentro, que el propio status del cliente
oculta por defecto. Cada una con su test.
Tres hallazgos más del camino. (1) El contrato traía tres cadenas y --exec
necesita un argv: volver a partir la línea por espacios habría roto una ruta
de cliente con espacio, que es el fallo exacto que las dos formas citadas existen
para evitar, así que IdentityLinkResult gana args. (2) El rigor de los tests
se midió neuterando el código, y de seis roturas deliberadas una no puso nada
en rojo: nada cubría «BackendState dice Running pero Self es nulo», donde
el handler panickeaba en vez de rehusar; ese test ahora existe. (3) El
guardián de variables de estilo cazó cuatro reglas CSS que no habrían pintado
nada (--sunken, --radius-1, --text-dim no existen en la piel).
Lo que queda, y queda dicho: una verificación de campo —correr meltemi identity una vez contra un cliente instalado y enlazado—, que no bloquea nada
porque los nombres salen del tipo y no de una conjetura; y la corrección del
tablero «Inicio de sesión» del lienzo de acabado, que vive fuera del árbol, en
el artefacto publicado de la sesión de diseño: la forma construible está dibujada
en design-system/ (sección 6b, con sus tres estados) y la edición del lienzo es
acción del mantenedor, porque el repositorio no puede editar lo que no contiene.
Gobernanza de alcance (changes
enmienda-edicion-movilyenmienda-agent-boss): la edición in situ de Fase 2 está acotada por la cerca de la specedit-surface; el compañero móvil de Fase 3 (companero-movil, meltemi.md §10) es el puesto remoto del Agent Boss — monitorear/aprobar/revisar/dirigir, sin autoría, túnel SSH exclusivamente, aviso de espera opt-in autohospedado — por las specsmobile-companionyremote-access.
apagado-entero-y-modos — abierta el 2026-09-17, implementada el 2026-09-18, vía completa
Sección titulada «apagado-entero-y-modos — abierta el 2026-09-17, implementada el 2026-09-18, vía completa»Nace de una revisión que el mantenedor pidió el 2026-09-17: contrastar nuestro
enfoque de adaptadores con claudian (plugin de Obsidian, MIT, que pilota
Claude Code, Codex, OpenCode, Grok y Pi) y decidir qué rescatar. La revisión
—los 1.671 archivos del árbol, a fondo su modelo neutral, su capa ACP y los
cinco proveedores— concluyó que nuestro enfoque resuelve lo mismo en una capa
mejor: normalizamos en el estándar y no en un modelo de eventos propio (seis
agentes de nivel 1 sin una línea de adaptador; ellos ~40 archivos por
proveedor, incluso para los que hablan ACP nativo), los adaptadores son
binarios gobernados fuera del proceso, Claude va por el binario oficial y no
por el SDK que sus términos nombran, y los checkpoints son git para todos y no
rewindFiles para uno. Lo que sí hacemos peor son dos cosas medidas, y
esta change son esas dos.
Apagado entero. En Windows, un CLI instalado por npm es un shim .cmd
bajo cmd.exe, y TerminateProcess sobre el shim deja vivo al node (o al
binario nativo) de abajo. Reproducido con un shim y un Stop-Process: el
nieto siguió vivo. Lo tenemos en las dos capas que lanzan proveedores: los
adaptadores (supervisor.rs, kill tras la gracia y kill_on_drop) y el
daemon, que delega el nivel 1 en AcpAgent del crate oficial, cuyo
ChildGuard mata igual. La spec viva promete «no queda ningún proceso
huérfano»; con un shim, hoy es falso. Remedio: un crate meltemi-process con
un Job Object por proveedor y KILL_ON_JOB_CLOSE —termina el árbol a
cualquier profundidad y, como cerrar el handle también termina, un crash del
lanzador tampoco deja huérfanos—, en vez del taskkill /t de claudian, que
no cubre el crash. Cero dependencias nuevas: windows-sys ya está pineado y
gana una feature. El daemon pasa a lanzar él mismo por spawn_process (que
el crate expone) y a conectar con Lines (también público), con lo que
conoce el pid y lo anota.
Modos anunciados. El esquema ACP pineado trae modes y config_options
en las respuestas de sesión; el daemon lee solo el segundo
(acp.rs:257,283). Un agente que anuncie por el campo de modos aparece sin
opción alguna — y modelo-y-esfuerzo concluyó «ningún proveedor anuncia
opciones» mirando una sola forma. Tampoco se miran current_mode_update ni
config_option_update. Remedio: leer las dos formas con la opción de
configuración ganando entera, fijar el modo heredado por session/set_mode,
y reflejar lo que el agente cambia por su cuenta. El contrato no cambia.
Primera tarea de esa parte: verificar contra cada agente instalado qué forma
anuncia, y persistirlo — para no repetir el error en dirección contraria.
Desenlace (implementada el 2026-09-18). Ocho tareas, ocho commits. El
crate meltemi-process existe y lo usan las dos capas que lanzan proveedores.
Los tres tests que miden el defecto se comprobaron mordiendo: neutralizada la
adopción, el mock-agent sobrevive al final de la sesión y el test lo dice por
su identificador; neutralizado el ruteo del verbo de modos y las dos ramas de
forward_update, los tres e2e nuevos fallan. Dos desvíos del design, los dos
escritos en el proposal: el contrato gana el evento de log agent_process
—porque los dos eventos que podían llevar el pid se escriben antes del
lanzamiento— y meltemid declara futures como dependencia directa, que ya
viajaba en el lockfile.
Lo que la verificación manual encontró, y no es lo que se esperaba. De las
seis entradas de nivel 1 del catálogo, solo opencode está instalada en este
equipo, y puebla las dos formas a la vez: el campo de modos con build y
plan, y las opciones de configuración con model (317 valores) y mode
(categoría mode, los mismos dos modos). El design D6 planteó la precedencia
como una regla para un caso incómodo; resultó ser el único caso real medible
aquí, y fusionar las dos formas habría dado dos selectores de modo o uno con
valores duplicados. La otra cara: la síntesis del campo viejo no queda
ejercitada por ningún binario real —haría falta un agente que puebla modos y
no opciones—, y docs/conformidad-manual.md lo dice con esas palabras en vez
de dejarlo implícito. Hallazgo lateral: la conclusión D9 de
modelo-y-esfuerzo-por-sesion («ningún proveedor pineado anuncia opciones de
sesión») ya no es cierta, no por error de entonces sino por su fecha.
Deuda declarada de una decisión, no de un olvido. Reemplazar la lista anunciada entera (D7) tiene un costo: un agente que anunciara sus modos por el campo viejo y sus opciones por el nuevo perdería el selector de modo al cambiar cualquier otra opción, porque la lista que reemplaza no lleva modo. Volver a sintetizarlo ahí sería la fusión que esa misma regla prohíbe, así que se deja como está, escrito en el código y aquí. Ningún agente instalado tiene esa forma.
Lo que la revisión dejó para el próximo re-anclaje de Codex, medido
contra el codex-cli 0.77.0 instalado: su esquema declara cuatro peticiones
de servidor y el adaptador cubre las dos de la generación v2; turn/steer,
item/tool/requestUserInput, item/permissions/requestApproval y
thread/fork|rollback|compact no existen en 0.77.0. Cuando existan, una
frase de claudian vale la pena: relevar a mitad de turno se resuelve como
aceptado solo con la aceptación nativa definitiva; ante ambigüedad se rechaza,
para que quien llamó conserve el texto.
Descartado por escrito: la vía del SDK (§2, §6), leer almacenes nativos de los agentes, inyectar prompt de sistema en la config de un agente, herramientas dinámicas, alias de nombres de método; y los huérfanos por crash del daemon en macOS/Linux, que son otra clase y otro remedio.
Prerrequisitos de daemon del Agent Boss (antes de companero-movil, sirven a TUI/GUI hoy)
Sección titulada «Prerrequisitos de daemon del Agent Boss (antes de companero-movil, sirven a TUI/GUI hoy)»| Change | Alcance |
|---|---|
✅ espera-humana (2026-07-26) |
Política de espera configurable ([permissions]: wait/implement-wait/no-client-grace): los flujos interactivos esperan al humano mientras haya cliente conectado; el fallo del push ya no resuelve la petición (la cola es la única fuente); sin clientes, denegación constitucional auditada tras la gracia |
✅ sesion-esperando (2026-07-26) |
El daemon fija waiting_permission mientras una petición espera decisión (contado, para peticiones simultáneas) y change/list declara gatePending con el artefacto que espera, leído del estado del ciclo |
✅ eventos-para-tardios (2026-07-26) |
Hub de eventos en el daemon y session/watch: la conexión que inició la sesión sigue recibiendo su stream, y cualquier otra lo pide por sesión. Diferido con razón escrita: las formas asíncronas de sdd/gate, sdd/review-decide y worktree/dispatch tocan la promesa ratificada de «pasos scriptables» y el stream las mitiga; entran como change propia si la evidencia de uso lo pide |
Fase 3 — se planifica al cerrar Fase 2
Sección titulada «Fase 3 — se planifica al cerrar Fase 2»companero-movil (propuesta abierta el 2026-09-24, 32º del orden del comparativo con Orca, sin arrancar hasta sus prerrequisitos; gobernada por las specs mobile-companion y remote-access: el puesto remoto del Agent Boss, cuatro verbos, sin autoría, túnel SSH exclusivamente, aviso de espera opt-in; su design debe resolver la frontera Windows del túnel — named pipe no reenviable por OpenSSH — sin abrir jamás un puerto de red del daemon) · funciones de equipo y organización (meltemi.md §3).
Namespaces del proyecto
Sección titulada «Namespaces del proyecto»- Organización (identidad paraguas):
askenaz-dev— GitHub, npm. Paquetes npm futuros (SDK, fase 2):@askenaz-dev/<pkg>. - Producto:
meltemi— dominiomeltemi.dev, binariosmeltemid/meltemi, cratesmeltemi/meltemid/meltemi-proto(crates.io es namespace plano, sin org). - Repositorio:
github.com/askenaz-dev/meltemi.
Pendientes exclusivos del arquitecto (ningún agente debe hacerlos)
Sección titulada «Pendientes exclusivos del arquitecto (ningún agente debe hacerlos)»- ✅ Ratificar meltemi.md,
constitution.mdyrumbo/— hecho 2026-07-11. 1b. ⬜ Ratificar las enmiendas encadenadas de meltemi.md: v1.1→v1.2 (formato-artefactos-meltemi), v1.2→v1.3 (enmienda-edicion-movil) y v1.3→v1.4 (enmienda-agent-boss). Todas las versiones están aplicadas al documento; falta la firma del mantenedor fundador (method-bootstrap: la herramienta no se auto-ratifica). 1c. ⬜ Ratificar la enmienda de la promesa de producto — v1.4→v1.5 de meltemi.md y el párrafo «Qué es Meltemi» de.meltemi/rumbo/product.md(lanzador-conversacional, design D5, aplicada el 2026-07-31): toda sesión corre gobernada y la disciplina spec-first deja de presentarse como condición previa. A diferencia de las anteriores, esta ratificación es gate de archivo: sin la firma,lanzador-conversacionalno archiva. Ambos textos están aplicados y marcados como pendientes en sus propios documentos. Al ratificar quedan dos cosas por hacer, en este orden: corrermeltemi project(el bloque proyectado compila el rumbo) y refrescar la frase pública, que sigue diciendo lo viejo enREADME.md,LEEME.md,site/index.htmlysite/es/index.html— deliberadamente sin tocar, porque anunciar al mundo una promesa sin firmar sería exactamente lo que la enmienda evita. Con ese refresco va también la fila dedocs/sesion-libre.mden el índice de documentación de los dos READMEs: enlazar «trabajo sin spec» bajo la promesa vieja publicaría la contradicción en vez de resolverla. - Registrar: ✅ org GitHub
askenaz-dev· ✅ org npmaskenaz-dev· ✅ dominiomeltemi.dev(comprado el 2026-07-25; servido por Cloudflare desde el 2026-10-21) · ⬜ cratesmeltemi,meltemid,meltemi-protoen crates.io (verificados LIBRES el 2026-07-11 — reservar con uncargo publishplaceholder o en el primer release para evitar squatting). - Decidir el mecanismo de firma del CLA cuando llegue #21.
- ⬜ Instalar ollama en la máquina de desarrollo (
winget install Ollama.Ollama+ollama pull qwen2.5-coder:7b) para la pierna local deguia-modelos-localesycorrida-integrada; sin eso la receta se publica como «verificada en forma». - ⬜ Decidir las versiones pineadas de Codex y OpenCode: la prueba del 2026-09-24 las dejó en 0.156.1 y 1.18.32. Para Codex la decisión ya tiene consecuencia en código:
codex-al-diare-ancló el esquema a 0.156.1, que es el piso del adaptador, y la corrida real del 2026-09-25 le dio nivel 2 con esa versión; volver a 0.77.0 ya no abre sesión. Para OpenCode sigue abierta (npm i -g opencode-ai@1.14.33para volver). - ⬜ Ratificar las dos enmiendas que traen
abrir-con-lo-tuyo(rumbo: la terminal integrada como no-objetivo) ydocs-en-el-sitio(§11: inglés como lengua fuente de la documentación de producto, método en español); ambas quedan aplicadas y marcadas pendientes hasta la firma. - ⬜
Designar el segundo custodio de claves y publicar la clave minisign en el árbolSustituido el 2026-10-23 porrelease-con-el-push: la firma manual se retira y no hay clave que publicar ni custodiar. Lo que queda del mantenedor:borrar el borrador v0.1.1(borrado el 2026-10-23),apagar GitHub Pages en este repositorio y borrar su entorno(apagado y borrado el 2026-10-26; tarea 7.3 cerrada),github-pagesadoptar el repositorio del IDE en(aplicado el 2026-10-23, congithub.tfde meltemi-webGH_ADMIN_TOKENcomo credencial del aviso por decisión del mantenedor) y designar quién sucede el control del repositorio y de la organización (sucesion-y-custodia, re-acotada). - ⬜ La release que prueba un desarrollador (
release-para-un-desarrollador, abierta el 2026-10-28; la tanda aterrizó el mismo día). En este orden: (a) correrdocs/prueba-de-uno.mden la máquina de desarrollo con los agentes propios, sobre el build de integración del commit demain(artefactomeltemi-unsigned-Windows-<sha>), porque la release aún no existe; (b) escribirdocs/qa/<fecha>-prueba-de-uno.mddesde la plantilla del guion; (c)cargo run -p meltemi-release -- changelog 0.3.0 --report docs/qa/<fecha>-prueba-de-uno.md; (d)cargo run -p meltemi-release -- set-version 0.3.0y push amain, que publica; (e) la fila «Cliente de escritorio» de meltemi-web, como change de ese repositorio. La ratificación 1c sigue siendo lo que deja alanzador-conversacionalfuera delCHANGELOG.mdmientras no llegue.