Files

14 KiB

Architecture

ComfyUI-Doctor is a ComfyUI custom node extension with three main surfaces:

  • a Python package that loads inside ComfyUI and registers PromptServer routes
  • browser-side JavaScript that renders the Doctor sidebar and panels
  • development/test tooling that keeps host compatibility, API contracts, and UI behavior stable

For route-level details, use the machine-readable OpenAPI contract: openapi.json.

Host Startup

ComfyUI loads the package entry point from __init__.py. That file keeps host-facing responsibilities together:

  • install or hand off the startup logger
  • initialize the full SmartLogger
  • configure LLM rate and concurrency limits
  • create the API logger
  • collect a system snapshot
  • register PromptServer routes through api_routes.py
  • expose node mappings and WEB_DIRECTORY

prestartup_script.py runs earlier in the ComfyUI startup lifecycle. It captures early terminal output before the full package import is available. The main package then hands off that logger so startup logs and runtime logs share one path. Doctor-owned terminal output uses one severity-aware identity, strips ANSI styling from persisted/plain sinks, and selects the full Unicode startup banner only when the effective stream can encode it; otherwise it emits the ASCII fallback.

Backend Layout

The backend is organized around a small entry point and focused service modules:

Area Primary files Responsibility
Package entry __init__.py, nodes.py, prestartup_script.py ComfyUI loading, node export, startup logging
API routes api_routes.py, services/routes.py PromptServer HTTP route registration and route handlers
Analysis analyzer.py, pattern_loader.py, pipeline/, services/prompt_helpers.py Error categorization, pattern matching, prompt construction
LLM llm_client.py, session_manager.py, services/llm_provider_adapters.py, services/outbound_policy.py, services/llm/ Provider requests, approved destinations and connect-time address checks, retry, proxy policy, rate/concurrency limits
Security security.py, outbound.py, sanitizer.py, services/security/ SSRF checks, outbound sanitization, admin guard, error envelopes
Logging and health terminal_output.py, logger.py, services/dynamic_vram_advisory.py Canonical terminal output, bounded runtime capture, and isolated nonfatal host advisories
Storage services/doctor_paths.py, history_store.py, services/secret_store.py Canonical data paths, history, encrypted credential storage
Diagnostics services/diagnostics/, services/intent/ Workflow, dependency, current host model/media/dataset asset folders and loaders, privacy, performance, and signature-pack checks
Community services/community_feedback.py, pipeline/plugins/ Feedback preview/submission and scan-only plugin trust reporting
Telemetry telemetry.py, web/statistics-island.js, web/tabs/stats_tab.js Local-only opt-in event buffer; controls in the statistics view

The domain packages under services/llm/, services/security/, services/infra/, and services/community/ provide stable import entry points for code that should not depend on individual implementation file paths.

API Surface

api_routes.py registers the main Doctor and debugger endpoints. Smaller service-owned handlers live in services/routes.py and are attached by api_routes.py.

The public API groups are:

  • debugger status, language, and history
  • LLM analysis, chat, provider defaults, key verification, and model listing
  • admin-gated server-side credential metadata and storage
  • statistics, resolution state, and feedback
  • runtime health, diagnostics, and plugin trust reports
  • local telemetry controls
  • resumable jobs and provider capability status

Write-sensitive routes use the Doctor admin guard. The API error shape is centralized through services/api_response.py, and the public contract is captured in docs/openapi.json. Doctor-owned docs use canonical /doctor/... route paths. Current ComfyUI hosts may also expose /api/doctor/... aliases through host route duplication, but that global alias behavior belongs to the host.

Data Flows

Startup and Logging

  1. prestartup_script.py captures early output.
  2. __init__.py imports the package with ComfyUI-relative imports.
  3. Canonical terminal formatting and the encoding-safe startup banner are handed off to the full package.
  4. SmartLogger.install() clears stale advisory state, replays one bounded public host-log snapshot, and then starts the normal runtime processor.
  5. The API logger writes ANSI-free operational events to the Doctor data directory.
  6. Route registration runs after ComfyUI server and aiohttp imports are available.

