Sub-ticket of epic #346, Mac workstream. Foundation for #355 and the M2–M4 tickets. Based on the MPS portability audit (comment on #355).
What: art_pipe has no device abstraction — every backend independently does cuda-if-available-else-cpu and installs CUDA wheels unconditionally. Add a cuda | mps | cpu seam so macOS (Apple Silicon, PyTorch MPS) is a first-class target. This is generic, upstreamable work — plan to PR it to Eric's ProArt repo rather than fork.
Scope (exact touchpoints from the audit):
src/artpipe/hardware.py — add torch.backends.mps.is_available() branch to detect() (:183-207); report unified memory as VRAM; no nvidia-smi path on Darwin (:104-166)
src/artpipe/main.py::_check_gpu_compat (:22-70) — treat MPS as GPU-available; skip sm/TORCH_CUDA_ARCH_LIST checks on Darwin
src/artpipe/torch_compat.py — Darwin branch: default PyPI torch (ships MPS), no cu-index mapping
Shared device helper (e.g. artpipe.device.resolve() returning device str + preferred dtype) and adopt it in the 13 backends that hardcode "cuda": flux_schnell.py:67, sdxl_lightning.py:58, sdxl_turbo.py:41, sd_turbo_tex.py:60, sf3d.py:44, text3d.py:62, triposr.py:46, triposg.py:46, instantmesh.py:68, shap_e.py:123, mdm.py:87 (int 0 — needs mapping), hymotion.py:101, rignet_infer.py:325; fix instantmesh.py:87 unconditional fp16
cv/checks.py:79-83 + cv/analysis.py:203-217 — mps branch for SigLIP/CLIP
Blender: src/artpipe/blender/headless/_helpers.py:137-165 — set cprefs.compute_device_type = "METAL" on macOS before refresh_devices() (today Cycles silently falls back to CPU)
Guard torch.cuda.empty_cache() call sites (pattern from trellis-mac patches/mps_compat.py)
Note: no Metal kernels in this ticket — CUDA-extension backends stay CUDA-only and must fail with a clear "requires CUDA" message on Mac (stub pattern from trellis-mac backends/stubs.py), not ImportError crashes.
Acceptance: on an Apple-Silicon Mac, artpipe setup installs stock torch, artpipe launch passes the GPU check reporting MPS + unified memory, a Tier-A backend (e.g. sdxl_lightning) runs on mps, a blocked backend (e.g. triposg) fails with the clear message, and Blender Cycles renders on Metal. CUDA behavior on Linux unchanged.
Sub-ticket of epic #346, Mac workstream. Foundation for #355 and the M2–M4 tickets. Based on the MPS portability audit (comment on #355).
**What:** art_pipe has no device abstraction — every backend independently does `cuda-if-available-else-cpu` and installs CUDA wheels unconditionally. Add a `cuda | mps | cpu` seam so macOS (Apple Silicon, PyTorch MPS) is a first-class target. This is generic, upstreamable work — plan to PR it to Eric's ProArt repo rather than fork.
**Scope (exact touchpoints from the audit):**
- [ ] `src/artpipe/hardware.py` — add `torch.backends.mps.is_available()` branch to `detect()` (:183-207); report unified memory as VRAM; no `nvidia-smi` path on Darwin (:104-166)
- [ ] `src/artpipe/main.py::_check_gpu_compat` (:22-70) — treat MPS as GPU-available; skip sm/`TORCH_CUDA_ARCH_LIST` checks on Darwin
- [ ] `src/artpipe/torch_compat.py` — Darwin branch: default PyPI torch (ships MPS), no cu-index mapping
- [ ] `src/artpipe/venv_setup.py` (:257-320, defaults :8-9) + `bootstrap.py` (:23,78) — on Darwin ignore `torch_index_url`, install stock torch; per-OS manifest override convention (e.g. `torch_index_url_darwin: ""`)
- [ ] Shared device helper (e.g. `artpipe.device.resolve()` returning device str + preferred dtype) and adopt it in the 13 backends that hardcode `"cuda"`: `flux_schnell.py:67`, `sdxl_lightning.py:58`, `sdxl_turbo.py:41`, `sd_turbo_tex.py:60`, `sf3d.py:44`, `text3d.py:62`, `triposr.py:46`, `triposg.py:46`, `instantmesh.py:68`, `shap_e.py:123`, `mdm.py:87` (int `0` — needs mapping), `hymotion.py:101`, `rignet_infer.py:325`; fix `instantmesh.py:87` unconditional fp16
- [ ] `cv/checks.py:79-83` + `cv/analysis.py:203-217` — mps branch for SigLIP/CLIP
- [ ] Blender: `src/artpipe/blender/headless/_helpers.py:137-165` — set `cprefs.compute_device_type = "METAL"` on macOS before `refresh_devices()` (today Cycles silently falls back to CPU)
- [ ] Guard `torch.cuda.empty_cache()` call sites (pattern from trellis-mac `patches/mps_compat.py`)
**Note:** no Metal kernels in this ticket — CUDA-extension backends stay CUDA-only and must fail with a clear "requires CUDA" message on Mac (stub pattern from trellis-mac `backends/stubs.py`), not ImportError crashes.
**Acceptance:** on an Apple-Silicon Mac, `artpipe setup` installs stock torch, `artpipe launch` passes the GPU check reporting MPS + unified memory, a Tier-A backend (e.g. sdxl_lightning) runs on `mps`, a blocked backend (e.g. triposg) fails with the clear message, and Blender Cycles renders on Metal. CUDA behavior on Linux unchanged.
Implemented on local branch feature/device-abstraction-mps in art_pipe (commit a186626, +384/−82 across 25 files). All scope items done: artpipe/device.py (resolve() cuda>mps>cpu + guarded empty_cache(), lazy-torch so the stdlib-only server still imports), hardware detect/live_stats MPS branch (Apple GPU + unified-memory-as-VRAM), _check_gpu_compat MPS path, Darwin torch-index handling in torch_compat/venv_setup/bootstrap (+ optional torch_index_url_darwin manifest key), all 13 hardcoded-cuda backends moved to the shared helper (incl. mdm int-device fix and instantmesh unconditional-fp16 fix), clear requires-CUDA guards on trellis/unirig/triposg/hunyuan3d_paint, SigLIP/CLIP mps branch, Blender Cycles METAL enable on macOS.
Verified on the M5 Max (128 GB): pytest 574 passed / 10 skipped / 0 failed; resolve() → ('mps', float16); hardware.detect() → "Apple M5 Max GPU", 131072 MB, mps_available: true; python -m artpipe serve/hardware endpoint returns the Apple GPU. Audit line-drift corrections and a real pre-existing bug fixed en route (detect() force-set cuda_available=True for any GPU entry) are noted in the commit.
Blocked on a decision: art_pipe's origin is Eric's server (clam.local:3000/EricSpiker/art_pipe) — not pushing to someone else's Gitea without Joey's go-ahead. Options: (a) push branch + open PR on Eric's Gitea if Joey has an account/fork there, (b) mirror art_pipe into git.spikersoft.com and PR there, then upstream later. Runtime model validation on MPS is #357 scope.
Working-tree note: the checkout has repo-wide CRLF noise (Windows-origin) plus an uncommitted README author-handle edit — left untouched; the commit was kept EOL-clean for upstreamability.
Implemented on local branch `feature/device-abstraction-mps` in art_pipe (commit `a186626`, +384/−82 across 25 files). All scope items done: `artpipe/device.py` (`resolve()` cuda>mps>cpu + guarded `empty_cache()`, lazy-torch so the stdlib-only server still imports), hardware detect/live_stats MPS branch (Apple GPU + unified-memory-as-VRAM), `_check_gpu_compat` MPS path, Darwin torch-index handling in torch_compat/venv_setup/bootstrap (+ optional `torch_index_url_darwin` manifest key), all 13 hardcoded-cuda backends moved to the shared helper (incl. mdm int-device fix and instantmesh unconditional-fp16 fix), clear requires-CUDA guards on trellis/unirig/triposg/hunyuan3d_paint, SigLIP/CLIP mps branch, Blender Cycles METAL enable on macOS.
**Verified on the M5 Max (128 GB):** pytest 574 passed / 10 skipped / 0 failed; `resolve()` → `('mps', float16)`; `hardware.detect()` → "Apple M5 Max GPU", 131072 MB, `mps_available: true`; `python -m artpipe serve` `/hardware` endpoint returns the Apple GPU. Audit line-drift corrections and a real pre-existing bug fixed en route (`detect()` force-set `cuda_available=True` for any GPU entry) are noted in the commit.
**Blocked on a decision:** art_pipe's `origin` is Eric's server (`clam.local:3000/EricSpiker/art_pipe`) — not pushing to someone else's Gitea without Joey's go-ahead. Options: (a) push branch + open PR on Eric's Gitea if Joey has an account/fork there, (b) mirror art_pipe into git.spikersoft.com and PR there, then upstream later. Runtime model validation on MPS is #357 scope.
Working-tree note: the checkout has repo-wide CRLF noise (Windows-origin) plus an uncommitted README author-handle edit — left untouched; the commit was kept EOL-clean for upstreamability.
Resolved in spikersoft-artpipe PR #1 (merged to main — ProArt now lives at spikerj/spikersoft-artpipe per the mirror decision). The cuda/mps/cpu device seam: artpipe.device.resolve() adopted across all 13 hardcoded-cuda backends, MPS-aware hardware detect/live_stats/_check_gpu_compat, Darwin torch installs (stock PyPI, manifest override key), clear requires-CUDA guards on trellis/unirig/triposg/hunyuan3d_paint, SigLIP/CLIP mps, Blender Cycles METAL enable. Validated across six doc slices on the M5; 682 pytest green at merge; CUDA behavior unchanged. Upstreaming to Eric's original repo is now optional/at-leisure since ProArt is consumed as SpikerSoft work. Closing.
Resolved in spikersoft-artpipe PR #1 (merged to `main` — ProArt now lives at `spikerj/spikersoft-artpipe` per the mirror decision). The cuda/mps/cpu device seam: `artpipe.device.resolve()` adopted across all 13 hardcoded-cuda backends, MPS-aware hardware detect/live_stats/_check_gpu_compat, Darwin torch installs (stock PyPI, manifest override key), clear requires-CUDA guards on trellis/unirig/triposg/hunyuan3d_paint, SigLIP/CLIP mps, Blender Cycles METAL enable. Validated across six doc slices on the M5; 682 pytest green at merge; CUDA behavior unchanged. Upstreaming to Eric's original repo is now optional/at-leisure since ProArt is consumed as SpikerSoft work. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Sub-ticket of epic #346, Mac workstream. Foundation for #355 and the M2–M4 tickets. Based on the MPS portability audit (comment on #355).
What: art_pipe has no device abstraction — every backend independently does
cuda-if-available-else-cpuand installs CUDA wheels unconditionally. Add acuda | mps | cpuseam so macOS (Apple Silicon, PyTorch MPS) is a first-class target. This is generic, upstreamable work — plan to PR it to Eric's ProArt repo rather than fork.Scope (exact touchpoints from the audit):
src/artpipe/hardware.py— addtorch.backends.mps.is_available()branch todetect()(:183-207); report unified memory as VRAM; nonvidia-smipath on Darwin (:104-166)src/artpipe/main.py::_check_gpu_compat(:22-70) — treat MPS as GPU-available; skip sm/TORCH_CUDA_ARCH_LISTchecks on Darwinsrc/artpipe/torch_compat.py— Darwin branch: default PyPI torch (ships MPS), no cu-index mappingsrc/artpipe/venv_setup.py(:257-320, defaults :8-9) +bootstrap.py(:23,78) — on Darwin ignoretorch_index_url, install stock torch; per-OS manifest override convention (e.g.torch_index_url_darwin: "")artpipe.device.resolve()returning device str + preferred dtype) and adopt it in the 13 backends that hardcode"cuda":flux_schnell.py:67,sdxl_lightning.py:58,sdxl_turbo.py:41,sd_turbo_tex.py:60,sf3d.py:44,text3d.py:62,triposr.py:46,triposg.py:46,instantmesh.py:68,shap_e.py:123,mdm.py:87(int0— needs mapping),hymotion.py:101,rignet_infer.py:325; fixinstantmesh.py:87unconditional fp16cv/checks.py:79-83+cv/analysis.py:203-217— mps branch for SigLIP/CLIPsrc/artpipe/blender/headless/_helpers.py:137-165— setcprefs.compute_device_type = "METAL"on macOS beforerefresh_devices()(today Cycles silently falls back to CPU)torch.cuda.empty_cache()call sites (pattern from trellis-macpatches/mps_compat.py)Note: no Metal kernels in this ticket — CUDA-extension backends stay CUDA-only and must fail with a clear "requires CUDA" message on Mac (stub pattern from trellis-mac
backends/stubs.py), not ImportError crashes.Acceptance: on an Apple-Silicon Mac,
artpipe setupinstalls stock torch,artpipe launchpasses the GPU check reporting MPS + unified memory, a Tier-A backend (e.g. sdxl_lightning) runs onmps, a blocked backend (e.g. triposg) fails with the clear message, and Blender Cycles renders on Metal. CUDA behavior on Linux unchanged.Implemented on local branch
feature/device-abstraction-mpsin art_pipe (commita186626, +384/−82 across 25 files). All scope items done:artpipe/device.py(resolve()cuda>mps>cpu + guardedempty_cache(), lazy-torch so the stdlib-only server still imports), hardware detect/live_stats MPS branch (Apple GPU + unified-memory-as-VRAM),_check_gpu_compatMPS path, Darwin torch-index handling in torch_compat/venv_setup/bootstrap (+ optionaltorch_index_url_darwinmanifest key), all 13 hardcoded-cuda backends moved to the shared helper (incl. mdm int-device fix and instantmesh unconditional-fp16 fix), clear requires-CUDA guards on trellis/unirig/triposg/hunyuan3d_paint, SigLIP/CLIP mps branch, Blender Cycles METAL enable on macOS.Verified on the M5 Max (128 GB): pytest 574 passed / 10 skipped / 0 failed;
resolve()→('mps', float16);hardware.detect()→ "Apple M5 Max GPU", 131072 MB,mps_available: true;python -m artpipe serve/hardwareendpoint returns the Apple GPU. Audit line-drift corrections and a real pre-existing bug fixed en route (detect()force-setcuda_available=Truefor any GPU entry) are noted in the commit.Blocked on a decision: art_pipe's
originis Eric's server (clam.local:3000/EricSpiker/art_pipe) — not pushing to someone else's Gitea without Joey's go-ahead. Options: (a) push branch + open PR on Eric's Gitea if Joey has an account/fork there, (b) mirror art_pipe into git.spikersoft.com and PR there, then upstream later. Runtime model validation on MPS is #357 scope.Working-tree note: the checkout has repo-wide CRLF noise (Windows-origin) plus an uncommitted README author-handle edit — left untouched; the commit was kept EOL-clean for upstreamability.
Resolved in spikersoft-artpipe PR #1 (merged to
main— ProArt now lives atspikerj/spikersoft-artpipeper the mirror decision). The cuda/mps/cpu device seam:artpipe.device.resolve()adopted across all 13 hardcoded-cuda backends, MPS-aware hardware detect/live_stats/_check_gpu_compat, Darwin torch installs (stock PyPI, manifest override key), clear requires-CUDA guards on trellis/unirig/triposg/hunyuan3d_paint, SigLIP/CLIP mps, Blender Cycles METAL enable. Validated across six doc slices on the M5; 682 pytest green at merge; CUDA behavior unchanged. Upstreaming to Eric's original repo is now optional/at-leisure since ProArt is consumed as SpikerSoft work. Closing.