Majoor Project Settings
A custom node extension that adds project management functionality to ComfyUI.
ComfyUI-Majoor-ProjectSettings 🚀
Project-aware outputs + workflow organization for ComfyUI — without adding any ComfyUI nodes.
This extension turns ComfyUI into a lightweight “mini pipeline”: you pick a project, it creates/maintains a clean folder structure under output/, auto-patches save/export nodes (paths + filename prefixes), and lets you save workflows inside the project (optionally mirrored to ComfyUI/workflows/).
Zero new nodes. Maximum order. Your future self will stop cursing your past self. (Maybe.)
Status & empty workflows
- The Project Settings status bar watches your canvas and turns red when the current graph is empty while prompting you (via dialog) to create or assign a project instead of flooding toasts.
- Toggle the
MajoorPS: Black status when no projectsetting (in the MajoorPS settings category) if you'd rather keep a neutral indicator while you experiment without an active project. MajoorPS: Legacy Ctrl+S hookis off by default because ComfyUI already ownsCtrl+SviaComfy.SaveWorkflow. Enable it only if you explicitly need the old capture-phase fallback.MajoorPS: Prompt on empty workflowis off by default; the status badge remains passive unless you opt into modal prompts.
Key Features
- Project management inside ComfyUI (create / select / list).
- Project Health panel showing active folder, workflow assignment, output target, patchable save nodes, missing-model scan state, and workflow save state.
- Topbar Project button, registered with the same ComfyUI button component pattern used by ComfyUI-Manager when available.
- ComfyUI command palette integration for opening the panel, assigning the active project, saving workflows, scanning missing models, and patching save nodes.
- Standardized folder structure per project under
output/PROJECTS/<project>/.... - Auto-patch “save/export” nodes:
- sets a safe relative output folder (always under
output/) - sets a filename prefix (project/asset/model/date driven)
- supports many custom nodes via configurable “path widget” names.
- sets a safe relative output folder (always under
- Template-based output paths using tokens (
{BASE},{MEDIA},{DATE},{NAME},{MODEL}, etc.). - Project-aware workflow save:
- saves workflows into the project folder
- optional mirror into
ComfyUI/workflows/for compatibility.
- Project signature in workflow (
graph.extra.mjr_project) to keep provenance. - Empty-graph guard: the status bar turns red when the current graph has no nodes and the extension will prompt you to create or switch to a project, and there is an optional
MajoorPS: Black status when no projectsetting so you can work in a test mode without the warning color. - Safe path guardrails: blocks absolute paths, drive paths,
.., and other escape attempts. - Model Utilities: Fix Missing Models inside the Project Settings panel (no top menu).
- Model Utilities: Download Missing Models inside the Project Settings panel (recipes + direct URLs).
- Advanced fingerprint cache (optional) for future hash-based model resolution.
Installation
Option A — Git (recommended)
- Go to your ComfyUI folder:
ComfyUI/custom_nodes/
- Clone:
git clone https://github.com/MajoorWaldi/ComfyUI-Majoor-ProjectSettings.git - Restart ComfyUI.
Option B — ZIP
- Unzip into:
ComfyUI/custom_nodes/ComfyUI-Majoor-ProjectSettings/
- Restart ComfyUI.
✅ The extension exposes a WEB_DIRECTORY (./web/js) and registers API routes on startup.
Frontend Development
The browser extension source is maintained in TypeScript under src/ and compiled to
runtime JavaScript under web/js/, because ComfyUI loads custom-node frontend assets through
WEB_DIRECTORY = "./web/js".
npm install
npm run build
npm run typecheck
npm run typecheck:strict
npm run test:frontend
- Edit
src/**/*.ts, not the generatedweb/js/**/*.jsfiles. - Keep
web/js/committed so ComfyUI and ComfyUI-Manager can load the extension without a build step. typecheck:strictis intentionally scoped to migrated modules while the large legacy UI is typed progressively.
UI Location
Depending on your ComfyUI version:
- If sidebar tabs are supported, you’ll see a Project Settings tab.
- Otherwise, the UI falls back to a floating panel.
The panel is split into Project, Model, and Workflow tabs. Project contains project health, output target creation, and patching options. Model contains model selection, registry search, and missing-model utilities. Workflow contains workflow assignment and project-aware workflow saving.
Recent ComfyUI frontends also get a compact Project button near the menu controls. It
uses ComfyUI's ComfyButton / ComfyButtonGroup component pattern, matching
ComfyUI-Manager's modern button integration, and falls back to the legacy .comfy-menu
button location on older frontends.
ComfyUI Commands
The extension registers ComfyUI commands so recent ComfyUI frontends can expose them in the command palette and topbar menu:
MajoorPS: Open Project SettingsMajoorPS: Assign workflow to active projectMajoorPS: Save workflow to projectMajoorPS: Scan missing modelsMajoorPS: Patch save nodes now
No default Ctrl+S keybinding is registered by this extension, because ComfyUI already
uses it for Comfy.SaveWorkflow. The legacy capture-phase browser shortcut is disabled
by default and remains available only through the MajoorPS: Legacy Ctrl+S hook setting.
Debugging logs 🐞
- To enable verbose debug logs in the UI, set
window.MJR_DEBUG = truein the browser dev console before interacting with the extension. When enabled, the UI will emit developer messages viaconsole.debug().
Project Structure (Default)
Everything lives under:
output/
└─ PROJECTS/
├─ _INDEX/
│ └─ projects.json
└─ <PROJECT_FOLDER>/
├─ 00_META/
│ └─ current.json
├─ 01_IN/
│ ├─ REFS/
│ └─ SOURCES/
├─ 02_OUT/
│ ├─ IMAGES/
│ ├─ VIDEOS/
│ └─ OTHER/
├─ 03_WORKFLOWS/
├─ 04_PRESENTATION/
└─ 05_DOCS/
projects.jsonstores your project index (last used, archived, etc.)current.jsonstores the active project on disk (useful for external scripts/tools)
Environment Variables
The extension supports various environment variables for customization:
Security & Access Control
MJR_API_KEY: API key for authentication (if not set, only loopback/localhost access is allowed)MJR_INSECURE_NO_AUTH=1: Disable authentication (NOT recommended in production)MJR_DISABLE_CSRF=1: Disable CSRF protection (NOT recommended)MJR_DISABLE_SAME_ORIGIN=1: Disable same-origin checks (NOT recommended)MJR_TRUST_PROXY=1: Trust X-Forwarded-For headers for client IP detection
Download Settings
MJR_SKIP_EXISTING_FILES=1: Skip download if file already exists (default:0- overwrite mode enabled)MJR_MODEL_DOWNLOAD_TIMEOUT: Download timeout in seconds (default:300)MJR_MODEL_DOWNLOAD_ALLOW_PRIVATE_IPS=1: Allow downloads from private IP addressesMJR_MODEL_DOWNLOAD_ALLOWED_HOSTS: Comma-separated list of allowed download hosts
Rate Limiting & Performance
MJR_RATE_LIMIT_PER_MIN: Rate limit per minute per endpoint (default:120)MJR_JOB_CLEANUP_HOURS: Hours before cleaning up old download jobs (default:1)
Example Configuration (Windows PowerShell)
# Enable overwrite mode for downloads (default behavior)
$env:MJR_SKIP_EXISTING_FILES="0"
# Or enable skip mode if you want to avoid re-downloading
$env:MJR_SKIP_EXISTING_FILES="1"
# Set custom download timeout (5 minutes)
$env:MJR_MODEL_DOWNLOAD_TIMEOUT="300"
Example Configuration (Linux/Mac)
# Enable overwrite mode for downloads (default behavior)
export MJR_SKIP_EXISTING_FILES=0
# Or enable skip mode if you want to avoid re-downloading
export MJR_SKIP_EXISTING_FILES=1
# Set custom download timeout (5 minutes)
export MJR_MODEL_DOWNLOAD_TIMEOUT=300
Note on file overwriting: By default (MJR_SKIP_EXISTING_FILES=0), the extension will overwrite existing model files when downloading. This ensures you always get the latest version and prevents issues with corrupted/incomplete downloads. Set MJR_SKIP_EXISTING_FILES=1 if you want to skip downloads when the file already exists.
Configuration: project_structure.json
You can customize the project directories and role mappings:
{
"dirs": [
"00_META",
"01_IN/REFS",
"01_IN/SOURCES",
"02_OUT/IMAGES",
"02_OUT/VIDEOS",
"02_OUT/OTHER",
"03_WORKFLOWS",
"04_PRESENTATION",
"05_DOCS"
],
"roles": {
"images": "02_OUT/IMAGES",
"videos": "02_OUT/VIDEOS",
"other": "02_OUT/OTHER",
"workflows": "03_WORKFLOWS"
}
}
dirs: physically created directoriesroles: logical aliases used by the extension
Output Templates (Path Resolver)
The extension generates relative output paths (always safe under output/) using templates.
Common Tokens
Typical server/UI token set:
{BASE}:PROJECTS/<project_folder>{MEDIA}: media subdir (e.g.02_OUT/IMAGES){DATE}:YYMMDD(e.g.251222){NAME}: normalized asset/shot name{KIND}: kind label (asset/shot/etc., normalized){MODEL}: normalized model label (optionally uppercased from UI)
Example Template
{BASE}/{MEDIA}/{DATE}/{NAME}/{MODEL}
Example resolved output:
PROJECTS/MY_PROJECT/02_OUT/IMAGES/251222/AdrianCloseUp/FLUX_DEV
Node Patching (Save/Export Nodes)
The extension scans the current graph and patches “save-like” nodes:
- detection: node type contains patterns like
save,export,combine(implementation-specific) - patch targets:
filename_prefix- plus one recognized path widget (configurable list)
Supported Path Widget Names
Runtime-config endpoint:
GET /mjr_project/config→path_widgets
If your custom node uses a different widget name for its output folder/path:
- add it to the server defaults (e.g.
PATH_WIDGETS_DEFAULTinserver/project_routes.py) - restart ComfyUI
Workflow Saving (Project-aware)
Endpoint:
POST /mjr_project/workflow/save
Behavior:
- saves the workflow to:
PROJECTS/<project_folder>/<workflows_role>/<optional_subdir>/<workflow_name>.json
- optionally mirrors to:
ComfyUI/workflows/
Returned fields usually include:
project_rel_pathworkflow_rel_dircomfy_workflow_relmirrored,mirror_error
Model Utilities: Fix Missing Models (Panel)
The Project Settings panel includes a "Fix Missing Models" button that scans the current graph for combo widgets whose selected model is no longer present in the available values. It proposes exact and near matches (fuzzy) and applies the selection back to the graph.
Behavior summary:
- Missing detection is local (in-memory widgets, no API required).
- Candidates are suggested via a server scan with exact + fuzzy matching.
- Applied fixes update widget values and refresh the graph.
Model Utilities: Download Missing Models (Panel)
The Project Settings panel includes a "Download Missing Models" button that resolves
missing model names to download recipes. You can paste direct URLs for missing items and
optionally remember them for next time in:
output/PROJECTS/_INDEX/model_sources.json
Rules:
- Only direct http/https URLs are accepted.
- Allowed extensions:
.safetensors,.ckpt,.pt,.pth,.bin - Optional SHA256 verification if provided.
- Hugging Face token can be provided via
HUGGINGFACE_HUB_TOKENorHF_TOKEN. - Default download size cap is 10GB per file; tune via
MJR_MODEL_DOWNLOAD_MAX_BYTESorMJR_MODEL_DOWNLOAD_MAX_GB. - All public hosts are allowed by default for maximum compatibility. To restrict hosts, set
MJR_MODEL_DOWNLOAD_ALLOW_ANY_HOST=0/mjr_project.download_allow_any_host=falseand configureMJR_MODEL_DOWNLOAD_ALLOWED_HOSTS(comma-separated list). - Private/local IPs are blocked by default (SSRF guard); override with
MJR_MODEL_DOWNLOAD_BLOCK_PRIVATE_IPS=0/mjr_project.download_block_private_ips=false. - POST endpoints enforce same-origin and CSRF token checks for browser requests.
- Timeout can be tuned via
MJR_MODEL_DOWNLOAD_TIMEOUT(seconds). - Online search endpoint is rate-limited per client IP via
MJR_MODEL_SEARCH_RATE_PER_MIN(default: 30/min).
Endpoints:
POST /mjr_models/resolve_recipesPOST /mjr_models/save_recipesPOST /mjr_models/downloadGET /mjr_models/download_status
Advanced: Fingerprint Cache
An optional cache can be built under:
output/PROJECTS/_INDEX/model_fingerprints.json
The cache stores lightweight fingerprints (sha256 of first 1MB + last 1MB + size bytes). This enables future hash-based resolution when model filenames or paths change.
Endpoints:
GET /mjr_models/fingerprint_cache_statusPOST /mjr_models/build_fingerprint_cachePOST /mjr_models/resolve_by_fingerprint
API Reference (High-Level)
Base URL: your ComfyUI host/port.
Set / Select a project
POST /mjr_project/set
{ "project_name": "My Cool Project" }
List projects
GET /mjr_project/list?include_archived=0|1
List available models (from ComfyUI)
GET /mjr_project/models
Get runtime config (includes path widgets)
GET /mjr_project/config
Resolve project by folder name
GET /mjr_project/resolve?folder=<project_folder>
Preview template resolution
POST /mjr_project/preview_template
{
"template": "{BASE}/{MEDIA}/{DATE}/{NAME}/{MODEL}",
"tokens": {
"BASE": "PROJECTS/MY_PROJECT",
"MEDIA": "02_OUT/IMAGES",
"DATE": "251222",
"NAME": "AdrianCloseUp",
"MODEL": "FLUX_DEV"
}
}
Create/validate a custom output dir + prefix (conceptual)
POST /mjr_project/create_custom_out
{
"project_id": "...",
"kind": "asset",
"name": "AdrianCloseUp",
"media": "images",
"model": "Flux Dev",
"model_upper": true,
"date": "251222",
"template": "{BASE}/{MEDIA}/{DATE}/{NAME}/{MODEL}"
}
Archive / Unarchive / Delete
POST /mjr_project/archivePOST /mjr_project/unarchivePOST /mjr_project/delete
“delete” is designed to be safe-by-default: it typically removes index entries and avoids dangerous disk nukes unless explicitly implemented.
Local UI State
The UI persists state in localStorage:
- key:
mjr_project_settings_state
So your settings survive browser refreshes and ComfyUI restarts (unless the browser decides it’s in a mood).
Repo Layout (Typical)
__init__.py- exposes
WEB_DIRECTORY - imports server routes
- exposes
server/project_routes.py(AIOHTTP endpoints viaPromptServer.instance.routes)project_store.py(folder structure + safe path utils + index/current handling)
web/js/majoor_project_settings.js(ComfyUI extension entry, UI, hooks)state_manager.js(persistence/state)ui_components.js(UI helpers)mjr/(api, graph scan, patching, dialogs, toasts, utilities)
Troubleshooting
“I don’t see the UI”
- Confirm folder is inside:
ComfyUI/custom_nodes/ComfyUI-Majoor-ProjectSettings/
- Restart ComfyUI (not just browser refresh).
- Check browser console (F12): logs are usually prefixed with something like
[mjr].
“My save nodes are not being patched”
- The node may not expose:
filename_prefix, and/or- a recognized path widget name (
output_path,folder,save_path, etc.)
- Add your widget name to the server’s
PATH_WIDGETS_DEFAULTand restart.
“Path rejected / invalid”
- The server intentionally blocks:
- absolute paths
- drive paths (
C:\...) ..traversal- unsafe characters / escape attempts
- This is by design: the extension is strict so it doesn’t become a foot-gun.
"Ctrl+S conflicts"
- ComfyUI owns
Ctrl+SthroughComfy.SaveWorkflow; this extension does not register a defaultCtrl+Skeybinding. - Only enable
MajoorPS: Legacy Ctrl+S hookif you accept that it can override core/browser save behavior. - Prefer capture-phase + stopping propagation (or disable your hotkey if exposed).
"Model download fails with permission error"
If model downloads succeed but fail when moving to the models folder:
Common causes:
- Models folder is on a different drive with restricted permissions
- Antivirus is blocking file creation
- Another program has the models folder open
- Insufficient disk space
Solutions:
- Check folder permissions: Right-click models folder → Properties → Security → Add write permissions
- Add models folder to antivirus exclusions
- Close any programs that might be accessing model files
- Run ComfyUI as administrator
- Check if you have enough disk space
- Change models directory to a location with proper permissions
Recovery: If download succeeded but move failed, the file is kept at:
ComfyUI/models/.mjr_tmp/{job_id}/{filename}
You can manually move this file to your models directory.
See docs/BUGFIX_WINDOWS_DOWNLOAD.md for detailed information.
Roadmap Ideas
- Project dashboard (notes, tags, quick links)
- More robust asset/shot detection from workflow metadata
- Preset templates per media type (images/videos/comps)
- Tight integration with an Asset/File Manager for a real pipeline feel
API Error Responses
All API endpoints return errors in the following standardized format:
{
"ok": false,
"error": "Error message describing what went wrong"
}
Common HTTP Status Codes
400 Bad Request: Invalid input, validation error, or malformed request404 Not Found: Project ID, workflow, or resource not found409 Conflict: Resource already exists (when overwrite=false)415 Unsupported Media Type: Missing or invalid Content-Type header (must be application/json)500 Internal Server Error: Server-side error (file I/O, database issues)
Example Error Responses
// Missing required field
{
"ok": false,
"error": "project_name is required"
}
// Invalid characters in input
{
"ok": false,
"error": "project_name contains invalid characters (/ \\ : .. not allowed)"
}
// Resource not found
{
"ok": false,
"error": "project_id not found"
}
// Validation failure
{
"ok": false,
"error": "invalid date format: '999999' (expected YYMMDD, e.g., 251220 for today)"
}
License
No license file is currently included in this repository/folder. Until a license is added by the author, treat the code as unlicensed (i.e., no permission is granted for redistribution or modification beyond what applicable law allows).
If you are the author/maintainer: add a LICENSE file and update this section accordingly.
Credits
Built for the ComfyUI ecosystem with one goal: less chaos, more structure, and outputs that look like you meant it. 😄