Error Analysis

  1. ComfyUI output is captured by SmartLogger.
  2. The analyzer and pattern pipeline classify the error.
  3. Node/workflow context is collected and pruned.
  4. Prompt helpers build a provider-neutral request payload.
  5. LLM calls go through approved-destination matching, adapter, retry, rate-limit, proxy, connect-time address checks, and outbound-sanitization layers.
  6. Results are stored in history and exposed to the frontend.

Nonfatal Host Advisory

  1. Startup replay reads at most 300 entries from the already-loaded public app.logger.get_logs() buffer without importing host code.
  2. Only the three exact supported DynamicVRAM source messages update the single bounded advisory slot: the prior and current PyTorch fallback forms plus the comfy-aimdo fallback. Ordinary warnings and near matches continue through their existing behavior.
  3. The advisory remains outside ErrorAnalyzer, traceback/history, and latest runtime-error state and is exposed only as an allowlisted projection in /doctor/health.
  4. The legacy and Preact Statistics paths use the same pure text formatter to show fixed Trust & Health guidance without rendering the raw host message.

Chat

  1. The frontend sends error context, user messages, provider settings, privacy mode, and optional credentials.
  2. Backend routes resolve credentials from request data, environment variables, local provider behavior, or the server-side store.
  3. The provider adapter builds the request.
  4. The route returns JSON or Server-Sent Events for streaming chat.

Diagnostics

  1. The frontend or caller posts workflow/context data to diagnostics endpoints.
  2. HealthCheckRequest is parsed by the diagnostics runner.
  3. Registered checks inspect workflow lint, dependencies, model assets, privacy/security, runtime performance, and signature packs.
  4. Reports are saved by the diagnostics store and exposed through report/history endpoints.

services/diagnostics/node_identity.py defines the bounded numeric/opaque-string identity contract shared by issue targets, workflow lint, signature targets and asset provenance. web/comfyui_frontend_compat.js resolves raw IDs and real subgraph execution paths with bounded enumeration; mutations require a unique exact target. Colons inside raw IDs are preserved. Malformed or duplicate workflow identities are skipped locally, so valid-node findings survive, but completeness on the malformed nodes is not guaranteed. Workflow lint exempts only the proven optional Switch and canonical Branch input families; host-selected branch execution checks remain owned by ComfyUI.

Model asset checks use ComfyUI's live folder_names_and_paths registry as the authoritative source when available, including custom roots and registered extensions. Older hosts retain a bounded fixed fallback. Workflow traversal also inspects bounded definitions.subgraphs content and preserves visible host plus concrete source provenance for nested assets. Positional widget values remain authoritative and uniquely matched named values are fallback only. First-party promoted image/video/output/audio loaders retain concrete source provenance; arbitrary custom upload-loader behavior is not inferred without authoritative node definitions. Input/dataset folders and every file candidate are real-path-contained within registered roots before any filesystem probe, read, or enumeration. The exact first-party SAM3DBody_Loader maps its model_file to the registered detection category before shared-extension inference. An absent or empty detection category never authorizes a checkpoints fallback.

Telemetry

Telemetry is local-only and disabled by default. When enabled, accepted events are validated against an allowlist and written to the local telemetry buffer. The browser UI can view, export, clear, and toggle telemetry through Doctor endpoints. The integration and stress test lanes use the Playwright harness backend for deterministic telemetry endpoint behavior.

Frontend Layout

ComfyUI loads frontend assets from web/.

Area Primary files Responsibility
Extension registration web/doctor.js, web/comfyui_frontend_compat.js ComfyUI extension setup and host API compatibility
State and API web/doctor_state.js, web/doctor_api.js, web/doctor_actions.js UI state, backend requests, user actions
Shell UI web/doctor_ui.js, web/doctor_right_panel.js, web/doctor_rendering.js, web/doctor_selectors.js Sidebar shell, right panel, rendering helpers, selectors
Chat web/chat-island.js, web/tabs/chat_tab.js, web/llm_provider_quick_switch.js Chat UI, Preact island, vanilla fallback, provider switch
Statistics and diagnostics web/statistics-island.js, web/tabs/stats_tab.js, web/utils/health_summary.js Stats dashboard, shared health/trust formatting, feedback, telemetry
Settings web/tabs/settings_tab.js, web/llm_key_store.js, web/privacy_utils.js Provider settings, credential handling, privacy mode
Resilience web/preact-loader.js, web/island_registry.js, web/ErrorBoundary.js, web/global_error_handler.js Local Preact loading, island fallback, error boundaries

