horde-engine wraps a pinned commit of ComfyUI so the AI Horde can run ComfyUI-designed inference pipelines programmatically. It is the default inference backend for AI Horde since v1.0.0.
Python >=3.12. GPU/CUDA required. The package name on PyPI is horde-engine; the Python module is hordelib.
Community: AI Horde Discord.
-
Install PyTorch for your CUDA version, then
horde-engine:pip install --extra-index-url https://download.pytorch.org/whl/cu128 horde-engine -
Set
AIWORKER_CACHE_HOMEto a model directory (see Model directory layout). -
Call
hordelib.initialise()once per process, then use the public API:import hordelib hordelib.initialise() from hordelib.api import HordeLib, ImageGenPayload horde = HordeLib() payload = ImageGenPayload( prompt="an ancient llamia monster", model="Deliberate", sampler_name="k_dpmpp_2m", cfg_scale=7.5, ddim_steps=25, width=512, height=512, seed=123456789, ) result = horde.basic_inference_single_image(payload) result.image.save("test.png")
hordelib.initialise() wipes sys.argv -- parse command-line arguments first. It also forbids dev-mode paths containing spaces (do not clone the repo to a path with spaces) and raises if you try to import any ComfyUI-touching code before calling it.
For more usage patterns, see the public API docs and the example scripts in examples/. For complete API surface reference, consult the test suite under tests/.
Requires an NVIDIA GPU with CUDA. On Linux, install the NVIDIA CUDA Toolkit first. Systems with 16 GB RAM or less need swap space and may need an enlarged /tmp:
sudo mount -o remount,size=16G /tmppip install --extra-index-url https://download.pytorch.org/whl/cu128 horde-engine
git clone https://github.com/Haidra-Org/hordelib.git
cd hordelib
uv sync --extra cu128 # torch backend: cu128 | rocm | cpuThe v3 refactor replaced the legacy dict-heavy pipeline machinery with a typed, testable, registry-driven layer. The key pieces:
| Layer | Location | Role |
|---|---|---|
| Public API | hordelib/api.py |
Declared consumer surface. Workers import from here only. |
| Bootstrap | hordelib/initialisation.py |
initialise() -- manifest installer, path patching, ComfyUI import, monkeypatches. |
| Typed pipeline | hordelib/pipeline/ |
ImageGenPayload (pydantic, clamp-dont-reject), PipelineTemplate/ParamBinding, priority-ordered PipelineRegistry, pure graph patch functions, IO/model resolution. All GPU-free and unit-tested. |
| Execution bridge | hordelib/execution/ |
ExecutionBackend protocol, in-process ComfyUI backend, VRAM monkeypatches, pure graph utilities. |
| Environment manifest | hordelib/installation/ |
manifest.json pins ComfyUI commit + external custom nodes. EnvironmentInstaller checks out/clones idempotently. |
| ComfyUI bridge | hordelib/comfy_horde.py |
Comfy_Horde -- the actual ComfyUI process. do_comfy_import() applies monkeypatches. |
| Model managers | hordelib/model_manager/ |
Per-category model records (pydantic), download/validate/lookup, LoRA/TI adhoc cache. |
| Pipeline JSON | hordelib/pipelines/ |
Backend-format pipeline files executed at runtime. |
| Pipeline designs | hordelib/pipeline_designs/ |
ComfyUI-app-editable source workflows (convert to pipelines/). |
| Custom nodes | hordelib/nodes/ |
First-party Horde nodes (HordeCheckpointLoader, HordeImageOutput) and vendored compat nodes. External nodes (controlnet aux, QR) are git-pinned in the manifest. |
dict payload --> normalize (horde_compat) --> ImageGenPayload
--> resolve_context (model files, loras, TIs)
--> registry.select (predicate + priority --> PipelineTemplate)
--> materialize (bindings + patch steps --> ComfyGraph)
--> backend.run_pipeline --> ResultingImageReturn
initialise()before everything. ImportingHordeLibor any ComfyUI-touching code beforeinitialise()raisesRuntimeError. The test suite enforces this.- Public API only. Consumers import from
hordelib.api. Anything not re-exported there is internal and may change without notice. Enforced bytests/meta/test_public_api_contract.py. - Clamp, don't reject. Payload validation coerces bad values to defaults rather than raising -- the Horde contract requires tolerance.
- Node titles are the parameter namespace. A KSampler titled
samplerproduces dotted parameterssampler.cfg,sampler.seed, etc. Renaming a title silently breaks parameter mapping. - Pipeline selection is registry-driven. Predicates + explicit priorities replace the old if/elif tree. Adding a new baseline requires one family module, one template, one register call, and one inference test. See Adding a baseline.
AIWORKER_CACHE_HOME must follow the AI Horde directory structure:
<AIWORKER_CACHE_HOME>/
clip/
codeformer/
compvis/
Deliberate.ckpt
...
controlnet/
embeds/
esrgan/
gfpgan/
safety_checker/
Models are managed through SharedModelManager (download, validate, list available). See examples/download_all_sd_models.py for bulk downloading.
Requirements: git, uv, AIWORKER_CACHE_HOME set to a model directory, and a CUDA GPU.
The whole toolchain lives in one uv-managed .venv. Sync it once with the CUDA build of
torch, then drive tools with uv run --no-sync (a plain uv run would re-resolve and drop the
cu128 extra, uninstalling torch):
uv sync --extra cu128 # one-time, and after dependency changes
# Full test suite. The import guard runs first in a clean process (it asserts no ComfyUI
# import happens before initialise()), then the rest of the suite runs:
uv run --no-sync pytest -x tests/meta -k test_no_initialise_comfy_horde
uv run --no-sync pytest -x tests --cov --ignore=tests/meta --durations=20
uv run --no-sync pytest -k <pattern> # run a subset
uv run --no-sync pre-commit run --all-files # lint + format gate (black + ruff + mypy)
uv build # build sdist + wheel(Equivalently, activate .venv and call pytest / pre-commit directly.)
The first test run downloads many multi-GB models and is very slow. Most CI/agent sandboxes
cannot run the full inference suite; prefer uv run --no-sync pre-commit run --all-files for
quick feedback.
Tests require a CUDA GPU, AIWORKER_CACHE_HOME, CIVIT_API_TOKEN, and the committed images_expected/ reference images. Image-output tests compare generated images against references via cosine/histogram similarity. Set HORDELIB_SKIP_SIMILARITY_FAIL=1 to downgrade similarity failures to skips on different hardware.
| Path | What it covers |
|---|---|
tests/pipeline/ |
Payload models, graph operations, template integrity, registry selection -- all GPU-free |
tests/execution/ |
Graph utilities, modality seams -- GPU-free |
tests/meta/ |
Public API contract, initialise()-before-use guard |
tests/test_horde_inference_*.py |
Full GPU inference with image-similarity oracles |
tests/installation/ |
Manifest round-trip, installer idempotency |
Design pipelines in the ComfyUI web app (cd ComfyUI && python main.py, then http://127.0.0.1:8188/). Assign stable title attributes to nodes -- these become the dotted parameter names. Save the design in hordelib/pipeline_designs/ as pipeline_<name>.json.
Convert to backend format by running the pipeline through the embedded ComfyUI (it auto-saves comfy-prompt.json), then save the result in hordelib/pipelines/ with the same filename.
Do not hand-edit pipelines/*.json if a pipeline_designs/ source exists.
Change the relevant commit SHA in hordelib/installation/manifest.json:
comfyui_reffor ComfyUI itselfreffor each external custom node
Full 40-character SHAs only. The next hordelib.initialise() (or python -m hordelib.installation) applies the update. Run the full test suite afterwards.
uv build # writes dist/horde_engine-<version>.tar.gz and -<version>-py3-none-any.whlThe version is derived from git tags by hatch-vcs: a clean checkout sitting exactly on a
vX.Y.Z tag builds X.Y.Z; anything else builds a dev version (e.g. 1.2.3.devN). ComfyUI is
not bundled into the wheel -- it is fetched per hordelib/installation/manifest.json on first
initialise(). To smoke-test the wheel away from the source tree (so the repo's hordelib/
cannot shadow the installed package), install it into a throwaway venv created outside the repo.
Releases are cut by pushing a version tag. The tag is the version (hatch-vcs), and the
release workflow builds with uv build and publishes to PyPI
via trusted publishing (then creates a GitHub Release for the tag).
git checkout main && git pull
git tag vX.Y.Z # must be vX.Y.Z and sit on the commit you want released
git push origin vX.Y.Z| Document | Content |
|---|---|
| docs/public_api.md | Declared consumer surface and key patterns |
| docs/adding-a-baseline.md | Checklist for supporting a new model architecture |
| docs/modality-readiness.md | Audit of audio/video modality seams |
| docs/plans/major-overhaul-1.md | v3 phased refactor plan and status |
| AGENTS.md | Comprehensive codebase map, conventions, and sensitive areas |
GNU Affero General Public License v3.0
horde-engine builds on a large number of open-source projects:
- ComfyUI (GPLv3) -- the graph/nodes inference engine this project wraps.
- comfyui_controlnet_aux (Apache 2.0) -- ControlNet preprocessors, installed via the manifest.
- ComfyUI-layerdiffuse -- layer diffusion nodes (vendored with compat fixes).
- facerestore_cf -- face restoration nodes (vendored with compat fixes).
- ComfyQR -- QR code generation, installed via the manifest.
- horde-sdk and horde-model-reference -- payload types and model metadata consumed by this library.