diff --git a/CHANGELOG.md b/CHANGELOG.md index 42dcf5b..d1e43ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,18 @@ The format is inspired by Keep a Changelog and SemVer. - `.github/PULL_REQUEST_TEMPLATE.md` - `.github/ISSUE_TEMPLATE/release_checklist.md` - `docs/RELEASE_NOTES_TEMPLATE.md` +- RunPod_Comfy implementation scaffold: + - `Runpod_Comfy/README.md` + - `Runpod_Comfy/setup/USER_README.md` + - `Runpod_Comfy/core/docker/Dockerfile` + - `Runpod_Comfy/core/docker/start.sh` + - `Runpod_Comfy/core/scripts/bootstrap.sh` + - `Runpod_Comfy/core/scripts/install_custom_nodes.sh` + - `Runpod_Comfy/core/scripts/download_models.sh` + - `Runpod_Comfy/image/active/comfyui.lock` + - `Runpod_Comfy/image/active/custom_nodes.lock.json` + - `Runpod_Comfy/image/active/models.json` + - `Runpod_Comfy/image/DEPLOY_RUNPOD.md` ## [0.1.0] - 2026-02-14 diff --git a/DECISIONS.md b/DECISIONS.md new file mode 100644 index 0000000..3e2717d --- /dev/null +++ b/DECISIONS.md @@ -0,0 +1,34 @@ +# DECISIONS + +## 2026-02-15 — Profile-first RunPod build flow +- We use profile files as inputs and generate lock files as build/runtime truth. +- Profile inputs: + - `Runpod_Comfy/profiles/runpod..yaml` + - `Runpod_Comfy/profiles/nodes..yaml` + - `Runpod_Comfy/profiles/models..yaml` + - Optional `Runpod_Comfy/profiles/urls..txt` +- Compiler output: + - `Runpod_Comfy/config/comfyui.lock` + - `Runpod_Comfy/config/custom_nodes.lock.json` + - `Runpod_Comfy/config/models.json` +- Docker base image is taken from generated `comfyui.lock` (`BASE_IMAGE` build arg). +- Goal: normal updates (new node repo/model URL/version bumps) should require editing config files only, not Python/Docker logic. +- Expected operator UX: + - Edit 3–4 simple profile files with real values. + - Run compiler. + - Build/push image. + - Deploy and smoke-test on RunPod. + +## 2026-02-15 — Work continuity model +- Planning/serious execution in OpenClaw web dashboard. +- Telegram for quick pings. +- Repo files (`TODO/WORKLOG/DECISIONS/WORKFLOW`) are continuity anchor across devices. + +## 2026-02-15 — Recipe architecture for long-term readability +- Use a 3-zone layout inside `Runpod_Comfy/`: + - `setup/` (operator-facing edits/tools; keep lightweight) + - `image/` (generated outputs + active locks + deploy runbook) + - `core/` (runtime internals + technical references) +- Keep one recipe folder per image variant under `setup/recipes//`. +- Compiler supports explicit args (`--id`, `--out`, `--image-tag`, `--no-activate`). +- Default outputs go to `image/builds//` and can be activated to `image/active/`. diff --git a/README.md b/README.md index f95d615..0faecc1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,13 @@ The code for the Easy Resize node is inspired by the Resize Image V2 node from C - **Error Handling**: Fallbacks for missing/invalid JSON in Wan 2.2 Easy Prompt; validation for aspect ratios and divisibility in Easy Resize. - **Compatibility**: Works with ComfyUI-Manager for easy installation via Git URL. No additional dependencies beyond standard Python and ComfyUI libraries. +## RunPod + +A dedicated RunPod setup scaffold is available in `Runpod_Comfy/`. + +- Entry guide: `Runpod_Comfy/README.md` +- Deploy notes: `Runpod_Comfy/docs/DEPLOY_RUNPOD.md` + ## Release & Stability For production usage, install a pinned stable tag/commit instead of following moving branch heads. diff --git a/Runpod_Comfy/README.md b/Runpod_Comfy/README.md new file mode 100644 index 0000000..7ff8954 --- /dev/null +++ b/Runpod_Comfy/README.md @@ -0,0 +1,10 @@ +# Runpod_Comfy + +This module is organized in three top-level folders: + +- `setup/` → operator-facing inputs and helper tools +- `image/` → generated build artifacts, active lock set, and deploy runbook +- `core/` → runtime internals (docker/scripts) and technical references + +Start here: +- `Runpod_Comfy/setup/USER_README.md` diff --git a/Runpod_Comfy/core/docker/Dockerfile b/Runpod_Comfy/core/docker/Dockerfile new file mode 100644 index 0000000..03fc462 --- /dev/null +++ b/Runpod_Comfy/core/docker/Dockerfile @@ -0,0 +1,23 @@ +ARG BASE_IMAGE=runpod/pytorch:2.6.0-py3.11-cuda12.4.1-devel-ubuntu22.04 +FROM ${BASE_IMAGE} + +ENV DEBIAN_FRONTEND=noninteractive \ + PIP_DISABLE_PIP_VERSION_CHECK=1 \ + PYTHONUNBUFFERED=1 \ + COMFYUI_PORT=8188 \ + COMFYUI_WORKDIR=/workspace/ComfyUI \ + RUNPOD_VOLUME_ROOT=/workspace + +WORKDIR /opt/bootstrap + +RUN apt-get update && apt-get install -y --no-install-recommends \ + git curl ca-certificates jq \ + && rm -rf /var/lib/apt/lists/* + +COPY Runpod_Comfy /opt/bootstrap/Runpod_Comfy + +RUN chmod +x /opt/bootstrap/Runpod_Comfy/core/scripts/*.sh /opt/bootstrap/Runpod_Comfy/core/docker/start.sh + +EXPOSE 8188 + +ENTRYPOINT ["/opt/bootstrap/Runpod_Comfy/core/docker/start.sh"] diff --git a/Runpod_Comfy/core/docker/start.sh b/Runpod_Comfy/core/docker/start.sh new file mode 100755 index 0000000..959e81f --- /dev/null +++ b/Runpod_Comfy/core/docker/start.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT=/opt/bootstrap/Runpod_Comfy +WORKDIR="${COMFYUI_WORKDIR:-/workspace/ComfyUI}" +PORT="${COMFYUI_PORT:-8188}" + +"$ROOT/core/scripts/bootstrap.sh" + +cd "$WORKDIR" + +exec python3 main.py --listen 0.0.0.0 --port "$PORT" diff --git a/Runpod_Comfy/docs/features/runpod_Container_REQUIRMENTS.md b/Runpod_Comfy/core/docs/features/runpod_Container_REQUIRMENTS.md similarity index 61% rename from Runpod_Comfy/docs/features/runpod_Container_REQUIRMENTS.md rename to Runpod_Comfy/core/docs/features/runpod_Container_REQUIRMENTS.md index ade9a11..632b2d1 100644 --- a/Runpod_Comfy/docs/features/runpod_Container_REQUIRMENTS.md +++ b/Runpod_Comfy/core/docs/features/runpod_Container_REQUIRMENTS.md @@ -1,3 +1,7 @@ +# RunPod Container Requirements + +> Note: moved to `Runpod_Comfy/core/docs/features/` during the 3-zone refactor (`setup/image/core`) so technical references live under `core/`. + # Requirments: 1. Cuda 12.8 - 12.9 - should work with RTX pro 6000 and B200 gpus !!! diff --git a/Runpod_Comfy/docs/references/github-repos_andOr_LINKS.md b/Runpod_Comfy/core/docs/references/github-repos_andOr_LINKS.md similarity index 74% rename from Runpod_Comfy/docs/references/github-repos_andOr_LINKS.md rename to Runpod_Comfy/core/docs/references/github-repos_andOr_LINKS.md index 29b0eef..53df15e 100644 --- a/Runpod_Comfy/docs/references/github-repos_andOr_LINKS.md +++ b/Runpod_Comfy/core/docs/references/github-repos_andOr_LINKS.md @@ -1,3 +1,7 @@ +# GitHub and Reference Links + +> Note: moved to `Runpod_Comfy/core/docs/references/` during the 3-zone refactor (`setup/image/core`) so technical references live under `core/`. + # Github - Links ### Runpod.io official - documentation diff --git a/Runpod_Comfy/core/scripts/bootstrap.sh b/Runpod_Comfy/core/scripts/bootstrap.sh new file mode 100755 index 0000000..0f1049e --- /dev/null +++ b/Runpod_Comfy/core/scripts/bootstrap.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT=/opt/bootstrap/Runpod_Comfy +WORKDIR="${COMFYUI_WORKDIR:-/workspace/ComfyUI}" +mkdir -p "$WORKDIR" + +source "$ROOT/image/active/comfyui.lock" + +if [[ ! -f "$WORKDIR/main.py" ]]; then + echo "[bootstrap] Cloning ComfyUI from $COMFYUI_REPO" + git clone "$COMFYUI_REPO" "$WORKDIR" +fi + +cd "$WORKDIR" + +echo "[bootstrap] Checking out ComfyUI ref: $COMFYUI_REF" +git fetch --all --tags || true +git checkout "$COMFYUI_REF" + +python3 -m pip install --upgrade pip +python3 -m pip install -r requirements.txt + +"$ROOT/core/scripts/install_custom_nodes.sh" +"$ROOT/core/scripts/download_models.sh" + +echo "[bootstrap] done" diff --git a/Runpod_Comfy/core/scripts/download_models.sh b/Runpod_Comfy/core/scripts/download_models.sh new file mode 100755 index 0000000..a0f382c --- /dev/null +++ b/Runpod_Comfy/core/scripts/download_models.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT=/opt/bootstrap/Runpod_Comfy +WORKDIR="${COMFYUI_WORKDIR:-/workspace/ComfyUI}" +LOCK="$ROOT/image/active/models.json" + +if [[ ! -f "$LOCK" ]]; then + echo "[models] lock file not found: $LOCK" + exit 0 +fi + +COUNT=$(jq '.models | length' "$LOCK") +for ((i=0; i $DST" + git clone "$REPO" "$DST" + fi + + pushd "$DST" >/dev/null + git fetch --all --tags || true + git checkout "$REF" + + if [[ -f requirements.txt ]]; then + python3 -m pip install -r requirements.txt || true + fi + + popd >/dev/null +done + +echo "[custom_nodes] done" diff --git a/Runpod_Comfy/image/DEPLOY_RUNPOD.md b/Runpod_Comfy/image/DEPLOY_RUNPOD.md new file mode 100644 index 0000000..c4376ef --- /dev/null +++ b/Runpod_Comfy/image/DEPLOY_RUNPOD.md @@ -0,0 +1,34 @@ +# Deploy on RunPod + +## 1) Build and push image + +Use GitHub Container Registry or Docker Hub. + +Example (GHCR): + +```bash +docker build -t ghcr.io/malkuthro/comfyui-koolook:runpod-v1 -f Runpod_Comfy/core/docker/Dockerfile . +docker push ghcr.io/malkuthro/comfyui-koolook:runpod-v1 +``` + +## 2) Create RunPod template + +- Container image: `ghcr.io/malkuthro/comfyui-koolook:runpod-v1` +- Exposed HTTP port: `8188` +- Volume mount: `/workspace` (recommended) + +## 3) Optional env vars + +- `COMFYUI_PORT=8188` +- `COMFYUI_WORKDIR=/workspace/ComfyUI` +- `HF_TOKEN=...` (if needed) +- `CIVITAI_TOKEN=...` (if needed) + +## 4) First boot expectations + +On first start: +- ComfyUI is cloned at pinned ref from `config/comfyui.lock` +- custom nodes are installed from `config/custom_nodes.lock.json` +- models are downloaded from `config/models.json` (enabled entries only) + +Subsequent starts reuse existing files from volume storage. diff --git a/Runpod_Comfy/image/active/comfyui.lock b/Runpod_Comfy/image/active/comfyui.lock new file mode 100644 index 0000000..6afeb27 --- /dev/null +++ b/Runpod_Comfy/image/active/comfyui.lock @@ -0,0 +1,7 @@ +# Generated by Runpod_Comfy/setup/tools/compile_profile.sh +RECIPE_ID=example +BASE_IMAGE=runpod/pytorch:2.6.0-py3.11-cuda12.4.1-devel-ubuntu22.04 +IMAGE_NAME=ghcr.io/your-user/comfyui-koolook +RUNPOD_IMAGE_TAG=upscaler-v1.0.0 +COMFYUI_REPO=https://github.com/comfyanonymous/ComfyUI.git +COMFYUI_REF=master diff --git a/Runpod_Comfy/image/active/custom_nodes.lock.json b/Runpod_Comfy/image/active/custom_nodes.lock.json new file mode 100644 index 0000000..739dd00 --- /dev/null +++ b/Runpod_Comfy/image/active/custom_nodes.lock.json @@ -0,0 +1,19 @@ +{ + "version": 1, + "nodes": [ + { + "id": "comfyui-koolook", + "repo": "https://github.com/malkuthro/ComfyUI-Koolook.git", + "ref": "main", + "target_dir": "ComfyUI-Koolook", + "install": [] + }, + { + "id": "comfyui-manager", + "repo": "https://github.com/ltdrdata/ComfyUI-Manager.git", + "ref": "main", + "target_dir": "ComfyUI-Manager", + "install": [] + } + ] +} diff --git a/Runpod_Comfy/image/active/models.json b/Runpod_Comfy/image/active/models.json new file mode 100644 index 0000000..5fb98e2 --- /dev/null +++ b/Runpod_Comfy/image/active/models.json @@ -0,0 +1,19 @@ +{ + "version": 1, + "models": [ + { + "name": "example_sdxl_checkpoint", + "url": "https://example.com/path/to/model.safetensors", + "dest": "models/checkpoints/model.safetensors", + "sha256": "", + "enabled": false + }, + { + "name": "example_vae", + "url": "https://example.com/path/to/vae.safetensors", + "dest": "models/vae/vae.safetensors", + "sha256": "", + "enabled": false + } + ] +} diff --git a/Runpod_Comfy/image/builds/.gitkeep b/Runpod_Comfy/image/builds/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Runpod_Comfy/setup/USER_README.md b/Runpod_Comfy/setup/USER_README.md new file mode 100644 index 0000000..ebf4826 --- /dev/null +++ b/Runpod_Comfy/setup/USER_README.md @@ -0,0 +1,67 @@ +# Runpod_Comfy Setup Guide + +This package is split into 3 readable zones: + +- `setup/` → what you edit (recipes + helper tools) +- `image/` → generated outputs (build artifacts + active locks) + deploy runbook +- `core/` → runtime internals (Docker + bootstrap scripts + technical references) + +## Quick Start + +### 1) Create a recipe + +```bash +Runpod_Comfy/setup/tools/new_profile.sh upscaler-v1 +``` + +Creates: +- `Runpod_Comfy/setup/recipes/upscaler-v1/runpod.yaml` +- `Runpod_Comfy/setup/recipes/upscaler-v1/nodes.yaml` +- `Runpod_Comfy/setup/recipes/upscaler-v1/models.yaml` +- `Runpod_Comfy/setup/recipes/upscaler-v1/urls.txt` + +### 2) Compile recipe + +```bash +Runpod_Comfy/setup/tools/compile_profile.sh --id upscaler-v1 +``` + +Generates into: +- `Runpod_Comfy/image/builds/upscaler-v1/comfyui.lock` +- `Runpod_Comfy/image/builds/upscaler-v1/custom_nodes.lock.json` +- `Runpod_Comfy/image/builds/upscaler-v1/models.json` + +By default compile also **activates** to: +- `Runpod_Comfy/image/active/comfyui.lock` +- `Runpod_Comfy/image/active/custom_nodes.lock.json` +- `Runpod_Comfy/image/active/models.json` + +### 3) Build image + +```bash +BASE_IMAGE=$(grep '^BASE_IMAGE=' Runpod_Comfy/image/active/comfyui.lock | cut -d= -f2-) +IMAGE_TAG=$(grep '^RUNPOD_IMAGE_TAG=' Runpod_Comfy/image/active/comfyui.lock | cut -d= -f2-) +docker build --build-arg BASE_IMAGE="$BASE_IMAGE" \ + -t comfyui-koolook:${IMAGE_TAG} -f Runpod_Comfy/core/docker/Dockerfile . +``` + +## Iterate safely + +- Minor tweaks: keep same recipe id, bump `image_tag` in `runpod.yaml` +- Major changes: clone to new id (`upscaler-v2`, `wan22-v1`) +- Optional no-activate compile: + +```bash +Runpod_Comfy/setup/tools/compile_profile.sh --id upscaler-v1 --no-activate +``` + +## Deploy + +RunPod deploy runbook: +- `Runpod_Comfy/image/DEPLOY_RUNPOD.md` + +## Compiler args + +```bash +Runpod_Comfy/setup/tools/compile_profile.sh --id [--out ] [--image-tag ] [--no-activate] +``` diff --git a/Runpod_Comfy/setup/recipes/examples/models.example.yaml b/Runpod_Comfy/setup/recipes/examples/models.example.yaml new file mode 100644 index 0000000..7f1e2f5 --- /dev/null +++ b/Runpod_Comfy/setup/recipes/examples/models.example.yaml @@ -0,0 +1,14 @@ +profile_id: example + +models: + - name: example_sdxl_checkpoint + url: https://example.com/path/to/model.safetensors + dest: models/checkpoints/model.safetensors + sha256: "" + enabled: false + + - name: example_vae + url: https://example.com/path/to/vae.safetensors + dest: models/vae/vae.safetensors + sha256: "" + enabled: false diff --git a/Runpod_Comfy/setup/recipes/examples/nodes.example.yaml b/Runpod_Comfy/setup/recipes/examples/nodes.example.yaml new file mode 100644 index 0000000..22403a7 --- /dev/null +++ b/Runpod_Comfy/setup/recipes/examples/nodes.example.yaml @@ -0,0 +1,14 @@ +profile_id: example + +nodes: + - id: comfyui-koolook + repo: https://github.com/malkuthro/ComfyUI-Koolook.git + ref: main + target_dir: ComfyUI-Koolook + install: [] + + - id: comfyui-manager + repo: https://github.com/ltdrdata/ComfyUI-Manager.git + ref: main + target_dir: ComfyUI-Manager + install: [] diff --git a/Runpod_Comfy/setup/recipes/examples/runpod.example.yaml b/Runpod_Comfy/setup/recipes/examples/runpod.example.yaml new file mode 100644 index 0000000..9556a05 --- /dev/null +++ b/Runpod_Comfy/setup/recipes/examples/runpod.example.yaml @@ -0,0 +1,12 @@ +profile_id: example + +# Docker build base +base_image: runpod/pytorch:2.6.0-py3.11-cuda12.4.1-devel-ubuntu22.04 + +# Optional image metadata used by compiler summary/lock file +image_name: ghcr.io/your-user/comfyui-koolook +image_tag: upscaler-v1.0.0 + +comfyui: + repo: https://github.com/comfyanonymous/ComfyUI.git + ref: master diff --git a/Runpod_Comfy/setup/recipes/examples/urls.example.txt b/Runpod_Comfy/setup/recipes/examples/urls.example.txt new file mode 100644 index 0000000..3cebe36 --- /dev/null +++ b/Runpod_Comfy/setup/recipes/examples/urls.example.txt @@ -0,0 +1,6 @@ +# Optional quick model list parser. +# Format (pipe-separated): +# url | dest | sha256(optional) | enabled(optional,true/false) | name(optional) +# +# Example: +# https://example.com/model.safetensors | models/checkpoints/model.safetensors | | false | my_model diff --git a/Runpod_Comfy/setup/tools/compile_profile.sh b/Runpod_Comfy/setup/tools/compile_profile.sh new file mode 100755 index 0000000..93ed578 --- /dev/null +++ b/Runpod_Comfy/setup/tools/compile_profile.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +RECIPE_ID="" +RECIPES_DIR="$ROOT/setup/recipes" +OUT_DIR="" +ACTIVATE=true +IMAGE_TAG_OVERRIDE="" + +usage() { + cat < [--recipes-dir ] [--out ] [--image-tag ] [--no-activate] + $0 # backward-compatible + +Defaults: + recipes-dir: Runpod_Comfy/setup/recipes + out: Runpod_Comfy/image/builds/ + activate: true (copies generated files to Runpod_Comfy/image/active) +EOF +} + +if [[ $# -eq 1 && "$1" != --* ]]; then + RECIPE_ID="$1" +else + while [[ $# -gt 0 ]]; do + case "$1" in + --id) RECIPE_ID="$2"; shift 2 ;; + --recipes-dir) RECIPES_DIR="$2"; shift 2 ;; + --out) OUT_DIR="$2"; shift 2 ;; + --image-tag) IMAGE_TAG_OVERRIDE="$2"; shift 2 ;; + --no-activate) ACTIVATE=false; shift ;; + -h|--help) usage; exit 0 ;; + *) echo "Unknown arg: $1"; usage; exit 1 ;; + esac + done +fi + +[[ -z "$RECIPE_ID" ]] && { usage; exit 1; } +[[ -z "$OUT_DIR" ]] && OUT_DIR="$ROOT/image/builds/$RECIPE_ID" + +RECIPE_DIR="$RECIPES_DIR/$RECIPE_ID" +RUNPOD_PROFILE="$RECIPE_DIR/runpod.yaml" +NODES_PROFILE="$RECIPE_DIR/nodes.yaml" +MODELS_PROFILE="$RECIPE_DIR/models.yaml" +URLS_FILE="$RECIPE_DIR/urls.txt" +CONFIG_DIR="$ROOT/image/active" + +for f in "$RUNPOD_PROFILE" "$NODES_PROFILE" "$MODELS_PROFILE"; do + [[ -f "$f" ]] || { echo "Missing: $f"; exit 1; } +done +mkdir -p "$OUT_DIR" + +python3 - "$RUNPOD_PROFILE" "$NODES_PROFILE" "$MODELS_PROFILE" "$URLS_FILE" "$OUT_DIR" "$RECIPE_ID" "$IMAGE_TAG_OVERRIDE" <<'PY' +import json, pathlib, re, sys +runpod_path = pathlib.Path(sys.argv[1]); nodes_path = pathlib.Path(sys.argv[2]); models_path = pathlib.Path(sys.argv[3]); urls_path = pathlib.Path(sys.argv[4]); out_dir = pathlib.Path(sys.argv[5]); recipe_id = sys.argv[6]; image_tag_override = sys.argv[7] + +def scalar(v): + v=v.strip() + if not v: return "" + if v.lower()=="true": return True + if v.lower()=="false": return False + if (v.startswith('"') and v.endswith('"')) or (v.startswith("'") and v.endswith("'")): return v[1:-1] + if re.fullmatch(r"-?\d+", v): return int(v) + return v + +def parse(path): + lines=path.read_text(encoding='utf-8').splitlines(); root={}; i=0 + while i2 else ""; enabled=(p[3].lower()!='false') if len(p)>3 and p[3] else True; name=p[4] if len(p)>4 and p[4] else pathlib.Path(dest).stem + out.append({"name":name,"url":url,"dest":dest,"sha256":sha,"enabled":enabled}) + return out + +runpod=parse(runpod_path); nodes_data=parse(nodes_path); models_data=parse(models_path) +base_image=runpod.get('base_image'); comfy=runpod.get('comfyui',{}) if isinstance(runpod.get('comfyui'),dict) else {} +if not base_image: raise ValueError('base_image is required') +image_name=runpod.get('image_name','') +image_tag= image_tag_override or runpod.get('image_tag', recipe_id) +nodes=nodes_data.get('nodes',[]); models=models_data.get('models',[]) +url_models=parse_urls(urls_path) +for n in nodes: + if 'repo' not in n or 'ref' not in n: raise ValueError(f'node requires repo/ref: {n}') + n.setdefault('target_dir', pathlib.Path(str(n['repo']).rstrip('/')).name.replace('.git','')) + if n.get('install') in ('',None): n['install']=[] +for m in models: + for req in ('name','url','dest'): + if req not in m: raise ValueError(f'model missing {req}: {m}') + m.setdefault('sha256',''); m.setdefault('enabled',True) +models.extend(url_models) + +comfy_lock='\n'.join([ + '# Generated by Runpod_Comfy/setup/tools/compile_profile.sh', + f'RECIPE_ID={recipe_id}', + f'BASE_IMAGE={base_image}', + f'IMAGE_NAME={image_name}', + f'RUNPOD_IMAGE_TAG={image_tag}', + f"COMFYUI_REPO={comfy.get('repo','https://github.com/comfyanonymous/ComfyUI.git')}", + f"COMFYUI_REF={comfy.get('ref','master')}", + '' +]) +(out_dir/'comfyui.lock').write_text(comfy_lock, encoding='utf-8') +(out_dir/'custom_nodes.lock.json').write_text(json.dumps({'version':1,'nodes':nodes},indent=2)+'\n',encoding='utf-8') +(out_dir/'models.json').write_text(json.dumps({'version':1,'models':models},indent=2)+'\n',encoding='utf-8') +print('=== compile summary ===') +print(f'Recipe ID : {recipe_id}') +print(f'Base image : {base_image}') +print(f'Image name : {image_name or "(unset)"}') +print(f'Image tag : {image_tag}') +print(f'ComfyUI ref : {comfy.get("ref","master")}') +print(f'Custom nodes : {len(nodes)}') +print(f'Models : {len(models)} (urls.txt additions: {len(url_models)})') +print(f'Output dir : {out_dir}') +PY + +if [[ "$ACTIVATE" == true ]]; then + mkdir -p "$CONFIG_DIR" + cp "$OUT_DIR/comfyui.lock" "$CONFIG_DIR/comfyui.lock" + cp "$OUT_DIR/custom_nodes.lock.json" "$CONFIG_DIR/custom_nodes.lock.json" + cp "$OUT_DIR/models.json" "$CONFIG_DIR/models.json" + echo "Activated build into: $CONFIG_DIR" +fi + +echo "[ok] compile complete" diff --git a/Runpod_Comfy/setup/tools/new_profile.sh b/Runpod_Comfy/setup/tools/new_profile.sh new file mode 100755 index 0000000..84da873 --- /dev/null +++ b/Runpod_Comfy/setup/tools/new_profile.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 1 ]]; then + echo "Usage: $0 " + echo "Example: $0 upscaler-v1" + exit 1 +fi + +ID="$1" +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +RECIPES="$ROOT/setup/recipes" +EXAMPLES="$RECIPES/examples" +TARGET="$RECIPES/$ID" + +mkdir -p "$TARGET" + +for kind in runpod nodes models; do + src="$EXAMPLES/${kind}.example.yaml" + dst="$TARGET/${kind}.yaml" + if [[ -f "$dst" ]]; then + echo "[skip] exists: $dst" + else + cp "$src" "$dst" + python3 - "$dst" "$ID" <<'PY' +from pathlib import Path +import re, sys +p=Path(sys.argv[1]); rid=sys.argv[2] +t=p.read_text(encoding='utf-8') +t=re.sub(r'^profile_id:\s*.*$', f'profile_id: {rid}', t, flags=re.M) +p.write_text(t, encoding='utf-8') +PY + echo "[new] $dst" + fi +done + +src_urls="$EXAMPLES/urls.example.txt" +dst_urls="$TARGET/urls.txt" +if [[ -f "$dst_urls" ]]; then + echo "[skip] exists: $dst_urls" +else + cp "$src_urls" "$dst_urls" + echo "[new] $dst_urls" +fi + +echo +echo "Next:" +echo " 1) edit $TARGET/{runpod.yaml,nodes.yaml,models.yaml,urls.txt}" +echo " 2) Runpod_Comfy/setup/tools/compile_profile.sh --id $ID" diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..bf26396 --- /dev/null +++ b/TODO.md @@ -0,0 +1,20 @@ +# TODO + +## NOW +- [ ] Fill real values for RunPod profile files (`Runpod_Comfy/profiles/*.example.yaml` copies) +- [ ] Compile selected profile and verify generated lock files +- [ ] Build and push first RunPod image + +## NEXT +- [ ] Deploy image on RunPod and run smoke test workflow +- [ ] Add helper script: `Runpod_Comfy/tools/build_from_lock.sh` +- [ ] Add profile validation checks (schema-lite) + +## BLOCKED +- [ ] Final production model URLs and checksums (waiting on selection) + +## DONE +- [x] Add profile compiler scaffold (`compile_profile.sh`) +- [x] Add example profile files (runpod/nodes/models + urls format) +- [x] Wire Dockerfile to configurable base image via build-arg +- [x] Generate lock files from sample profile and sanity-check JSON diff --git a/WORKFLOW.md b/WORKFLOW.md new file mode 100644 index 0000000..5be3f6b --- /dev/null +++ b/WORKFLOW.md @@ -0,0 +1,41 @@ +# Workflow (Cristian + kflame) + +This is the operating flow for this repo. + +## 1) Where planning happens +- Primary workspace: OpenClaw web dashboard session. +- Telegram: quick pings only. + +## 2) Source of truth +- Tasks: `TODO.md` +- Progress/handoff: `WORKLOG.md` +- Decisions: `DECISIONS.md` +- Code/config truth: repo files + commits + +## 3) Start of each work block +1. Read `TODO.md` +2. Read latest entry in `WORKLOG.md` +3. Read `DECISIONS.md` +4. Pick one task and execute + +## 4) End of each work block +1. Update `WORKLOG.md` (done/next/blockers) +2. Update `TODO.md` statuses +3. If a meaningful choice was made, update `DECISIONS.md` +4. Commit changes with clear message + +## 5) Task status model +- `NOW`: actively working +- `NEXT`: queued next +- `BLOCKED`: waiting on external dependency +- `DONE`: complete + +## 6) Resume from any device +Use this order: +1. `WORKLOG.md` latest entry +2. `TODO.md` NOW/NEXT items +3. `DECISIONS.md` +4. Git history (`git log --oneline -n 10`) + +## 7) Rule of thumb +If it matters later, write it to file now. diff --git a/WORKLOG.md b/WORKLOG.md new file mode 100644 index 0000000..364ba6c --- /dev/null +++ b/WORKLOG.md @@ -0,0 +1,44 @@ +# WORKLOG + +## 2026-02-15 +### Done +- Implemented profile-driven scaffold for RunPod Comfy builds. +- Added: + - `Runpod_Comfy/profiles/runpod.example.yaml` + - `Runpod_Comfy/profiles/nodes.example.yaml` + - `Runpod_Comfy/profiles/models.example.yaml` + - `Runpod_Comfy/profiles/urls.txt` + - `Runpod_Comfy/tools/compile_profile.sh` +- Updated `Runpod_Comfy/docker/Dockerfile` to use `ARG BASE_IMAGE` + `FROM ${BASE_IMAGE}`. +- Updated `Runpod_Comfy/README.md` with compile/build flow. +- Ran sample compile: `Runpod_Comfy/tools/compile_profile.sh example`. +- Validated generated JSON structure via Python loader. +- Commit: `af028bf`. + +### Next (top 3) +1. Create real profile files for Cristian's RunPod target. +2. Compile and inspect generated lock files. +3. Build + push image, deploy pod, smoke test. + +### Thread recap (copied from Telegram for continuity) +- Agreed division of work: assistant builds production-ready profile compiler scaffold; Cristian fills real values next session. +- Delivered scaffold scope: + - Config layer with profile files for runpod/nodes/models (+ optional urls parser) + - Compiler that generates `config/comfyui.lock`, `config/custom_nodes.lock.json`, `config/models.json` + - Docker wired to consume generated lock data + - Sanity checks + dry docker build command validation +- Tomorrow execution plan: + 1. Edit 3–4 profile files with real CUDA/image/nodes/models. + 2. Run compiler + docker build + docker push. + 3. Deploy image on RunPod and run smoke test. + +### Blockers +- Real model URLs/checksums not finalized. + +### Additional context imported from Telegram (extended) +- Desired abstraction confirmed: config-driven workflow where adding node repos/model URLs and bumping versions does not require code edits. +- Strong emphasis on "production-ready" compiler/scaffold with placeholders now and real values tomorrow. +- Tomorrow checklist reaffirmed: + 1. Fill real profile values (CUDA/image/nodes/models). + 2. Compile profile, build image, push image. + 3. Deploy on RunPod and validate.