--- name: civitai-orchestration-sdcpp description: Use when testing or integrating Civitai Orchestration image generation via the sdcpp engine, especially SD1/SDXL/Z-Image requests and Z-Image LoRAs. version: 1.0.0 author: Hermes Agent license: MIT metadata: hermes: tags: [civitai, orchestration, sdcpp, image-generation, zimage, lora] related_skills: [third-party-api-data-sync, terminal-docs-research-fallback] --- # Civitai Orchestration sdcpp ## Overview Civitai Orchestration runs image-generation workflows at `https://orchestration.civitai.com`. For Stable Diffusion / Z-Image style jobs, the important step type is `$type: "imageGen"` with `input.engine: "sdcpp"`. This skill records the working request shapes verified on Alex's VPS with `CIVITAI_TOKEN` / `CIVITAI_API_KEY` in `/home/avalon/.hermes/.env`. ## When to Use - Testing Civitai `sdcpp` image generation. - Integrating Civitai Orchestration as a provider in Video Story or related apps. - Debugging `sdcpp` failures around model URNs, ecosystems, LoRAs, or sampler fields. - Generating Z-Image / Z-Image Turbo outputs with or without LoRAs. Do **not** use this for Civitai Site API model browsing alone; use the Site API docs/workflows for that. ## Auth and Endpoints Environment: ```bash CIVITAI_TOKEN=... # or CIVITAI_API_KEY=... ``` Base URL: ```text https://orchestration.civitai.com ``` Submit: ```http POST /v2/consumer/workflows?wait=60&whatif=false Authorization: Bearer Content-Type: application/json ``` Poll: ```http GET /v2/consumer/workflows/{workflowId} Authorization: Bearer ``` Use `whatif=true` first to validate and preview Buzz cost without executing. ## Critical Request Shape All image workflows need a step discriminator: ```json { "allowMatureContent": true, "steps": [ { "$type": "imageGen", "input": { "engine": "sdcpp", "ecosystem": "zImage", "model": "turbo", "operation": "createImage", "prompt": "...", "width": 1024, "height": 1024, "steps": 9, "cfgScale": 1, "quantity": 1 } } ] } ``` For `sdcpp`, use these field names: - `sampleMethod` not `sampler` - `schedule` not `scheduler` - `strength` not `denoiseStrength` for img2img / `createVariant` For Comfy engines, the field names differ (`sampler`, `scheduler`, `denoiseStrength`). Do not mix them. ## sdcpp vs Comfy: Which Operations Per Ecosystem The `sdcpp` engine does **not** support `createVariant` or `editImage` for SD1/SDXL/Z-Image. Use the correct engine per goal: | Goal | Ecosystem | Engine | Operation | Notes | |------|-----------|--------|-----------|-------| | txt2img | zImage | `sdcpp` | `createImage` | Fast, verified working | | txt2img | sd1 | `sdcpp` | `createImage` | Use `checkpoint` AIR | | txt2img | sdxl | `sdcpp` | `createImage` | Use `checkpoint` AIR | | txt2img | flux1 | `sdcpp` | `createImage` | Verified working | | txt2img | flux2Dev | `sdcpp` | `createImage` | Verified working | | txt2img | flux2Klein | `sdcpp` | `createImage` | Simplest Flux, no extra model refs | | img2img / remix | sd1 | `comfy` | `createVariant` | `image` + `denoiseStrength` + **`model` AIR URN required** | | img2img / remix | sdxl | `comfy` | `createVariant` | `image` + `denoiseStrength` + **`model` AIR URN required** | | img2img / remix | flux1 | `comfy` | `createVariant` | `image` + `denoiseStrength` + **`model` AIR URN required** | | img2img / remix | flux2Dev | `sdcpp` | `createVariant` | `image` + `strength` | | img2img / remix | flux2Klein | `sdcpp` | `createVariant` | `image` + `strength` — **simplest and most reliable reference-image path** | | inpainting | flux2Dev | `comfy` | `editImage` | `images[]` array | **Critical**: If you try `sdcpp` + `ecosystem: sdxl` + `operation: createVariant`, you get a 400 validation error: `"JSON deserialization for type '...SdxlVariantImageGenInput' was missing required properties including: 'model'"` — because the schema does not exist. Switch to `engine: "comfy"`. **Flux1 sdcpp `createVariant` requires extra model refs**: Unlike Flux2Dev/Flux2Klein, Flux1 sdcpp `createVariant` requires `diffuserModel`, `vaeModel`, `clipLModel`, and `t5XXLModel` AIR URNs. If missing, you get: `"JSON deserialization ... was missing required properties including: 'diffuserModel'"`. Use Flux2Klein for simpler reference-image workflows instead. ## Working Flux2Klein sdcpp createVariant (Reference Image → New Scene) `flux2Klein` + `sdcpp` is the simplest reference-image path. Unlike Flux1 sdcpp, it does **not** require `diffuserModel`, `vaeModel`, `clipLModel`, or `t5XXLModel`. ```json { "allowMatureContent": true, "steps": [{ "$type": "imageGen", "input": { "engine": "sdcpp", "ecosystem": "flux2Klein", "operation": "createVariant", "image": "https://image.civitai.com/.../original=true/....jpg", "strength": 0.65, "prompt": "same characters, now in a luxurious bedroom with silk sheets, warm candlelight", "width": 1216, "height": 832, "sampleMethod": "euler", "schedule": "simple", "steps": 8, "cfgScale": 1, "quantity": 1, "modelVersion": "4b" } }] } ``` Key: - `modelVersion`: `"4b"` or `"9b"` (default `"4b"`). Much simpler than Flux1's full model AIRs. - `strength`: 0.0 = no change, 1.0 = complete change. Default 0.7. - Typical Flux2Klein params from ComfyUI workflows: Euler sampler, 8 steps, CFG 1, 1216×832. ## Working Z-Image Turbo Verified succeeded. Cost: 8 Buzz for 1024², 9 steps. ```json { "allowMatureContent": true, "steps": [ { "$type": "imageGen", "input": { "engine": "sdcpp", "ecosystem": "zImage", "model": "turbo", "operation": "createImage", "prompt": "a cute robot reading a book in a sunlit library, crisp detailed illustration", "negativePrompt": "blurry, low quality", "width": 1024, "height": 1024, "steps": 9, "cfgScale": 1, "quantity": 1 } } ] } ``` Notes: - Civitai normalizes this internally to `diffuserModel: "urn:air:zimageturbo:checkpoint:civitai:2168935@2442439"`. - Vision verification matched the prompt well: cute robot reading in sunlit library. ## Working Z-Image Base Verified succeeded. Cost: 20 Buzz for 1024², 20 steps. ```json { "allowMatureContent": true, "steps": [ { "$type": "imageGen", "input": { "engine": "sdcpp", "ecosystem": "zImage", "model": "base", "operation": "createImage", "prompt": "a cozy cabin in snowy mountains at sunrise, cinematic, detailed", "negativePrompt": "blurry, low quality", "width": 1024, "height": 1024, "steps": 20, "cfgScale": 4, "quantity": 1 } } ] } ``` Notes: - Vision verification matched: cozy cabin, snow, mountains, sunrise light. - Civitai currently also normalized this request to a Z-Image Turbo diffuser in the returned input. Treat `model: "base"` vs `"turbo"` as Civitai-managed aliases and inspect returned workflow input if exact backend matters. ## Working SD1 / DreamShaper Verified succeeded. Cost: 4 Buzz for 512², 20 steps. ```json { "allowMatureContent": true, "steps": [ { "$type": "imageGen", "input": { "engine": "sdcpp", "ecosystem": "sd1", "operation": "createImage", "model": "urn:air:sd1:checkpoint:civitai:4384@128713", "prompt": "masterpiece, best quality, a cute robot reading a book, studio lighting", "negativePrompt": "worst quality, low quality, blurry", "width": 512, "height": 512, "steps": 20, "cfgScale": 7, "clipSkip": 2, "quantity": 1 } } ] } ``` Important: for SD1/SDXL checkpoints, use `checkpoint` in AIR URNs, not `model`: ```text urn:air:sd1:checkpoint:civitai:@ urn:air:sdxl:checkpoint:civitai:@ ``` Using `urn:air:sdxl:model:...` caused silent worker failures in earlier tests. ## Z-Image Turbo with LoRA Verified succeeded with the NexBlend Z-Image Turbo LoRA. Working LoRA resource: ```text model id: 2669120 version id: 2997054 trained word: nexblend tested AIR: urn:air:zimageturbo:lora:civitai:2669120@2997054 ``` Payload: ```json { "allowMatureContent": true, "steps": [ { "$type": "imageGen", "input": { "engine": "sdcpp", "ecosystem": "zImage", "model": "turbo", "operation": "createImage", "prompt": "nexblend, asian fashion model portrait, professional studio photo, elegant outfit, detailed skin texture, soft cinematic lighting", "negativePrompt": "blurry, low quality, distorted hands", "width": 1024, "height": 1024, "steps": 9, "cfgScale": 1, "quantity": 1, "loras": { "urn:air:zimageturbo:lora:civitai:2669120@2997054": 0.8 } } } ] } ``` Cost preview showed `fixed.additionalResources: 1`, making total 9 Buzz. Vision verification: professional Asian fashion-model portrait, high quality. ## LoRA AIR Pitfall For Z-Image Turbo LoRAs, use lowercase/internal ecosystem in the LoRA AIR: ```text urn:air:zimageturbo:lora:civitai:@ ``` These variants failed or stalled in tests: ```text urn:air:zImage:lora:civitai:2669120@2997054 # failed instantly urn:air:zImageTurbo:lora:civitai:2669120@2997054 # failed instantly urn:air:zimage:lora:civitai:2669120@2997054 # accepted but hung/processed slowly in test ``` Best rule: inspect the returned workflow `steps[0].input.diffuserModel`; for Z-Image Turbo it was `urn:air:zimageturbo:checkpoint:...`, so LoRAs should use `zimageturbo` too. ## Output Handling Successful image outputs are under: ```text workflow.steps[n].output.images[] ``` Not always under `blobs[]`. Each image has: - `id` - `available` - `url` - `previewUrl` - `nsfwLevel` - expiration fields Signed URLs are temporary. For app integration, download immediately and persist to the app's own storage. Never expose signed URLs in logs or chat. ## Debugging Recipe Use a Python or curl script that: 1. Loads token from env without printing it. 2. Submits with `whatif=true`. 3. If validation passes, submits with `whatif=false&wait=60` or `wait=0`. 4. Polls every 5-15s until `succeeded`, `failed`, or `canceled`. 5. Reads `output.images[]`, not just `output.blobs[]`. 6. Downloads available image URLs immediately. 7. Redacts all URLs and tokens from logs. Minimal Python pattern: ```python import os, requests, time TOKEN = os.environ["CIVITAI_TOKEN"] BASE = "https://orchestration.civitai.com/v2/consumer/workflows" HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} payload = {"allowMatureContent": True, "steps": [{"$type": "imageGen", "input": {...}}]} r = requests.post(BASE, params={"whatif": "true", "wait": 0}, headers=HEADERS, json=payload) r.raise_for_status() r = requests.post(BASE, params={"whatif": "false", "wait": 0}, headers=HEADERS, json=payload) r.raise_for_status() workflow = r.json() wid = workflow["id"] while workflow["status"] in {"scheduled", "pending", "processing", "unassigned"}: time.sleep(10) workflow = requests.get(f"{BASE}/{wid}", headers=HEADERS).json() for step in workflow.get("steps", []): images = (step.get("output") or {}).get("images") or [] for image in images: if image.get("available") and image.get("url"): data = requests.get(image["url"]).content # write/upload data; do not log signed URL ``` ## Common Pitfalls 1. **Wrong AIR type**: SD1/SDXL checkpoints should use `checkpoint`, not `model`. 2. **Wrong Z-Image LoRA ecosystem**: Use `zimageturbo` for Z-Image Turbo LoRA AIRs, not `zImage` or `zImageTurbo`. 3. **Gallery URLs vs single image URLs**: Civitai URLs like `https://civitai.red/images/` are **gallery posts** containing multiple images (often 50–100). The API `GET /api/v1/images?ids=` returns an `items` array. Filter by `baseModel`, prompt content, or `modelVersionIds` to find the specific image you want. Do not assume the first item is the right one. 4. **Looking only for `blobs[]`**: sdcpp image output appeared in `output.images[]`. 5. **Assuming `wait=60` always returns terminal state**: Z-Image Turbo took ~58s in one test and returned `processing`; poll after submit. 6. **Mixing engine parameter names**: `sdcpp` uses `sampleMethod` / `schedule`; Comfy uses `sampler` / `scheduler`. 7. **Using SDXL `clipSkip`**: SDXL docs say `clipSkip` is invalid. Use it only for SD1 if needed. 8. **Silent failures**: Bad resources can fail instantly with `errors: []` and debit+credit refund. Check `transactions`, `jobs[].status`, and normalized `input`. 9. **sdcpp does NOT support img2img for SD1/SDXL/Z-Image**: Use `engine: "comfy"` with `operation: "createVariant"` for remixes. For Flux ecosystems, use `flux2Klein` or `flux2Dev` with `sdcpp` — the simplest reference-image path. See `references/flux2klein-createVariant.md`. 10. **Blocking inline polls for hours**: Civitai queues are often very slow. Inline scripts will time out. Submit with `wait=0`, then poll asynchronously via cron or a background process. See `references/async-polling-and-queue-behavior.md` and `scripts/check_civitai_workflows.py`. 11. **Civitai image API `ids` lookup returns wrong image**: `GET /api/v1/images?ids=` returns a gallery/post with 50–100 items, not the specific image. The first item is often completely unrelated. Do not use this endpoint for metadata extraction. Use bulk feeds, direct image URLs, or upload local images to blob storage. See `references/civitai-image-api-id-lookup-pitfall.md`. 12. **`civitai.red` gallery URLs are post IDs, not image IDs**: URLs like `https://civitai.red/images/` resolve to galleries containing multiple images. The `ids` parameter on the Site API returns the same post for many different IDs. Always filter bulk results or use direct `image.civitai.com` URLs. ## Verified Workflow Results (Session Log) From live testing (June 2026): **Succeeded:** - `6621915-20260603011327874` — Flux2Klein `createImage`, 3 Buzz, output `nsfwLevel: r` - `6621915-20260603011339232` — Flux2Klein `createVariant` (uploaded reference → new scene), 3 Buzz, output `nsfwLevel: pg13` (not explicit — Civitai may moderate or the prompt wasn't strong enough) - `6621915-20260602234936834` — Z-Image Turbo no LoRA, 8 Buzz - `6621915-20260602235037058` — Z-Image Base no LoRA, 20 Buzz - `6621915-20260602235123246` — SD1/DreamShaper, 4 Buzz - `6621915-20260602235313207` — Z-Image Turbo + NexBlend LoRA, 9 Buzz - `6621915-20260603004705697` — Adult NSFW hardcore, eventually succeeded after hours in queue **Failed:** - `6621915-20260603010749753` — Comfy SDXL `createVariant` (cyberpunk remix): `failed` after 23 min, cost 0 (refunded), `output.errors: []`, `job.result: None`. Silent failure with no diagnostic message. - LoRA AIR variants `zImage`/`zImageTurbo` for NexBlend: instant failure with `errors: []`. **Key Discovery:** Flux2Klein `sdcpp` `createVariant` is the simplest confirmed working reference-image path on Civitai Orchestration. Comfy SDXL `createVariant` silently fails with empty errors. ## References - `references/sdcpp-vs-comfy-operation-matrix.md` — OpenAPI-level confirmation of which engine supports which operations per ecosystem, with the exact 400 error text. - `references/flux2klein-createVariant.md` — Flux2Klein sdcpp reference-image workflow, the simplest img2img/remix path on Civitai Orchestration. - `references/civitai-image-api-id-lookup-pitfall.md` — Why `GET /api/v1/images?ids=` returns the wrong image, and the correct workarounds for metadata extraction. - `references/async-polling-and-queue-behavior.md` — Why workflows stay `scheduled` for hours, how to avoid inline timeouts, and the cron-based polling pattern. - `references/nsfw-moderation-notes.md` — Observed `nsfwLevel` behavior and Civitai moderation on adult content. - `templates/comfy-sdxl-createVariant.json` — Starter payload for Comfy SDXL img2img / character remix. - `scripts/check_civitai_workflows.py` — Reusable polling script with state tracking and auto-download. ## Verification Checklist - [ ] `GET https://civitai.com/api/v1/me` returns 200 with the token. - [ ] `whatif=true` returns expected cost and no validation error. - [ ] Real workflow reaches `succeeded`. - [ ] `steps[0].output.images[0].available == true`. - [ ] Image is downloaded and visually checked. - [ ] For LoRA tests, cost includes `fixed.additionalResources` and prompt uses the LoRA trained word when applicable. - [ ] Signed URLs and token values are redacted from all user-facing logs.