Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
902 commits
Select commit Hold shift + click to select a range
965d3cd
fix(image): qwen edit tower keeps float32 products without process tf32
asher Oct 9, 2026
ce9cdbd
fix(image): read edit images upright and name the flag of one refused
asher Oct 9, 2026
06d611d
feat(image): refuse an mmproj that is not the encoder's vision tower
asher Oct 9, 2026
72fdd9d
test(image): hold the edit tower to a float64 oracle
asher Oct 9, 2026
e0c0604
test(image): check 6 holds the edit conditionings to its files
asher Oct 9, 2026
d614a13
test(image): check 7 counts the adapted layers exactly
asher Oct 9, 2026
f025d21
fix(image): edit tower runs one block at a time and leaves bfloat16 w…
asher Oct 9, 2026
56b7e6f
fix(image): qwen step plan prices the prefix rows a step reads
asher Oct 9, 2026
7842519
docs(image): move the reference size refusal out of the flag table
asher Oct 9, 2026
e1cf2a1
test(image): an encoder release leaves no mlx cache
asher Oct 9, 2026
61fc4e1
fix(image): a staged load releases the encoder when its encode raises
asher Oct 9, 2026
6205ff5
fix(image): a memory refusal never prints its peak equal to its budget
asher Oct 9, 2026
eeb443e
feat(image): GMLX_IMAGE_KQ_ROUTES takes a comma list of routes
asher Oct 9, 2026
d4429ef
fix(image): a shed lora kernel pair is counted in the tables that hol…
asher Oct 9, 2026
370e3c9
test(image): the exact gates read the process tf32 state, not the var…
asher Oct 9, 2026
5d484ec
fix(image): put the edit tower in the pyright gate
asher Oct 9, 2026
00766a1
feat(config): image_models block with server.image and defaults.image…
asher Oct 9, 2026
f34b368
feat(serve): image models load into the residency pool beside chat mo…
asher Oct 9, 2026
0693f97
feat(serve): unload, keep, ps and the resident view name each model's…
asher Oct 9, 2026
fadf9e2
fix(serve): type the image entry functions of the residency pool
asher Oct 9, 2026
90ba0f3
feat(serve): the image routes run generations, edits and variations o…
asher Oct 9, 2026
dae2f5c
docs(changelog): image models in serve and the image routes
asher Oct 9, 2026
8773e27
fix(serve): image entries tear down outside the pool lock, never load…
asher Oct 9, 2026
99b3219
fix(config): preload takes image ids, discovery skips them, and each …
asher Oct 9, 2026
2f4c586
fix(serve): an image request whose client leaves stops at its next step
asher Oct 9, 2026
7e7d936
test(e2e): the image routes end to end with the openai client on both…
asher Oct 9, 2026
a907366
fix(serve): an image model that shares a chat model's encoder encodes…
asher Oct 9, 2026
4280f71
test(e2e): the image measurement times the first byte of a stream wit…
asher Oct 9, 2026
26182f9
feat(serve): chat decode keeps a share of the gpu while an image renders
asher Oct 9, 2026
6d08227
test(e2e): the image measurement times chat and an image beside each …
asher Oct 9, 2026
21b4f18
docs(env): shorten the chat share row to fit the table
asher Oct 9, 2026
ae9dba2
feat(image): qwen-image 2.1 turbo samples on its own eight sigmas
asher Oct 9, 2026
11418e7
fix(serve): image routes free a left stream, cap sizes, bound their c…
asher Oct 9, 2026
8116e10
docs(images): shorten the size row to fit the table
asher Oct 9, 2026
eb24163
feat(image): qwen-image residual adds and vae 3x3 convs run on the kq…
asher Oct 9, 2026
5c005ad
feat(serve): image step routes for samplers that run elsewhere, and i…
asher Oct 9, 2026
6cc2637
docs(images): say chat stays responsive beside an image and name the …
asher Oct 9, 2026
f1d76df
fix(serve): let image step tensor bodies past the media gate json check
asher Oct 9, 2026
81dbd1f
feat(serve): image step encode takes refs false to skip the reference…
asher Oct 9, 2026
a198771
docs(images): the encode refs field moves out of the route table
asher Oct 9, 2026
10f7c5c
fix(serve): image step encode keeps each reference image at its own size
asher Oct 9, 2026
9bcfbe1
fix(serve): image step conditionings take comfyui's reference slots
asher Oct 9, 2026
0c01b94
fix(image): the qwen-image block calls its attention output and mlp a…
asher Oct 10, 2026
fe0a550
build(pyright): check the gpu share module
asher Oct 10, 2026
7ddf385
test(image): the qwen-image site gates read the residual op as the ga…
asher Oct 10, 2026
85d3273
fix(e2e): the image steps harness samples z-image on its own schedule
asher Oct 10, 2026
fcac080
feat(serve): image models in /v1/models and image job metrics in /v1/…
asher Oct 10, 2026
75f26c9
fix(image): a qwen3-vl text prompt taps the same with and without the…
asher Oct 10, 2026
16adad9
fix(serve): step routes cap sizes, plan memory, book their caches, en…
asher Oct 10, 2026
4473084
test(serve): the chat pacer caps a pause and starts afresh, wire offs…
asher Oct 10, 2026
b3117fe
feat(image): pull, discover, list, rm and doctor know image models, a…
asher Oct 10, 2026
1748176
feat(launch): comfyui runs with the gmlx node pack, and open-webui tu…
asher Oct 10, 2026
ded574a
fix(image): a quantized norm whose scales follow it in the file loads…
asher Oct 10, 2026
fbb982e
fix(pull): the image fit line names the ram the three parts take, wit…
asher Oct 10, 2026
ad6b846
fix(pull): the plan names the memory class default only for its quant…
asher Oct 10, 2026
0ebee4d
fix(pull): the plan says the qwen-image research license allows no co…
asher Oct 10, 2026
f2e391e
fix(image): the memory plan and the load gate count the dit tensors t…
asher Oct 10, 2026
dccbb28
feat(pull): each memory class pulls the image quants closest to full …
asher Oct 10, 2026
4aff44d
fix(launch): the summary printed before the client starts reaches a p…
asher Oct 10, 2026
381d1ac
docs(image): image generation, comfyui and step route guides, the mem…
asher Oct 10, 2026
6f69ec5
feat(image): a family names the tensors a converter may store flatten…
asher Oct 10, 2026
2f21a9c
feat(image): an encoder spec keeps a tail under the token cap and can…
asher Oct 10, 2026
6bfe876
feat(image): krea 2 fingerprint, variants, encoder tap and schedule
asher Oct 10, 2026
34746fe
feat(image): krea 2 dit module tree and forward, held to diffusers on…
asher Oct 10, 2026
546cd1b
feat(image): krea 2 time vectors run as dense fp32 products, and chec…
asher Oct 10, 2026
321c4f7
test(image): check 2 holds the krea 2 encoder tap to the pipeline's q…
asher Oct 10, 2026
f326e80
feat(image): krea 2 decodes with the qwen-image vae, read in the wan …
asher Oct 10, 2026
2a6fcac
test(image): check 4 holds both krea 2 schedules to diffusers bit for…
asher Oct 10, 2026
bf2fae4
test(image): check 6 holds a whole krea 2 turbo run on the seed's noi…
asher Oct 10, 2026
cb6f37f
feat(image): krea 2 lora key map for the native, diffusers and comfyu…
asher Oct 10, 2026
0fb1716
test(image): check 7 holds a krea 2 step under a comfy-org lora to di…
asher Oct 10, 2026
8637861
feat(serve): krea 2 takes the step contract under the comfy conventio…
asher Oct 10, 2026
0c6a5be
fix(image): krea 2 plans its step from its own measured cells, where …
asher Oct 10, 2026
0d8fd2a
feat(image): pull krea-2-turbo and krea-2 raw with their memory-class…
asher Oct 10, 2026
996cdca
docs(image): krea 2 turbo and raw rows in the model, memory-class, ed…
asher Oct 10, 2026
8a24bcb
docs(benchmarks): krea 2 turbo draws a 1024 image in 23.4 s against c…
asher Oct 10, 2026
c2340b3
fix(rm): an encoder, vae or chat model a discovered image model uses …
asher Oct 10, 2026
f777019
fix(pull): a file at a download path that is not the part is refused …
asher Oct 10, 2026
c68be73
fix(pull): a qwen3-vl chat model without its vision tower is not shar…
asher Oct 10, 2026
97bb2a0
fix(discover): a qwen-image dit pairs with a chat model encoder by id…
asher Oct 10, 2026
e29e5ab
fix(pull): of several text encoders on disk the class default quant w…
asher Oct 10, 2026
cc0f65e
fix(pull): the discovery hint names the quant of the dit it found, an…
asher Oct 10, 2026
9710d4f
fix(pull): the disk check counts the packed vae written beside its so…
asher Oct 10, 2026
2070d98
fix(serve): an image model whose encoder does not fit beside its dit …
asher Oct 10, 2026
fe2d9d6
fix(pull): the fit line, a dit's validation and doctor memory count t…
asher Oct 10, 2026
80dbba8
feat(launch): open-webui turns on image edits when the default image …
asher Oct 10, 2026
422f665
fix(list): --edit lists an image model only when it has the encoder's…
asher Oct 10, 2026
1c55746
docs: image rows for env vars, launch, exit codes, list, rm, doctor a…
asher Oct 10, 2026
945e45a
test(image): a reused vae needs its source digest, doctor names a vae…
asher Oct 10, 2026
00c4022
test(serve): serve admits each krea 2 class default at the size the d…
asher Oct 10, 2026
6c87c1c
feat(pull): a krea 2 pull on 16 gb writes defaults.size 512x512, and …
asher Oct 10, 2026
e82bcb3
docs(images): edit false means no instruction edits, and the edits ro…
asher Oct 10, 2026
3d3c61f
fix(image): a krea 2 raw gguf is refused by name, and pull, docs and …
asher Oct 10, 2026
c78af50
feat(image): a krea 2 dit of unknown weights runs only under variant:…
asher Oct 10, 2026
e46d685
docs(notices): the krea 2 ports from diffusers name commit e0abab83 i…
asher Oct 10, 2026
38870de
fix(pull): the krea 2 license line names its one revenue condition, w…
asher Oct 10, 2026
2bfc8b6
fix(launch): open-webui makes images at the defaults.size of the defa…
asher Oct 10, 2026
dab3431
docs: krea 2 turbo in the readme, changelog, generate family table, s…
asher Oct 10, 2026
fef8069
docs(comfyui): init and the comfyui install come first, the pack's se…
asher Oct 10, 2026
b085adb
fix(pull): an image pull's plan and license line reach a pipe or a fi…
asher Oct 10, 2026
7c71c21
test(image): the identity and load stubs of the edit and models-entry…
asher Oct 10, 2026
9f9902e
fix(serve): a config write reloads a foreground server over http at t…
asher Oct 10, 2026
1cec27e
fix(image): --strength takes 0.01 to 1 as the routes do, and the mask…
asher Oct 10, 2026
0c94fba
fix(pull): the fit line says when an image model's parts fit loaded i…
asher Oct 10, 2026
bfeffc1
docs(images): drop the plan restatement, the chat share measurement, …
asher Oct 10, 2026
f42a41c
test(memfit): the krea 2 step fit holds q8_0 cells and the 640 and 89…
asher Oct 10, 2026
c51d2f7
docs(images): the krea 2 license cell fits the table width
asher Oct 10, 2026
31fbf2a
test(image): krea 2 check 3 on check 8's trajectory with the exact an…
asher Oct 10, 2026
17bcd39
test(image): krea 2 check 7 exact and site gates on the comfy-org and…
asher Oct 10, 2026
95fd3a4
test(image): krea 2 check 3 exact faults that call every leaf, and th…
asher Oct 10, 2026
49f0710
test(image): krea 2 oracle scripts name the trajectory fixtures they …
asher Oct 10, 2026
21062b1
test(image): krea 2 exact gate free rows at twice gmlx's own fp32 flo…
asher Oct 10, 2026
9c18775
test(image): krea 2 exact gate velocity at twice gmlx's own fp32 floo…
asher Oct 10, 2026
5bac9f0
test(docs): the env doc tripwire exempts the settings variable only t…
asher Oct 10, 2026
efefa23
test(spec): the long context reference takes its head on the last row…
asher Oct 10, 2026
2ba81d6
test(serve): the seam restore puts back the media salt flag and apc w…
asher Oct 10, 2026
ef4c433
perf(spec): the mtp head waits for the accept before its first draft …
asher Oct 10, 2026
02a9802
fix(pull): the help and docs name only image models pull knows, dropp…
asher Oct 10, 2026
3de776d
fix(pull): an image model this chip does not run is refused before an…
asher Oct 10, 2026
7715af6
fix(image): the float16 refusal says z-image misses the reference che…
asher Oct 10, 2026
9265ce3
docs(readme): the readme and installation say image generation needs …
asher Oct 10, 2026
c4e7bea
docs(api): image edits take a form or a json body
asher Oct 10, 2026
5f17f87
docs(glossary): dit, vae, text encoder, steps, guidance and sampler
asher Oct 10, 2026
3424363
docs(images): rewrite images.md for a first image, with the api refer…
asher Oct 10, 2026
e14445e
docs(internals): checking a new architecture for kv cache copies at d…
asher Oct 10, 2026
fe0031e
docs(comfyui): install comfyui from scratch, run a first workflow and…
asher Oct 10, 2026
54fd2c9
docs(troubleshooting): an image generation entry for each message a f…
asher Oct 10, 2026
ce25a71
docs(cli): image generate says what it does to fit, and the step rout…
asher Oct 10, 2026
6e3e391
docs(config): plain words for the image caches and the chat share
asher Oct 10, 2026
3d7ca98
docs(quickstart): point to image generation and its loras
asher Oct 10, 2026
cc86f4d
fix(serve): a request that names an entry adapter sets its strength i…
asher Oct 10, 2026
4508b1f
fix(load): glm-5.3-flash ggufs with llama.cpp's glm5-next arch name l…
asher Oct 10, 2026
1285573
test(load): the adapter export table covers the glm5-next arch name
asher Oct 10, 2026
28965d1
fix(vlm): glm-5.3-flash mmproj files with llama.cpp's glm5v projector…
asher Oct 10, 2026
7fe41ce
feat(load): one rope scaling resolver with llama.cpp's rules and table
asher Oct 10, 2026
a9d34ff
feat(load): llama.cpp rope scaling flags and config block reach every…
asher Oct 10, 2026
53e0d67
fix(cache): the prompt cache on disk keeps kv made under each rope sc…
asher Oct 10, 2026
61debd5
feat(models): qwen4exp attention, indexer and image positions rotate …
asher Oct 10, 2026
efe32c8
fix(load): mistral3 takes its rope scaling type from the header key, …
asher Oct 10, 2026
795b660
feat(load): a rope swap after the build gives class-built architectur…
asher Oct 10, 2026
27e5ef0
feat(models): the qwen 3.5 family's multi-axis rope takes the resolve…
asher Oct 10, 2026
5a8766e
feat(spec): a dflash drafter takes the whole rope scaling of its own …
asher Oct 10, 2026
2226ce7
feat(models): deepseek4 and deepseek41 compressed layers take the res…
asher Oct 10, 2026
9b36ab8
feat(load): hy_v3, hyv4, muse-glimmer, minimax-m3, falcon-h1, granite…
asher Oct 10, 2026
d971950
fix(load): gemma3 full layers take the header's linear rope factor
asher Oct 10, 2026
e03a7f2
feat(load): gemma and gemma2 take the rope scaling options, with gemm…
asher Oct 10, 2026
9366455
feat(load): gemma4 full layers scale their proportional rope pairs
asher Oct 10, 2026
69675b0
feat(spec): the gemma4 assistant rotates as its target
asher Oct 10, 2026
f560188
docs(models): a long context page covers the rope scaling flags, the …
asher Oct 10, 2026
0c2b122
fix(spec): native mtp heads of the qwen 3.5 family and hy v3 rotate w…
asher Oct 10, 2026
04ac33b
fix(spec): a dflash or dspark drafter takes the run's rope options ov…
asher Oct 10, 2026
2e7db04
fix(models): deepseek4 and deepseek41 keep the class rope table when …
asher Oct 10, 2026
ca7937a
fix(load): a load with hf_source refuses the rope scaling options it …
asher Oct 10, 2026
c91df25
fix(cache): the prompt cache on disk and a distill cache key the reso…
asher Oct 10, 2026
c784ed4
refactor(load): drop the unused with_base and the beta keys of archs …
asher Oct 10, 2026
616adac
docs(models): long context leads with factor 2 and its 300k test, and…
asher Oct 10, 2026
ecd6a45
fix(load): the qwen3 omni text tower under the thinker takes the rope…
asher Oct 10, 2026
fadaba7
test(models): fused hyper-connection decode matches the kernel pair b…
asher Oct 10, 2026
9308d9f
docs(changelog): the glm5-next load fix ships in 0.4.24, so the 0.5 n…
asher Oct 10, 2026
c4f5b6f
build(pyright): gate the rope swap module, with its override base typed
asher Oct 10, 2026
4678c86
fix(run): bound the mlx buffer cache in run and chat as serve does
asher Oct 10, 2026
b0ecc59
test(serve): the media salt seam test finds each salt layer anywhere …
asher Oct 10, 2026
6b3d2d5
perf(models): run each hyper-connection cycle as the two-kernel pair …
asher Oct 10, 2026
6d70f5a
docs(changelog): add the released 0.4.24 section
asher Oct 10, 2026
3bdfeb7
fix(spec): release the last prefill chunk's logits after the first token
asher Oct 10, 2026
c1e955f
fix(spec): size the prompt kv once in the owned prefill instead of pe…
asher Oct 10, 2026
cf62899
test(docs): the long context config check reads the page's factor 2 e…
asher Oct 11, 2026
c4db104
test(image): give the empty negative prompt a toy row in the via-step…
asher Oct 11, 2026
cadf0cd
build(deps): require mlx 0.32.3
asher Oct 11, 2026
26e637f
test(image): the tiled encode check allows the tf32 rounding of the e…
asher Oct 11, 2026
ee44495
fix(gemma4): skip_logits leaves out the head, as the qwen3_5 forward …
asher Oct 11, 2026
73557bc
test(spec): first-token and greedy checks accept a fork where the bar…
asher Oct 11, 2026
bc00200
fix(models): qwen4exp and glm5-next skip_logits leaves out the head, …
asher Oct 11, 2026
f020f0c
test(spec): the fork check replays the engine's recorded prefill chun…
asher Oct 11, 2026
3b94c43
test(spec): KQUANT_TEST_MTP_STREAM=experts loads the tier 3 target as…
asher Oct 11, 2026
2ae9630
fix(models): deepseek-v4 and the glm5-next vision container skip_logi…
asher Oct 11, 2026
e1e9e9d
test(spec): the step-97 chunk record stays inside the env-override test
asher Oct 11, 2026
f8c0329
fix(cache): the prompt cache counts streamed weight bytes as free roo…
asher Oct 11, 2026
cf9a34e
fix(cache): a qwen4exp prompt-cache checkpoint restores from disk aft…
asher Oct 11, 2026
9499a3c
chore(vendor): the manifest records the edited mlx-vlm prompt cache h…
asher Oct 11, 2026
eb7b52a
fix(cache): a qwen4exp prompt-cache checkpoint written at another blo…
asher Oct 11, 2026
4908f2c
fix(cache): a qwen4exp prompt-cache skeleton keys on the block size, …
asher Oct 11, 2026
46cf9fb
feat(comfyui): the ComfyUI node pack ships inside gmlx, with UI-forma…
asher Oct 11, 2026
ae9d35b
fix(comfyui): the node pack's Apache-2.0 license is stated in the roo…
asher Oct 11, 2026
f0fbc89
feat(comfyui): gmlx comfyui install, uninstall and status put the nod…
asher Oct 11, 2026
09ab1d2
feat(comfyui): the gmlx nodes find gmlx where install recorded it, lo…
asher Oct 11, 2026
e8ec0c5
docs(comfyui): the ComfyUI guide installs the node pack with gmlx com…
asher Oct 11, 2026
bcf055b
ci(comfyui): the node pack's suites run against real ComfyUI weekly, …
asher Oct 11, 2026
424b527
test(process-state): the per-test comfyui settings path is not read a…
asher Oct 11, 2026
4d0a208
fix(comfyui): gmlx comfyui keeps a settings file it cannot read, refr…
asher Oct 11, 2026
011e2f5
fix(launch): gmlx launch comfyui exits 69 when no ComfyUI is there, l…
asher Oct 11, 2026
4e9a20b
fix(comfyui): the gmlx nodes check the server again at each run, give…
asher Oct 11, 2026
2066049
fix(comfyui): stand-in nodes say to run gmlx comfyui install after th…
asher Oct 11, 2026
0d2efbe
fix(comfyui): the status node says ComfyUI-Manager lists the gmlx nod…
asher Oct 11, 2026
9e5a753
fix(comfyui): gmlx serve refreshes the nodes while a recorded ComfyUI…
asher Oct 11, 2026
cd7256a
ci(comfyui): the node pack runs on the oldest ComfyUI it supports and…
asher Oct 11, 2026
b015f34
docs(comfyui): the ComfyUI guide opens with the install and a referen…
asher Oct 11, 2026
e5c7d4a
docs(comfyui): troubleshooting covers each status, stand-in, step con…
asher Oct 11, 2026
95ee9d7
fix(comfyui): install clears a gone ComfyUI from the record when it f…
asher Oct 11, 2026
8aa6654
docs(comfyui): a gone ComfyUI's entry says what install then does, an…
asher Oct 11, 2026
95ca204
ci(comfyui): the node pack job also runs when the path from python -m…
asher Oct 11, 2026
e86068e
fix(image): a qwen-image 2.1 gguf labeled qwen_image21 and a krea 2 g…
asher Oct 11, 2026
b69e2da
fix(spinner): the spinner's exit is typed to never suppress an exception
asher Oct 11, 2026
4a8199e
chore(merge): main 0.4.24 into the 0.5 line
asher Oct 11, 2026
b26b138
fix(pull): gmlx pull and check refuse an image gguf whose tensors gml…
asher Oct 11, 2026
246ecd5
fix(comfyui): install records no gmlx whose shebang names another pyt…
asher Oct 11, 2026
aebfaae
ci(comfyui): the node pack job also runs when the commands package in…
asher Oct 11, 2026
4bce250
fix(comfyui): install records a uv relocatable venv's gmlx again and …
asher Oct 11, 2026
d68530d
fix(pull): gmlx pull and check give gmlx image's reason for an image …
asher Oct 11, 2026
fd02e4c
fix(comfyui): the loaders list the server's image models and show its…
asher Oct 11, 2026
a305c92
fix(serve): a config speech service whose extra is missing warns and …
asher Oct 12, 2026
4a8916a
fix(serve): only a missing extra turns a speech service off, and relo…
asher Oct 12, 2026
2158fd3
fix(serve): the step model list names the default image model
asher Oct 12, 2026
ddf601c
fix(comfyui): pick the server by handshake, list models in the backgr…
asher Oct 12, 2026
fcbaa81
fix(serve): a sighup reload names the services a missing extra left off
asher Oct 12, 2026
81ed348
fix(comfyui): only a server without step routes is not gmlx; cancel s…
asher Oct 12, 2026
ecb5c53
fix(comfyui): the model list keeps 10 s, an unknown server state wait…
asher Oct 12, 2026
c810054
fix(stream): --stream-experts and stream: experts stream a model unde…
asher Oct 12, 2026
793ce03
fix(comfyui): the model list holds no unpulled model, only the defaul…
asher Oct 12, 2026
baae280
fix(stream): credit a forced stream's experts in the headroom
asher Oct 12, 2026
8acb265
fix(stream): latch both stream flags for the load-time warm touch
asher Oct 12, 2026
551b854
fix(stream): a metal init error leaves no stream budget
asher Oct 12, 2026
ba7dcc4
fix(stream): discovery marks by text bytes and sync rechecks the mark
asher Oct 12, 2026
91d5914
fix(stream): stream flag docs name both budget regimes
asher Oct 12, 2026
b47092e
fix(stream): headroom credits the table once and drops unmapped stacks
asher Oct 12, 2026
643e637
fix(cli): latch the stream flags for chat too
asher Oct 12, 2026
18a5216
fix(serve): sync drops only an experts mark and keeps the lines after it
asher Oct 12, 2026
3533228
fix(stream): deduct only the uncredited share and end a keyless build…
asher Oct 12, 2026
17bde22
fix(stream): any install accounting ends the build credit, an unmap l…
asher Oct 12, 2026
abbad96
fix(stream): the build credit ends after the install's last share, an…
asher Oct 12, 2026
6eed45a
fix(serve): a table-only stream build prices its resident experts
asher Oct 12, 2026
c2145df
fix(serve): a stream build prices its env window and refits when the …
asher Oct 12, 2026
c49df97
fix(serve): a refit after a build releases evicted image pipelines ou…
asher Oct 12, 2026
3029e30
fix(serve): a build that must evict an image gone idle takes the imag…
asher Oct 12, 2026
4f211e3
fix(serve): unload, clear and the idle reaper release an image gone i…
asher Oct 12, 2026
9d44f2c
fix(serve): the image worker defer names the count cap on a pool with…
asher Oct 12, 2026
8b83a94
fix(types): read_video takes OpenCV through the video extra helper, s…
asher Oct 12, 2026
388f7d8
test(serve): the media gate and video tests run without OpenCV, the d…
asher Oct 12, 2026
cc91049
fix(serve): a cached snapshot missing some files loads as it did befo…
asher Oct 12, 2026
fa625d6
test: a conftest's fixtures reach its tests when pytest 9.1 is given …
asher Oct 12, 2026
d9b0ac6
test: unit tests see one fixed 128 GB test Mac, so a small CI runner …
asher Oct 12, 2026
f0b7c84
docs(testing): what a test needs to pass in CI, and how to run the su…
asher Oct 12, 2026
901e7e7
test: the test Mac reports its kernel counters too, and a test's arme…
asher Oct 12, 2026
105e665
test: every test sees the 7.5 GB CI runner unless it declares a large…
asher Oct 12, 2026
30f47b2
test: the pacer order, opencv hint and hd512 route tests no longer de…
asher Oct 12, 2026
a4a5cb5
test: a GPU run keeps the real chip name and architecture, so kernel …
asher Oct 12, 2026
f25e8e4
test(comfyui-pack): the step log names each failing test with its tra…
asher Oct 12, 2026
c50402c
fix(serve): a launch session socket leaves room for the relay's close…
asher Oct 12, 2026
55ce444
test(comfyui-pack): the interrupt test interrupts once a step is unde…
asher Oct 12, 2026
99f900c
ci: the test job spreads the suite over one worker per core
asher Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,34 @@ jobs:
brew audit --strict --formula asher/gmlx/gmlx
brew install asher/gmlx/gmlx
brew test asher/gmlx/gmlx
- name: The ComfyUI node pack installs from the formula
# gmlx comfyui install finds the pack inside the Homebrew install,
# copies it, links it into a fake ComfyUI folder and records the
# install kind and Homebrew's gmlx link. Uninstall removes the link
# again. The copy and the record go to the runner's temporary folder.
run: |
export XDG_DATA_HOME="$RUNNER_TEMP/xdg"
export GMLX_COMFY_SETTINGS="$RUNNER_TEMP/comfyui.json"
comfy="$RUNNER_TEMP/ComfyUI"
mkdir -p "$comfy/custom_nodes"
touch "$comfy/main.py"
tested=$( (gmlx comfyui status --json || true) \
| python3 -c 'import json, sys; print(json.load(sys.stdin)["comfyui_tested"])')
echo "__version__ = \"$tested\"" > "$comfy/comfyui_version.py"
gmlx comfyui install --comfyui-dir "$comfy"
test -f "$comfy/custom_nodes/comfyui-gmlx/__init__.py"
test -f "$comfy/custom_nodes/comfyui-gmlx/example_workflows/z-image-turbo-t2i.json"
# status exits 1 on a problem; the check below names it.
gmlx comfyui status --json > "$RUNNER_TEMP/comfyui-status.json" || true
python3 - "$RUNNER_TEMP/comfyui-status.json" "$(brew --prefix)/bin/gmlx" <<'EOF'
import json, sys
s = json.load(open(sys.argv[1]))
assert s["copy"] == "current" and s["gmlx_install"] == "homebrew", s
assert s["gmlx_command"] == sys.argv[2], (s["gmlx_command"], sys.argv[2])
assert not s["problems"], s["problems"]
EOF
gmlx comfyui uninstall
test ! -e "$comfy/custom_nodes/comfyui-gmlx"
- name: Revert the formula
if: failure()
working-directory: tap
Expand Down
204 changes: 184 additions & 20 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ name: tests
on:
push:
branches: [main]
# A release tag runs only the comfyui-pack job.
tags: ["v*.*.*"]
pull_request:
schedule:
# Weekly run against the newest in-range mlx-lm / mlx-vlm releases, so a
# dependency release that breaks the seam patches surfaces without a push.
# Weekly: the drift report (the drift job), what the newest mlx-vlm and
# mlx-lm releases change in the copy under gmlx/_vendor, and the
# comfyui-pack job against ComfyUI's newest release and master. The test
# and lint jobs do not run on the schedule.
- cron: "0 6 * * 1"

