---
title: "Hoja de ruta"
sidebarTitle: "Hoja de ruta"
description: "Dirección del producto y justificación; consulta el changelog para los cambios publicados."
---

# Hoja de ruta de Eliza

Dirección de alto nivel y justificación. No es exhaustivo; consulta el **[Changelog](changelog.mdx)** publicado (o `docs/changelog.mdx` en el repositorio) para los cambios publicados con sus POR QUÉs.

<div id="principles-energy-and-experience-desktop">

## Principios: energía y experiencia (desktop)

</div>

**Objetivo:** Superar el *costo percibido* de los **shells de desarrollo siempre activos** en la batería del portátil mientras se mantiene **más distintivo visualmente** que una superficie de editor plana—**mejor UX y DX**, no una demostración de especificaciones.

- **Comparación honesta:** **Cursor** (y similares) incluye una **gran superficie persistente**: shell estilo Chromium/Electron, editor, extensiones, LSP, indexación, a menudo múltiples contextos web. La interfaz de escritorio de Eliza es **más estrecha y orientada a tareas**: compañero, chat, configuración y puentes—sobre **Electrobun / WKWebView** más **3D** opcional. **El total de J/s depende de la carga de trabajo**; una comparación justa necesita el mismo escenario y herramientas (Activity Monitor, `powermetrics`, Instruments). Nuestro estándar es **excelente experiencia por vatio** para un **compañero de IA local**, no declarar victoria en cada comparación directa con un IDE completo.
- **Lo que optimizamos:** **Trabajo desperdiciado**—GPU y temporizadores para documentos **ocultos**, canvases **fuera de pantalla** y **polling HTTP redundante**. **Calidad consciente de la batería** cuando está desenchufado (límite de DPR, splats de Spark más ajustados, sin sombras direccionales, menos ticks de API en segundo plano). **Rico por defecto** cuando el usuario está **mirando la aplicación** y conectado a corriente.
- **Controles ya implementados (ver changelog + docs de desktop):** Pausa de visibilidad de `VrmViewer`; `desktop:getPowerState` → `VrmEngine.setLowPowerRenderMode`; intervalos controlados por visibilidad (dashboard, stream, logs de juego, fine-tuning, créditos cloud); pausa de `rAF` del grafo 3D vectorial cuando está oculto; hooks de desarrollo **opt-out** para que las herramientas de DX no quemen vatios accidentalmente (proxy de captura de pantalla, consola agregada).
- **Próximas direcciones de UX/DX:** Perfil visible para el usuario de **Eficiencia** / **Rendimiento** (un solo toggle), **`prefers-reduced-motion`**, **límite de frames en reposo** opcional para el avatar cuando la fidelidad de movimiento importa menos que la batería, y **texto en la aplicación** más claro cuando los ahorros de batería están activos (para que los usuarios confíen en la compensación).

<div id="done-this-cycle">

## Completado (este ciclo)

</div>

