Skip to main content

A wrapper around ComfyUI to allow use by AI Horde.

Project description

horde-engine

PyPI Version Downloads GitHub license

Build Test Images Test Images All Models Release Changelog

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.


Quick start

  1. Install horde-engine together with a PyTorch build for your hardware (see Choosing a PyTorch build). For NVIDIA:

    # CUDA 13+ driver -> torch 2.12.0 (the default line):
    pip install --extra-index-url https://download.pytorch.org/whl/cu130 horde-engine
    # CUDA 12.x driver -> the newest CUDA 12.8 build is torch 2.11.0:
    pip install --extra-index-url https://download.pytorch.org/whl/cu128 horde-engine "torch==2.11.0"
    
  2. Set AIWORKER_CACHE_HOME to a model directory (see Model directory layout).

  3. 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/.


Installation

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 /tmp

From PyPI

# CUDA 13+ driver -> torch 2.12.0 (the default line):
pip install --extra-index-url https://download.pytorch.org/whl/cu130 horde-engine
# CUDA 12.x driver -> the newest CUDA 12.8 build is torch 2.11.0:
pip install --extra-index-url https://download.pytorch.org/whl/cu128 horde-engine "torch==2.11.0"

From source (development)

git clone https://github.com/Haidra-Org/hordelib.git
cd hordelib
uv sync   # installs the latest torch (2.12.0, the CUDA 12.6 build) -- see "Choosing a PyTorch build"

Choosing a PyTorch build

horde-engine does not pin torch: it declares torchvision/torchaudio as version ranges, and torchvision pins the exact matching torch in its metadata, so installing the library pulls the latest supported torch (2.12.0 -> torchvision 0.27.0 / torchaudio 2.11.0; torchaudio has no 2.12 release). You only pick the build (which CUDA/ROCm wheels) for your hardware.

For development, uv sync installs the CUDA 12.6 build of torch 2.12.0 (the index hordelib routes to in [tool.uv.sources]). It runs on any CUDA 12.6+ driver and, via NVIDIA driver backward-compatibility, on CUDA 13 drivers too -- the broadest single build. To use a different build, override it ad-hoc after syncing:

uv sync
# then, only if you want a build other than the cu126 default:
UV_TORCH_BACKEND=auto uv pip install torch torchvision torchaudio                # auto-detect your GPU
uv pip install torch --extra-index-url https://download.pytorch.org/whl/cu130    # exact CUDA 13 build

With pip, select the index with --extra-index-url:

Hardware index Notes
NVIDIA, CUDA 13+ driver cu130 torch 2.12.0; a 13.0 build covers any 13.x driver (incl. 13.2).
NVIDIA, CUDA 13.2 (exact) cu132 torch 2.12.0; cu130 also runs on a 13.2 driver.
NVIDIA, CUDA 12.6+ driver cu126 torch 2.12.0; the only CUDA-12 build of 2.12.0.
NVIDIA, CUDA 12.x, older torch cu128 No 2.12.0 wheel; caps at torch 2.11.0 (add "torch==2.11.0").
AMD (Linux only) rocm6.4 torch 2.9.1 only (see note below).
No GPU cpu ~100x slower; testing only.

ROCm: only torch 2.9.1 (ROCm 6.4) is currently installable. PyTorch publishes torch 2.10-2.12 on rocm7.x but not the matching pytorch-triton-rocm (3.6.0/3.7.0) those wheels hard-depend on, so they cannot be resolved yet. Install it ad-hoc: uv pip install torch==2.9.1 torchvision torchaudio pytorch-triton-rocm --extra-index-url https://download.pytorch.org/whl/rocm6.4.


Architecture (v3)

The 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.

Pipeline flow

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

Key invariants

  • initialise() before everything. Importing HordeLib or any ComfyUI-touching code before initialise() raises RuntimeError. 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 by tests/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 sampler produces dotted parameters sampler.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.

Model directory layout

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.


Development

Requirements: git, uv, AIWORKER_CACHE_HOME set to a model directory, and a CUDA GPU.

Build, lint, test

The whole toolchain lives in one uv-managed .venv. Sync it once (installs the CUDA 12.6 build of torch 2.12.0 via [tool.uv.sources]), then drive tools with uv run --no-sync:

uv sync                          # 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.

Key test areas

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

Designing and converting pipelines

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.

Updating ComfyUI or external custom nodes

Change the relevant commit SHA in hordelib/installation/manifest.json:

  • comfyui_ref for ComfyUI itself
  • ref for 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.

Local wheel build

uv build        # writes dist/horde_engine-<version>.tar.gz and -<version>-py3-none-any.whl

The 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.

Release process

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

Documentation

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

License

GNU Affero General Public License v3.0

Acknowledgments

horde-engine builds on a large number of open-source projects:

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

horde_engine-3.1.1.tar.gz (359.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

horde_engine-3.1.1-py3-none-any.whl (465.0 kB view details)

Uploaded Python 3

File details

Details for the file horde_engine-3.1.1.tar.gz.

File metadata

  • Download URL: horde_engine-3.1.1.tar.gz
  • Upload date:
  • Size: 359.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for horde_engine-3.1.1.tar.gz
Algorithm Hash digest
SHA256 ddc83510d0c3f6231972fda791352f22a294fe0d5c90670f63f3f56aedb56c9b
MD5 a52b061353aa9956f9973c756fa22894
BLAKE2b-256 01ebb0f686481a98c97fc4cfb44e2826e28ec2f63c66a2450869e6bcbdd091f5

See more details on using hashes here.

Provenance

The following attestation bundles were made for horde_engine-3.1.1.tar.gz:

Publisher: release.yml on Haidra-Org/hordelib

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file horde_engine-3.1.1-py3-none-any.whl.

File metadata

  • Download URL: horde_engine-3.1.1-py3-none-any.whl
  • Upload date:
  • Size: 465.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for horde_engine-3.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b71414f564019b47521d9f89e7a1f6612e3baad4c8658a6a29775098a0996cbf
MD5 706aa7c600d2124510bb3f2b0924b69f
BLAKE2b-256 f0237aba032fb93bd06e27538e8dc796070c4f403077a80a20aaf27b04298422

See more details on using hashes here.

Provenance

The following attestation bundles were made for horde_engine-3.1.1-py3-none-any.whl:

Publisher: release.yml on Haidra-Org/hordelib

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page