- Implement ComfyCliExecutor for async command execution - Add REST API endpoints for comfy-cli: - Configuration management (/comfy-cli/config/*) - Model management (/comfy-cli/model/*) - Node management (/comfy-cli/node/*) - Create API handlers: ConfigHandler, ModelHandler, NodeHandler - Register routes in comfy_cli_routes.py - Update main __init__.py to support dual CLI (cm-cli + comfy-cli) - Add comprehensive documentation: - COMFY_CLI_API.md: Complete API reference - COMFY_CLI_QUICKSTART.md: Quick start guide - Update README.md with dual CLI support - Update AGENTS.md development guide - Add comfy-cli reference documentation in docs/references/ - Remove trailing spaces from all Python and Markdown files - Ensure all code passes syntax validation Features: - Async job tracking for long-running operations - Structured JSON responses - Comprehensive error handling - Direct filesystem access for model listing (more reliable) - Support for CivitAI and HuggingFace API tokens
40 KiB
ComfyCLI 配置与使用指南
文档版本:1.5 最后更新:2026-03-17 适用环境:ComfyUI-Nvidia-Docker 部署 适配 comfy-cli 版本:≥1.3.8(已验证 1.6.0 稳定版) 验证报告:
comfy-cli-verification-report.mdDocker 自动化脚本:comfy-cli-docker-setup.sh命令参考手册:comfy-cli-command-reference.md— 所有 CLI 命令的参数和输出格式 表格解析指南:comfy-cli-table-parser.md— box table → JSON/CSV 解析方案 ⭐新增 API Reference:comfy-cli-api-reference.md— REST API 设计参考 REST 实现指南:comfy-cli-rest-implementation.md— REST 服务器实现代码
目录
1. 概述
1.1 什么是 ComfyCLI
comfy-cli 是由 Comfy-Org 官方维护的命令行工具,用于管理和操作 ComfyUI。与 ComfyUI-Manager 的 cm-cli 不同,comfy-cli 是一个独立的管理工具,提供:
- ✅ 模型下载与管理(核心优势)
- ✅ 自定义节点管理
- ✅ ComfyUI 安装与更新
- ✅ 工作区管理
- ✅ Workflow 执行
- ✅ 后台服务管理
1.2 与 cm-cli 的对比
| 功能 | cm-cli | comfy-cli |
|---|---|---|
| 模型下载 | ❌ | ✅ |
| 模型列表/删除 | ❌ | ✅ |
| 节点管理 | ✅ | ✅ |
| ComfyUI 安装 | ❌ | ✅ |
| 工作区管理 | ❌ | ✅ |
| REST API | ✅ (通过 custom node) | ❌ |
1.3 适用场景
- 需要通过命令行下载和管理模型
- 需要脚本化 ComfyUI 管理操作
- 需要多工作区管理
- 需要与现有 ComfyUI-Manager 共存
2. ComfyCLI 架构
2.1 核心组件
comfy-cli/
├── comfy_cli/
│ ├── __init__.py # 包初始化
│ ├── cmdline.py # 命令行入口和命令注册
│ ├── config_manager.py # 配置文件管理
│ ├── workspace_manager.py # 工作区管理
│ ├── constants.py # 常量定义
│ ├── command/
│ │ ├── install.py # 安装命令
│ │ ├── launch.py # 启动命令
│ │ ├── models/ # 模型管理命令
│ │ │ └── models.py # 下载/删除/列表
│ │ └── custom_nodes/ # 自定义节点命令
│ │ └── command.py # 节点管理实现
│ └── utils/ # 工具函数
└── pyproject.toml # 项目配置
2.2 配置文件系统
~/.config/comfy-cli/
└── config.ini # 主配置文件
config.ini 结构:
[DEFAULT]
default_workspace = /path/to/ComfyUI
recent_workspace = /path/to/last/used
default_launch_extras = --listen 0.0.0.0
enable_tracking = true
background = ('127.0.0.1', 8188, 12345)
civitai_api_token = xxx
hf_api_token = xxx
2.3 工作区检测机制
comfy-cli 通过 Git 仓库识别 ComfyUI 安装:
COMFY_ORIGIN_URL_CHOICES = {
"git@github.com:comfyanonymous/ComfyUI.git",
"https://github.com/comfyanonymous/ComfyUI.git",
"https://github.com/Comfy-Org/ComfyUI.git",
# ...
}
工作区优先级:
--workspace=<path>- 显式指定--recent- 最近使用--here- 当前目录- 当前目录是 ComfyUI 仓库
set-default设置的默认路径- 默认路径 (
~/comfy/ComfyUI)
3. 安装指南
3.1 前置要求
- Python 3.9+(必须与 ComfyUI 使用相同环境)
- Git(用于仓库检测)
- pip 或 uv(推荐)
3.2 在 Docker 环境中安装
对于 ComfyUI-Nvidia-Docker 部署,有两种安装方式:
方式 A:在容器内安装(推荐)
# 进入运行中的容器
docker exec -it comfyui-nvidia bash
# 激活虚拟环境(如果有)
source /comfy/mnt/venv/bin/activate
# 安装 comfy-cli
pip install comfy-cli
# 验证安装
comfy --version
方式 B:使用 user_script.bash 持久化
编辑 run/user_script.bash:
#!/bin/bash
# user_script.bash - 在容器启动时执行
# 安装 comfy-cli
if ! command -v comfy &> /dev/null; then
echo "Installing comfy-cli..."
/comfy/mnt/venv/bin/pip install comfy-cli
fi
# 设置默认工作区
/comfy/mnt/venv/bin/comfy set-default /basedir 2>/dev/null || true
3.3 验证安装
# 检查版本
comfy --version
# 查看帮助
comfy --help
# 检查环境
comfy env
4. 配置系统详解
4.1 配置文件位置
| 操作系统 | 配置文件路径 |
|---|---|
| Linux | ~/.config/comfy-cli/config.ini |
| macOS | ~/Library/Application Support/comfy-cli/config.ini |
| Windows | %LOCALAPPDATA%\comfy-cli\config.ini |
4.2 配置项说明
[DEFAULT]
# 默认工作区路径(通过 comfy set-default 设置)
default_workspace = /basedir
# 最近使用的工作区(自动更新)
recent_workspace = /basedir
# 启动 ComfyUI 时的默认参数
default_launch_extras = --listen 0.0.0.0 --port 8188
# 是否启用使用追踪(可选)
enable_tracking = false
# 后台运行的 ComfyUI 信息 (host, port, pid)
# 自动管理,不要手动修改
background = ('127.0.0.1', 8188, 5678)
# CivitAI API Token(用于下载需要认证的模型)
civitai_api_token = your_token_here
# HuggingFace API Token(用于下载私有模型)
hf_api_token = your_token_here
4.3 配置管理命令
# 查看当前配置
comfy env
# 设置默认工作区
comfy set-default /basedir
# 设置启动参数
comfy set-default /basedir --launch-extras="--listen 0.0.0.0"
# 查看当前工作区
comfy which
4.4 环境变量覆盖
comfy-cli 支持通过环境变量覆盖配置:
| 环境变量 | 配置项 | 优先级 |
|---|---|---|
CIVITAI_API_TOKEN |
civitai_api_token | 高 |
HF_API_TOKEN |
hf_api_token | 高 |
COMFY_CLI_WORKSPACE |
default_workspace | 高 |
优先级顺序:
- CLI 参数(如
--set-civitai-api-token) - 环境变量
- config.ini 配置
5. 工作区管理
5.1 工作区概念
工作区是 ComfyUI 的安装目录,包含:
/basedir/ # 工作区根目录
├── ComfyUI/ # ComfyUI 核心代码
├── custom_nodes/ # 自定义节点
├── models/ # 模型文件
│ ├── checkpoints/
│ ├── loras/
│ ├── vae/
│ └── ...
├── input/ # 输入文件
├── output/ # 输出文件
└── user/ # 用户文件
5.2 指定工作区的方法
方法 1:使用 --workspace 参数
comfy --workspace=/basedir model download --url "..."
comfy --workspace=/basedir node install ComfyUI-Impact-Pack
方法 2:设置默认工作区
# 一次性设置
comfy set-default /basedir
# 之后可省略 --workspace
comfy model download --url "..."
方法 3:使用 --recent
# 自动使用最近的工作区
comfy --recent model download --url "..."
方法 4:使用 --here
cd /basedir
comfy --here model download --url "..."
5.3 多工作区管理
# 设置多个工作区
comfy set-default /basedir
comfy --workspace=/opt/comfy-test node install SomeNode
# 查看当前工作区
comfy which
# 列出所有模型(在当前工作区)
comfy model list
6. 模型管理
6.1 下载模型
从 CivitAI 下载
# 下载模型(需要 API Token)
comfy --workspace=/basedir model download \
--url "https://civitai.com/models/43331" \
--set-civitai-api-token "YOUR_TOKEN"
# 指定保存路径
comfy --workspace=/basedir model download \
--url "https://civitai.com/models/43331" \
--relative-path "models/checkpoints" \
--filename "my_model.safetensors"
从 HuggingFace 下载
# 下载公开模型
comfy --workspace=/basedir model download \
--url "https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors"
# 下载私有模型(需要 Token)
comfy --workspace=/basedir model download \
--url "https://huggingface.co/username/private-model/resolve/main/model.safetensors" \
--set-hf-api-token "YOUR_HF_TOKEN"
从直接 URL 下载
comfy --workspace=/basedir model download \
--url "https://example.com/models/model.safetensors" \
--relative-path "models/checkpoints"
6.2 列出模型
# 列出所有模型
comfy --workspace=/basedir model list
# 列出指定目录的模型
comfy --workspace=/basedir model list \
--relative-path "models/checkpoints"
# 列出 LoRA 模型
comfy --workspace=/basedir model list \
--relative-path "models/loras"
6.3 删除模型
# 删除指定模型
comfy --workspace=/basedir model remove \
--relative-path "models/checkpoints" \
--model-names "model1.safetensors" "model2.ckpt"
# 交互式选择删除
comfy --workspace=/basedir model remove
# 跳过确认提示
comfy --workspace=/basedir model remove \
--model-names "model.safetensors" \
--confirm
6.4 模型路径映射
comfy-cli 内置的模型类型映射:
model_path_map = {
"lora": "loras",
"hypernetwork": "hypernetworks",
"checkpoint": "checkpoints",
"textualinversion": "embeddings",
"controlnet": "controlnet",
}
7. 自定义节点管理
7.1 节点列表
# 显示已安装的节点
comfy --workspace=/basedir node simple-show installed
# 显示启用的节点
comfy --workspace=/basedir node simple-show enabled
# 显示禁用的节点
comfy --workspace=/basedir node simple-show disabled
# 显示未安装的节点
comfy --workspace=/basedir node simple-show not-installed
# 显示所有节点
comfy --workspace=/basedir node simple-show all
# 显示详细信息
comfy --workspace=/basedir node show installed
7.2 安装节点
# 安装单个节点
comfy --workspace=/basedir node install ComfyUI-Impact-Pack
# 安装多个节点
comfy --workspace=/basedir node install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack
# 使用快速依赖安装
comfy --workspace=/basedir node install SomeNode --fast-deps
# 跳过依赖安装
comfy --workspace=/basedir node install SomeNode --no-deps
# 指定 channel
comfy --workspace=/basedir node install SomeNode --channel recent
7.3 更新节点
# 更新所有节点
comfy --workspace=/basedir node update all
# 更新特定节点
comfy --workspace=/basedir node update ComfyUI-Impact-Pack
# 指定 channel 和 mode
comfy --workspace=/basedir node update all --channel recent --mode remote
7.4 启用/禁用节点
# 禁用节点
comfy --workspace=/basedir node disable ComfyUI-Impact-Pack
# 启用节点
comfy --workspace=/basedir node enable ComfyUI-Impact-Pack
7.5 卸载节点
# 卸载节点
comfy --workspace=/basedir node uninstall ComfyUI-Impact-Pack
7.6 依赖管理
# 安装依赖
comfy --workspace=/basedir node install-deps
# 从 workflow 生成依赖
comfy --workspace=/basedir node deps-in-workflow \
--workflow /path/to/workflow.json \
--output /path/to/deps.json
7.7 快照管理
# 保存快照
comfy --workspace=/basedir node save-snapshot
# 保存到指定文件
comfy --workspace=/basedir node save-snapshot --output backup.json
# 恢复快照
comfy --workspace=/basedir node restore-snapshot backup.json
# 列出快照
comfy --workspace=/basedir node simple-show snapshot-list
7.8 调试节点问题(Bisect)
# 开始 bisect 会话
comfy --workspace=/basedir node bisect start
# 标记当前状态为好
comfy --workspace=/basedir node bisect good
# 标记当前状态为坏
comfy --workspace=/basedir node bisect bad
# 重置 bisect 会话
comfy --workspace=/basedir node bisect reset
8. ComfyUI 生命周期管理
8.1 安装 ComfyUI
# 默认安装(最新 nightly 版本)
comfy install
# 指定工作区
comfy --workspace=~/my-comfy install
# 安装特定版本
comfy install --version latest
# 安装 nightly 版本
comfy install --version nightly
# 跳过 Manager 安装
comfy install --skip-manager
# 从特定 PR 安装
comfy install --pr "#1234"
# 指定 GPU 类型
comfy install --nvidia
comfy install --amd
comfy install --cpu
8.2 启动 ComfyUI
# 前台启动
comfy --workspace=/basedir launch
# 后台启动
comfy --workspace=/basedir launch --background
# 带参数启动
comfy --workspace=/basedir launch -- --listen 0.0.0.0 --port 8188
# 使用默认参数启动
comfy --workspace=/basedir launch --
# 测试前端 PR
comfy --workspace=/basedir launch --frontend-pr "#456"
8.3 停止 ComfyUI
# 停止后台运行的实例
comfy stop
8.4 更新 ComfyUI
# 更新 ComfyUI 核心
comfy --workspace=/basedir update comfy
# 更新所有(包括节点)
comfy --workspace=/basedir update all
8.5 运行 Workflow
# 运行 workflow 文件
comfy --workspace=/basedir run \
--workflow /path/to/workflow.json
# 等待完成
comfy --workspace=/basedir run \
--workflow /path/to/workflow.json \
--wait
# 详细输出
comfy --workspace=/basedir run \
--workflow /path/to/workflow.json \
--verbose
# 指定主机和端口
comfy --workspace=/basedir run \
--workflow /path/to/workflow.json \
--host 127.0.0.1 \
--port 8188 \
--timeout 60
9. Docker 环境特殊配置
9.1 ComfyUI-Nvidia-Docker 目录结构
run/ # 容器运行数据
├── venv/ # Python 虚拟环境
├── ComfyUI/ # ComfyUI 源代码
└── ...
basedir/ # 用户数据(持久化)
├── custom_nodes/ # 自定义节点
├── models/ # 模型文件
├── input/ # 输入
├── output/ # 输出
└── user/ # 用户配置
9.2 在 Docker 中安装 comfy-cli
方法 A:通过 user_script.bash(推荐)
⚠️ 重要提示:在 Docker 环境中,comfy set-default 会失败,因为 comfy-cli 通过 Git 仓库检测验证 ComfyUI 安装,而 /basedir 目录下没有 ComfyUI 的 Git 仓库(代码在 /comfy/mnt/ComfyUI)。
解决方案:直接写入 config.ini 配置文件,绕过 Git 检测。
方案 A1:使用自动化脚本(推荐)
我们提供了完整的自动化脚本 docs/comfy-cli-docker-setup.sh,包含:
- ✅ 自动检测并安装 comfy-cli
- ✅ 直接配置 config.ini(绕过 Git 检测)
- ✅ 环境变量支持(CivitAI/HF API Token)
- ✅ 配置验证
使用步骤:
# 1. 复制脚本到 run 目录
cp docs/comfy-cli-docker-setup.sh run/user_script.bash
# 2. 确保执行权限
chmod +x run/user_script.bash
# 3. 重启容器
docker restart comfyui-nvidia
# 4. 查看日志确认配置成功
docker logs comfyui-nvidia | grep -A 20 "ComfyCLI"
方案 A2:手动编写 user_script.bash
创建/编辑 run/user_script.bash:
#!/bin/bash
# user_script.bash - 容器启动时执行
echo "=== Setting up comfy-cli ==="
# 配置变量
VENV_PIP="/comfy/mnt/venv/bin/pip"
COMFY_CMD="/comfy/mnt/venv/bin/comfy"
CONFIG_DIR="$HOME/.config/comfy-cli"
CONFIG_FILE="$CONFIG_DIR/config.ini"
# 检查并安装 comfy-cli
if ! $COMFY_CMD --version &> /dev/null; then
echo "Installing comfy-cli..."
$VENV_PIP install comfy-cli -q
fi
# 创建配置目录
mkdir -p "$CONFIG_DIR"
# 直接写入 config.ini(绕过 set-default 的 Git 检测)
cat > "$CONFIG_FILE" << EOF
[DEFAULT]
default_workspace = /basedir
recent_workspace = /basedir
default_launch_extras = --listen 0.0.0.0 --port 8188
enable_tracking = false
EOF
echo "Config file written to $CONFIG_FILE"
# 验证配置
$COMFY_CMD which
为什么不能直接用 comfy set-default?
comfy-cli 的 set-default 命令会验证路径是否为有效的 ComfyUI Git 仓库:
# comfy_cli/workspace_manager.py
def _is_comfy_repo(path: Path) -> bool:
"""检查是否为 ComfyUI 仓库"""
git_dir = path / ".git"
if not git_dir.exists():
return False
# 检查 remote URLs 是否匹配 ComfyUI 官方仓库
...
在 Docker 环境中:
/comfy/mnt/ComfyUI是 ComfyUI 代码(可能有 Git)/basedir是用户数据目录(没有 Git)set-default /basedir会失败:Specified path is not a ComfyUI path
直接写入 config.ini 是安全的,因为:
- comfy-cli 读取配置时不验证 Git
- 模型/节点管理只关心子目录结构(
models/,custom_nodes/) - ComfyUI 启动时会正确加载模型路径
方法 B:手动安装(不推荐)
# 进入容器
docker exec -it comfyui-nvidia bash
# 激活虚拟环境
source /comfy/mnt/venv/bin/activate
# 安装 comfy-cli
pip install comfy-cli
# ❌ 这会失败:Specified path is not a ComfyUI path
comfy set-default /basedir
# ✅ 改为直接编辑配置文件
mkdir -p ~/.config/comfy-cli
cat > ~/.config/comfy-cli/config.ini << EOF
[DEFAULT]
default_workspace = /basedir
recent_workspace = /basedir
enable_tracking = false
EOF
# 验证
comfy which
# 退出容器
exit
9.3 环境变量配置
在 docker-compose.yml 或 docker run 中添加:
environment:
- CIVITAI_API_TOKEN=your_token_here
- HF_API_TOKEN=your_token_here
- COMFY_CLI_WORKSPACE=/basedir
9.4 权限问题处理
ComfyUI-Nvidia-Docker 使用 WANTED_UID/WANTED_GID 映射用户权限:
docker run ... \
-e WANTED_UID=$(id -u) \
-e WANTED_GID=$(id -g) \
...
确保 comfy-cli 配置文件的权限正确:
# 在容器内
chown -R $(id -u):$(id -g) ~/.config/comfy-cli/
9.5 模型下载优化
在 Docker 环境中,模型下载到 basedir,这是持久化存储:
# 模型会保存到 /basedir/models/...
docker exec comfyui-nvidia comfy model download \
--url "https://..." \
--relative-path "models/checkpoints"
10. REST API 集成方案
10.1 方案概述
由于 comfy-cli 本身不提供 REST API,需要通过 custom node 将命令暴露为 HTTP 端点。
📚 相关文档:
- API Reference:
comfy-cli-api-reference.md— 所有命令的输入输出格式详解 - 实现指南:
comfy-cli-rest-implementation.md— 完整的 REST API 服务器实现代码
有两种实现方案:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 方案 A:扩展现有 cm-cli-rest | 复用现有代码 | 需要修改现有项目 |
| 方案 B:新建 comfy-cli-rest | 独立、清晰 | 需要从头开发 |
推荐:方案 A(扩展 cm-cli-rest)
10.1.1 为什么需要 REST API?
直接调用 CLI 的问题:
| 问题 | CLI 直接调用 | REST API |
|---|---|---|
| 输出格式 | 原始文本,需解析 | 结构化 JSON |
| 异步任务 | 需手动管理进程 | 统一任务队列 |
| 错误处理 | 退出码 + stderr | 统一错误响应 |
| 认证授权 | 无 | 可集成 |
| 并发控制 | 无 | 可限制 |
10.1.2 输出解析策略
| 命令类型 | 原始输出 | 建议解析方式 |
|---|---|---|
model list |
每行一个文件名 | 按行分割 → 数组 |
node simple-show |
每行一个节点名 | 按行分割 → 数组 |
model download |
进度 + 完成消息 | 正则提取进度% |
env |
键值对列表 | 分割 : → 对象 |
node show |
多行详细信息 | 复杂解析或改用文件系统 |
推荐:对于简单查询(list),直接文件系统访问比 CLI 更可靠。
10.2 方案 A:扩展 cm-cli-rest
10.2.1 项目结构
cm-cli-rest/
├── __init__.py # 入口点
├── api/
│ ├── routes.py # 路由定义
│ └── handlers/
│ ├── nodes.py # 节点管理
│ ├── models.py # 【新增】模型管理
│ └── jobs.py # 任务跟踪
├── comfy_cli/
│ └── executor.py # 【新增】comfy-cli 执行器
├── config/
│ └── config.json # 配置
└── README.md
10.2.2 comfy-cli 执行器实现
# comfy_cli/executor.py
import asyncio
import json
import os
import subprocess
import uuid
from typing import Dict, Optional, Any
class ComfyCliExecutor:
"""comfy-cli 命令执行器"""
def __init__(self, workspace_path: str = "/basedir"):
self.workspace_path = workspace_path
self.comfy_cmd = ["comfy", f"--workspace={workspace_path}"]
self.jobs: Dict[str, Dict] = {}
async def execute(
self,
command: list,
async_mode: bool = True
) -> Dict[str, Any]:
"""执行 comfy-cli 命令"""
job_id = str(uuid.uuid4())
full_cmd = self.comfy_cmd + command
if async_mode:
# 异步执行(用于长时间运行的命令)
task = asyncio.create_task(
self._run_async(job_id, full_cmd)
)
self.jobs[job_id] = {
"status": "running",
"command": command,
"task": task
}
return {
"job_id": job_id,
"status": "running",
"message": f"Command started: {' '.join(command)}"
}
else:
# 同步执行
result = await self._run_sync(full_cmd)
return result
async def _run_async(self, job_id: str, cmd: list):
"""异步运行命令"""
try:
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
cwd=self.workspace_path
)
stdout, stderr = await process.communicate()
if process.returncode == 0:
self.jobs[job_id] = {
"status": "completed",
"output": stdout.decode(),
"error": stderr.decode()
}
else:
self.jobs[job_id] = {
"status": "failed",
"error": stderr.decode(),
"output": stdout.decode()
}
except Exception as e:
self.jobs[job_id] = {
"status": "failed",
"error": str(e)
}
async def _run_sync(self, cmd: list) -> Dict[str, Any]:
"""同步运行命令"""
try:
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
cwd=self.workspace_path
)
stdout, stderr = await process.communicate()
if process.returncode == 0:
return {
"success": True,
"data": stdout.decode(),
"error": None
}
else:
return {
"success": False,
"data": None,
"error": stderr.decode()
}
except Exception as e:
return {
"success": False,
"data": None,
"error": str(e)
}
def get_job_status(self, job_id: str) -> Optional[Dict]:
"""获取任务状态"""
return self.jobs.get(job_id)
def remove_job(self, job_id: str) -> bool:
"""移除任务"""
if job_id in self.jobs:
del self.jobs[job_id]
return True
return False
10.2.3 模型管理 Handler
# api/handlers/models.py
from aiohttp import web
import json
from ..comfy_cli.executor import ComfyCliExecutor
executor = ComfyCliExecutor(workspace_path="/basedir")
async def download_model(request):
"""下载模型"""
try:
data = await request.json()
url = data.get("url")
relative_path = data.get("relative_path", "models/checkpoints")
filename = data.get("filename")
civitai_token = data.get("civitai_api_token")
hf_token = data.get("hf_api_token")
if not url:
return web.json_response({
"success": False,
"error": {"code": "MISSING_URL", "message": "URL is required"}
}, status=400)
# 构建命令
cmd = ["model", "download", "--url", url]
if relative_path:
cmd.extend(["--relative-path", relative_path])
if filename:
cmd.extend(["--filename", filename])
if civitai_token:
cmd.extend(["--set-civitai-api-token", civitai_token])
if hf_token:
cmd.extend(["--set-hf-api-token", hf_token])
# 执行命令(异步)
result = await executor.execute(cmd, async_mode=True)
return web.json_response({
"success": True,
"data": result
}, status=202) # 202 Accepted
except json.JSONDecodeError:
return web.json_response({
"success": False,
"error": {"code": "INVALID_JSON", "message": "Invalid JSON"}
}, status=400)
except Exception as e:
return web.json_response({
"success": False,
"error": {"code": "INTERNAL_ERROR", "message": str(e)}
}, status=500)
async def list_models(request):
"""列出模型"""
try:
relative_path = request.query.get("relative_path", "models")
cmd = ["model", "list"]
if relative_path:
cmd.extend(["--relative-path", relative_path])
result = await executor.execute(cmd, async_mode=False)
if result["success"]:
# 解析输出
models = result["data"].strip().split("\n") if result["data"] else []
return web.json_response({
"success": True,
"data": {"models": models, "path": relative_path}
})
else:
return web.json_response({
"success": False,
"error": {"code": "LIST_FAILED", "message": result["error"]}
}, status=500)
except Exception as e:
return web.json_response({
"success": False,
"error": {"code": "INTERNAL_ERROR", "message": str(e)}
}, status=500)
async def remove_model(request):
"""删除模型"""
try:
data = await request.json()
model_names = data.get("model_names", [])
relative_path = data.get("relative_path", "models/checkpoints")
confirm = data.get("confirm", False)
if not model_names:
return web.json_response({
"success": False,
"error": {"code": "MISSING_NAMES", "message": "model_names is required"}
}, status=400)
cmd = ["model", "remove", "--relative-path", relative_path]
for name in model_names:
cmd.extend(["--model-names", name])
if confirm:
cmd.append("--confirm")
result = await executor.execute(cmd, async_mode=False)
if result["success"]:
return web.json_response({
"success": True,
"data": {"message": f"Removed {len(model_names)} model(s)"}
})
else:
return web.json_response({
"success": False,
"error": {"code": "REMOVE_FAILED", "message": result["error"]}
}, status=500)
except Exception as e:
return web.json_response({
"success": False,
"error": {"code": "INTERNAL_ERROR", "message": str(e)}
}, status=500)
async def get_job_status(request):
"""获取任务状态"""
job_id = request.match_info.get("job_id")
status = executor.get_job_status(job_id)
if status:
return web.json_response({
"success": True,
"data": status
})
else:
return web.json_response({
"success": False,
"error": {"code": "JOB_NOT_FOUND", "message": f"Job {job_id} not found"}
}, status=404)
async def remove_job(request):
"""移除任务"""
job_id = request.match_info.get("job_id")
if executor.remove_job(job_id):
return web.json_response({
"success": True,
"data": {"message": f"Job {job_id} removed"}
})
else:
return web.json_response({
"success": False,
"error": {"code": "JOB_NOT_FOUND", "message": f"Job {job_id} not found"}
}, status=404)
10.2.4 路由定义
# api/routes.py
from aiohttp import web
from .handlers import nodes, models, jobs
def setup_routes(app):
"""注册路由"""
# 健康检查
app.router.add_get("/cm-cli-rest/health", health_check)
# 节点管理(现有)
app.router.add_get("/cm-cli-rest/nodes", nodes.list_nodes)
app.router.add_post("/cm-cli-rest/nodes/install", nodes.install_node)
# ...
# 模型管理(新增)
app.router.add_post("/cm-cli-rest/models/download", models.download_model)
app.router.add_get("/cm-cli-rest/models", models.list_models)
app.router.add_post("/cm-cli-rest/models/remove", models.remove_model)
# 任务跟踪
app.router.add_get("/cm-cli-rest/jobs", jobs.list_jobs)
app.router.add_get("/cm-cli-rest/jobs/{job_id}", models.get_job_status)
app.router.add_delete("/cm-cli-rest/jobs/{job_id}", models.remove_job)
async def health_check(request):
"""健康检查"""
return web.json_response({
"status": "healthy",
"service": "cm-cli-rest",
"version": "0.2.0", # 更新版本号
"features": ["nodes", "models", "jobs"],
"timestamp": datetime.utcnow().isoformat()
})
10.2.5 API 端点列表
| 方法 | 端点 | 描述 | 异步 |
|---|---|---|---|
| GET | /cm-cli-rest/health |
健康检查 | ❌ |
| POST | /cm-cli-rest/models/download |
下载模型 | ✅ |
| GET | /cm-cli-rest/models |
列出模型 | ❌ |
| POST | /cm-cli-rest/models/remove |
删除模型 | ❌ |
| GET | /cm-cli-rest/jobs |
列出任务 | ❌ |
| GET | /cm-cli-rest/jobs/{id} |
获取任务状态 | ❌ |
| DELETE | /cm-cli-rest/jobs/{id} |
移除任务 | ❌ |
10.2.6 请求/响应示例
下载模型请求:
curl -X POST http://localhost:8188/cm-cli-rest/models/download \
-H "Content-Type: application/json" \
-d '{
"url": "https://civitai.com/models/43331",
"relative_path": "models/checkpoints",
"filename": "my_model.safetensors",
"civitai_api_token": "your_token"
}'
响应(202 Accepted):
{
"success": true,
"data": {
"job_id": "abc12345",
"status": "running",
"message": "Command started: model download --url ..."
}
}
查询任务状态:
curl http://localhost:8188/cm-cli-rest/jobs/abc12345
响应:
{
"success": true,
"data": {
"status": "completed",
"output": "Model downloaded successfully...",
"error": null
}
}
列出模型:
curl "http://localhost:8188/cm-cli-rest/models?relative_path=models/checkpoints"
响应:
{
"success": true,
"data": {
"models": [
"model1.safetensors",
"model2.ckpt",
"model3.safetensors"
],
"path": "models/checkpoints"
}
}
10.3 方案 B:新建 comfy-cli-rest
如果希望保持独立,可以创建新的 custom node:
# 目录结构
custom_nodes/comfy-cli-rest/
├── __init__.py
├── server.py
├── handlers/
│ ├── models.py
│ ├── nodes.py
│ └── workflows.py
├── comfy_executor.py
├── config.json
└── requirements.txt
requirements.txt:
aiohttp>=3.9.0
__init__.py:
import asyncio
import os
from aiohttp import web
from server import PromptServer
from .handlers import models, nodes
from .comfy_executor import ComfyCliExecutor
WEB_DIRECTORY = "./web"
executor = ComfyCliExecutor(
workspace_path=os.environ.get("COMFYUI_BASEDIR", "/basedir")
)
@PromptServer.instance.routes.get("/comfy-cli/health")
async def health_check(request):
return web.json_response({
"status": "healthy",
"service": "comfy-cli-rest",
"version": "1.0.0"
})
@PromptServer.instance.routes.post("/comfy-cli/model/download")
async def download_model(request):
return await models.download_model(request, executor)
@PromptServer.instance.routes.get("/comfy-cli/model/list")
async def list_models(request):
return await models.list_models(request, executor)
# ... 其他路由
10.4 安全考虑
-
API 认证
{ "api_key": "your_secret_key", "enabled": true } -
输入验证
- 验证所有路径参数,防止路径遍历攻击
- 限制可执行的命令白名单
-
速率限制
- 限制每个 IP 的请求频率
- 限制并发任务数量
-
日志记录
- 记录所有 API 调用
- 记录错误和异常
11. 故障排除
11.1 常见问题
问题 1:comfy: command not found
原因: comfy-cli 未安装或未添加到 PATH
解决:
# 在容器内
source /comfy/mnt/venv/bin/activate
pip install comfy-cli
# 或使用完整路径
/comfy/mnt/venv/bin/comfy --version
问题 2:ComfyUI not found 或 Specified path is not a ComfyUI path
原因: 工作区配置错误,或在 Docker 环境中使用 set-default 命令
解决:
Docker 环境特殊情况:
comfy set-default /basedir 会失败,因为 comfy-cli 通过 Git 仓库检测验证路径,而 /basedir 是数据目录而非 Git 仓库。
# ❌ 这会失败
comfy set-default /basedir
# 错误:Specified path is not a ComfyUI path: /basedir
# ✅ 方案 A:使用自动化脚本(推荐)
# 将 docs/comfy-cli-docker-setup.sh 复制为 run/user_script.bash 并重启容器
# ✅ 方案 B:直接编辑配置文件
mkdir -p ~/.config/comfy-cli
cat > ~/.config/comfy-cli/config.ini << EOF
[DEFAULT]
default_workspace = /basedir
recent_workspace = /basedir
enable_tracking = false
EOF
# ✅ 方案 C:每次使用 --workspace 参数
comfy --workspace=/basedir model list
非 Docker 环境:
# 设置默认工作区
comfy set-default /path/to/ComfyUI
# 或显式指定
comfy --workspace=/basedir model list
问题 3:模型下载失败(401/403)
原因: 缺少 API Token
解决:
# 设置 Token
comfy model download --url "..." \
--set-civitai-api-token "YOUR_TOKEN"
# 或使用环境变量
export CIVITAI_API_TOKEN="YOUR_TOKEN"
comfy model download --url "..."
问题 4:权限错误
原因: Docker 用户权限映射问题
解决:
# 在容器内修复权限
chown -R $(id -u):$(id -g) ~/.config/comfy-cli/
chown -R $(id -u):$(id -g) /basedir/
问题 5:Python 版本不兼容
原因: comfy-cli 需要 Python 3.9+
解决:
# 检查 Python 版本
python --version
# 使用正确的 Python 环境
/comfy/mnt/venv/bin/python -m pip install comfy-cli
11.2 调试技巧
# 启用详细日志
comfy --workspace=/basedir model download --url "..." -v
# 查看 comfy-cli 配置
cat ~/.config/comfy-cli/config.ini
# 检查环境
comfy env
# 验证工作区
comfy which
11.3 获取帮助
# 主帮助
comfy --help
# 命令帮助
comfy model --help
comfy model download --help
comfy node --help
# 查看源码
# https://github.com/Comfy-Org/comfy-cli
12. 附录
12.1 完整命令参考
comfy [OPTIONS] COMMAND [ARGS]
Options:
--workspace PATH Path to ComfyUI workspace
--recent Execute from recent path
--here Execute from current path
--version Print version and exit
--help Show help
Commands:
install Download and install ComfyUI
update Update ComfyUI environment
launch Launch ComfyUI
stop Stop background ComfyUI
set-default Set default ComfyUI path
which Show which ComfyUI is selected
env Print environment variables
model Model management
download Download model file
list List models
remove Remove models
node Custom node management
install Install nodes
uninstall Uninstall nodes
update Update nodes
enable Enable nodes
disable Disable nodes
show Show node list
simple-show Show node list (simple)
save-snapshot Save snapshot
restore-snapshot Restore snapshot
run Run workflow
feedback Provide feedback
12.2 配置文件模板
# ~/.config/comfy-cli/config.ini
[DEFAULT]
default_workspace = /basedir
recent_workspace = /basedir
default_launch_extras = --listen 0.0.0.0 --port 8188
enable_tracking = false
civitai_api_token =
hf_api_token =
12.3 Docker Compose 示例
version: '3.8'
services:
comfyui:
image: mmartial/comfyui-nvidia-docker:latest
container_name: comfyui-nvidia
runtime: nvidia
environment:
- USE_UV=true
- WANTED_UID=1000
- WANTED_GID=1000
- BASE_DIRECTORY=/basedir
- SECURITY_LEVEL=normal
- CIVITAI_API_TOKEN=${CIVITAI_API_TOKEN}
- HF_API_TOKEN=${HF_API_TOKEN}
volumes:
- ./run:/comfy/mnt
- ./basedir:/basedir
ports:
- "127.0.0.1:8188:8188"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
12.4 参考资源
- comfy-cli 官方仓库: https://github.com/Comfy-Org/comfy-cli
- comfy-cli PyPI: https://pypi.org/project/comfy-cli/
- ComfyUI-Nvidia-Docker: https://github.com/mmartial/ComfyUI-Nvidia-Docker
- ComfyUI-Manager: https://github.com/ltdrdata/ComfyUI-Manager
- cm-cli-rest: https://github.com/fno2010/cm-cli-rest
修订历史
| 版本 | 日期 | 作者 | 变更 |
|---|---|---|---|
| 1.5 | 2026-03-17 | Zero | 添加表格解析指南 comfy-cli-table-parser.md,修正输出格式说明(box table) |
| 1.4 | 2026-03-16 | Zero | 添加 CLI 命令参考手册 comfy-cli-command-reference.md |
| 1.3 | 2026-03-16 | Zero | 添加 API Reference 和 REST 实现指南文档链接、输出解析策略说明 |
| 1.2 | 2026-03-16 | Zero | 添加 Docker 环境 set-default 失败解决方案、自动化脚本 comfy-cli-docker-setup.sh |
| 1.1 | 2026-03-16 | Zero | 添加参数命名规则说明、完成 v1.6.0 源码验证 |
| 1.0 | 2026-03-16 | Zero | 初始版本 |
版本说明
本文档基于以下 comfy-cli 版本调研编写:
| 来源 | 版本 | 说明 |
|---|---|---|
| PyPI 最新稳定版 | 1.6.0 |
✅ 已验证,推荐使用 |
| GitHub main 分支 | 开发中 | 文档编写时(2026-03-16)的代码状态 |
| 最低兼容版本 | 1.3.8 |
低于此版本可能有命令差异 |
验证你安装的版本:
comfy --version
如果版本低于 1.3.8,建议升级:
pip install --upgrade comfy-cli
参数命名规则
comfy-cli 使用 typer 框架,Python 参数名会自动转换为 CLI 标志:
| Python 参数名 | CLI 标志 | 转换规则 |
|---|---|---|
relative_path |
--relative-path |
snake_case → kebab-case |
model_names |
--model-names |
snake_case → kebab-case |
confirm |
--confirm |
无变化 |
fast_deps |
--fast-deps |
snake_case → kebab-case |
示例:
# Python 源码
relative_path: Annotated[str | None, typer.Option(...)]
# CLI 使用
comfy model download --relative-path "models/checkpoints"
所有文档中的命令参数都遵循此规则。完整验证报告见 comfy-cli-verification-report.md。
本文档由 Zero (零号) 生成。所有命令已通过 v1.6.0 源码验证。