- **Dashboard SSE: action callbacks reemplazan en su lugar** — En `generateChatResponse`, LLM `onStreamChunk` aún **añade** deltas de tokens; `HandlerCallback` texto de acciones usa **`replaceCallbackText`**: la primera callback congela `preCallbackText` (salida del modelo transmitida), cada callback subsiguiente reemplaza solo el **sufijo** después de esa línea base vía `emitSnapshot` / `onSnapshot`. **Por qué:** Coincide con la UX de **mensaje progresivo** de Discord/Telegram (editar una burbuja) sin cambiar el contrato de callback de elizaOS ni añadir un protocolo WebSocket paralelo. **Docs:** `docs/runtime/action-callback-streaming.md`, `docs/changelog.mdx` (2026-04-05). **Código:** `packages/agent/src/api/chat-routes.ts`.
- **Procedencia de carga de plugins + descubrimiento de stagehand** — `collectPluginNames()` registra la primera **razón** por la que cada plugin entró en el conjunto de carga (`plugins.allow`, auto-activación por env, features, etc.); `resolvePlugins()` incluye **`(added by: …)`** cuando los plugins opcionales fallan al instalar para que los operadores corrijan **config/env** en lugar de perseguir bugs fantasma del runtime. **Stagehand:** `findPluginBrowserStagehandDir()` recorre **padres** desde el archivo del runtime para encontrar `plugins/plugin-browser/stagehand-server` — **por qué** la profundidad fija `../` fallaba para layouts de submódulo `eliza/`. **Docs:** `docs/plugin-resolution-and-node-path.md` (sección de plugins opcionales), `docs/guides/developer-diagnostics-and-workspace.md`.
- **Migraciones PGlite de life-ops** — Las sentencias **`CREATE INDEX`** principales se ejecutan **después** de los backfills de **`ALTER TABLE`** / columnas de ownership para que las bases de datos legacy sin `domain` / `subject_*` no fallen en las actualizaciones; **`runMigrationWithSavepoint`** usa **`BEGIN`/`COMMIT`** explícitos para que **SAVEPOINT** sea válido bajo PGlite. **Por qué:** bases de datos reales encontraban errores de migración durante la evolución del esquema de life-ops. **Tests:** `packages/agent/test/lifeops-pglite-schema.test.ts`.
- **Scripts de dependencias del workspace** — `fix-workspace-deps.mjs`, `replace-workspace-versions.mjs`, `restore-workspace-refs.mjs`, `workspace-prepare.mjs` y `workspace-discovery.mjs` reducen la cirugía manual del workspace; el `package.json` raíz expone aliases `workspace:*` / `fix-deps`. **Por qué:** los checkouts locales `./eliza` y `plugins/*` desajustan frecuentemente los bordes de `workspace:*` y semver. **Docs:** `docs/guides/developer-diagnostics-and-workspace.md`.
- **Banners de terminal para desarrollo (TTY)** — Tablas de configuración enmarcadas + encabezados figlet opcionales + ANSI cuando stdout es un TTY (se respetan `NO_COLOR` / `FORCE_COLOR`). **Por qué:** el desarrollo de escritorio con cuatro procesos necesita un env efectivo **escaneable** para humanos/agentes — **no** UI de producto. **Docs:** `docs/apps/desktop-local-development.md`, `docs/guides/developer-diagnostics-and-workspace.md`.
- **Gitignore: `cache/audio/`, `scripts/bin/*`** — Mantiene las cachés de medios locales grandes y los binarios opcionales (por ejemplo, `yt-dlp`) fuera de git; **`scripts/bin/.gitkeep`** preserva el directorio para PATH. **Por qué:** los clones no deben heredar artefactos de cientos de MB.
- **Electrobun / Vite: un solo `three` para Spark + VRM** — `apps/app/vite.config.ts` **`sparkPatchPlugin`** (`resolveId` + hoist de splatDefines) y **`optimizeDeps.include`** para `three` + `three/examples/jsm/*` para que `@sparkjsdev/spark` y la pila de avatar compartan **un solo** `THREE.ShaderChunk`. **Por qué:** `three` anidado (por ejemplo, bajo Electrobun) causaba fallos de resolución de **`splatDefines`** y advertencias de "múltiples instancias de Three.js"; **`resolve.alias`** solo rompía la producción de Rollup. **Docs:** `docs/apps/desktop-vrm-three-and-spark.md`, `docs/changelog.mdx`.
- **Resiliencia VRM** — Rutas VRM / DRACO predeterminadas lazy, fallback a **`eliza-1`** en lugar de assets **`default`** faltantes, fallos de Spark/world aislados para que **VRM** aún cargue. **Por qué:** el timing de inicialización de módulos incluidos y los fondos splat opcionales no deben bloquear el avatar compañero. **Código:** `VrmViewer.tsx`, `VrmEngine.ts`, `state/vrm.ts`.
- **Persistencia de login cloud** — `cloud-routes.ts` usa **`cloudDisconnectEpoch`** (incrementar al desconectar, capturar antes del poll) en lugar de **`cloud.enabled === false`** para omitir la persistencia. **Por qué:** la guarda anterior bloqueaba el **primer** login cuando cloud nunca había sido activado. **Docs:** `docs/apps/desktop-vrm-three-and-spark.md` (sección API).
- **Plugin OpenRouter: fijar npm roto `alpha.12`** — El `package.json` raíz fija **`@elizaos/plugin-openrouter`** a una versión exacta conocida como buena (actualmente **`2.0.0-alpha.13`**). **Por qué:** **`2.0.0-alpha.12`** publicó archivos ESM `dist/node` y `dist/browser` **truncados**: solo `utils/config` está incluido, pero las exportaciones aún referencian **`openrouterPlugin`** / default — Bun falla al cargar (*símbolo no declarado*). **Por qué no parchear dist en postinstall:** el chunk de implementación del plugin está ausente, no es un error de exportación de una línea; fijar la versión es la mitigación correcta hasta que upstream republique. **Docs:** `docs/plugin-resolution-and-node-path.md` (sección *Pinned: @elizaos/plugin-openrouter*), `docs/plugin-registry/llm/openrouter.md`, `docs/changelog.mdx`, `README.md`. **Nota de código:** `scripts/patch-deps.mjs` (bloque de comentarios junto a otros workarounds de upstream).
- **Colisiones de puerto (dev + desktop embebido)** — **`dev:desktop` / `dev:desktop:watch`** pre-asignan puertos loopback libres para **`ELIZA_API_PORT`** y **`ELIZA_PORT`** (Vite) antes de lanzar API, Vite y Electrobun para que env, proxy y la URL del renderer estén alineados. **Agente embebido:** Electrobun elige el siguiente puerto libre desde el **`ELIZA_PORT`** preferido en lugar del **`lsof` + SIGKILL** predeterminado; el opcional **`ELIZA_AGENT_RECLAIM_STALE_PORT=1`** restaura la recuperación. **Runtime:** `eliza.ts` / `dev-server.ts` sincronizan **`process.env`** al puerto real de enlace de la API donde sea seguro. **UI:** **`injectApiBase`** en el estado del agente para la ventana principal + todas las ventanas de superficie. **Por qué:** dos stacks de Eliza o procesos residuales no deberían requerir búsqueda manual de puertos o matar procesos no relacionados; los enlaces dinámicos deben propagarse al renderer y las herramientas de desarrollo. **Docs:** `docs/apps/desktop-local-development.md`, `docs/apps/desktop.md` (secciones de puertos). **Código:** `scripts/lib/allocate-loopback-port.mjs`, `apps/app/electrobun/src/native/loopback-port.ts`, `agent.ts`, `index.ts`, `surface-windows.ts`, `vite.config.ts`, `dev-server.ts`, `eliza.ts`.
- **Observabilidad de desarrollo de desktop (IDEs / agentes)** — **`GET /api/dev/stack`**, **`desktop:stack-status`**, **proxy de captura de pantalla** activado por defecto (`/api/dev/cursor-screenshot`, loopback + token), **consola agregada** activada por defecto (`.eliza/desktop-dev-console.log` + `/api/dev/console-log` tail con allow-list de basename). **Por qué:** el desarrollo multi-proceso es opaco para herramientas que no pueden ver la ventana nativa; hooks HTTP explícitos + archivos evitan adivinar puertos y mantienen loopback/tokens acotados. Variables de entorno de opt-out documentadas. **Docs:** `docs/apps/desktop-local-development.md` (sección *IDE and agent observability*). **Reglas:** `.cursor/rules/eliza-desktop-dev-observability.mdc`.
- **Mapeo Electrobun Darwin → macOS (WebGPU)** — **`getMacOSMajorVersion()`** usa **`Darwin − 9`** para **20–24** (macOS 11–15) y **`Darwin + 1`** para **≥ 25** (macOS 26+ Tahoe). **Por qué:** `os.release()` es Darwin; Tahoe es **macOS 26** en **Darwin 25**—la antigua fórmula única reportaba **16** y rompía la mensajería y las compuertas de WebGPU de WKWebView. **Docs:** `docs/apps/electrobun-darwin-macos-webgpu-version.md`. **Tests:** `webgpu-browser-support.test.ts`.
- **Reset de menú de desktop (proceso principal)** — Confirmar + reset de API + reinicio + sondeo de estado se ejecutan en el **main** de Electrobun; el renderer sincroniza vía **`menu-reset-eliza-applied`** y el compartido **`completeResetLocalStateAfterServerWipe`**. **Por qué:** WKWebView retrasaba la red del renderer después de diálogos nativos; los usuarios veían "no pasa nada" después de confirmar. El sondeo de base accesible usa solo **`res.ok`**. **Docs:** `docs/apps/desktop-main-process-reset.md`. **Tests:** `menu-reset-from-main.test.ts`, `reset-main-process.test.ts`.
- **Divulgación de Edge TTS** — Documentar y exponer **`ELIZA_DISABLE_EDGE_TTS`** (registro + `docs/cli/environment.md` + doc de TTS). **Por qué:** el orquestador auto-carga Edge TTS → `node-edge-tts` → Microsoft; "sin clave API" no es "sin conexión."
- **Cobertura Vitest de app-core** — La configuración raíz hace glob de **`packages/app-core/test/**/*.test.ts(x)`** y **`src/**/*.test.tsx`**; excluye e2e de app-core bajo `test/` del job unitario predeterminado. **Por qué:** nuevos tests bajo `test/state` y `test/runtime` se omitían; una única ruta TSX fija era frágil.
- **Timeouts de CI de Node.js** — Usar `actions/setup-node@v4` con `check-latest: false` en todas partes; añadir caché global de Bun y `timeout-minutes` a test, release, nightly, benchmark-tests, publish-npm. **Por qué:** evitar descargas de nodejs.org y limitar duraciones de jobs. Ver `docs/build-and-release.md` "Node.js and Bun in CI: WHYs".
- **Fortalecimiento del workflow de release** — Shell estricto (`bash -euo pipefail`) para pasos de fallo rápido; bucles de reintento para `bun install` con una ejecución final para que el paso falle si todos los reintentos fallaron; el volcado de crash usa el CLI ASAR mantenido; `find -print0` / `while IFS= read -r -d ''` para rutas seguras; ruta de DMG vía find+stat; eliminación de artefactos node-gyp antes de empaquetar; reporte de tamaño incluye eliza-dist; paso único de build de Capacitor; E2E de DMG empaquetado usa timeout CDP de 240s en CI y vuelca stdout/stderr en timeout. **Por qué:** Builds reproducibles, fallos claros y CI depurable; ver `docs/build-and-release.md` "Release workflow: design and WHYs".
- **Resolución de plugins (NODE_PATH)** — Configurar `NODE_PATH` en tres lugares para que `import("@elizaos/plugin-*")` dinámico resuelva desde CLI (`run-node.mjs` hijo), carga directa de eliza (`eliza.ts` al cargar) y Electrobun (dev: recorrer hacia arriba para encontrar `node_modules`; empaquetado: `node_modules` ASAR). **Por qué:** Node no busca la raíz del repositorio cuando la entrada está bajo `dist/` o cwd es un subdirectorio; sin esto, "Cannot find module" rompía coding-agent y otros. Ver `docs/plugin-resolution-and-node-path.md`.
- **Resiliencia de inicio de Electrobun** — Mantener el servidor API activo cuando el runtime falla al cargar para que la UI pueda mostrar un error en lugar de "Failed to fetch". **Por qué:** Un solo módulo nativo faltante (por ejemplo, onnxruntime en Intel Mac) solía dejar toda la ventana muerta sin explicación.
- **DMG Intel Mac x64** — El workflow de release ejecuta install y build de desktop bajo `arch -x86_64` para el artefacto macos-x64 para que los binarios nativos `.node` sean x64. **Por qué:** CI se ejecuta en arm64; sin Rosetta enviábamos binarios arm64 y los usuarios Intel obtenían "Cannot find module .../darwin/x64/...".
- **Dependencias de plugins auto-derivadas** — `copy-electrobun-plugins-and-deps.mjs` recorre las dependencias del `package.json` de cada paquete @elizaos en lugar de una lista curada. **Por qué:** Las listas curadas omitían nuevas dependencias de plugins y causaban fallos silenciosos en la app empaquetada; el recorrido automático se mantiene correcto a medida que los plugins cambian.
- **Tests de regresión para el inicio** — Tests E2E verifican el comportamiento de keep-server-alive y fallo de carga de eliza.js. **Por qué:** Un test que falla previene la eliminación de las guardas de manejo de excepciones mejor que solo la documentación.
- **Corrección de resolución de plugins** — `NODE_PATH` configurado a la raíz del repositorio `node_modules` en `eliza.ts`, `run-node.mjs` y `agent.ts` (Electrobun dev). **Por qué:** `import("@elizaos/plugin-*")` dinámico desde `eliza.js` incluido no podía resolver paquetes en la raíz; `NODE_PATH` le dice a Node dónde buscar. No-op en la app empaquetada (guarda existsSync). Ver `docs/plugin-resolution-and-node-path.md`.
- **Parche de exports de Bun** — Postinstall en `patch-deps.mjs` reescribe los plugins `@elizaos` afectados (y cualquier paquete similar) para que `exports["."]` ya no tenga `"bun": "./src/index.ts"` cuando ese archivo no existe. **Por qué:** El tarball publicado solo incluye `dist/`; Bun elige la condición `"bun"` primero y falla. Eliminar la condición muerta deja que Bun use `"import"` → `./dist/index.js`. Ver "Bun and published package exports" en `docs/plugin-resolution-and-node-path.md`.
- **SIGPIPE 141 en reporte de tamaño de release** — Los pipelines `du | sort | head` en el paso "Report packaged app size" se ejecutan en un subshell con `|| r=$?` y permiten exit 141; stderr de `sort` silenciado. **Por qué:** Bajo `-euo pipefail`, 141 terminaría el paso antes de que pudiéramos permitirlo; el subshell lo captura. Ver `docs/build-and-release.md`.
- **Rutas NFA: plugin opcional** — `/api/nfa/status` y `/api/nfa/learnings` cargan lazy `@elizaos/plugin-bnb-identity` y tienen fallback cuando falta. **Por qué:** Core y tests funcionan sin el plugin; la declaración de tipo ambiental mantiene el typecheck satisfecho.

