Files: 20. Audited: 20 / 20. Refactored: 0 / 20.
The boot/load layer that sits between Layer 1 (entry points) and Layer 4
(API server). Owns: agent loader (eliza.ts), dev server entry
(dev-server.ts), embedding warmup, local-inference handler
registration, runtime boot/retry policy, startup overlays, and a couple
of misplaced things.
- Layer 1's
entry.tsanddev-ui.mjsorchestrator delegate here (startEliza,bootElizaRuntime). Anything Layer 1 sets in env arrives here and is consumed by the wrappers ineliza.ts/dev-server.ts. - Layer 4 (
api/server.ts) imports from this layer (buildCharacterFromConfig,getStartupEmbeddingAugmentation,ensureTextToSpeechHandler). Every weak boundary here leaks upward. - The MASTER.md §0 chat bug (provider-issue misnamed) reaches into
this layer through
repairRuntimeAfterBoot→ensureLocalInferenceHandler(which talks to local-inferencerouting-policy). If routing returns "no handler" the chat fallback inagent/api/chat-routes.tsfires the rename target string. - This layer is mostly an upstream-wrapper layer — every "core"
concept (
startEliza,bootElizaRuntime,applyCloudConfigToEnv,applyN8nConfigToEnv,collectPluginNames,CHANNEL_PLUGIN_MAP,EMBEDDING_PRESETS,buildCharacterFromConfig,shutdownRuntime) is re-exported from@elizaos/agent/runtime/...with a thin app-core overlay. The audit needs to call out which overlays earn their keep and which are pure pass-through.
- Spec drift in the task brief. The brief says
eliza.ts"persists SECRET_SALT (recently — at line ~3198)." Verified: this file is 1508 LOC with no SECRET_SALT logic. The SECRET_SALT write lives upstream ateliza/packages/agent/src/runtime/eliza.ts:2921-2925. MASTER.md task 16 (derive SECRET_SALT from master key) lands in the upstream agent file, not this wrapper. - Dead wrapper modules. Several files exist as polished wrappers with no live caller (verified by grep).
- Duplication between
eliza.tsand the standalone wrapper files.eliza.tsre-definesCHANNEL_PLUGIN_MAPbyte-for-byte even thoughchannel-plugin-map.tsexists as the canonical wrapper. - Defensive
syncBrandEnvAliases()calls sprinkled before/after every upstream call (14 sites ineliza.ts). - Boundary smells:
telegram-standalone-{handler,policy}.tslive inruntime/but Telegram is a connector. Their presence here is cycle/scope debt. - Commandment 9 violations:
dev-server.tshas 17console.*calls; the file even comments that this is intentional ("bypass logger filtering" line 437).
| Status | Meaning |
|---|---|
[ ] pending |
Not yet read |
[~] reading |
Being audited |
[!] findings |
Audited, findings recorded, no edit yet |
[*] refactor |
Audited and edited (commit hash appended) |
[x] clean |
Audited, no changes warranted |
[-] delete |
Audited and slated for deletion |
[?] blocked |
Audited but blocked on a lower-layer dep |
- [!]
eliza/packages/app-core/src/runtime/eliza.ts— 1508 LOC. The agent loader and the source-of-truth for app-core's overlay over@elizaos/agent/runtime/eliza. dedup:CHANNEL_PLUGIN_MAPis redefined byte-for-byte at lines 80-127 with the sameINTERNAL_CHANNEL_PLUGIN_OVERRIDESshape thatchannel-plugin-map.tsalready exports —eliza.tsshouldimport { CHANNEL_PLUGIN_MAP } from "./channel-plugin-map.js"and stop re-merging. dedup:14×syncBrandEnvAliases()calls (lines 197-248, 1009, 1027, 1302, 1461) wrap every upstream call ("just in case env drifted") — a single boundary owner (likely upstream'sbootElizaRuntime) should sync once. types:7×as nevercasts onruntime.services.set/get/delete(lines 193, 678, 705, 767, 814, 815, 821) — commandment-7 violation; the upstream services-map type is too narrow and the wrapper is escaping rather than fixing the upstream signature. errors:everyensure*helper (ensureN8nAuthBridge,ensureN8nAutoStart,ensureN8nDispatchService,ensureTriggerEventBridge,ensureN8nRuntimeContextProvider,ensureConnectorTargetCatalog,ensureTelegramBotPolling) wraps intry { ... } catch (err) { logger.warn(...) }and continues — six "best effort" boundaries that mask first-boot failures. legacy:theRuntimeAutonomyCompat/RuntimeAdapterAutonomyCompatinterfaces (lines 132-179) are duck-typed shims for an in-flight upstream refactor — TODO-or-rename. boundaries:telegrampolling / handler wiring (lines 535, 853-901) lives in a runtime module; Telegram is a platform connector and belongs inconnectors/telegram/(seetelegram-standalone-handler.tsaudit). slop:line 86/** Swarm / PTY paths call TEXT_TO_SPEECH; Edge TTS supplies that model with no API key. */and similar narrative comments describe past work, not current invariants. Highest-value extractions (smaller than electrobun's 11+; this file is large but coherent): (a) n8n bridges cluster (~217 LOC:_n8nAuthBridge,_n8nAutoStart,_n8nDispatch,_triggerEventBridge,_n8nRuntimeContextProvider,_connectorTargetCatalog,_discordEnumerationCache+ theirensure*setters, lines 575-836) →runtime/n8n-bridges.ts; (b) PGlite recovery cluster (~250 LOC:collectErrorObjects,getPgliteErrorCode,collectErrorMessages,isManualResetPgliteError,getPgliteDataDirFromError,resolveManagedPgliteDataDir,isAutoResettablePgliteDir,resetPluginSqlPgliteSingleton,quarantinePgliteDataDir,normalizePgliteStartupError,upstreamStartElizaWithPgliteCompat,attemptPgliteAutoReset,getPgliteRecoveryRetrySkipPlugins, lines 1036-1297) →runtime/pglite-recovery.ts; (c) autonomy bootstrap (~88 LOC:AUTONOMY_*consts,getAutonomyService,startAndRegisterAutonomyService,RuntimeAutonomyCompat,ensureAutonomyBootstrapContext) →runtime/autonomy-bootstrap.ts. After splits,eliza.tstarget ≤900 LOC: env-sync overlays +bootElizaRuntime/startEliza/repairRuntimeAfterBootonly. - [!]
eliza/packages/app-core/src/runtime/dev-server.ts— 516 LOC. Dev-mode entry point. errors:17×console.*calls (lines 12, 44, 56, 423, 437-466, 477, 485, 491, 498, 507, 513) — commandment-9 violation; the file's own comment at line 437 admits "Use console.log for startup timing to bypass logger filtering" — intentional but still a violation; resolve by configuring the logger to honor aSTARTUP_TIMING=1flag, not by bypassing it. dedup:dotenv-load at lines 49-54 duplicatescli/run-main.ts'sloadDotEnv— same.envfiles via two bootstraps (Layer 1 audit already flagged this; reaffirm). dedup:shouldIgnoreUnhandledRejectionis shared withrun-main.ts(good — already extracted toerror-handlers.ts). types:apiUpdateStartup(lines 67-83) is typed inline — should reuse the published API server type, not redefine the union. errors:thetry { dotenv.config() } catch { /* non-fatal */ }at lines 49-54 is the canonical "swallow and continue" pattern flagged across Layer 0/1; here it's defensible because dotenv is genuinely optional. boundaries:dev-server does the right thing — it draws its env contract from@elizaos/shared(resolveDesktopApiPort,resolveApiToken,syncResolvedApiPort,colorizeDevSettingsStartupBanner) and not from rawprocess.envlookups. slop:the boxed startup banner (lines 446-463) belongs incli/banner.ts, not inline. - [!]
eliza/packages/app-core/src/runtime/build-character-from-config.ts— 96 LOC. dedup:syncBrandEnvAliasesdefined locally at line 12 — IDENTICAL three-line function aseliza.ts:197-200. Promote toutils/env.jsor a sharedruntime/env-sync.ts. types:Parameters<typeof upstreamBuildCharacterFromConfig>[0]indirection at line 18 — fine, but(config.ui ?? {}) as { presetId?: string; avatarIndex?: number; language?: unknown; }(lines 21-25) is a weak cast where the upstreamCharacter["ui"]should be the typed source. legacy:uiConfig.language as unknownthen immediatelynormalizeCharacterLanguage(uiConfig.language)— the normalization helper accepts unknown, so the cast is for show. boundaries:this is a real overlay (style-preset resolution + message-example normalization), not a pass-through wrapper. Keep, but tightenuiConfigtyping. - [!]
eliza/packages/app-core/src/runtime/channel-plugin-map.ts— 12 LOC. Duplicated byeliza.ts:80-127. dedup:both files declare the exact sameINTERNAL_CHANNEL_PLUGIN_OVERRIDES = { signal, whatsapp, wechat }const and merge it intoupstreamChannelPluginMap.index.ts:63re-exportsCHANNEL_PLUGIN_MAPfrom this file;eliza.ts:124-127re-exports its own copy. Action: delete the redefinition ineliza.ts, import from this file instead. - [-]
eliza/packages/app-core/src/runtime/embedding-manager.ts— 413 LOC. Dead code. DefinesElizaEmbeddingManagerclass. Verified zero callers across/Users/home/milady/eliza,/Users/home/milady/apps,/Users/home/milady/scripts(only self-references and a doc comment). The actual warmup path (eliza.ts:warmupEmbeddingModel) importsensureModel,findExistingEmbeddingModelForWarmupReuse, etc. directly fromembedding-manager-support.ts. The class wrapper, plus its idle-timer / dispose / dimension-migration plumbing, is unused. Action: delete the file. Re-export shim at lines 397-413 (re-exports from-support.ts) is also dead — confirmed no consumer imports them through the wrapper. - [!]
eliza/packages/app-core/src/runtime/embedding-manager-support.ts— 474 LOC. Live. Used byeliza.ts:warmupEmbeddingModel. HoldsensureModel,downloadFile,sanitizeModelRepo/Filename,EMBEDDING_PRESETS-aware reuse logic,EmbeddingMeta. errors:getLogger()at line 75-89 falls back toconsoleafter atry { require("@elizaos/core") } catch {}— commandment-9 violation in the fallback, justified ONLY because the helpers are designed to be importable from a node context where the runtime hasn't booted; prefer accepting an injected logger rather than reaching for global console. legacy:the// best-effort cleanupsafeUnlink(line 140-146) and// non-fatal: …will retryreadEmbeddingMeta(line 97-106) swallow errors but each is at a clear boundary (filesystem cleanup) — keep but document with the boundary in mind. types:writeEmbeddingMetareturns void on failure with only a logger.warn — fine for a metadata write that retry-on-next-boot can recover. boundaries:owns its own download host allowlist (lines 180-208) — stricter than other downloaders in the repo; the allowlist (huggingface.co,hf.co) should be a shared constant from@elizaos/shared, not a local function. -
eliza/packages/app-core/src/runtime/embedding-presets.ts— 27 LOC. Live. Re-exportsEMBEDDING_PRESETSfrom@elizaos/agentand overrides theperformancepreset'slabel/descriptionto clarify the embedding model is for memory vectors, not chat. Status: clean. The override is the entire reason this wrapper exists; it earns its keep. -
eliza/packages/app-core/src/runtime/embedding-warmup-policy.ts— 41 LOC. Live.shouldWarmupLocalEmbeddingModel()consumed byeliza.ts:warmupEmbeddingModel. Pure env policy; clean. - [-]
eliza/packages/app-core/src/runtime/local-model-resolver.ts— 247 LOC. Dead code.MILADY_MODELenv-var resolver for picking the right Eliza-1 quant + backend per host. Verified zero callers across/Users/home/milady/eliza,/Users/home/milady/apps,/Users/home/milady/scripts. Only references are: documentation ineliza/packages/training/{cloud/README,AGENTS,CLAUDE}.md(docs ASSUME this file is wired in but it isn't), a Python comment inmodel_registry.py:208referring to it, and thelocal-ai.jsonplugin registry entry that namesMILADY_MODELas an env var. The runtime never actually readsMILADY_MODELto pick a quant —local-ai.jsondeclares it as user-configurable but no TS code consumes the resolver. Action: either wire the resolver intoservices/local-inference/active-model.ts(matching the docs) or delete it. Pending product decision; until then mark[-] deletecandidate. - [-]
eliza/packages/app-core/src/runtime/boot-progress.ts— 123 LOC. Dead code.BootProgressReporterextendsEventEmitter; definesBOOT_PHASES(config / plugins / database / embeddings / runtime / skills / ready) and emits weightedprogressevents. Verified zero callers across the entire monorepo (grep -rn "boot-progress\|BootProgressReporter\|BOOT_PHASES"). The actual live startup-progress surface isstartup-overlay.ts(consumed byapi/server.ts:469);boot-progress.tsis the unused alternative. The doc comment at line 4 says "Used by the TUI loading screen" — TUI loading screen is not currently wired. Action: delete the file; if the TUI ever lands, build it on thestartup-overlay.tssurface that's already live. -
eliza/packages/app-core/src/runtime/startup-overlay.ts— 78 LOC. Live.updateStartupEmbeddingProgressis called fromeliza.ts:978(warmup progress callback);getStartupEmbeddingAugmentationis read fromapi/server.ts:469. Module-levelsnapshotsingleton with 120s staleness check. Status: clean. Minor: pure functions on top of a single mutable; could be a class but the singleton-per-process model fits the consumer pattern. -
eliza/packages/app-core/src/runtime/runtime-bootstrap-policy.ts— 59 LOC. Live.resolveRuntimeBootstrapFailureconsumed bydev-server.ts:238to decide retry vs. error-state on each boot attempt. Owns: fatal PGlite codes set, exponential backoff (nextRuntimeBootRetryDelayMs), error-attempt threshold (3), error-duration threshold (2 min). Pure policy file; clean. Decision logic is enforced bydev-server.ts'sbootstrapRuntimeloop — single owner. -
eliza/packages/app-core/src/runtime/api-dev-settings-banner.ts— 132 LOC. Live.formatApiDevSettingsBannerTextconsumed bydev-server.ts:467to render the post-listen settings table. Pure formatter; uses@elizaos/sharedhelpers (resolveApiSecurityConfig,formatDevSettingsTable,prependDevSubsystemFigletHeading). Clean. Minor: rows array hardcodes 9 settings; if the API server gains a 10th env knob, bothresolveApiSecurityConfigand this banner need to learn about it. Acceptable: the settings table is end-user-facing curated content, not auto-generated.
- [!]
eliza/packages/app-core/src/runtime/ensure-local-inference-handler.ts— 471 LOC. The runtime-side handler-registration entry point for local inference. types:RuntimeWithModelRegistrationcast at line 58-68 is a structural type pretending to be the upstreamAgentRuntime— should land in@elizaos/coretyped properly so wrappers stop re-typing it. errors:tryRegisterAospLlamaLoaderandtryRegisterCapacitorLoaderusetry/catchthat demote import failures tologger.error/logger.debugand returnfalse— for AOSP this is correct (the module is build-conditional and the user opted in via env), for Capacitor this is correct (the module is platform-conditional). The comments document the trade-offs explicitly; error handling is justified here. errors:the loader-precedence comment at lines 335-349 is excellent documentation of an inherently-stateful subsystem. boundaries:this file owns the priority-0 registration ofTEXT_SMALL/TEXT_LARGE/TEXT_EMBEDDINGagainst the runtime model registry. It is the bridge from the routing-policy subsystem (services/local-inference/router-handler,routing-policy) into the agent runtime — directly load-bearing for the MASTER.md §0 chat fallback. When this returns without registering a handler, the runtime'sgetModel(TEXT_SMALL)returns undefined → upstream fires the chat fallback string. legacy:theLOCAL_INFERENCE_PRIORITY = 0comment at lines 74-87 is durable history (the historical bug + fix), keep. slop:none. -
eliza/packages/app-core/src/runtime/mobile-local-inference-gate.ts— 27 LOC. Live. Consumed byeliza.ts:485to decide whether to register the local-inference handler on mobile platforms. Pure env policy; clean. -
eliza/packages/app-core/src/runtime/capacitor-llama.d.ts— 13 LOC. Skipped per task brief (.d.ts). Note: provides minimal ambient module decl for@elizaos/capacitor-llamasoensure-local-inference-handler.ts:299's dynamic import compiles cleanly when the package isn't installed. Legitimate boundary marker, likeapps/app/src/native-plugin-stubs.tsfrom Layer 1. - [!]
eliza/packages/app-core/src/runtime/ensure-text-to-speech-handler.ts— 109 LOC. Live. Consumed byeliza.ts:494andapi/server.ts:152(lazy import). dedup:parallel structure toensure-local-inference-handler.ts— sameRuntimeWithModelRegistrationcast, samegetModel/registerModelshape, same env-disabled guard, same dynamic import-or-throw. The two files share enough structure that aruntime/handler-registration-base.tshelper (ensureModelHandler({ modelType, provider, importer, isDisabled })) would let both shrink to ~30 LOC each. Recommended but only after the local-inference variant stabilizes — its loader-precedence is tightly coupled. errors:line 102-107 thetry { import("@elizaos/plugin-edge-tts/node") } catch (error) { throw new Error(...) }is a wrap-and-rethrow with context, good error handling. types:EdgeTtsPluginModuleshape (line 44-47) accepts bothdefault.modelsandedgeTTSPlugin.models— legacy dual-export support? If only one export form is current, drop the other.
- [!]
eliza/packages/app-core/src/runtime/telegram-standalone-handler.ts— 308 LOC. Misplaced. Telegram is a platform connector, not core runtime. The file owns: chat-allowlist parsing, channel-type mapping, message chunking, full Telegraf message-receive →runtime.ensureConnection→messageService.handleMessage→ reply-callback flow. boundaries:lives inruntime/but every other connector lives underconnectors/or its own plugin package. Action: move toconnectors/telegram/standalone-handler.ts(matching the file's name). errors:outertry/catchat line 110-307 logs and replies "Sorry, I encountered an error processing your message" — that user-facing string is exactly the chat-fallback class flagged in MASTER.md Phase 4; reword once Phase 4 lands. types:TelegramStandaloneUser/Chat/Messagepartial structural types (lines 12-35) duplicate Telegraf's actual types —import type { Update } from "telegraf"would be stronger. types:RuntimeMessageServiceCompat(lines 44-53) is another duck-typed shim hinting thatAgentRuntime.messageServiceshould be in the upstream type. - [!]
eliza/packages/app-core/src/runtime/telegram-standalone-policy.ts— 19 LOC. Live. Consumed byeliza.ts:535(shouldStartTelegramStandaloneBot). boundaries:same as above — should move alongside its handler underconnectors/telegram/. dedup:theisExplicitTruehelper (lines 3-9) is a private duplicate of the same env-truthy parsing inembedding-warmup-policy.ts:13-19andmobile-local-inference-gate.ts:23-25. Three files, three identical helpers. Promote toutils/env-truthy.ts.
-
eliza/packages/app-core/src/runtime/app-route-plugin-registry.ts— 45 LOC. Live.registerAppRoutePluginLoaderconsumed by 5+ plugins (app-polymarket,plugin-computeruse,plugin-elizacloud,app-shopify,app-hyperliquid);listAppRoutePluginLoadersconsumed byeliza.ts:407. Module-singleton viaSymbol.for("elizaos.app.route-plugin-registry")— same global-registry pattern as Layer 1'sapp-shell-components.ts. boundaries:cross-bundle global; matches the established pattern in this repo. Status: clean. -
eliza/packages/app-core/src/runtime/error-handlers.ts— 66 LOC. Live. Consumed bydev-server.ts:483andcli/run-main.ts. Pure utility; clean. Honors commandment 9 (no console; only string operations). TheshouldIgnoreUnhandledRejectionrecursion + 402-status / "insufficient credits" /responseBody/errors[]/causetraversal is the right shape to detect provider-credit exhaustion deep in the SDK error chain.
The audit task brief said eliza.ts "persists SECRET_SALT (recently — at line ~3198 per MASTER.md context)." This is false:
| Claim | Truth |
|---|---|
eliza.ts is ~3200 LOC |
1508 LOC |
| Line ~3198 contains SECRET_SALT logic | No SECRET_SALT logic in this file at all |
| MASTER.md task 16 lands here | Lands upstream at eliza/packages/agent/src/runtime/eliza.ts:2921-2925 |
MASTER.md task 16 ("Derive SECRET_SALT from master key") will need to land in the upstream @elizaos/agent package, not in this app-core wrapper. The Layer 6 audit (agent runtime) should pick that up.
This file is large but coherent — it is not the 19-concern god module that electrobun/src/index.ts is. Three high-value seams should be extracted; the rest is the thin overlay on top of @elizaos/agent's exports and earns its keep.
| # | Concern | LOC range | Owns | Target module |
|---|---|---|---|---|
| 1 | n8n bridges cluster | 575-836 (~262 LOC) | _n8nAuthBridge, _n8nAutoStart, _n8nDispatch, _triggerEventBridge, _n8nRuntimeContextProvider, _connectorTargetCatalog, _discordEnumerationCache + each ensure* setter |
runtime/n8n-bridges.ts |
| 2 | PGlite recovery cluster | 1036-1297 (~262 LOC) | error-chain walk, manual-reset detection, data-dir resolution, singleton close+reset, dir quarantine, error normalization, attemptPgliteAutoReset, getPgliteRecoveryRetrySkipPlugins |
runtime/pglite-recovery.ts |
| 3 | Autonomy bootstrap | 77-79, 111-122, 132-179, 181-195, 251-338 (~120 LOC) | AUTONOMY_* consts, RuntimeAutonomyCompat, RuntimeAdapterAutonomyCompat, getAutonomyService, startAndRegisterAutonomyService, ensureAutonomyBootstrapContext |
runtime/autonomy-bootstrap.ts |
| — | Telegram bot polling | 535, 838-901 | _telegramBot, stopTelegramBotPolling, ensureTelegramBotPolling |
move to connectors/telegram/ along with the existing handler/policy |
Everything else is rightful overlay: bootElizaRuntime / startEliza (env-sync + warmup + plugin-collector overlay + boot-error normalization + retry orchestration), repairRuntimeAfterBoot (one-shot post-boot wiring), applyCloudConfigToEnv / applyN8nConfigToEnv overlays, collectPluginNames overlay (auto-add Edge TTS when orchestrator is enabled), and the shim casts.
The brief asks how the six local-inference files relate. Drawn:
eliza.ts:warmupEmbeddingModel
│
├─→ embedding-warmup-policy.shouldWarmupLocalEmbeddingModel (env policy)
├─→ embedding-presets.detectEmbeddingPreset (hardware → preset)
└─→ embedding-manager-support.ensureModel (download + sanitize)
↑
│ (also reused via:)
│
embedding-manager-support.findExistingEmbeddingModelForWarmupReuse
embedding-manager-support.embeddingGgufFilePresent
eliza.ts:repairRuntimeAfterBoot
│
├─→ mobile-local-inference-gate.shouldEnableMobileLocalInference (env policy)
└─→ ensure-local-inference-handler.ensureLocalInferenceHandler
│
├─→ services/local-inference/handler-registry
├─→ services/local-inference/{engine,device-bridge,registry,assignments}
├─→ services/local-inference/router-handler (top-priority dispatcher)
├─→ try import "@elizaos/agent/runtime/aosp-llama-adapter" (AOSP, dyn)
└─→ try import "@elizaos/capacitor-llama" (mobile, dyn — typed by capacitor-llama.d.ts)
── DEAD ──
embedding-manager.ts (ElizaEmbeddingManager class, 413 LOC) — zero callers
local-model-resolver.ts (MILADY_MODEL Eliza-1 resolver, 247 LOC) — zero callers
boot-progress.ts (BootProgressReporter, 123 LOC) — zero callers
Live files: 6. embedding-presets.ts, embedding-warmup-policy.ts, embedding-manager-support.ts, mobile-local-inference-gate.ts, ensure-local-inference-handler.ts, capacitor-llama.d.ts.
Dead files: 3. embedding-manager.ts, local-model-resolver.ts, boot-progress.ts. Combined LOC: 783 LOC removable (verified: zero importers in eliza/, apps/, scripts/).
| File | Should live in | Reason |
|---|---|---|
runtime/telegram-standalone-handler.ts (308 LOC) |
connectors/telegram/standalone-handler.ts |
Telegram is a connector; only the runtime startup gate (ensureTelegramBotPolling) belongs here, and that should call into the connector module. |
runtime/telegram-standalone-policy.ts (19 LOC) |
connectors/telegram/standalone-policy.ts |
Sibling to the above. |
runtime/local-model-resolver.ts (247 LOC) |
(delete OR services/local-inference/eliza-one-resolver.ts) |
Currently dead; if wired in, it belongs next to the local-inference loader, not in runtime/. |
runtime/boot-progress.ts (123 LOC) |
(delete) | Unused alternative to startup-overlay.ts which IS wired in. |
The brief asks if these are different surfaces. Verdict: no — they're competing surfaces for the same concept and boot-progress.ts lost.
startup-overlay.ts(78 LOC) — module-levelsnapshot: Snapshot | null, mutated byupdateStartupEmbeddingProgress(phase, detail?)from inside the warmup callback. Read byapi/server.ts:469viagetStartupEmbeddingAugmentation()to merge intoGET /api/status. Live: this is what the renderer polls.boot-progress.ts(123 LOC) —BootProgressReporter extends EventEmitter, weighted phase model withphase("config" | "plugins" | "database" | "embeddings" | "runtime" | "skills" | "ready")andsubProgress(phase, fraction, detail). Doc comment claims "Used by the TUI loading screen." Dead: no caller.
The BootProgressReporter is the more sophisticated design; startup-overlay.ts is the one that's wired. Either replace the wired one with the better design (a real refactor), or delete boot-progress.ts. Choose deletion until a concrete TUI/UI consumer wants the EventEmitter shape.
error-handlers.ts itself honors commandment 9: zero console.*, only string operations and recursion through error chains. It exists precisely so the global handlers in dev-server.ts and cli/run-main.ts share the same provider-credits-exhaustion classifier.
The commandment-9 violations are in dev-server.ts itself (17 console.* calls, line 437 admits this is intentional):
dev-server.ts:12, 44, 56, 423, 437-466, 477, 485, 491, 498, 507, 513
Plus eliza.ts:1379-1380 ("Control UI: http://localhost:..." / "Server running. Press Ctrl+C to stop.") and eliza.ts:1474 (the printDirectRuntimeHelp block) and eliza.ts:1490 (printDirectRuntimeVersion) — these are user-facing CLI output, the standard exception to commandment 9.
The dev-server boxed banner (lines 446-463) and "Imports complete (Xms)" timing logs are the real violations. Resolve by either (a) configuring the logger to emit unfiltered when STARTUP_TIMING=1, or (b) extracting the banner to cli/banner.ts (which already exists and uses console.log-but-as-CLI-output, so it's the right home).
The brief asks. Owns three policy decisions:
- Fatal vs. retryable PGlite errors —
FATAL_PGLITE_CODESset (ELIZA_PGLITE_DATA_DIR_IN_USE,ELIZA_PGLITE_CORRUPT_DATA,ELIZA_PGLITE_MANUAL_RESET_REQUIRED). Fatal codes returnshouldRetry: falseand surface asstate: "error". - Exponential backoff —
nextRuntimeBootRetryDelayMs(attempt)=1000 * 2 ** clamp(attempt-1, 0, 5), capped at 30s. - When to surface the error to the UI —
RUNTIME_BOOT_ERROR_ATTEMPT_THRESHOLD = 3attempts ORRUNTIME_BOOT_ERROR_DURATION_MS = 2 minutesof failures, whichever comes first, flips state fromstarting→error(UI shows error UI).
Enforced exclusively by dev-server.ts's bootstrapRuntime loop (lines 195-261). Single owner. Pure policy file with no IO. Status: clean.
- Delete the three dead files (
embedding-manager.ts413 LOC,local-model-resolver.ts247 LOC,boot-progress.ts123 LOC = 783 LOC removed). Each verified zero importers across the monorepo. Highest impact-per-effort in the entire layer. - Extract the n8n bridges cluster from
eliza.ts(~262 LOC →runtime/n8n-bridges.ts). Sixensure*functions with six module-level_n8n*singletons that all share the same lifecycle (start-or-reset on boot, stop on shutdown). One module gives them one owner. - Extract the PGlite recovery cluster from
eliza.ts(~262 LOC →runtime/pglite-recovery.ts). Includes thequarantinePgliteDataDirflow, theplugin-sqlsingleton reset, and the error-message parser. Self-contained; testable in isolation. - Move
telegram-standalone-{handler,policy}.tsunderconnectors/telegram/(~327 LOC moved + slim wrapper inruntime/). Boundary fix; reduceseliza.ts'simportset. - Delete the
CHANNEL_PLUGIN_MAPredefinition ineliza.ts:80-127and import from the existingchannel-plugin-map.ts. Trivial dedup — the wrapper file exists for exactly this purpose.
After 1+5 (purely deletions/dedup, no behavior change): layer drops from ~5,300 LOC to ~4,500 LOC and the eliza.ts import-set shrinks. After 2+3 (extractions, behavior-preserving): eliza.ts drops to ~900 LOC and each extracted module is independently testable.
| File / lines | Commandment | Violation |
|---|---|---|
eliza.ts 193, 678, 705, 767, 814-821 |
7 (DTO fields required by default; no as to skip type errors) |
7× as never casts on runtime.services.set/get/delete to escape an upstream services-map signature that's too narrow. Fix upstream type, not the wrapper. |
eliza.ts 6× ensure* helpers |
8 (logger only, never console) — actually fine for log channel. Real violation: each has try { ... } catch (err) { logger.warn(...) } and continues. The boot-time bridges that fail silently mean a feature is "armed" but doesn't work. |
Should fail boot or surface to apiUpdateStartup as a degraded state, not log-and-continue. |
dev-server.ts 17× console.* |
9 (logger only, never console) | Self-admitted intentional bypass at line 437. Either configure logger to honor a startup-timing flag, or move the boxed banner to cli/banner.ts. |
runtime/telegram-standalone-handler.ts, runtime/telegram-standalone-policy.ts |
1 (dependencies point inward only — runtime is the inner layer; connectors are outer) | Telegram-specific code lives in the runtime layer instead of in connectors. The runtime/eliza.ts:ensureTelegramBotPolling should call into a connector module, not own the Telegraf import. |
embedding-manager-support.ts:75-89 getLogger() |
9 | Falls back to console when @elizaos/core can't be required. Justified at the boundary, but should accept an injected logger and let the caller decide. |
eliza.ts 14× syncBrandEnvAliases() |
(housekeeping) | Defensive sludge: every upstream call is bracketed by env-syncs "in case" the brand env drifted between calls. The env should be synced once, at boot, by the canonical owner. |
runtime/eliza.tsandruntime/dev-server.tsare the two consumers of@elizaos/shared'sresolveDesktopApiPort/syncResolvedApiPort. They both correctly resolve the port through the shared helper rather than readingprocess.env.ELIZA_API_PORTdirectly. This is the layer that gets the API-base contract right (compare to Layer 7'sRuntimeGate.tsx, the source of MASTER.md §0's bug).runtime/dev-server.ts:421-428has a CRITICAL log if the bound port differs from the requested port — exactly the diagnostic that would have surfaced MASTER.md §0's port-shift earlier. This is good. The disconnect was at the renderer side (Layer 7), not the API side.runtime/ensure-local-inference-handler.ts:74-87historical comment aboutLOCAL_INFERENCE_PRIORITYgoing from -1 to 0 is directly load-bearing for the chat fallback bug class: when this returns without registering a priority-0 handler, the runtime'sgetModel(TEXT_SMALL)returnsundefined→ upstreamchat-routes.tsfires thePROVIDER_ISSUE_CHAT_REPLYstring. Phase 4 of MASTER.md (chat-fallback rename) cannot be considered complete without auditing the routing-policy + handler-registry path that flows through this file.