Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
327b197
feat(run): add --json NDJSON output mode for agents
bigcat88 May 18, 2026
21efd7b
fix(tracking): enable session-only telemetry when non-interactive
bigcat88 May 18, 2026
18ada41
feat(run): emit node_errors / validation_warnings as a list of records
bigcat88 May 18, 2026
1cf0cfc
docs(run): surface UI-workflow support in --help and json-output.md
bigcat88 May 18, 2026
1cc19bd
feat(run): broaden local_path coverage with locality check
bigcat88 May 18, 2026
717571e
feat(run): populate local_path whenever the file actually exists on disk
bigcat88 May 18, 2026
fe26e9e
fix(run): harden local_path and substitute 0.0.0.0 wildcard host
bigcat88 May 18, 2026
a46f62d
feat(run)!: drop local_path from the JSON output contract
bigcat88 May 18, 2026
60c8b4a
chore(run): memoize text-mode workspace lookup and refresh docstring
bigcat88 May 18, 2026
ebd78e1
feat(run): add --print-prompt for dry-run preview of the converted body
bigcat88 May 18, 2026
379604f
docs(run): clarify why --print-prompt skips the pre-flight server probe
bigcat88 May 18, 2026
b5d5895
fix(run): expand ~ in --workflow path before existence check
bigcat88 May 18, 2026
f85c6f2
fix(run): wire --timeout through the pre-flight server probe
bigcat88 May 18, 2026
e2db035
test(env_checker): pin the default probe timeout value
bigcat88 May 18, 2026
a43b326
docs(json-output): add json language tag to NDJSON example blocks
bigcat88 May 18, 2026
a94130e
fix(run,tracking): two correctness bugs caught in final pre-merge review
bigcat88 May 18, 2026
a121a29
docs(json-output): tighten contract wording for several drifts
bigcat88 May 18, 2026
f08ff92
feat(run): always emit prompt_preview in --json mode
bigcat88 May 18, 2026
dd2c80a
feat(run): raise default --timeout from 30s to 120s
bigcat88 May 18, 2026
14d754d
fix(run): guard on_message / on_executing against malformed WS frames
bigcat88 May 18, 2026
89f2ce6
docs(json-output): name prompt_preview as terminal under --print-prompt
bigcat88 May 18, 2026
e9c8767
test(run): add CLI-runner integration tests for --json non-TTY path
bigcat88 May 18, 2026
6b61695
test(run): drop the local_path-absence regression test
bigcat88 May 18, 2026
9c67f32
docs(json-output): align Stability section with the Overview contract
bigcat88 May 19, 2026
d15d1bb
fix(run): coerce output node_id to str + rename interrupted kind +
bigcat88 May 19, 2026
16a278c
docs(json-output): tighten contract wording (7 corroborated findings)
bigcat88 May 19, 2026
c1e1fed
fix: finish "workflow graph" rename + 3 doc-consistency follow-ups
bigcat88 May 19, 2026
6062026
docs(json-output): canonicalize Open-set convention + shrink local_pa…
bigcat88 May 19, 2026
ca0a6f9
chore: align timeout defaults + mop up a leftover "submitted body"
bigcat88 May 19, 2026
a691ca9
refactor(run,json-output): cut redundancy across code, docs, and tests
bigcat88 May 19, 2026
d06dd5e
fix(run): catch UnicodeDecodeError alongside JSONDecodeError on /prom…
bigcat88 May 19, 2026
f8da96c
fix(run): emit failed event on client SIGINT (Ctrl-C)
bigcat88 May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 74 additions & 14 deletions comfy_cli/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,25 @@ def update(
rprint(f"[yellow]Failed to update node id cache: {e}[/yellow]")


@app.command(help="Run API workflow file using the ComfyUI launched by `comfy launch --background`")
@app.command(
help=(
"Run a workflow on the ComfyUI launched by `comfy launch --background`. "
"Accepts both ComfyUI API format and exported UI workflow JSON; "
"UI workflows are converted to API format client-side via /object_info."
)
)
@tracking.track_command()
def run(
workflow: Annotated[str, typer.Option(help="Path to the workflow API json file.")],
workflow: Annotated[
str,
typer.Option(
help=(
"Path to the workflow JSON file. Both ComfyUI API format and "
"exported UI format are accepted; UI workflows are converted "
"to API format client-side."
)
),
],
wait: Annotated[
bool,
typer.Option(help="If the command should wait until execution completes."),
Expand All @@ -444,22 +459,60 @@ def run(
typer.Option(help="The port where the ComfyUI instance is running, e.g. 8188."),
] = None,
timeout: Annotated[
int | None,
typer.Option(help="The timeout in seconds for the workflow execution."),
] = 30,
int,
typer.Option(
help=(
"Per-event timeout in seconds: bails out if the server is silent "
"for this long. Also caps HTTP connect, /prompt POST, and websocket "
"handshake. NOT a wall-clock execution deadline — a workflow that "
"streams progress events faster than the timeout can run "
"indefinitely."
),
),
] = 120,
api_key: Annotated[
str | None,
typer.Option(
"--api-key",
envvar="COMFY_API_KEY",
help=(
"Comfy API key for API Nodes (Partner Nodes). "
"Embedded in the prompt body as extra_data.api_key_comfy_org on POST /prompt. "
"Embedded in the POST /prompt request body as extra_data.api_key_comfy_org. "
"For scripting, prefer the COMFY_API_KEY environment variable so the secret "
"stays out of shell history."
),
),
] = None,
json_output: Annotated[
bool,
typer.Option(
"--json",
help=(
"Emit NDJSON events to stdout instead of human-readable output. "
"One JSON object per line, terminated by \\n. See docs/json-output.md "
"for the event reference and stability contract. In this mode, "
"--verbose has no effect and Rich progress is suppressed. "
"Workflow input accepts both API and UI format JSON (UI input "
"triggers a `converted` event before `queued`). The converted "
"workflow graph is always emitted as a `prompt_preview` event "
"before `queued`, so agents have a full audit trail of what "
"the CLI submitted."
),
),
] = False,
print_prompt: Annotated[
bool,
typer.Option(
"--print-prompt",
help=(
"Print the API-format workflow graph that WOULD be sent to /prompt and exit. "
"Does not POST and does not execute. For UI-format input the workflow is "
"converted first (requires a reachable ComfyUI for /object_info); API input "
"is printed as-is with no server hit. In --json mode emits a `prompt_preview` "
"event; otherwise pretty-prints to stdout."
),
),
] = False,
):
if api_key:
api_key = api_key.strip() or None
Expand All @@ -472,22 +525,29 @@ def run(
if not port and len(s) == 2:
port = int(s[1])

local_paths = False
if config.background:
bg_host, bg_port = config.background[0], config.background[1]
if not host:
host = config.background[0]
local_paths = True
if port:
local_paths = False
else:
port = config.background[1]
host = bg_host
if not port:
port = bg_port

if not host:
host = "127.0.0.1"
if not port:
port = 8188

run_inner.execute(workflow, host, port, wait, verbose, local_paths, timeout, api_key=api_key)
run_inner.execute(
workflow,
host,
port,
wait,
verbose,
timeout,
api_key=api_key,
json_mode=json_output,
print_prompt=print_prompt,
)


def validate_comfyui(_env_checker):
Expand Down
Loading
Loading