Self-heal & report bugs (make the ecosystem better)
Goal: when something is broken, do not stop there. Diagnose it, try to fix it
so the user keeps working, and get the fix or report to whoever can fix it
upstream.
Scope of autonomy. Read this first. For defects in OUR repos
(artokun/comfyui-mcp, comfyui-mcp-panel, comfyui-mcp-issue-worker) act
autonomously. Fix, then file, then inform the user with a short summary. Do not
pepper them with permission prompts. For THIRD-PARTY and ComfyUI-core defects
it is offer-and-ask (Step 6). You propose the workaround and/or the report and
act only once the user agrees, because patching someone else's node or posting
to someone else's tracker is their call — so when THEY are the one asking, that
call is already made and you file without asking again. Even for our repos, pause and ask for
a fix that touches the user's own workflow or data, for anything large or
risky, and for anything you cannot make safe.
This is for bugs in software, not ordinary workflow or generation errors (OOM,
missing model, bad params: use troubleshooting). First decide whose bug it is.
When to file — a real defect that cost the user something
This bar governs what YOU decide to file on your own initiative. An explicit
request from the user is handled at the end of this section and is not subject
to it.
Two questions, both must be YES:
- Is it ours, and does it still reproduce? On the CURRENT version — check
before filing, not after. A defect already fixed upstream of the user's
install is noise. Exception — a crash, lost or corrupted work, or a
destroyed workflow is filed on a SINGLE occurrence, with whatever evidence
exists (log tail, stack, minidump, the failing call). Those are rarely
reproducible on demand, and they are the ones most expensive to lose.
- Did it cost the user something? It blocked them, produced a wrong result
they would have kept, lost or corrupted their work, or crashed ComfyUI.
File when both hold:
- A tool, panel, or orchestrator call crashes ComfyUI, loses work, or corrupts a
workflow.
- A tool returns wrong or misleading output the user would act on, or succeeds
while doing something different from what it reported.
- A silent failure: something that should have happened did not, and nothing
said so. (Silence is the expensive kind — the user cannot see it.)
- You could not complete the task, and the reason is a defect in our software.
Do NOT file — say it in chat and move on. None of these apply when the user
asks.
When the user asks explicitly ("report this", "fix this bug"), the bar above
does not apply — you never have to justify cost or reproducibility to them.
Their request settles THAT it is reported; it does not change WHERE, which
Step 2 still decides:
Ours — file it, no further questions.
Third-party or ComfyUI core — their request IS the go-ahead Step 6 exists
to obtain, so route it to that project's GitHub and file it without asking a
second time.
Not a defect at all (OOM, a missing model or node, bad params, a mistake) —
say plainly that it is not a bug in our software and fix it via
troubleshooting. If they still want it recorded after hearing that, file it.
Their call, made with the facts.
A transient you recovered from at no cost to the user — a retry that worked.
Recovering does NOT excuse a crash, lost or corrupted work, or a wrong result
the user might keep. Judge those on the bar above exactly as if you had not
recovered; recovering afterwards undoes none of them. (A crash or lost work
also needs only the one occurrence — see the exception in question 1.)
A missing capability or a feature you wish existed. We are in a stabilisation
freeze, so these are parked on arrival — filing one adds a ticket nobody will
action.
Behaviour that surprised you but was correct, or that you have not actually
diagnosed. An unverified hunch costs a maintainer the whole investigation.
A one-off you cannot reproduce — EXCEPT a crash or lost/corrupted work,
which is filed the first time it happens (see the exception above). For
anything lesser, note it; if it recurs, that second occurrence is the report.
One report per root cause. If several symptoms trace to one component in one
session, file ONE report covering them, not one per symptom. Three separate
reports for three faults in the same backend are three triage passes for one
fix.
Still NOT bug reports (route elsewhere): ordinary generation and workflow
failures such as OOM, a missing model or node, bad params, or user mistakes go
to troubleshooting. Third-party and custom-node bugs go to their GitHub
(Step 6), where you offer and ask first rather than auto-file — unless the user
asked for the report, which is already the go-ahead.
The intake Worker dedupes server-side, so you need not research duplicates — but
that is not a licence to file freely. Over-reporting is now the expensive
failure mode: every low-value report costs a maintainer a read, a triage, and a
close, and it buries the reports that matter. When genuinely in doubt, tell the
user what you saw and let them decide.
Step 1 — Diagnose (root cause, not symptom)
- Read the exact error and stack. For ComfyUI runs:
get_history(action="diagnose"), get_system_stats (action:"logs").
- Follow the stack to the actual file and line. Read the code there.
- Form a concrete root cause and a minimal fix you can defend.
Step 2 — Classify whose bug it is
- Ours.
comfyui-mcp (server/tools/orchestrator/agent),
comfyui-mcp-panel (the sidebar pack / panel JS / __init__.py), or
comfyui-mcp-issue-worker (the intake Worker). Go to Steps 3 to 5 (self-heal, then Worker or PR).
- Third-party. A custom node pack, or ComfyUI core itself. Go to Step 6 (their GitHub; our Worker cannot file there).
Step 3 — Fix it locally FIRST (this is the default, not "when you can")
For any defect in OUR repos (comfyui-mcp / comfyui-mcp-panel /
comfyui-mcp-issue-worker), the default is to fix it before or alongside
filing. Patch the code where it actually runs so the user is unblocked at once
and the report arrives as a near-PR (code plus diff) rather than a ticket. Do
this every time; do not wait to be asked and do not downgrade it to optional.
comfyui-mcp: find the running install from the stack path. If a source
checkout exists, fix the .ts source and npm run build; if only the built
package is present, patch the dist/*.js directly. The patch takes effect on
the next respawn that reloads it. panel_reload covers the agent and its
comfyui tool server, but the long-lived orchestrator process (which serves
the panel_* tools) only reloads code on a full process restart. Disconnect
followed by Connect does NOT restart it either; say so when the patch is in
that process.
comfyui-mcp-panel: patch the file under the pack (web/js/… for UI,
__init__.py for the pack). UI changes need a hard refresh.
Exactly ONE attempt. Do not spiral. Make one focused, minimal, reversible
patch. If that single attempt does not land, or the bug is upstream-only (in
the SDK, in ComfyUI, or it needs a release you cannot make from here), stop
patching, mark it upstream-only, and include the precise change needed in the
report instead. A future update will overwrite a local patch. That is expected;
the user runs the patched version in the meantime. Capture the diff
(git diff, or diff the file you touched) so Step 5 can attach it.
THIRD-PARTY and ComfyUI-core defects are the exception. There you still offer
and ask first before patching or filing, unless the user asked for it (Step 6).
Step 4 — Verify the fix
comfyui-mcp: run the safety gate, which is npm run build (exit 0),
npm test, and npm run test:agent. Do not claim a fix that fails the gate.
- Otherwise: re-run the operation that failed and confirm it now works.
Step 5 — Report it to US (autonomous)
Always scrub secrets first. You are sending this off-machine without a
human reading it, so this is non-negotiable. Replace any sk-…, ghp_…,
github_pat_…, Bearer …, ANTHROPIC_API_KEY, CIVITAI_API_TOKEN, HF_TOKEN,
.env/.dev.vars contents, Authorization: headers, and ?token=/?key=
query params with [REDACTED]; shorten home paths to ~/…. The intake Worker
runs a second secret-scrub server-side as a backstop, but never rely on it.
Scrub here, every time.
Build the body (reuse this shape). When you fixed it, include the diff so we
can reproduce and merge:
### What happened / root cause
### Steps to reproduce
### Exact error (scrubbed)
### Fix
<applied locally: yes/no> <upstream-only: yes/no>
<the diff / patch, or the precise change needed if upstream-only>
### Environment
OS / ComfyUI version / **ComfyUI FRONTEND version** / GPU+VRAM / **comfyui-mcp
version** / **panel version**.
The FRONTEND version is a separate package from ComfyUI itself and they move
independently — `get_system_stats (action:"health")` prints both on the ComfyUI
line. Include it for ANY panel/UI bug. It is not a formality: comfyui-mcp-panel#779
was a blank agent panel on a fresh install where ComfyUI was 0.30.0 on the broken
machine and 0.30.2 on a working one — indistinguishable, and not the cause. The
frontend was 1.50.3 vs 1.47.12, which was the whole answer, and it took an hour of
eliminating the install, two browsers, the cache and the orchestrator to get to a
number that one line of output already had.
Always include BOTH our versions — a bug is only actionable if we know which mcp +
panel build it came from. They're already in your **ENVIRONMENT line** (the
`mcp <ver> · panel <ver>` segment), so just copy them from there. Fallbacks if the
ENV line is missing them: mcp = its `package.json` `version` (or `install_comfyui (action:"environment")`);
panel = `PANEL_VERSION` near the top of the pack's `comfyui-mcp-panel.js`.
Then file it. The report itself is autonomous via the Worker (below). It files
under the PROJECT's own server-side identity, so no user GitHub account is
touched and nothing is done as the user. That is the default and needs no ask.
Default path for everyone is the Worker. POST the report to our intake
Worker. No GitHub account needed; it files and dedups under the project
identity, never yours. This is the autonomous path. Use it for every our-repo
bug REPORT.
Engineer path, ONLY with the user's explicit go-ahead, and only if THEY
want to author a fix PR under THEIR GitHub account. Running gh files,
forks, and PRs as whatever account is currently gh-authed on this machine.
That is acting as the user's GitHub identity, so it is NOT autonomous and NOT
a Worker fallback. Before ever running gh to file, fork, or PR: run
gh auth status, tell the user which account it would act as, and proceed
only if they explicitly agree to submit as that account. If they only want
the bug reported (not to personally author a PR), use the Worker. Never fork,
PR, or gh issue create under an ambient account they did not choose. If the
fix is clean and they agree: branch or gh repo fork, apply the fix, run the
gate (Step 4), push, gh pr create --fill. Never merge; it is for our
review. A Worker 403 or failure falls back to the report_issue prefilled
link below, NEVER to an unprompted gh command.
The Worker POST needs no GitHub account.
The Worker files the issue synchronously. On success the POST response ALWAYS
carries the issue url inline ({ ok:true, url, number, deduped?, job_id }),
so the manual path is one POST with no polling. This shell snippet is the
manual, non-Claude fallback and requires jq for safe JSON parsing. Claude
agents should use the report_issue tool, which already implements this
correctly.
# URL is baked in; override with $COMFYUI_MCP_ISSUE_WORKER_URL if set. The
# client key is a soft anti-spam gate — read it from $COMFYUI_MCP_ISSUE_CLIENT_KEY.
WORKER_URL="${COMFYUI_MCP_ISSUE_WORKER_URL:-https://comfyui-mcp-issue-worker.artokun.workers.dev}"
# Soft anti-spam gate (ships with the panel; not a real secret — the GitHub
# token is server-side in the Worker). Override with $COMFYUI_MCP_ISSUE_CLIENT_KEY.
CLIENT_KEY="${COMFYUI_MCP_ISSUE_CLIENT_KEY:-9b6f2abf09b64006dc6e033f59d2dc8112e34d8347a923c2}"
# 1) Submit — ONE synchronous POST. Write the JSON to a temp file first (the
# body has newlines/quotes). --max-time bounds the request so a hung
# connection can't wedge us.
# body: { "repo": "comfyui-mcp" | "comfyui-mcp-panel", "title", "body", "labels": ["via-panel"] }
# The User-Agent is EXPLICIT and load-bearing (#937). Cloudflare bans some
# default client signatures outright — a Python `urllib.request` POST to this
# endpoint returns 403 with `error code: 1010` (the browser-signature ban),
# while the byte-identical request with any ordinary UA succeeds seconds later.
# Sending a named UA keeps every client path on a known-good signature instead
# of whatever its stdlib happens to advertise.
RESP=$(curl -fsS --max-time 15 -X POST "$WORKER_URL" \
-H "Content-Type: application/json" -H "X-Client-Key: $CLIENT_KEY" \
-H "User-Agent: comfyui-mcp-report-bug/1.0" -H "Accept: application/json" \
--data @"$BODY_JSON_FILE" || true)
# 2) VALIDATE THE WHOLE BODY FIRST with `jq -e .` — it rejects anything that
# isn't a single valid JSON document (trailing garbage → non-zero), so the
# extraction below only ever runs on clean JSON (no partial output before a
# later parse error). Require ok==true AND status!="error" AND a url matching
# the exact GitHub issue shape. EXACTLY ONE outcome: real url → filed;
# anything else (non-2xx/timeout/unreachable, ok!=true, status:"error",
# missing/invalid url, invalid JSON) → prefilled report_issue fallback.
if ! printf '%s' "$RESP" | jq -e -s 'length == 1' >/dev/null 2>&1; then
echo "worker did not return valid JSON — fall back to the report_issue tool for a prefilled GitHub link"
else
URL=$(printf '%s' "$RESP" | jq -r \
'select(.ok==true and (.status!="error")) | .url // empty | select(test("^https://github.com/[^/]+/[^/]+/issues/[0-9]+$"))')
if [ -n "$URL" ]; then
echo "filed: $URL"
else
echo "worker did not return an issue link — fall back to the report_issue tool for a prefilled GitHub link"
fi
fi
On Windows, use this instead. It needs no jq and no Python (#937). The
jq requirement above is what pushed Windows agents onto Python's
urllib.request in the first place, and that client's default User-Agent is
exactly the signature Cloudflare rejects. PowerShell parses JSON natively, so
this path has neither problem:
$WorkerUrl = if ($env:COMFYUI_MCP_ISSUE_WORKER_URL) { $env:COMFYUI_MCP_ISSUE_WORKER_URL }
else { "https://comfyui-mcp-issue-worker.artokun.workers.dev" }
$ClientKey = if ($env:COMFYUI_MCP_ISSUE_CLIENT_KEY) { $env:COMFYUI_MCP_ISSUE_CLIENT_KEY }
else { "9b6f2abf09b64006dc6e033f59d2dc8112e34d8347a923c2" }
# Invoke-RestMethod parses the JSON body itself and THROWS on a non-2xx, so
# both failure shapes land in the same catch — no partial-output window.
try {
$resp = Invoke-RestMethod -Method Post -Uri $WorkerUrl -TimeoutSec 15 `
-ContentType "application/json" `
-Headers @{ "X-Client-Key" = $ClientKey; "User-Agent" = "comfyui-mcp-report-bug/1.0"; "Accept" = "application/json" } `
-InFile $BodyJsonFile
} catch { $resp = $null }
# Same single "filed" condition as the bash path: ok==true, status not "error",
# and a url matching the exact GitHub issue shape. Anything else falls back.
if ($resp -and $resp.ok -eq $true -and $resp.status -ne "error" -and
$resp.url -match '^https://github\.com/[^/]+/[^/]+/issues/\d+$') {
"filed: $($resp.url)"
} else {
"worker did not return an issue link — fall back to the report_issue tool for a prefilled GitHub link"
}
A real url from the POST is the only "filed" outcome. Any submit failure
(401, non-2xx, timeout, unreachable), ok not true, a status:"error"
body, a missing or invalid url, or invalid JSON means fall back to
report_issue for a prefilled link the user submits in one click. Never tell
the user it was accepted without a real issue link. A GET /status/<job_id>
endpoint exists to re-fetch the link later, but it is NOT needed to file, so
do not poll. Show the link only if they want it. The filing is autonomous,
so a one-line "filed #123" is enough (Step 7).
Fallback (no gh, no Worker URL): use the report_issue tool for a
prefilled GitHub issue link the user can submit in one click.
Step 6 — Third-party / ComfyUI-core bugs (offer + ASK first, unless they asked)
Our Worker only files into OUR repos, so these go to their GitHub. Unlike
our-repo defects (Steps 3 to 5, which you handle autonomously), third-party
bugs are offer-and-ask at every step. Patching someone else's node and posting
to someone else's tracker are the user's calls, not yours — which is why an
explicit "report this" from the user already settles it. When they have asked,
file it without a second confirmation; ask only when the offer originated with
you.
- Ask before patching. You may offer a local workaround (for example, patch
the custom node so the user is not blocked), but apply it only once the user
says yes. Same keep-the-patch logic once approved.
- Ask before filing — unless they already asked. Identify the node or
project's GitHub repo (from its metadata,
install_custom_node
(action: "list"), or its folder). Then, with the user's go-ahead (which an
explicit "report this" already is), use report_issue with that owner/repo (it returns a
prefilled link the user reviews and submits; it does not auto-file into
third-party repos), OR gh issue create -R owner/repo if gh is authed and
they agree.
- If the user has no GitHub account, offer to walk them through creating one
(github.com/signup) so they can file it. That is how the bug reaches the
people who can fix it. We cannot file it for them.
Step 7 — Inform the user (the only message they need)
A short, concrete summary, not a request. For example:
Hit a bug in panel_set_widget (it errored on subgraph inner nodes). I
patched it locally so it works now, and filed a bugfix report on your behalf
(#123). You're running the patched version; a future update will replace the
patch once we ship the fix upstream.
If upstream-only, say it is logged with us (or the third-party project) and
what the temporary workaround is, if any.
Absolute rules
- Scrub secrets before anything leaves the machine, every time.
- Never merge a PR; humans review.
- Patches stay minimal and reversible; never touch the user's workflow data
without asking.
- Do not claim a fix you did not verify (Step 4).
- Do not file to be thorough. A report is a claim on a maintainer's
attention; if you cannot say what it cost the user, it is not one. Applies to
what you file on your own initiative — when the user asks, that is their call
to make and no justification is owed.
Sources
- Official: comfyui-mcp intake Worker and this skill (this repo).
- Empirical: none. Product reporting policy, not reverse-engineered from a vendor graph.
1---2name: report-bug3description: Self-heal and report bugs. Use when a defect in comfyui-mcp, the sidebar panel, a third-party custom node, or ComfyUI core actually cost the user something - it blocked them, produced a wrong result they would keep, lost or corrupted work, or crashed ComfyUI. For OUR repos (comfyui-mcp, comfyui-mcp-panel, comfyui-mcp-issue-worker) diagnose and fix locally FIRST so the user is unblocked, then file with the diff so reports arrive as near-PRs, not tickets; attempt the fix ONCE, and if upstream-only say so with the precise change. Our intake Worker takes our repos; third-party goes to the node's own GitHub. Do NOT file a transient you recovered from at no cost, a missing capability (stabilisation freeze - parked on arrival), or behaviour that was merely surprising; say those in chat. A crash or lost/corrupted work is STILL filed even if you recovered, on a single occurrence. One report per root cause. An explicit "report this" bypasses this bar - route it and file.4---56# Self-heal & report bugs (make the ecosystem better)78Goal: when something is broken, do not stop there. Diagnose it, try to fix it9so the user keeps working, and get the fix or report to whoever can fix it10upstream.1112**Scope of autonomy. Read this first.** For defects in OUR repos13(`artokun/comfyui-mcp`, `comfyui-mcp-panel`, `comfyui-mcp-issue-worker`) act14autonomously. Fix, then file, then inform the user with a short summary. Do not15pepper them with permission prompts. For THIRD-PARTY and ComfyUI-core defects16it is offer-and-ask (Step 6). You propose the workaround and/or the report and17act only once the user agrees, because patching someone else's node or posting18to someone else's tracker is their call — so when THEY are the one asking, that19call is already made and you file without asking again. Even for our repos, pause and ask for20a fix that touches the user's own workflow or data, for anything large or21risky, and for anything you cannot make safe.2223This is for bugs in software, not ordinary workflow or generation errors (OOM,24missing model, bad params: use `troubleshooting`). First decide whose bug it is.2526## When to file — a real defect that cost the user something2728This bar governs what YOU decide to file on your own initiative. An explicit29request from the user is handled at the end of this section and is not subject30to it.3132Two questions, both must be YES:33341. **Is it ours, and does it still reproduce?** On the CURRENT version — check35 before filing, not after. A defect already fixed upstream of the user's36 install is noise. **Exception —** a crash, lost or corrupted work, or a37 destroyed workflow is filed on a SINGLE occurrence, with whatever evidence38 exists (log tail, stack, minidump, the failing call). Those are rarely39 reproducible on demand, and they are the ones most expensive to lose.402. **Did it cost the user something?** It blocked them, produced a wrong result41 they would have kept, lost or corrupted their work, or crashed ComfyUI.4243File when both hold:4445- A tool, panel, or orchestrator call crashes ComfyUI, loses work, or corrupts a46 workflow.47- A tool returns wrong or misleading output the user would act on, or succeeds48 while doing something different from what it reported.49- A silent failure: something that should have happened did not, and nothing50 said so. (Silence is the expensive kind — the user cannot see it.)51- You could not complete the task, and the reason is a defect in our software.5253**Do NOT file** — say it in chat and move on. None of these apply when the user54asks.5556**When the user asks explicitly** ("report this", "fix this bug"), the bar above57does not apply — you never have to justify cost or reproducibility to them.58Their request settles THAT it is reported; it does not change WHERE, which59Step 2 still decides:6061- **Ours** — file it, no further questions.62- **Third-party or ComfyUI core** — their request IS the go-ahead Step 6 exists63 to obtain, so route it to that project's GitHub and file it without asking a64 second time.65- **Not a defect at all** (OOM, a missing model or node, bad params, a mistake) —66 say plainly that it is not a bug in our software and fix it via67 `troubleshooting`. If they still want it recorded after hearing that, file it.68 Their call, made with the facts.6970- A transient you recovered from at no cost to the user — a retry that worked.71 Recovering does NOT excuse a crash, lost or corrupted work, or a wrong result72 the user might keep. Judge those on the bar above exactly as if you had not73 recovered; recovering afterwards undoes none of them. (A crash or lost work74 also needs only the one occurrence — see the exception in question 1.)75- A missing capability or a feature you wish existed. We are in a stabilisation76 freeze, so these are parked on arrival — filing one adds a ticket nobody will77 action.78- Behaviour that surprised you but was correct, or that you have not actually79 diagnosed. An unverified hunch costs a maintainer the whole investigation.80- A one-off you cannot reproduce — EXCEPT a crash or lost/corrupted work,81 which is filed the first time it happens (see the exception above). For82 anything lesser, note it; if it recurs, that second occurrence is the report.8384**One report per root cause.** If several symptoms trace to one component in one85session, file ONE report covering them, not one per symptom. Three separate86reports for three faults in the same backend are three triage passes for one87fix.8889Still NOT bug reports (route elsewhere): ordinary generation and workflow90failures such as OOM, a missing model or node, bad params, or user mistakes go91to `troubleshooting`. Third-party and custom-node bugs go to their GitHub92(Step 6), where you offer and ask first rather than auto-file — unless the user93asked for the report, which is already the go-ahead.9495The intake Worker dedupes server-side, so you need not research duplicates — but96that is not a licence to file freely. Over-reporting is now the expensive97failure mode: every low-value report costs a maintainer a read, a triage, and a98close, and it buries the reports that matter. When genuinely in doubt, tell the99user what you saw and let them decide.100101## Step 1 — Diagnose (root cause, not symptom)102103- Read the exact error and stack. For ComfyUI runs: `get_history(action="diagnose")`, `get_system_stats (action:"logs")`.104- Follow the stack to the actual file and line. Read the code there.105- Form a concrete root cause and a minimal fix you can defend.106107## Step 2 — Classify whose bug it is108109- **Ours.** `comfyui-mcp` (server/tools/orchestrator/agent),110 `comfyui-mcp-panel` (the sidebar pack / panel JS / `__init__.py`), or111 `comfyui-mcp-issue-worker` (the intake Worker). Go to Steps 3 to 5 (self-heal, then Worker or PR).112- **Third-party.** A custom node pack, or ComfyUI core itself. Go to Step 6 (their GitHub; our Worker cannot file there).113114## Step 3 — Fix it locally FIRST (this is the default, not "when you can")115116For any defect in OUR repos (`comfyui-mcp` / `comfyui-mcp-panel` /117`comfyui-mcp-issue-worker`), the default is to fix it before or alongside118filing. Patch the code where it actually runs so the user is unblocked at once119and the report arrives as a near-PR (code plus diff) rather than a ticket. Do120this every time; do not wait to be asked and do not downgrade it to optional.121122- `comfyui-mcp`: find the running install from the stack path. If a source123 checkout exists, fix the `.ts` source and `npm run build`; if only the built124 package is present, patch the `dist/*.js` directly. The patch takes effect on125 the next respawn that reloads it. `panel_reload` covers the agent and its126 comfyui tool server, but the long-lived orchestrator process (which serves127 the `panel_*` tools) only reloads code on a full process restart. Disconnect128 followed by Connect does NOT restart it either; say so when the patch is in129 that process.130- `comfyui-mcp-panel`: patch the file under the pack (`web/js/…` for UI,131 `__init__.py` for the pack). UI changes need a hard refresh.132133**Exactly ONE attempt. Do not spiral.** Make one focused, minimal, reversible134patch. If that single attempt does not land, or the bug is upstream-only (in135the SDK, in ComfyUI, or it needs a release you cannot make from here), stop136patching, mark it `upstream-only`, and include the precise change needed in the137report instead. A future update will overwrite a local patch. That is expected;138the user runs the patched version in the meantime. Capture the diff139(`git diff`, or diff the file you touched) so Step 5 can attach it.140141THIRD-PARTY and ComfyUI-core defects are the exception. There you still offer142and ask first before patching or filing, unless the user asked for it (Step 6).143144## Step 4 — Verify the fix145146- `comfyui-mcp`: run the safety gate, which is `npm run build` (exit 0),147 `npm test`, and `npm run test:agent`. Do not claim a fix that fails the gate.148- Otherwise: re-run the operation that failed and confirm it now works.149150## Step 5 — Report it to US (autonomous)151152**Always scrub secrets first.** You are sending this off-machine without a153human reading it, so this is non-negotiable. Replace any `sk-…`, `ghp_…`,154`github_pat_…`, `Bearer …`, `ANTHROPIC_API_KEY`, `CIVITAI_API_TOKEN`, `HF_TOKEN`,155`.env`/`.dev.vars` contents, `Authorization:` headers, and `?token=`/`?key=`156query params with `[REDACTED]`; shorten home paths to `~/…`. The intake Worker157runs a second secret-scrub server-side as a backstop, but never rely on it.158Scrub here, every time.159160Build the body (reuse this shape). When you fixed it, include the diff so we161can reproduce and merge:162163```164### What happened / root cause165### Steps to reproduce166### Exact error (scrubbed)167### Fix168<applied locally: yes/no> <upstream-only: yes/no>169<the diff / patch, or the precise change needed if upstream-only>170### Environment171OS / ComfyUI version / **ComfyUI FRONTEND version** / GPU+VRAM / **comfyui-mcp172version** / **panel version**.173174The FRONTEND version is a separate package from ComfyUI itself and they move175independently — `get_system_stats (action:"health")` prints both on the ComfyUI176line. Include it for ANY panel/UI bug. It is not a formality: comfyui-mcp-panel#779177was a blank agent panel on a fresh install where ComfyUI was 0.30.0 on the broken178machine and 0.30.2 on a working one — indistinguishable, and not the cause. The179frontend was 1.50.3 vs 1.47.12, which was the whole answer, and it took an hour of180eliminating the install, two browsers, the cache and the orchestrator to get to a181number that one line of output already had.182Always include BOTH our versions — a bug is only actionable if we know which mcp +183panel build it came from. They're already in your **ENVIRONMENT line** (the184`mcp <ver> · panel <ver>` segment), so just copy them from there. Fallbacks if the185ENV line is missing them: mcp = its `package.json` `version` (or `install_comfyui (action:"environment")`);186panel = `PANEL_VERSION` near the top of the pack's `comfyui-mcp-panel.js`.187```188189Then file it. The report itself is autonomous via the Worker (below). It files190under the PROJECT's own server-side identity, so no user GitHub account is191touched and nothing is done as the user. That is the default and needs no ask.192193- **Default path for everyone is the Worker.** POST the report to our intake194 Worker. No GitHub account needed; it files and dedups under the project195 identity, never yours. This is the autonomous path. Use it for every our-repo196 bug REPORT.197- **Engineer path, ONLY with the user's explicit go-ahead, and only if THEY198 want to author a fix PR under THEIR GitHub account.** Running `gh` files,199 forks, and PRs as whatever account is currently `gh`-authed on this machine.200 That is acting as the user's GitHub identity, so it is NOT autonomous and NOT201 a Worker fallback. Before ever running `gh` to file, fork, or PR: run202 `gh auth status`, tell the user which account it would act as, and proceed203 only if they explicitly agree to submit as that account. If they only want204 the bug reported (not to personally author a PR), use the Worker. Never fork,205 PR, or `gh issue create` under an ambient account they did not choose. If the206 fix is clean and they agree: branch or `gh repo fork`, apply the fix, run the207 gate (Step 4), push, `gh pr create --fill`. **Never merge**; it is for our208 review. A Worker 403 or failure falls back to the `report_issue` prefilled209 link below, NEVER to an unprompted `gh` command.210211 The Worker POST needs no GitHub account.212213 The Worker files the issue synchronously. On success the POST response ALWAYS214 carries the issue `url` inline (`{ ok:true, url, number, deduped?, job_id }`),215 so the manual path is one POST with no polling. This shell snippet is the216 manual, non-Claude fallback and requires `jq` for safe JSON parsing. Claude217 agents should use the `report_issue` tool, which already implements this218 correctly.219220 ```bash221 # URL is baked in; override with $COMFYUI_MCP_ISSUE_WORKER_URL if set. The222 # client key is a soft anti-spam gate — read it from $COMFYUI_MCP_ISSUE_CLIENT_KEY.223 WORKER_URL="${COMFYUI_MCP_ISSUE_WORKER_URL:-https://comfyui-mcp-issue-worker.artokun.workers.dev}"224 # Soft anti-spam gate (ships with the panel; not a real secret — the GitHub225 # token is server-side in the Worker). Override with $COMFYUI_MCP_ISSUE_CLIENT_KEY.226 CLIENT_KEY="${COMFYUI_MCP_ISSUE_CLIENT_KEY:-9b6f2abf09b64006dc6e033f59d2dc8112e34d8347a923c2}"227228 # 1) Submit — ONE synchronous POST. Write the JSON to a temp file first (the229 # body has newlines/quotes). --max-time bounds the request so a hung230 # connection can't wedge us.231 # body: { "repo": "comfyui-mcp" | "comfyui-mcp-panel", "title", "body", "labels": ["via-panel"] }232 # The User-Agent is EXPLICIT and load-bearing (#937). Cloudflare bans some233 # default client signatures outright — a Python `urllib.request` POST to this234 # endpoint returns 403 with `error code: 1010` (the browser-signature ban),235 # while the byte-identical request with any ordinary UA succeeds seconds later.236 # Sending a named UA keeps every client path on a known-good signature instead237 # of whatever its stdlib happens to advertise.238 RESP=$(curl -fsS --max-time 15 -X POST "$WORKER_URL" \239 -H "Content-Type: application/json" -H "X-Client-Key: $CLIENT_KEY" \240 -H "User-Agent: comfyui-mcp-report-bug/1.0" -H "Accept: application/json" \241 --data @"$BODY_JSON_FILE" || true)242243 # 2) VALIDATE THE WHOLE BODY FIRST with `jq -e .` — it rejects anything that244 # isn't a single valid JSON document (trailing garbage → non-zero), so the245 # extraction below only ever runs on clean JSON (no partial output before a246 # later parse error). Require ok==true AND status!="error" AND a url matching247 # the exact GitHub issue shape. EXACTLY ONE outcome: real url → filed;248 # anything else (non-2xx/timeout/unreachable, ok!=true, status:"error",249 # missing/invalid url, invalid JSON) → prefilled report_issue fallback.250 if ! printf '%s' "$RESP" | jq -e -s 'length == 1' >/dev/null 2>&1; then251 echo "worker did not return valid JSON — fall back to the report_issue tool for a prefilled GitHub link"252 else253 URL=$(printf '%s' "$RESP" | jq -r \254 'select(.ok==true and (.status!="error")) | .url // empty | select(test("^https://github.com/[^/]+/[^/]+/issues/[0-9]+$"))')255 if [ -n "$URL" ]; then256 echo "filed: $URL"257 else258 echo "worker did not return an issue link — fall back to the report_issue tool for a prefilled GitHub link"259 fi260 fi261 ```262 **On Windows, use this instead. It needs no `jq` and no Python** (#937). The263 `jq` requirement above is what pushed Windows agents onto Python's264 `urllib.request` in the first place, and that client's default User-Agent is265 exactly the signature Cloudflare rejects. PowerShell parses JSON natively, so266 this path has neither problem:267268 ```powershell269 $WorkerUrl = if ($env:COMFYUI_MCP_ISSUE_WORKER_URL) { $env:COMFYUI_MCP_ISSUE_WORKER_URL }270 else { "https://comfyui-mcp-issue-worker.artokun.workers.dev" }271 $ClientKey = if ($env:COMFYUI_MCP_ISSUE_CLIENT_KEY) { $env:COMFYUI_MCP_ISSUE_CLIENT_KEY }272 else { "9b6f2abf09b64006dc6e033f59d2dc8112e34d8347a923c2" }273274 # Invoke-RestMethod parses the JSON body itself and THROWS on a non-2xx, so275 # both failure shapes land in the same catch — no partial-output window.276 try {277 $resp = Invoke-RestMethod -Method Post -Uri $WorkerUrl -TimeoutSec 15 `278 -ContentType "application/json" `279 -Headers @{ "X-Client-Key" = $ClientKey; "User-Agent" = "comfyui-mcp-report-bug/1.0"; "Accept" = "application/json" } `280 -InFile $BodyJsonFile281 } catch { $resp = $null }282283 # Same single "filed" condition as the bash path: ok==true, status not "error",284 # and a url matching the exact GitHub issue shape. Anything else falls back.285 if ($resp -and $resp.ok -eq $true -and $resp.status -ne "error" -and286 $resp.url -match '^https://github\.com/[^/]+/[^/]+/issues/\d+$') {287 "filed: $($resp.url)"288 } else {289 "worker did not return an issue link — fall back to the report_issue tool for a prefilled GitHub link"290 }291 ```292293 A real `url` from the POST is the only "filed" outcome. Any submit failure294 (`401`, non-2xx, timeout, unreachable), `ok` not `true`, a `status:"error"`295 body, a missing or invalid url, or invalid JSON means fall back to296 `report_issue` for a prefilled link the user submits in one click. Never tell297 the user it was accepted without a real issue link. A `GET /status/<job_id>`298 endpoint exists to re-fetch the link later, but it is NOT needed to file, so299 do not poll. Show the link only if they want it. The filing is autonomous,300 so a one-line "filed #123" is enough (Step 7).301- **Fallback** (no `gh`, no Worker URL): use the `report_issue` tool for a302 prefilled GitHub issue link the user can submit in one click.303304## Step 6 — Third-party / ComfyUI-core bugs (offer + ASK first, unless they asked)305306Our Worker only files into OUR repos, so these go to their GitHub. Unlike307our-repo defects (Steps 3 to 5, which you handle autonomously), third-party308bugs are offer-and-ask at every step. Patching someone else's node and posting309to someone else's tracker are the user's calls, not yours — which is why an310explicit "report this" from the user already settles it. When they have asked,311file it without a second confirmation; ask only when the offer originated with312you.313314- **Ask before patching.** You may offer a local workaround (for example, patch315 the custom node so the user is not blocked), but apply it only once the user316 says yes. Same keep-the-patch logic once approved.317- **Ask before filing — unless they already asked.** Identify the node or318 project's GitHub repo (from its metadata, `install_custom_node`319 (`action: "list"`), or its folder). Then, with the user's go-ahead (which an320 explicit "report this" already is), use `report_issue` with that `owner/repo` (it returns a321 prefilled link the user reviews and submits; it does not auto-file into322 third-party repos), OR `gh issue create -R owner/repo` if `gh` is authed and323 they agree.324- If the user has no GitHub account, offer to walk them through creating one325 (github.com/signup) so they can file it. That is how the bug reaches the326 people who can fix it. We cannot file it for them.327328## Step 7 — Inform the user (the only message they need)329330A short, concrete summary, not a request. For example:331332> Hit a bug in `panel_set_widget` (it errored on subgraph inner nodes). I333> patched it locally so it works now, and filed a bugfix report on your behalf334> (#123). You're running the patched version; a future update will replace the335> patch once we ship the fix upstream.336337If upstream-only, say it is logged with us (or the third-party project) and338what the temporary workaround is, if any.339340## Absolute rules341342- Scrub secrets before anything leaves the machine, every time.343- Never merge a PR; humans review.344- Patches stay minimal and reversible; never touch the user's workflow data345 without asking.346- Do not claim a fix you did not verify (Step 4).347- Do not file to be thorough. A report is a claim on a maintainer's348 attention; if you cannot say what it cost the user, it is not one. Applies to349 what you file on your own initiative — when the user asks, that is their call350 to make and no justification is owed.351352## Sources353354- **Official:** comfyui-mcp intake Worker and this skill (this repo).355- **Empirical:** none. Product reporting policy, not reverse-engineered from a vendor graph.