Skip to content

feat: honor COMFY_LOCAL_URL env var for the local ComfyUI address (BE-3959)#571

Open
mattmillerai wants to merge 3 commits into
mainfrom
matt/be-3959-comfy-local-url
Open

feat: honor COMFY_LOCAL_URL env var for the local ComfyUI address (BE-3959)#571
mattmillerai wants to merge 3 commits into
mainfrom
matt/be-3959-comfy-local-url

Conversation

@mattmillerai

Copy link
Copy Markdown
Collaborator

ELI-5

comfy-cli always assumed your local ComfyUI lives at 127.0.0.1:8188. If you
had one running somewhere else (say deep-comfy's native ComfyUI on :8189,
started outside comfy-cli), your only option was to pass --host/--port on
every single command — and comfy env / comfy upload / comfy download
had no override at all. This PR adds one environment variable, COMFY_LOCAL_URL,
that points every command at the right address:

export COMFY_LOCAL_URL=http://127.0.0.1:8189
comfy env        # reports :8189
comfy run ...    # targets :8189
comfy jobs status $ID
comfy upload img.png

A per-command --host/--port flag still wins over the env var. Fixes the
comfy-local-mcp breakage on boxes where ComfyUI isn't on :8188 (BE-3956).

What changed

New module comfy_cli/local_address.py:

  • parse_local_url(value) — accepts http://host:port, host:port, or
    http://host (port defaults to 8188; scheme optional and, if present,
    must be http; bracketed IPv6 literals like [::1]:8189 supported). Raises
    ValueError on garbage.
  • resolve_local_host_port(host, port, background) — precedence
    flag > COMFY_LOCAL_URL > config.background > 127.0.0.1:8188, with
    host and port resolved independently (an explicit --port with no
    --host still takes the env var's host, etc.). A malformed COMFY_LOCAL_URL
    is ignored with a one-line stderr warning (deduplicated per process) so a
    typo can't hard-break every command.

Routed through it at every local resolution site:

  • target.py::resolve_target local leg — the central chokepoint, so this
    alone fixes upload/download, models search, project, workflow, and
    the CQL object_info fetch.
  • host_port.py::resolve_host_port — the shared resolver for comfy run and
    every comfy jobs subcommand; env layer inserted between the flag and the
    config.background fallback.
  • command/job_watcher.py — per-job recorded state still wins:
    flag > state.port > env > default (so a running watcher keeps polling
    the server it was launched against). IPv6 host now bracketed before
    _snapshot (matches the jobs resolver; pre-existing gap for state.host).
  • env_checker.pycomfy env (and its --json, which comfy-local-mcp's
    server_info returns) now probes AND reports the resolved address
    instead of the hardcoded http://localhost:8188 strings.
  • CQL default-fill sites (cql/engine.py, cql/loader.py) switched from a
    literal 127.0.0.1/8188 signature default to None, plus the leaf
    callers in command/workflow.py, command/workflow_fragments.py,
    command/nodes.py, and cmdline.py, so they stop shadowing the env var
    with a literal default and resolve through resolve_target.
  • command/setup.py cosmetic probe + the comfy which panel probe in
    cmdline.py.

Docs: COMFY_LOCAL_URL documented in README.md, the agent-facing
comfy_cli/skills/comfy/SKILL.md routing section, and the new module's
docstring.

Testing

  • New tests/comfy_cli/test_local_address.py (39 tests): parse_local_url
    (full URL / host:port / bare host / IPv6 [::1]:8189 / http://host /
    invalid inputs raise), precedence (flag > env > background > default,
    independent host/port, invalid env ignored + deduped warning), and
    integration that resolve_target(where='local'), jobs._resolve_host_port,
    the run resolver, and comfy env --json all honor the env var (flag wins).
  • Full suite green (2612 passed, 37 skipped); ruff check + ruff format --check clean under the CI-pinned ruff==0.15.15.
  • End-to-end smoke with COMFY_LOCAL_URL=http://127.0.0.1:8189 exported
    and no flags — comfy --json jobs status, comfy --json run, and
    comfy upload all target :8189 (server_not_running / connection-refused
    on 127.0.0.1:8189); with --port 8188 the flag wins (targets :8188).

Judgment calls

  • No new COMFY_LOCAL_URL handling in launch.pycomfy launch starts
    a server on a chosen port; it shouldn't be redirected by the env var. Left as-is.
  • CQL signature defaults 127.0.0.1/8188None is the only behavior
    change to existing code (everything else is additive). For the no-env case it
    resolves to the identical 127.0.0.1:8188; all networked callers already pass
    host/port explicitly, so the default only ever applied to the no-arg/offline path.
  • Not a capability-denying change (negative-claim falsification N/A — this PR
    adds a capability, no deny/dead-end path).

…-3959)