<div id="short-term--follow-ups">

## Corto plazo / seguimientos

</div>

- **Action callbacks:** Si un plugin realmente necesita **múltiples segmentos independientes** del asistente desde un solo turno de acción (no reemplazo progresivo), podríamos añadir un flag de callback opcional o una API separada — ninguno requerido hoy. **Por qué diferir:** El valor predeterminado coincide con Discord/Telegram; YAGNI hasta que un plugin concreto lo solicite.
- **OpenRouter: desfijar cuando upstream corrija** — Cuando `@elizaos/plugin-openrouter` publique una release después de **`alpha.12`** con bundles completos verificados `dist/node/index.node.js` (y browser), relajar el pin exacto. Actualmente fijado a **`alpha.13`**. **Por qué:** Permanecer en un pin fijo para siempre pierde correcciones reales; solo evitamos tarballs rotos hasta que npm tenga un artefacto bueno.
- **Higiene de plugins upstream** — Algunos plugins (por ejemplo, `@elizaos/plugin-discord`) listan `typescript` en `dependencies` en lugar de `devDependencies`; lo omitimos vía `DEP_SKIP` para evitar hinchazón del bundle. **Por qué:** Corregir upstream reduciría nuestra lista de omisiones y mantendría el package.json del plugin correcto.
- **Opcional: filtrar deps incluidas** — Intencionalmente copiamos todas las deps transitivas (incluyendo las que tsdown puede haber inlineado) porque los plugins pueden hacer dynamic-require en runtime. **Por qué:** Excluir deps "probablemente incluidas" arriesgaría "Cannot find module" en la app empaquetada. Si alguna vez obtenemos análisis estático de dist/ del plugin para saber qué nunca se requiere en runtime, podríamos reducir la copia; no es prioridad.

<div id="longer-term">

## Largo plazo

</div>

- **Desktop:** El binario universal/fat de macOS (un solo .app con arm64+x64) es posible vía `lipo` o targets de empaquetado de desktop pero añade tiempo de build y complejidad; DMGs separados son aceptables por ahora.
- **CI:** Considerar cachear los rebuilds nativos de desktop por arquitectura para acelerar la matriz de release.