concurrency:
Expand All @@ -15,6 +19,7 @@ concurrency:

jobs:
test:
if: github.event_name != 'schedule' && github.ref_type != 'tag'
# macos-26, not older images: the published mlx-kquant wheels are tagged
# macosx_26_0_arm64 (built with MACOSX_DEPLOYMENT_TARGET=26.2 for the
# Xcode 26.5 SDK miscompile workaround) - an older runner can't install
Expand All @@ -40,23 +45,24 @@ jobs:
cargo test --locked
- name: Install
run: |
pip install "mlx==0.32.1"
pip install "mlx==0.32.3"
# Wheel, not sdist. Must satisfy the pyproject floor or the
# editable install upgrades it; tests/test_ci_pins.py gates that.
pip install "mlx-kquant==0.4.18"
# `assistant` pulls the MCP SDK: without it the stdio tool-server
# tests (env isolation especially) importorskip themselves away.
pip install -e ".[vlm,chat,assistant]" pytest httpx build
pip install "mlx-kquant==0.5.0"
# `all` brings the chat, voice and assistant extras, so their tests
# run instead of skipping themselves away.
pip install -e ".[all]" pytest pytest-xdist httpx build
- name: Import canary
# A broken package import must fail the build loudly — the test files
# A broken package import must fail the build loudly. The test files
# importorskip only true optionals, never gmlx itself.
run: python -c "import gmlx, gmlx.commands.cli, gmlx.serve.server, gmlx.serve.patches, gmlx.spec.engine, gmlx.spec.speculative"
- name: Wheel completeness
# The editable install above can't catch packaging drops: build the
# wheel (via sdist, so a stale build/ dir can't leak deleted modules
# into it) and require it to ship exactly the tracked package modules,
# plus every tracked file matching the pyproject package-data globs
# (upstream_seams.json, the vendored misaki data).
# (the vendored misaki data, the deepseek_v41 chat template, the
# ComfyUI node pack's LICENSE and workflows).
run: |
python -m build
python - <<'EOF'
Expand Down Expand Up @@ -89,21 +95,23 @@ jobs:
missing_data = [d for d in data if d not in shipped]
if missing_data:
sys.exit(f"wheel is missing package-data files: {missing_data}")
# The ComfyUI node pack: every file, its workflows and LICENSE.
pack = [t for t in tracked_all if t.startswith("gmlx/comfyui_pack/")]
missing_pack = [p for p in pack if p not in shipped]
if not pack or missing_pack:
sys.exit(f"wheel is missing ComfyUI node pack files: {missing_pack}")
print(f"wheel ships all {len(tracked)} tracked modules"
f" + {len(data)} package-data files, nothing else")
EOF
- name: Arch coverage doc
# docs/arch-coverage.md is generated; a new arch (or an mlx-lm release
# renaming a model_type - the weekly cron catches those) must not leave
# the committed doc lying about what loads.
# docs/arch-coverage.md is generated; a new arch must not leave the
# committed doc lying about what loads.
run: python scripts/check-coverage.py --check --strict
- name: Seam drift check (pyright)
# Pyright infers upstream signatures from the installed mlx-vlm /
# mlx-lm source, so it needs this job's environment, not the
# deps-free lint job. One interpreter is enough: the checked
# surface does not vary by Python version. On the weekly cron a
# new upstream release can fail this step with no repo change;
# that is the drift signal, handled per docs/internals/upstream-upgrades.md.
- name: Type check (pyright)
# pyright checks gmlx's calls into the copied mlx-vlm and mlx-lm, whose
# imports of mlx, transformers and the rest only this job installs, not
# the deps-free lint job. One interpreter is enough: the checked
# surface does not vary by Python version.
if: matrix.python-version == '3.12'
run: |
pip install "pyright[nodejs]==1.1.414"
Expand All @@ -113,11 +121,41 @@ jobs:
# Hosted runners have no dependable Metal device; the conftest flips
# the default device to CPU when this is set.
KQUANT_FORCE_CPU: "1"
run: pytest -q
# One worker per core, so a failure shows in minutes, not an hour.
run: pytest -q -rfE -n auto
- name: No stock mlx-vlm or mlx-lm
# No requirement of gmlx with all its extras installs mlx-vlm, mlx-lm
# or mlx-embeddings, which requires a stock mlx-vlm, and the copy's
# version files name the releases the manifest records.
run: |
python - <<'EOF'
import importlib.metadata as md, json, re, sys
found = []
for dist in ("mlx-vlm", "mlx-lm", "mlx-embeddings"):
try:
found.append(f"{dist} {md.version(dist)}")
except md.PackageNotFoundError:
pass
problems = [f"installed: {d}" for d in found]
manifest = json.load(open("gmlx/_vendor/manifest.json"))
files = {"mlx_vlm": "version.py", "mlx_lm": "_version.py"}
for pkg, info in manifest["packages"].items():
text = open(f"gmlx/_vendor/{pkg}/{files[pkg]}").read()
m = re.search(r"__version__\s*=\s*[\"']([^\"']+)", text)
if m is None or m.group(1) != info["version"]:
problems.append(f"{pkg}: version file does not say "
f"{info['version']}")
if problems:
sys.exit("\n".join(problems))
print("no stock mlx-vlm, mlx-lm or mlx-embeddings; the copy holds",
", ".join(f"{p} {i['version']}"
for p, i in manifest["packages"].items()))
EOF