Preact islands improve the Chat and Statistics surfaces, but each island has a vanilla fallback so the sidebar remains usable if the island loader fails. Tab activation receives the exact owned pane. Chat island activation and unmount operate on that concrete container, while late async render cleanup is discarded safely after tab-manager destruction rather than acting on detached DOM or an unrelated matching element. Validation-error display is normalized in the frontend so known prompt-validation failures use stable local catalog text and grouping metadata. Public raw errors and graph links can surface eligible input-level errors to a visible subgraph boundary while retaining source provenance; unknown or unproven topology falls back safely without private store access or breaking runtime error reporting.

Security and Storage Boundaries

Security-sensitive behavior is centralized:

  • LLM requests only reach operator-approved destinations; outbound URLs are built from the approved entry and resolved addresses are checked at connect time.
  • Outbound sanitization prevents raw private context from leaving the process; Authorization and X-API-Key values are always redacted in text and structured payloads, regardless of privacy mode.
  • Privacy modes control how much local context can be sent to remote providers.
  • Write-sensitive endpoints use the admin guard.
  • Server-side credentials use the secret store and are never exposed through status APIs.
  • Community plugins are scanned for trust metadata without importing plugin code.
  • Telemetry is local-only and opt-in.
  • Doctor-owned frontend settings opt out of the host frontend's independent setting-change telemetry.
  • Plain backend and exception status strings are inserted as literal text; intentional rich chat rendering stays on its separate sanitized path.
  • DynamicVRAM health output exposes fixed allowlisted guidance rather than raw host log text, device names, command lines, paths, prompts, or provider data.

Storage should go through services/doctor_paths.py so Desktop, portable, and standard ComfyUI installations resolve Doctor data consistently. Runtime identity and storage evidence are separate: a managed Desktop interpreter can remain classified as Desktop while the data directory comes from ComfyUI's private system-user API.

Testing Architecture

The full local acceptance gate is scripts/run_full_tests_windows.ps1 on Windows or scripts/run_full_tests_linux.sh on Linux/WSL. It covers:

  1. supply-chain dependency scan
  2. detect-secrets
  3. pre-commit hooks
  4. host-like package/startup validation
  5. backend unit tests
  6. default Playwright E2E

Backend test collection leaves the canonical production __init__.py byte-stable. Host-shaped package loading is validated separately rather than renaming the entry point or substituting a backup during pytest collection.

The route harness uses a normal importlib package spec and loader for the unchanged canonical entry point. Mandatory backend tests run isolated Ruff S102, S307 and E702 checks over all tracked Python files and verify the scanner with inert failure fixtures. No host reference code is executed by compatibility checks.

Additional focused lanes:

  • npm run test:integration runs @integration telemetry tests against the harness backend by default, or a live backend when COMFYUI_URL is set.
  • npm run test:stress runs opt-in @stress telemetry burst/state tests against the harness backend.
  • python scripts/focused_gate.py runs the supplemental focused security/contract/E2E regression lane. It is not a replacement for the full acceptance gate.
  • python scripts/check_host_compatibility.py evaluates source-linked contracts with separate frontend runtime lanes for the Desktop bundle, ComfyUI package pin, and standalone frontend source.

Compatibility Principles

  • Keep package imports compatible with ComfyUI custom-node loading.
  • Keep frontend registration compatible with current and deprecated host sidebar APIs where support exists.
  • Keep host compatibility checks version-aware and aligned with prompt queue source metadata, execution event payloads, model registries, nested workflow serialization, validation-error state, setting telemetry, Desktop layout, DynamicVRAM applicability/feature threshold, the SAM3D Body detection-root contract, core-pinned and standalone asynchronous setting handlers, system statistics metadata, job-cancel contracts, and frontend queue/cancel adoption.
  • Keep public route changes reflected in docs/openapi.json.
  • Keep local harness tests deterministic; live backend tests must be explicit opt-in.