ComfyUI Higgsfield Opensource Challenge The analysis ← Build log

The analysis

ComfyUI substrate inventory

Read at: magieva-core branch fix/residency-fail-closed-round-lesson, commit ef3798123c5 (2026-10-27). All line numbers are against that commit.

Headline finding. Magieva has a genuinely shipped ComfyUI substrate, not a plan: a complete Local Resource Manager (LRM) connector that speaks ComfyUI's real HTTP API, five embedded workflow graphs (four registered), GCE GPU provisioning that installs ComfyUI from scratch and registers it back into LRM, a task-executor video provider, a weight-licence hosting gate with per-model pins, and a desktop Electron install/run path. But it is fragmented into three parallel invocation paths that do not share a gate, and several seams that look wired are dead: internal/psdedit/local.go POSTs to an LRM route that does not exist, the contentstudio COMFYUI_API_URL façade is set by nothing in any deployment config, the comfyui_lrm transport has no registered Go driver, and the desktop's ComfyUI registration is opt-in and defaults off. The planning docs are stale in both directions — docs/planning/26.35/os-video-model-integration/README.md:3 still says "Planning. Nothing built." while its own Phase 1 is live in production, and docs/planning/26.35/status/M3.md says "No ComfyUI workflow graphs for video" while four such graphs now exist and two are verified by execution on real GPUs.


What is actually shipped

Status key: (a) live/wired · (b) exists but behind a flag / env var / unshipped · (c) planned only.

Capability Entry point (path:line) What it does Evidence it is live
ComfyUI connector (LRM)services/local-resource-manager/connector_comfyui.go:25Full Connector + GenerationConnector + GPUInfoProvider: health, model list, workflow submit, poll, output extraction, image uploadRegistered in factory connector.go:195-196; compile-time assertions connector_comfyui.go:917-919; tests connector_comfyui_test.go, connector_generation_test.go, comfyui_video_capability_test.go, comfyui_video_output_test.go
Workflow template storeservices/local-resource-manager/comfyui_workflows.go:22-23, :51-93//go:embed comfyui_workflows/*.json; maps (capability × model) → graph file. Model-keyed so one model's graph is never served for another'slookupWorkflowTemplate :98; comfyui_workflows_test.go
Param injectionservices/local-resource-manager/comfyui_workflow_params.goGraph-agnostic injection of prompt/negative/seed/dimensions/frame-count/checkpoint, matching on class_type + graph links, never node idsfindPromptNodes :91; setLoadImageFilename comfyui_workflows.go:190; comfyui_workflows_test.go
LRM HTTP APIservices/local-resource-manager/main.go:320-371/v1/generate, /v1/generate/async, /v1/generate/jobs/:id, /v1/images/generations, /v1/chat/completions, /api/v1/local/backends, /api/v1/local/models, /api/v1/local/eligibility/:orgIdRoute registrations in main.go; declared in endpoints.go:22-44 for AEIOUY
GPU runner provisioningservices/gpu-runner-service/provisioner.go, provisioner_gce.go, startup_script.shCreates a GCE VM, runs startup_script.sh (NVIDIA driver → ComfyUI clone → venv → torch cu128 → node packs → weights staging → launch on 0.0.0.0:8188), polls /system_stats, registers with LRM as origin=platform_gpumanager.go awaitReadyAndRegister; startup_script_test.go (boot-path invariants incl. the 1038lab RMBG fix); lrm_client.go:61
Capability → GPU tier routingservices/gpu-runner-service/provisioner.go:96-103defaultTierForCapability returns rtx6000 for everything (was text-to-video → h100-mega)provisioner.go:137-160 resolveTier precedence override → Bernini → registry → capability
Per-model tier from registryservices/gpu-runner-service/catalog.go:89tierForModel reads ai_model_execution_tiers.gpu_tier_key / gpu_tier_fallback_key (read-only Integrations pool)catalog_test.go; verified live in ws-18 by mutating the row (M3.md "Follow-up: the catalog readers")
ComfyUI video providerinternal/task-executor/providers/video/comfyui.go:41SupportsModel("comfyui/…"), picks capability from ImageURL presence, submits to LRM async, polls, downloadsRegistered unconditionally registry.go:61-63; lrm_client.go shared plumbing
AIMRS local executioninternal/aimrs/local_exec.go:248 (ExecuteLocalGeneration), :341 (ExecuteLocalImage)POSTs to {resolved.EndpointURL}/generate and /images/generations; Capability is the ComfyUI workflow selectorCallers internal/task-executor/archetypes/river_artistic.go:2735, :2808, :2901
River local media pathsriver_artistic.go:2901 (tryLocalImage), :2808 (tryLocalVideo), :2735 (tryLocalImageVariation)Resolve via AIMRS; if IsLocal(), generate at Cost: 0 with route_type=local_device metadata; fall through to cloud on any missfallbackLocalImageCheckpoint :2585 = flux1-schnell; defaultLocalVideoCheckpoint = ltx-video
Weight-licence hosting gateinternal/modellicense/validate.go:31ValidatePlatformHosting → HostedAllowed/RequiresAgreement/Prohibited/Unknown; fail-closedEnforced at services/gpu-runner-service/manager.go (Provision) and services/local-resource-manager/backend_handler.go:224
$0 pricing for ComfyUIinternal/intelligence/sync/pricing/runner.go:250localFreeProviders allowlist includes comfyuiExplicit allowlist, "never a heuristic"
Local-provider billing bypassinternal/contentstudio/compute_operations.go:53isLocalProvider returns true for comfyui—
Desktop ComfyUI install/runweb/electron/main/backends/NativeProcessOrchestrator.ts:361, web/scripts/setup-comfyui.shClones ComfyUI, creates venv, installs ComfyUI-LTXVideo + ComfyUI-RMBG, writes launcher on port 8188runComfyUISetup :1056; port-ownership refusal :505
Desktop backend install APIapi/operations/desktop_install_backend.go:93supportedBackends = {"ollama": true, "comfyui": true}Validated backend-type guard
Catalog seedsinfra/supabase/migrations/20260630000100_INTEGRATIONS_comfyui_image_models.sql, 20260831130000, 20260831130100, 20260831130200comfyui provider row; FLUX/SDXL/SD3.5/LTX-Video image models; 7 canonical video models + 7 comfyui_lrm bindings + 9 adapters; per-model tier rowsM3.md: "catalog AND first-frame work are live in PRODUCTION on 26.35.5"

(b) Exists but behind a flag / env var / unshipped

Thing Where Gate
Desktop ComfyUI auto-registrationweb/electron/main/startup.ts:1535-1536localProcessing.image.enabled, default false — "Opt-in … because ComfyUI is heavy"
GPU auto-provision on demandgeneration_proxy_handler.go:317GPU_RUNNER_AUTOPROVISION (default "true"), video modality only
Weight mirroring to GCSstartup_script.sh:135-157GPU_RUNNER_WEIGHTS_BUCKET unset everywhere → staging skipped, "shipped inert" (M3.md)
Platform GPU in production—M3.md: prod sets no GPU_RUNNER_* (provisioner is dryrun) and has 0 rows in local_backends, while all 7 comfyui/* models are is_available=t → a prod user gets a 20s retry loop then failure. "Deployed ≠ renders."
contentstudio ComfyUI render façadeinternal/contentstudio/character_render_controlnet.go:175COMFYUI_API_URL is referenced only in code + planning docs; set in no helm value, compose file, or env. No services/comfyui-service exists in the repo (only named in docs/planning/26.28/atlas-2d3d-character-pipeline/README.md:138)
comfyui_lrm transport driverinternal/modelparams/transport.go:186RegisterDriver is never called outside tests; Transport("comfyui_lrm").Valid() is false → Layer-1 coercion only, Layer-2 rendering withheld (schema_params.go:82-101)
first_last_frame_to_video_wan22_a14b.jsoncomfyui_workflows.go:82-92Present and GPU-verified but deliberately unregistered: GenerationRequest carries one input image and setLoadImageFilename binds it to every LoadImage node; this graph has two
internal/psdedit/local.gointernal/psdedit/local.go:72POSTs to {baseURL}/api/v1/local/generate — no such LRM route exists (main.go has /v1/generate and `/api/v1/local/backendsmodelspoliciesusageeligibilitynodes). Also sends image_base64, but LRM's GenerationRequest.InputImageData is json:"-" (generation_types.go:51) so it would be dropped. Capability strings are image_to_image/upscale/inpaint (underscores) vs the store's image-to-image (hyphen); no upscale or inpaint template exists at all. Wired only when LOCAL_RESOURCE_MANAGER_URL is set (env.go:52`)

The ComfyUI integration contract

LRM → ComfyUI (the real protocol)

All in services/local-resource-manager/connector_comfyui.go. HTTP only — there is no websocket client anywhere in LRM (grep for websocket in services/local-resource-manager/*.go returns only the unrelated relay connector for desktop Ollama, connector_relay.go:1). Progress is polled.

Purpose Call Line
HealthGET {base}/system_stats → ComfyUISystemStats{Devices[]}:45-46
List checkpointsGET {base}/object_info/CheckpointLoaderSimple, reads input.required.ckpt_name[0][]:73-74
Weight reconciliationGET {base}/object_info (all nodes):632
Upload input imagePOST {base}/upload/image (multipart) → returns filename:681-700
Submit graphPOST {base}/prompt body {"prompt": <graph>, "client_id": <uuid>} → {"prompt_id","number"}:261-295
PollGET {base}/history/{prompt_id} → map[promptID]ComfyUIHistoryEntry; absent ⇒ processing:299-331
Error detectentry.status.status_str == "error":334
Output URLGET {base}/view?filename=…&subfolder=…&type=…:442
GPU infovia /system_stats devices:490

Output extraction is a documented trap. comfyOutputKeys = ["videos","gifs","audio","images"] (:379) — core SaveVideo emits the mp4 under images, not videos; the comment records this was corrected against a live ComfyUI (frontend 1.49.6) on 2026-08-26. MIME is derived from extension (comfyMimeByExt, :384), because the old code hardcoded image/png for everything.

Fail-loud guards (both are the fix for a real silent-wrong-output defect):

Callers → LRM

Caller Endpoint Payload
internal/aimrs/local_exec.go:296 (ExecuteLocalGeneration)POST {EndpointURL}/generate{modality, capability, model, prompt, negative_prompt, width, height, duration, fps, input_image_url, strength, num_outputs, control}
internal/aimrs/local_exec.go:383 (ExecuteLocalImage)POST {EndpointURL}/images/generationsOpenAI-shaped {prompt, model, n, size, negative_prompt, seed, steps, cfg_scale}
internal/task-executor/providers/video/comfyui.go:277POST {LRM}/v1/generate/async{organization_id, modality:"video", capability, model, prompt, width, height, fps, duration, input_image_url?}
…then pollsGET {LRM}/v1/generate/jobs/{id}?backend_id=…{status, progress, outputs[{url,mime_type}], error}

EndpointURL is lrmClient.baseURL + "/v1" (services/aimrs-service/handlers.go:166), so ExecuteLocalGeneration lands on LRM's synchronous /v1/generate.

⚠️ The three invocation paths do not share a billing gate — this is load-bearing

HandleUniversalGeneration (sync, /v1/generate) refuses platform-GPU generation for any provider that is not Bernini:

// generation_proxy_handler.go:239-249
if backend.Origin == OriginPlatformGPU {
    if h.billing == nil { … "platform GPU billing not configured" }
    if backend.ProviderName != ProviderBernini {
        return 503 {"error":"no flat pricing configured for this platform model","code":"NO_PRICING"}
    }

HandleAsyncGeneration (/v1/generate/async, :344-396) has no billing gate and no provider check — it goes straight to genConn.GenerateAsync.

HandleImageGeneration (/v1/images/generations, :59-181) also has no billing gate and no provider check — it goes straight to genConn.Generate at :140.

So of the three ComfyUI invocation paths, only one gates:

Path Route Platform-GPU ComfyUI
river_artistic.tryLocalImage → ExecuteLocalImagePOST /v1/images/generationsworks, unbilled (no gate)
task-executor video providerPOST /v1/generate/asyncworks, unbilled (no gate)
river_artistic.tryLocalVideo / tryLocalImageVariation → ExecuteLocalGenerationPOST /v1/generate503 NO_PRICING (Bernini-only gate)

The consequence is inverted from what one would expect: the two paths that do work on a platform GPU are the two with no billing gate, and the one path that is correctly gated is the one that cannot serve ComfyUI at all. aimrs.ExecuteLocalGeneration is therefore usable for ComfyUI only on origin=customer_device.

GPU runner → LRM registration

services/gpu-runner-service/lrm_client.go:70-83 POSTs to /api/v1/local/backends:

{"organization_id":"…","provider_name":"comfyui","display_name":"platform-gpu rtx6000 (comfyui/wan2.2-ti2v-5b)",
 "base_url":"http://<ip>:8188","backend_type":"image","capabilities":["<one capability>"],
 "origin":"platform_gpu","max_concurrent":4,
 "hosted_models":[{"model_id":"comfyui/wan2.2-ti2v-5b","license":"apache-2.0"}]}

Note backend_type is "image" for ComfyUI and "video" only for Bernini (:66-69) — a ComfyUI runner is registered as an image backend even when it was provisioned for a video capability. hosted_models deliberately carries no clearance field: LRM re-reads org_license_acceptances itself (lrm_client.go:34-44), so the two gates judge the same fact independently.


Shipped workflow graphs

Five files in services/local-resource-manager/comfyui_workflows/; four registered.

File Registered key Nodes / models What it does Verification
background_removal.json{background-removal} (model-agnostic)LoadImage → RMBG → SaveImageBria RMBG-2.0 background removal; the graph names its own weightsThe only template that existed pre-26.35
text_to_video_wan22.json{text-to-video, wan2.2-ti2v-5b}UNETLoader wan2.2_ti2v_5B_fp16.safetensors; CLIPLoader umt5_xxl_fp8_e4m3fn_scaled.safetensors; VAELoader wan2.2_vae.safetensors; Wan22ImageToVideoLatent; KSampler; ModelSamplingSD3; CreateVideo; SaveVideoWan 2.2 TI2V-5B text-to-videoVERIFIED on real GPU 2026-08-26: 121 frames @ 832×480, h264. ComfyUI's own video_wan2_2_5B_ti2v.json exported to API format. Re-confirmed staging 2026-08-27
image_to_video_wan22_ti2v.json{image-to-video, wan2.2-ti2v-5b}Same as above plus restored LoadImage (node 56)Wan 2.2 TI2V-5B image-to-videoVERIFIED 2026-08-28: 832×480, 121 frames, 255 s. Conditioning checked, not just completion — frame 0 mean|diff| 1.41 vs uploaded image, rising to 163 by frame 120
image_to_video_wan22_a14b.json{image-to-video, wan2.2-i2v-a14b}UNETLoader ×2 (wan2.2_i2v_high_noise_14B_fp8_scaled, …low_noise_14B_fp8_scaled); CLIPLoader umt5_xxl…; VAELoader wan_2.1_vae; WanImageToVideo; KSamplerAdvanced ×2; CreateVideo; SaveVideoWan 2.2 I2V-A14B MoE pair — the case that forced (capability × model) keyingVERIFIED 2026-08-28: 640×640, 81 frames, 1254 s, peak 21737/23034 MiB on an L4. DERIVED, not exported — upstream is a subgraph routed through lightx2v LoRAs we do not stage
first_last_frame_to_video_wan22_a14b.jsonNOT REGISTEREDWanFirstLastFrameToVideo; UNETLoader ×2; LoadImage ×2 (nodes 80, 89); KSamplerAdvanced ×2Wan 2.2 I2V-A14B first/last-frame-to-videoVERIFIED 2026-08-28 (L4, 640×640, 81 frames, 20 min 58 s, peak 21151/23034 MiB) but deliberately unwired — see (b) above

Models with NO graph (registered in the catalog and offered in the picker, but a request fails loudly): wan2.2-t2v-a14b, ltx-2.3, ltx-2.5, scail-2, ltx-video. This is the honest fail-loud path, not a silent fallback — but it means the customer-facing model list (customer-docs/site-src/reference/models/comfyui--local.md:10-23) advertises models that cannot render.


Models and licences

The gate

internal/modellicense/ classifies weight licences for platform-GPU hosting, deliberately separate from BORG's SPDX code-licence check (policy.go:1-15): "a model's node-pack/code can be MIT while its downloadable weights carry a restrictive license." The canonical example given is Bria RMBG-2.0 — ComfyUI-RMBG node code permissive, RMBG-2.0 weights requiring a commercial agreement.

ValidatePlatformHosting(modelID, license, hasClearance) (validate.go:31): HostedAllowed → nil · RequiresAgreement → nil only if clearance · Prohibited → always error · Unknown → error (fail closed).

Enforced independently at both hosting paths: gpu-runner-service/manager.go (Provision, before creating the VM) and local-resource-manager/backend_handler.go:224 (on origin=platform_gpu registration). Both read clearance from org_license_acceptances, never from the request body (backend_handler.go:193, lrm_client.go:34-44).

Model → licence map

Pins in internal/modellicense/policy.go (knownWeightLicense, :41-80), asserted by internal/modellicense/os_video_models_test.go:22-47:

Model id Licence Disposition
comfyui/wan2.2-ti2v-5b, comfyui/wan2.2-t2v-a14b, comfyui/wan2.2-i2v-a14bapache-2.0HostedAllowed
comfyui/scail-2mitHostedAllowed
comfyui/ltx-2.3, comfyui/ltx-2.5, Lightricks/LTX-2-19b-IC-LoRA-*ltx-2.x-communityRequiresAgreement — fails closed
comfyui/ltx-video (0.9.x)unpinned (LTXV Open Weights)Unknown — fails closed (os_video_models_test.go:140-148)
rmbg-2.0, rmbg-1.4, briaai/rmbg, briabria-rmbgRequiresAgreement
bernini, wan2.2, wan-2.2, qwen2.5-vlapache-2.0HostedAllowed

Two subtleties worth carrying into any reuse:


Desktop / local install path

Install — web/scripts/setup-comfyui.sh (166 lines), invoked by NativeProcessOrchestrator.runComfyUISetup (:1056), which locates the script at Resources/scripts/setup-comfyui.sh (packaged) or ../../../scripts/setup-comfyui.sh (dev). It checks Python ≥3.10, creates a venv at ~/.magieva/comfyui-data/venv, clones ComfyUI, installs requirements.txt, installs two custom-node packs, and writes a launcher at ~/.magieva/bin/comfyui/comfyui_launcher that runs main.py --listen 0.0.0.0 --port 8188 --enable-cors-header.

Run — backend definition at NativeProcessOrchestrator.ts:361-378: binaryName: 'comfyui_launcher', processName: 'magieva-comfyui', hostPort: 8188, healthProbePath: '/system_stats', capabilities ['text-to-image','text-to-video','image-to-image','background-removal'] (hyphenated to match LRM's canonical vocabulary). Port ownership is checked before spawn (:505, refuses with pair_owns_port).

Announce — startup.ts:1535 registerComfyUINode, gated on localProcessing.image.enabled (default false), calls install({backend_type:'comfyui', expose_via:'cloudflared'}) then bridge.sendBackendReady({backendType:'comfyui', capabilities, maxConcurrent: 1}). The desktop does not POST to LRM directly — it goes through the event-bridge (docs/planning/26.27/local-magieva/03-local-media-routing-comfyui-aimrs.md documents this correction).

Model selection — LocalModelSelector.ts:75 selectDefaultImageModel: ≥24 GB → sd3.5_large, ≥16 GB → flux1-schnell, else SDXL. canRunLTXVideo (:187) gates on ≥14 GB RAM; canRunBriaRMBG (:196) on ≥3 GB.

Two concrete defects in this path:

  1. setup-comfyui.sh:128 clones kijai/ComfyUI-RMBG — the 404 URL that the GPU-side script explicitly fixed to 1038lab/ComfyUI-RMBG (startup_script.sh:64-66), and which startup_script_test.go:103-107 now asserts against. The desktop path still has the broken URL.
  2. CapabilityAdvisor.ts is at web/electron/main/briareus/CapabilityAdvisor.ts, not web/electron/main/backends/CapabilityAdvisor.ts as cited by docs/planning/26.35/os-video-model-integration/README.md and the migration header — and it contains no ComfyUI or local-backend logic at all (127 lines, chat-model budget only: assessModel, recommendChatModel). The migration's claim that it "drives the two-path runnability check" for ComfyUI is not true of this file. deriveHardwareProfile, also cited, does not exist there.

Planned but NOT built

Claim Doc that claims it Reality at ef3798123c5
"Planning. Nothing built."docs/planning/26.35/os-video-model-integration/README.md:3Stale. Phase 1 (catalog, routing, licence pins, tier readers) is live in production per status/M3.md
"No ComfyUI workflow graphs for video."docs/planning/26.35/status/M3.md (last updated 2026-08-27)Stale. Four video graphs exist; three GPU-verified (2026-08-26/28). The workflow files post-date the doc
h200 GPU tierREADME.md Phase 2; 20260831130100 column commentNot added. "H200 appears only as a costing line in the 26.36 Kimi K3 plan"
Customer-hardware VRAM floors for the new models20260831130000 header; 20260831130100 customer-tier rowsNot measured. local_backend_type/local_min_* stay NULL → CapabilityAdvisor reads non-local → models not offered on customer hardware. 08-measurements.md is the empty ledger
Control / LoRA runtime graphs04-control-and-lora-assets.md §4.3ControlBlock exists in generation_types.go:82 and travels the wire, but connector_comfyui.go:220-231 hard-errors on any control request. Adapters are seeded in the DB (20260831130200) with no graph to consume them
services/comfyui-service render nodedocs/planning/26.28/atlas-2d3d-character-pipeline/README.md:138Does not exist. The contentstudio façade that would call it (POST {COMFYUI_API_URL}/render) is unreachable
Apple Silicon measurement03-apple-silicon.mdNothing measured; is_supported NULL for every customer_apple row except the incumbent LTX-Video
Horror-corpus training pipeline05-training-pipeline.mdPhase 5, gated on Phase 0
comfyui_lrm Layer-2 param renderinginternal/modelparams/transport.go:168-185No driver registered; Layer-1 coercion only
Async-handoff for local mediadocs/planning/26.28/local-magieva/04-comfyui-media-activation.md ("🔴 Remaining: #14 (deferred)")Still deferred
Staging e2e for i2i (input_image_url consumption)same doc, "Staging-verify the LRM ComfyUI connector actually consumes input_image_url"Still open

Reusable in a competition entry

Directly reusable as an open-source ComfyUI app (little or no Magieva-internal coupling):

  1. The workflow-graph corpus + the (capability × model) keying discipline. comfyui_workflows/*.json are ComfyUI's own templates exported to API format, with _README blocks recording provenance, upstream version, and measured wall-clock/peak-VRAM. The workflowTemplateKey design (comfyui_workflows.go:37-44) and the rule "a model with no template must FAIL, naming the model" is a genuinely good pattern for any multi-model ComfyUI app.
  2. comfyui_workflow_params.go in full. Graph-agnostic injection matching on class_type and following the graph's own links — survives a re-export that renumbers nodes. The isLink guard (never overwrite a link with a literal, :45-54) and findPromptNodes (resolve positive vs negative by following links, :91) are the two pieces that make it robust. This is the single most reusable file in the inventory.
  3. The connector's output-extraction layer. comfyOutputKeys + comfyMimeByExt + sortOutputsRichestFirst encode hard-won knowledge (core SaveVideo emits under images) that any ComfyUI client needs.
  4. The fail-loud guards. Refusing to answer a video request with a txt2img PNG, and refusing control requests that nothing honours, are the right defaults and are cheap to port.
  5. setup-comfyui.sh — a working, idempotent macOS/Linux ComfyUI installer (once the RMBG URL is fixed to 1038lab).
  6. The licence-classification idea — separating code licence from weight licence, with most-restrictive-wins and per-adapter classification. Reusable as a concept even if the specific pins are Magieva's.

Magieva-internal plumbing that would need replacing:

  1. LRM itself. The whole /v1/generate + /v1/generate/async + /api/v1/local/backends surface, LocalBackend, Origin (customer_device/platform_gpu), the X-Organization-ID attribution header, LocalUsageRecorder, and the token-hold billing gate. A competition app would talk to ComfyUI directly.
  2. The AIMRS resolution layer. ExecuteLocalGeneration depends on a resolved EndpointURL and IsLocal() from a separate routing service. Not portable.
  3. The GCE provisioner + tier catalog. provisioner_gce.go, gpuTiers, ai_model_execution_tiers, ai_model_adapters — cloud-specific.
  4. internal/modellicense's enforcement points (org_license_acceptances, platform_gpu origin) — the policy is reusable, the enforcement is Magieva's DB.
  5. The desktop event-bridge registration (sendBackendReady → event-bridge → LRM) — three services deep.
  6. internal/psdedit/local.go and the contentstudio façade — both currently broken; do not port as-is.

Judgement. The reusable core is roughly comfyui_workflow_params.go + comfyui_workflows.go + comfyui_workflows/*.json + the connector's submit/poll/extract half — a self-contained "ComfyUI workflow runner with model-keyed graphs and safe param injection." Everything else is either Magieva's multi-tenant routing/billing substrate or an unwired seam.


Gaps and unknowns

Verified gaps (code-level, no runtime needed):

Not verified / unknown (stated rather than guessed):