guest-entry:
# The static Linux binary `gmlx launch --container` ships, built the way
# the release job builds it and tested as is, without a VM.
if: github.ref_type != 'tag'
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v6
Expand All @@ -141,6 +179,7 @@ jobs:
python scripts/check_guest_entry_dist.py

lint:
if: github.event_name != 'schedule' && github.ref_type != 'tag'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand All @@ -150,6 +189,15 @@ jobs:
# Pinned: a new ruff's new default rules shouldn't fail an untouched repo.
- run: pip install ruff==0.15.20
- run: ruff check .
- name: Copy check
# gmlx/_vendor holds mlx-vlm and mlx-lm as copied. Every reference to
# them must name the copy, every copied file must match its manifest
# entry, and ruff's E9, F821 and F811 rules must find only what the
# baseline records.
run: |
python scripts/vendor_upstream.py rewrite --check
python scripts/vendor_upstream.py verify
python scripts/vendor_upstream.py lint
- run: python scripts/check-docs.py
- name: Docs site build
# The release workflow publishes this site. --strict fails on a link,
Expand All @@ -158,3 +206,119 @@ jobs:
python -m pip install --upgrade pip
pip install --group docs
mkdocs build --strict

drift:
# What the newest mlx-vlm and mlx-lm releases change in the copy, as a
# Markdown report in the run summary. It informs a port and never fails
# the run; see docs/internals/upstream-upgrades.md.
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Drift report
# pipefail: a failed report fails the step, not only tee.
run: |
set -o pipefail
scripts/upstream_canary.sh | tee -a "$GITHUB_STEP_SUMMARY"

