ImaGen #2: ComfyUI local backend on mRock (FLUX schnell) #2
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Implement the ComfyUI local backend — first real adapter for the ImaGen framework. Runs FLUX.1 [schnell] on mRock, talks to a local ComfyUI server, returns PNG bytes via the Backend interface.
Prerequisite: ImaGen#1 (bootstrap + Backend interface) must be merged.
Why ComfyUI + FLUX schnell
Scope
1. ComfyUI on mRock
Two install paths — pick whichever fits mRock's existing service pattern:
~/services/comfyui/docker-compose.ymlwith--gpus all, volume mounts for models, port 8188. Recommended if mRock already has a docker setup.comfyui-serverfrom a Python venv. More overhead to maintain but slimmer.Either way:
http://mrock:8188(Tailscale-internal, not public).flux1-schnell.safetensorsplaced inmodels/checkpoints/(download from HuggingFaceblack-forest-labs/FLUX.1-schnell, ~24 GB).ae.safetensors,clip_l.safetensors,t5xxl_fp8_e4m3fn.safetensors) inmodels/vae/andmodels/clip/.GET http://mrock:8188/system_statsreturns 200 within 60s of service start.Document the install steps in
docs/setup-comfyui-mrock.mdso it's reproducible.2. Go adapter (
internal/backend/comfyui.go)Implements the Backend interface from #1:
base_url,model,default_steps, optionaldefault_sampleranddefault_scheduler./api/v1/extra_models-style workflow shape — concretely theflux1-schnell4-step workflow).POST /promptwith the workflow + a uniqueclient_id.GET /history/{prompt_id}until execution completes (or websocket-subscribes for status updates if the framework's runtime supports it cleanly).GET /view?filename=....{model, seed_used, latency_ms, steps, sampler, scheduler, vram_peak_mib}(last one if available from/queueor/system_stats).Map ImaGen
Request.Width / Height / Seed / Stepsinto the workflow JSON's KSampler node + EmptyLatentImage node values. If the request's Steps is 0, usedefault_steps. Same for seed (0 → random).3. Smoke test
End-to-end latency target: < 8 s for 1024x1024 / 4 steps on mRock (FLUX schnell typical performance).
4. Resilience
boot-whitetower mrock(per~/.m/docs/scripts.md).docs/setup-comfyui-mrock.md.Acceptance criteria
http://mrock:8188andimagen backendsshowsflux-schnell-local: ok.docs/setup-comfyui-mrock.mdexists and is followable from a clean mRock state.internal/backend/comfyui.gohas unit tests with a mocked HTTP server (no real mRock dependency in tests).imagen config sampleincludes theflux-schnell-localblock as the default backend.Out of scope
Refs
~/.m/docs/scripts.md(boot-whitetower)Workflow
Coder role. Blocked on #1 — do NOT start before #1 is merged. When #1 is in, m or otto/head assigns mAi here and the webhook spawns a coder.
Phase 1 PoC done — first FLUX schnell image generated on mRock.
Per @hades's instruction, sequenced as PoC-first before the Go adapter.
Install path
Native Python venv + systemd unit (Arch Linux on mRock). docker-compose was the issue's recommendation, but mRock's Docker has no nvidia runtime configured and Ollama itself runs as a native systemd service, so matching that pattern was the lighter touch.
~/dev/comfyui, Python 3.12 venv, torch 2.6.0+cu124./etc/systemd/system/comfyui.service(committed underscripts/comfyui.service), enabled, listening on0.0.0.0:8188. Tailscale is the only auth fence.GET http://mrock:8188/system_statsreturns 200 with the 4070 Ti SUPER recognised (16 GB total, ~10 GB free with Ollama running).Models
Black-Forest-Labs's
FLUX.1-schnellrepo is gated on HuggingFace — anonymouscurlreturns HTTP 401. Switched to ungated mirrors of the same Apache-2.0 release:flux1-schnell.safetensors(~23.8 GB, fp16)Comfy-Org/flux1-schnellmodels/unet/ae.safetensors(~335 MB)sirorable/flux-ae-vaemodels/vae/clip_l.safetensors(~246 MB)comfyanonymous/flux_text_encodersmodels/clip/t5xxl_fp8_e4m3fn.safetensors(~4.9 GB)comfyanonymous/flux_text_encodersmodels/clip/Note: the issue spec said
models/checkpoints/, but that's the slot for fullCheckpointLoaderSimplepayloads (model + clip + vae bundled). The FLUX schnell file is unet-only, so it goes tomodels/unet/and the workflow usesUNETLoader. Doc and download script updated to match.First image
Prompt: "a small fishbowl with a cat staring out, photo, soft light", 1024×1024, 4 steps, fp8 weight dtype, seed 1234567.
End-to-end
POST /prompt→GET /history/{id}→GET /view= 9.79 s (slightly over the < 8 s target on first cold start; should hit target on warm runs once weights cached).PNG at
/home/m/dev/ImaGen/poc/first-image.pngon mRiver, 1024×1024 RGB, 1.05 MB. Cat clearly visible behind a glass fishbowl on a wooden surface — exactly the prompt.VRAM coexistence
ComfyUI peak ≈ 5.5 GB resident with FLUX schnell + fp8 t5 + fp8 weight dtype. Ollama parks 1–2 GB normally, more when a model is hot. Together they fit in 16 GB as long as ollama doesn't have a large model resident. Captured this in
docs/setup-comfyui-mrock.mdwith the option of moving Ollama off mRock once ImaGen sees real load — flag for ops, not blocking the adapter work.Phase 1 deliverables
http://mrock:8188,/system_stats200/home/m/dev/ImaGen/poc/first-image.pngon mRiverdocs/setup-comfyui-mrock.md(reproducible from a clean mRock state)scripts/Holding here for @hades's ack before starting phase 2 (Go adapter, mocked HTTP unit tests,
imagen config sampleupdate, smoke via theimagenCLI).Commit:
a24ac2826fPhase 2 done — Go adapter shipped, ready to merge.
End-to-end CLI smoke test against the live ComfyUI on mRock:
Sidecar contents (excerpt):
Image at
/home/m/dev/ImaGen/poc/second-image-via-cli.png(mRiver). 1024×1024 RGB, 1.17 MB, full cat face peeking out of a glass fishbowl.Adapter (
internal/backend/comfyui.go)base_url,model. Optional:default_steps(4),default_sampler(euler),default_scheduler(simple),vae(ae.safetensors),clip_l,clip_t5,weight_dtype(fp8_e4m3fn).Request.Width / Height / Seed / Stepsplus per-call sampler/scheduler overrides viaBackendOptsinto the right node inputs./promptwith a uniqueclient_id, polls/history/{id}at 250 ms (configurable), pulls bytes via/view, peeks at/system_statspost-gen forvram_used_mib./prompt5xx and transient network errors, no retry on 4xx (config bug, not a transient failure).comfyui at … unreachable — if mRock is asleep, run: boot-whitetower mrock.node_errorsmentioningunet_namenot in list →comfyui /prompt 400: model "X" not present in the ComfyUI server's models/unet/ — see docs/setup-comfyui-mrock.md. Matches both the 4xx flavour and the 200-with-node_errors flavour ComfyUI uses across versions.Registration happens via
init()in the sameinternal/backendpackage, so the existing anonymous import incmd/imagen/main.gopicks it up — no changes needed there.Tests (
internal/backend/comfyui_test.go)httptest.Servermock, no real mRock dependency. Poll interval squashed to 1 ms. 14 tests covering:DefaultRun cleanly under
go test ./...— no-shortguard or env var needed since nothing reaches outside the test process.Config sample (
imagen config init)flux-schnell-localis now the default;mockstays in the sample for offline testing. The user-facing block names the unet file by basename — themodels/unet/location is the ComfyUI server convention captured indocs/setup-comfyui-mrock.md.Acceptance criteria
http://mrock:8188;imagen backendsshowsflux-schnell-localwithregisteredstatus when called against the sample config.docs/setup-comfyui-mrock.mdexists, reproducible from a clean mRock state (Phase 1).internal/backend/comfyui_test.go— mocked HTTP, no real mRock dependency.imagen config sampleincludesflux-schnell-localas default backend.go build ./...andgo test ./...clean.Ready for review and merge into main.
Commit:
127bbf3ed5Merged into main
Branch
mai/hermes/issue-2-imagen-2-comfyuimerged via--no-ffat4183d4c. Pushed to origin/main.a24ac28127bbf34183d4cAcceptance criteria
http://mrock:8188;imagen backendsshowsflux-schnell-local: ok/home/m/dev/ImaGen/poc/second-image-via-cli.png, 10.3 s end-to-enddocs/setup-comfyui-mrock.mdfollowable from clean mRockinternal/backend/comfyui.gohas unit tests with mocked HTTP serverimagen config sampleincludesflux-schnell-localas defaultinternal/config/config.goupdated, default_backend: flux-schnell-localgo build ./... && go test ./...clean on the merged main.Three real corrections vs the issue spec
black-forest-labs/FLUX.1-schnellHF repo is gated (HTTP 401 without HF_TOKEN). Using ungated mirrorsComfy-Org/flux1-schnell+sirorable/flux-ae-vae. Same Apache-2.0 weights, byte-identical.models/unet/, notmodels/checkpoints/. UNETLoader pulls from unet/. Doc + script corrected.All three saved to mai-memory under group
imagenso future workers don't repeat the trap.Follow-ups now ready to start (this issue unblocked them):