ComfyUI Node

SG Publish

One run becomes one tracked Version, graph attached

By ksallee·Created about a month ago·Updated 17 days ago· 11
SG Publish
  • images
  • video
  • mask
    ◄project►
    ◄link▾►
    ◄task▾►
    ◄status►
    ◄root_name►
    ◄code_template►
    ◄register_filesfalse►
    ◄note►
    ◄colour_space►
    ◄source_versions►
    ◄link_id0►
    ◄attach_workflowtrue►
    ◄format8-bit PNG►
    ◄sequence_path►
    ◄still_path►
    ◄movie_path►

    Every generation has two possible endings. It goes in a folder and you forget what made it, or it becomes a thing with a name that the rest of the production can find. SG Publish is the second ending: wire your output in, run, and you get a Version on your Flow Production Tracking site with the media uploaded, the model/prompt/seed/sampler recorded, and the workflow attached.

    Two things up front. It has no outputs - a terminal output node like SaveImage, so it always runs and nothing reads from it. And it makes no pixels: ComfyUI writes the frames, this node files them.

    Why it beats "save image + metadata"

    The usual ComfyUI habit is that provenance rides inside the PNG, where any host that recompresses it strips the graph (image-io-metadata.md). A studio can't run on that: shots link to entities, versions get reviewed, and "which model, which seed, what did it come from" has to be answerable for the whole show. SG Publish writes those facts onto the site, and attaches the graph anyway.

    How the provenance actually gets gathered

    From the graph itself, through hidden inputs, not from you. Model, seed, sampler, steps and CFG come out of the executed prompt graph, and the prompt counts as text that reached a conditioning input on this branch - not "text near a seed". It also walks back through its own inputs, so each Version describes only its branch: three lookdev variants in one graph make three honest Versions.

    Nine typed fields on Version hold the summary (sg_ai_model, sg_ai_prompt, sg_ai_seed and so on), created idempotently under Settings → SG → SG Site Setup, or from a shell on a farm:

    PYTHONPATH=src <comfy-python> -m comfyui_sg.fields
    

    A site with none of those fields still works: the facts go into the Version's description. The full record rides along as .provenance.json, and seed is stored as text - ComfyUI seeds reach 2**64-1 and a numeric field blows up long before that.

    The inputs that matter

    images (IMAGE) and video (VIDEO) are both optional, and what you wire decides what the Version is: a VIDEO is the review media, an IMAGE batch alone is frame 1 as a still, both wired means the video wins. Wiring neither is refused.

    Then project, link, task, status from your site, and two naming widgets you'll touch constantly:

    • root_name - the name shared by every version of this publish, e.g. {entity}_matte.
    • code_template - what this Version is called, e.g. {root_name}_v{version:03d}. The :03d pads the number.

    register_files ("Create Published Files") is the one that surprises people. A Version has exactly one uploaded media file, so a sequence can't be the media. Tick it and the files are copied under a Local File Storage root and registered as PublishedFiles; leave it off and a multi-frame batch is refused at run time, naming the count and the two ways out - tick the box, or send the batch through CreateVideo and wire the VIDEO.

    mask is the alpha for the frames, on ComfyUI's convention: white is transparent in the file. Size and count must match the frames exactly - a mismatch is refused rather than resampled, because a matte scaled to fit the plate is a different matte.

    In the advanced fold: format (8-bit PNG / 16-bit PNG / EXR 32-bit float - the review still stays 8-bit PNG, so pick EXR when a comp consumes the frames), colour_space (recorded, never applied), source_versions, link_id, attach_workflow, and the path templates sequence_path / still_path / movie_path. Empty falls back to Settings.

    Install

    Manager → Custom Nodes Manager → search Flow Production Tracking → Install → restart. Or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/ksallee/sg-comfyui.git
    cd sg-comfyui
    <comfy-python> -m pip install -r requirements.txt
    

    Needs ComfyUI 0.34.0+, Python 3.11, and a site you can log in to. Dependencies are just sg-groundtruth, requests and Pillow - deliberately no torch/numpy pinning, a good call, since a node that pins either can break your install. First run: Settings → SG → site address → Log in → Test → pick a project, then load 00_example from the Templates browser, category sg-comfyui. On a farm, enter a Script name and Application key instead.

    When it goes wrong

    • No project, no resolvable link, no publish. Both are refused before the site is touched, naming the missing one.
    • "Create Published Files" refuses and your site has no storage. Add a Local File Storage under Site Preferences → File Management, then name it under Settings → SG → Storage. Untick the box until then.
    • The storage root isn't mounted. The publish stops before the Version exists and names the root. Originals are never moved, and a failed publish names the copies it left, so a retry costs a copy, not a re-render.
    • Versions read "ComfyUI (unknown client)". Submitting over HTTP yourself? Your client has to name itself: send extra_data.comfy_usage_source in the /prompt body.
    • The workflow isn't attached. It comes from EXTRA_PNGINFO, which the standard frontend sends and API-style submitters (the comfy CLI, MCP servers) may not. The record says so rather than pretending.
    • Publishing from Windows is untested, per the README, and a loader inside a subgraph is replaced rather than promoted.
    CategoryFlow Production Tracking

    Inputs (19)

    NameTypeDefaultDescription
    imagesoptIMAGEThe frames out of the graph to publish.
    videooptVIDEOThe clip out of the graph to publish, from LoadVideo, CreateVideo or a video model.
    projectoptCOMBOProject to publish into.
    linkoptCOMBOThe Shot, Asset or other entity this Version belongs to.
    taskoptCOMBOTask this Version is for, if there is one.
    statusoptCOMBOStatus to set on the new Version.
    root_nameoptSTRINGThe name shared by all versions of this publish, without a version number, for example {entity}_matte. It can be used in the path templates and as the Published File name. Empty uses the default under Settings, then SG.
    code_templateoptSTRINGThe name given to the new Version, for example {root_name}_v{version:03d}. {version:03d} pads the number to three digits. Empty uses the default under Settings, then SG.
    register_filesoptBOOLEANfalsePublish the files themselves beside the Version, copied to the storage root this project's profile names.
    noteoptSTRINGA note for the people who will read this Version, written to its description.
    colour_spaceoptSTRINGThe colour space these pixels are already in, for example sRGB or ACEScg. It is recorded with the Version, never applied to the pixels.
    source_versionsoptSTRINGVersion ids this was made from, separated by commas, for example 1042, 1043.
    link_idoptINT00–2147483647The id to link this Version to, used instead of the link picker when it is not 0.
    attach_workflowoptBOOLEANtrueAttach the graph that made this Version, so the run can be opened again.
    formatoptCOMBO8-bit PNGWhat the published frames are written as, for example EXR 32-bit float for a scene-linear plate. The review still stays 8-bit PNG.
    sequence_pathoptSTRINGWhere a batch of two or more frames is written, relative to the storage root, for example {entity}/{root_name}/{version_name}/{version_name}.%04d{ext}. Empty uses Sequence path under Settings.
    still_pathoptSTRINGWhere a batch of one frame is written, relative to the storage root, for example {entity}/{root_name}/{version_name}{ext}. Empty uses Still path under Settings.
    movie_pathoptSTRINGWhere the clip is written, relative to the storage root, for example {entity}/{root_name}/{version_name}{ext}. Empty uses Movie path under Settings.
    maskoptMASKThe alpha for the frames, on ComfyUI's convention: white in the mask is transparent in the file.

    Outputs (0)

    No outputs