pack-changes:
# Whether a push or pull request changes the ComfyUI node pack, its
# tests, the verb that installs it, the path python -m gmlx takes to that
# verb or this workflow, which the comfyui-pack job needs outside the
# schedule and tags.
if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref_type == 'branch')
runs-on: ubuntu-latest
outputs:
pack: ${{ steps.diff.outputs.pack }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- id: diff
env:
BASE: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
run: |
# A new branch has no usable base, so its push runs the job.
if git cat-file -e "$BASE^{commit}" 2>/dev/null; then
changed=$(git diff --name-only "$BASE" HEAD -- gmlx/comfyui_pack tests/comfyui_pack \
gmlx/commands/comfyui.py gmlx/commands/cli.py gmlx/commands/__init__.py \
gmlx/__init__.py gmlx/__main__.py \
.github/workflows/test.yml)
else
changed=all
fi
echo "pack=$([ -n "$changed" ] && echo true || echo false)" >> "$GITHUB_OUTPUT"

comfyui-pack:
# The ComfyUI node pack against real ComfyUI and the stub server in
# tests/comfyui_pack, loaded through the link that `gmlx comfyui install`
# makes. Each run clones ComfyUI and installs torch, so the job runs on
# the weekly schedule, on a release tag, and when a push or pull request
# changes the pack or its tests. It checks the ComfyUI commit that the
# release tests pin, the oldest ComfyUI release the pack supports, as
# gmlx/comfyui_pack/version.py names it, and a newer release: on the
# schedule the newest tag, otherwise the version that version.py names
# as tested. On the schedule it also runs ComfyUI master, which only
# reports.
needs: [pack-changes]
if: >-
${{ !cancelled() && (github.event_name == 'schedule'
|| github.ref_type == 'tag'
|| needs.pack-changes.outputs.pack == 'true') }}
runs-on: macos-26
timeout-minutes: 60
continue-on-error: ${{ matrix.comfyui == 'master' }}
strategy:
fail-fast: false
matrix:
comfyui: [pin, floor, release, master]
exclude:
- comfyui: ${{ github.event_name == 'schedule' && 'none' || 'master' }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: ComfyUI and its requirements
env:
PIN: 8d534945ebd53cff61e8def81757c6a6c1b9cf2d
REPO: https://github.com/comfyanonymous/ComfyUI
run: |
case "${{ matrix.comfyui }}" in
pin) ref=$PIN ;;
floor) ref=v$(sed -n 's/^COMFYUI_FLOOR = "\(.*\)"$/\1/p' gmlx/comfyui_pack/version.py) ;;
release)
if [ "${{ github.event_name }}" = schedule ]; then
ref=$(git ls-remote --tags --refs "$REPO" 'v*' | sed 's#.*refs/tags/##' | sort -V | tail -1)
else
ref=v$(sed -n 's/^COMFYUI_TESTED = "\(.*\)"$/\1/p' gmlx/comfyui_pack/version.py)
fi ;;
master) ref=master ;;
esac
git init -q comfyui
git -C comfyui fetch -q --depth 1 "$REPO" "$ref"
git -C comfyui checkout -q FETCH_HEAD
echo "ComfyUI $ref at $(git -C comfyui rev-parse --short HEAD)" >> "$GITHUB_STEP_SUMMARY"
python -m venv comfyui/.venv
comfyui/.venv/bin/pip install -q -r comfyui/requirements.txt
- name: Install the pack with gmlx
# The comfyui verb imports none of gmlx's dependencies, so it runs
# from the checkout.
run: python -m gmlx comfyui install --comfyui-dir "$PWD/comfyui"
- name: Unit and headless suites
run: |
comfyui/.venv/bin/python tests/comfyui_pack/run_tests.py \
--comfy "$PWD/comfyui" --label "${{ matrix.comfyui }}" --out "$PWD/pack-results" \
--pack "$PWD/comfyui/custom_nodes/comfyui-gmlx"
- name: Report
if: always()
run: cat pack-results/*.md >> "$GITHUB_STEP_SUMMARY" 2>/dev/null || true
- uses: actions/upload-artifact@v7
if: always()
with:
name: comfyui-pack-${{ matrix.comfyui }}
path: pack-results
Loading
Loading