# ComfyUI Blocks

Package, test, and preview a reviewed core-image workflow.

The reviewed adapter now supports core text-to-image and image-to-image generation. Use `CheckpointLoaderSimple`, `CLIPTextEncode`, `EmptyLatentImage`, `KSampler`, `VAEEncode` and `VAEDecode` with existing `PreviewImage` output. One installed safetensors checkpoint basename, one sampling pass, batch 1 and at most 40 steps are admitted. Generation dimensions are 64–1024 in multiples of 8, subject to the existing four-megapixel aggregate working budget (1024-square image-to-image can exceed it). The connection must report that checkpoint; filenames do not prove file hashes, licenses or GPU readiness. No weights are downloaded. `comfyModelRequirements(workflow)` returns the required model names. Text and numeric controls use typed scalar bindings. The import wizard preserves real sample inputs and prepares padded image-to-image fixture copies; project inputs are never silently resized. See `examples/comfy-text-to-image.stillmade.json` and replace the checkpoint placeholder before review.

A ComfyUI Block is a portable declaration of a reviewed image capability. Users
see its controls and resulting image, not its internal node wiring. Start with
[the complete example](/block-sdk/examples/comfy-invert.stillmade.json).

### Import an existing ComfyUI workflow

Choose **Import ComfyUI workflow** in the import tools, or choose its JSON file
with **Import package**. Export the **API format** from ComfyUI first; its
[API documentation](https://docs.comfy.org/development/cloud/overview) describes
the numbered node map. Visual exports containing `nodes` and `links` cannot be
converted without the exact frontend/node definitions and receive export guidance.
The importer accepts the prompt map itself or `{ "prompt": { … } }`. A ZIP may
contain one `workflow.json`, `workflow_api.json`, or `*.comfy.json` file.

The mapping screen asks for the Block name, description, source license, input
and result names, and the main image input/output. Multiple image inputs or
outputs require an explicit main choice. Optional semantic roles distinguish
source images from character references. Resize controls can stay fixed or become
user-editable inputs. Every LoadImage and PreviewImage must be mapped; unknown
nodes, dependencies, credentials, cycles, and disconnected processing are rejected.
This adapter accepts the reviewed image and diffusion classes listed below, not arbitrary custom-node workflows.

Choose a sample for every image input. The browser creates a copy no larger than
128 pixels per side, with a combined fixture budget, and includes those pixels
in the downloaded source. Originals are unchanged. The sample stays local until
you explicitly run the backend review. Optional expected dimensions add fixture
assertions; leaving them blank still requires a valid decoded single image.
Choose sample images you may distribute with this Block.

**Continue to tests and preview** creates an SDK package, not an installation or
a successful test. The existing account connection, real fixtures, separate
sample execution, preview, rights review and **Confirm Import** follow. Importing
never republishes third-party code. The original API JSON is retained in
`manifest.provenance.comfyuiImport.source`; execution uses normalized placeholders
instead of its saved image filenames. Original `_meta.title` remains attribution,
not executable behavior. Review this retained source before sharing a release.

The downloadable SDK exposes the same static conversion API:

```js
import {inspectComfyImport, buildComfyImportPackage}
  from './packages/block-sdk/index.js';
import {comfyImageInvert} from './packages/block-sdk/comfyui-example.js';

// Replace with a supported API export. No backend is contacted by either call.
const raw = structuredClone(comfyImageInvert.comfyui.prompt);
raw['1'].inputs.image = 'my-example.png';
const inspection = inspectComfyImport(raw);
console.log(inspection.inputCandidates, inspection.outputCandidates);

const pkg = buildComfyImportPackage(raw, {
  manifest: {...comfyImageInvert.manifest, id: 'my.invert', name: 'My invert'},
  inputs: comfyImageInvert.comfyui.inputs,
  outputs: comfyImageInvert.comfyui.outputs,
  tests: comfyImageInvert.tests,
});
// Save pkg as JSON, then import it for real backend review and confirmation.
```

`inspectComfyImport(raw)` returns `format`, inert `source`, normalized `prompt`,
`nodes`, `inputCandidates`, `outputCandidates`, `warnings`, and
`execution: "not-run"`. It does not choose names, roles, primary ports or fixtures.
`buildComfyImportPackage(raw, {manifest, inputs, outputs, tests})` requires those
explicit choices, validates their contracts and selected resize values, and
returns a package without execution receipts. Source is limited to 64 KiB and
the complete package to the usual bounded JSON/import limits.

### Package and runtime contract

Set `manifest.runtime` to `comfyui`, `entry` to `src/comfyui.json`, and declare
`permissions: {project: [], capabilities: ["comfyui.execute"]}`. The top-level
package contains `manifest`, `comfyui`, `tests`, and an optional `view`. It cannot
contain `code` or `recipe`. Put the workflow in `comfyui` or, in an editable folder,
`src/comfyui.json`. Endpoints, tokens, connection IDs, file paths, dependencies,
and Python never belong in the package. Input/output types and semantic roles
use the same StillMade contract as other Blocks.

The workflow has four fields: `schemaVersion: 1`, `prompt`, `inputs`, and
`outputs`. `prompt` is an API-format map of numbered nodes with `class_type` and
`inputs`. Supported core classes are `LoadImage`, `ImageInvert`, `ImageScale`, `PreviewImage`, `CheckpointLoaderSimple`, `CLIPTextEncode`, `EmptyLatentImage`, `KSampler`, `VAEEncode` and `VAEDecode`. Every node must contribute to a declared output. A `LoadImage`
uses an empty filename placeholder and a binding such as
`image: {node: "1", input: "image", encoding: "uploaded-image"}`. StillMade uploads
verified input pixels and supplies the generated basename. Resize controls use
`encoding: "scalar"`. An output selects one image from a declared PreviewImage:
`image: {node: "3", collection: "images", index: 0}`.

Each fixture has `name`, `input`, and `expectations`. For example:

```json
{"name":"One pixel","input":{"image":{"width":1,"height":1,"data":[20,80,200,255]}},"expectations":{"image":{"kind":"image","count":1,"width":1,"height":1,"maxBytes":4096}}}
```

Every output requires `kind: "image"` and `count: 1`. Optional width, height,
maximum encoded bytes, and lowercase `sha256` check the host-decoded and
re-encoded PNG, not a claimed backend descriptor. Use deterministic hash fixtures
when exact image behavior matters. Bounds: 16 nodes, 8 inputs/outputs, one
megapixel per single-frame image, and four megapixels total working images.
Small inline fixtures fit the four-megabyte import limit. Large media inputs
should use existing account-owned media references.

In Settings → ComfyUI connections, save the public HTTPS endpoint and optional
bearer token. Tokens use the same stable account encryption key as BYOK with a
separate encryption purpose. They are never returned to the browser or guest UI.
StillMade rejects private network endpoints, redirects and arbitrary requests.
The backend is an explicitly selected service you operate or trust. Checking
its core-node schema is compatibility evidence, not attestation of its Python
implementation. Desktop loopback and arbitrary custom nodes are not available through this adapter. Reviewed core diffusion nodes may use the backend’s GPU after explicit approval.

Import the JSON or ZIP, choose the connection, and click **Run tests and sample**.
StillMade scans the package, records durable jobs, runs every fixture and a
separate sample, decodes outputs, and displays the before/after result. Only then
can you confirm rights and **Confirm Import**. Confirmation revalidates the
account/source/connection-bound receipt without silently submitting another job.
Changing source, connection revision, backend contract, or an expired receipt
requires another review. Saving a connection, opening a page, and custom iframe
JavaScript cannot confirm remote execution. Preview runs never install or
publish a Block. Cancellation targets only owned jobs; unsupported remote
cancellation can leave work running on the selected backend. The SDK rejects a
cancelled invocation immediately even if its trusted host callback is still
waiting. Source and input contracts are captured before dispatch; editing the
caller’s package during execution cannot change output validation.

In a saved project, the host checks edit access and finds a completed review for
this exact package and connection. A current backend compatibility check runs
without resubmitting fixtures. A successful import review can be reused for
project execution after its import-confirmation expiry; changed source,
connection revision, backend schema, or security status invalidates that reuse.
The host asks for **Run in project** before submitting the actual project input.
If review is required, **Run tests and sample** and its preview come first, then
a separate **Run in project** action. Custom interfaces cannot skip these actions.
Durable production jobs are associated with the saved project. Local demo and
Marketplace previews remain samples and cannot claim project access.

Offline `validate` and `pack` check and package source. For ComfyUI, `pack` returns
`reviewRequired: true` and zero executed tests. `test` and `preview` return
`RUNTIME_UNAVAILABLE` without a trusted host executor. A host integration may
pass `options.comfyui(package, input, {signal})` to `runPackageAsync` or
`testPackage`, returning `{outputs, metadata}` where every metadata entry has
verified width, height, bytes, `mimeType: "image/png"`, `frames: 1`, and optionally
SHA-256. This callback is trusted host code; it is never loaded from a package.

The server supports reviewed ComfyUI packages inside Project Types through the
account-bound envelope below. The import wizard opens each included ComfyUI Block
in its connection review panel. Unattended ComfyUI automation remains unavailable.
Existing recipe/JavaScript Project Types and exact-output fixture checks are unchanged.

### ComfyUI packages in Project Types: host integration

The offline CLI can package ComfyUI-only or mixed hosted/local Project Types:

```sh
node packages/block-cli/cli.js validate ./workflow.json
node packages/block-cli/cli.js pack ./workflow.json ./workflow.stillmade.json
```

This performs static/schema checks on every embedded package and preserves exact
source. It never runs a provider, connects to ComfyUI, or executes local fixtures.
The result explicitly reports `tests: 0`, `reviewRequired: true`,
`liveVerified: false`, and `workflowComplete: false`. Import the result into
StillMade for authenticated backend review, local tests, sample execution, and
user confirmation. Unsupported ComfyUI nodes still fail the static package scan.


The authenticated review/import/release/install APIs accept `typeComfyuiReviews`
alongside `typeCapabilityReviews`. It is request metadata, never portable source:

```json
{
  "typeComfyuiReviews": {
    "<exact package SHA-256>": {
      "receiptId": "<account review UUID>",
      "connectionId": "<account connection UUID>",
      "connectionRevision": 1
    }
  }
}
```

Provide exactly one entry for every embedded ComfyUI package, including unused
or disabled packages. The server authenticates every fixture and sample against
the selected backend contract, then checks the ledger again at the save boundary.
Missing, expired, foreign, cancelled, or changed-connection evidence is rejected.
Saved imports, release reports, and installation reports retain the fixture and
sample media. Another account must provide its own reviews. No prompt is
submitted by receipt verification.

A trusted SDK host can supply `verifyComfyPackage` in the third argument to
`verifyHostedProjectTypePackages(type, verifyCapabilityPackage, options)`.
The callback must return the server-verified Block report, including `receiptId`,
`connectionId`, and `connectionRevision`. The resulting opaque handle supports
`testProjectType` and `previewProjectType`; JSON claims cannot substitute for it.
Offline rehearsal defers reviewed ComfyUI execution and its dependent outputs.
Interactive rehearsal requires `verifyHostedResult` before downstream execution;
retained run metadata uses `comfyuiRun`. A passing package admission report still
does not prove that the complete connected workflow ran.

In the import or builder review, choose **Review Block** beside each ComfyUI
package, select your connection, and run its tests/sample (or reuse a fresh
matching review). Finish the package checks, inspect the result, and confirm
import. Connected workflow preview separately confirms each ComfyUI execution
and refetches its exact run evidence before handing images downstream. These
interactive controls do not enable unattended remote execution.


### Connected ComfyUI execution in a project

**Run connected steps** can continue through ComfyUI Blocks when you approve each
run on your account connection. It reuses the existing reviewed-connection dialog;
missing fixtures require a separate review before the project input runs. Image
references reach the broker intact, so the server can check project access and
bind the exact input. Local image processors decode accepted images as needed.

The host uses `planSegment(..., {interactive: true})` and supplies an authenticated
`verifyHostedResult` callback to `runSegment`. ComfyUI results retain `comfyuiRun`
and `mediaReceipts`; hosted model results retain `capabilityRun`. These callbacks
are trusted StillMade integration code, never imported Block code. A resumed run
or **Use results** re-fetches and verifies each remote result against the current
project, source, inputs, and connection metadata before accepting it. Waiting for
consent or a remote backend does not consume the local computation budget.

Cancellation or failed verification stops downstream work and retains earlier
completed results for review. The default non-interactive planner still stops at
ComfyUI or hosted model Blocks; future-media automation cannot submit those jobs.