Add a process-wide override for the local ComfyUI target so every command
(env, run, jobs, upload/download, nodes, workflow, models search, project,
CQL) can point at a ComfyUI on a non-8188 address started outside comfy-cli.

New module comfy_cli/local_address.py:
- parse_local_url: http://host:port | host:port | http://host (port default
  8188, scheme optional/http-only, IPv6 [::1]:8189 supported).
- resolve_local_host_port: precedence flag > COMFY_LOCAL_URL > config.background
  > 127.0.0.1:8188, host and port resolved independently. A malformed env var
  is ignored with a one-line stderr warning (deduped) so it can't hard-break
  every command.

Routed through it at every local resolution site: target.resolve_target (fixes
upload/download, models, project, workflow, CQL), host_port.resolve_host_port
(run + jobs), job_watcher (flag > state > env > default), and env_checker
(comfy env now probes AND reports the resolved address). CQL default-fill sites
switched from a literal 127.0.0.1/8188 default to None so they stop shadowing
the env var and resolve through resolve_target.
@mattmillerai mattmillerai added agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review labels Jul 21, 2026
@mattmillerai
mattmillerai marked this pull request as ready for review July 21, 2026 23:15
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 25554a9c-3a59-48c9-9e3f-a8e89d890c16

📥 Commits

Reviewing files that changed from the base of the PR and between d2858b9 and a8fae2f.

📒 Files selected for processing (16)
  • README.md
  • comfy_cli/cmdline.py
  • comfy_cli/command/job_watcher.py
  • comfy_cli/command/nodes.py
  • comfy_cli/command/setup.py
  • comfy_cli/command/workflow.py
  • comfy_cli/command/workflow_fragments.py
  • comfy_cli/cql/engine.py
  • comfy_cli/cql/loader.py
  • comfy_cli/env_checker.py
  • comfy_cli/host_port.py
  • comfy_cli/local_address.py
  • comfy_cli/skills/comfy/SKILL.md
  • comfy_cli/target.py
  • tests/comfy_cli/test_env_checker.py
  • tests/comfy_cli/test_local_address.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-3959-comfy-local-url
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-3959-comfy-local-url

Comment @coderabbitai help to get the list of available commands.

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request labels Jul 21, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

Found 6 finding(s).

Severity Count
🟡 Medium 4
🟢 Low 2

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

Comment thread comfy_cli/cmdline.py
Comment thread comfy_cli/env_checker.py
Comment thread comfy_cli/local_address.py
Comment thread comfy_cli/local_address.py
Comment thread comfy_cli/command/setup.py
Comment thread comfy_cli/local_address.py Outdated
…port fall-through (BE-3959)

Address cursor-review panel findings on COMFY_LOCAL_URL support:

- Bracket bare IPv6 literals at the probe choke point (check_comfy_server_running)
  and at the `comfy which` / `comfy env` / setup display sites, so an address like
  COMFY_LOCAL_URL=http://[::1]:8189 yields a valid http://[::1]:8189 URL instead of
  the malformed http://::1:8189 (which made the server always read as "down").
  _bracket_host is idempotent so already-bracketed callers aren't double-bracketed.
- Reject '['/']' in _validate_host: a stray-bracket authority (e.g. a[xyz]) is now
  ignored-with-warning rather than flowing into a malformed URL or being parsed as a
  Rich markup tag and crashing the command. Well-formed IPv6 is unaffected (brackets
  are stripped before validation).
- parse_local_url returns port=None when the value omits a port, so a host-only
  COMFY_LOCAL_URL falls through to a recorded background port instead of shadowing it
  with a defaulted 8188 (honors the documented independent env > background > default).
- Redact user:pass@ userinfo from the invalid-value warning (both the echoed value and
  the parse error message) so credentials in a mistyped var aren't logged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review enhancement New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant