artokun/train-character-lora
Train a character/identity LoRA locally on FLUX.1-dev via the comfyui-mcp train_* tools (GPU Docker + ostris ai-toolkit). Use when the user wants to train a LoRA of a person/character from their photos on the local GPU — covers dataset prep, launch, monitoring, and using the result in ComfyUI. For WAN/Z-Image training via the ai-toolkit UI see ai-toolkit-trainer.
npx skills add https://github.com/artokun/comfyui-mcp --skill train-character-lora
The trainer runs ostris ai-toolkit's run.py inside a headless GPU Docker container,
driven entirely through train_* MCP tools — you (the LLM) are the UI. You generate the
dataset, launch the job, watch progress, and the finished LoRA lands in ComfyUI
models/loras/ + the LoRA catalog automatically.
quantization — RTX 4090 class).
train_doctor — preflight once per session. Checks docker daemon, --gpus allGPU passthrough, trainer image, HF_TOKEN. If image:false → run train_build_image
(one-time, several minutes — CUDA + torch + ai-toolkit). If hfTokenSet:false, warn the
user: the first run downloads FLUX.1-dev (gated HF repo) and needs HF_TOKEN in the MCP
server env.
train_prepare_dataset — stage the images. See "Dataset" below.train_start — launch. Returns a job id immediately; training runs detached.train_status {id} — poll progress (progress.step/totalSteps/loss, recentsamples, log tail). Poll on a slow cadence (every few minutes) — a 2000-step run is
roughly an hour on a 4090. Don't block on it.
status:"completed" means the .safetensors was copied tomodels/loras/<name>.safetensors and upserted into the LoRA catalog (result has the
paths + catalog id). Verify by loading it in a Flux workflow (LoraLoaderModelOnly,
strength 1.0) with the trigger word in the prompt.
Call train_prepare_dataset with items: [{path, caption?}, ...] and a defaultCaption.
backgrounds, distances (close-up + half-body + full-body). Variety beats count.
ohwx, zxc_person) — NOT areal word. Use it as defaultCaption and pass it as trigger to train_start.
expression); the constant identity is learned from the images themselves. Start each
caption with the trigger word, e.g. `ohwx person sitting in a cafe, laughing, natural
light`. Keep them short and factual. When in doubt, the trigger word alone
(defaultCaption) is a workable baseline.
img_00001.<ext> etc. — source files are never modified.| Param | Default | When to change |
|-------|---------|----------------|
| steps | 2000 | 200 for a smoke test; 1500–3000 real runs. More ≠ better (overbake = plasticky). |
| lr | 1e-4 | 5e-5 for a tighter/subtler identity. |
| rank | 16 | 32 for very detailed characters. |
| resolution | [512,768,1024] | [512] if VRAM-constrained. |
| quantize | true | Keep true on 24GB. |
| saveEvery / sampleEvery | 250 | Lower (100) to watch early progress. |
train_status.progress.samples are host paths — look at them. (ai-toolkit prints nosaved-sample lines, so they populate at finalize from the output dir; mid-run you can look
directly in the job's output/<name>/samples/ folder.) Identity should be
recognizable by ~1/3 of the run; if samples stay generic past halfway, the run will
likely underfit — cancel (train_cancel) and check captions/trigger.
saveEvery steps under the job's output/ dir, so a cancelledrun isn't a total loss.
no_docker / no_image from train_start → run train_doctor, follow its hints.resolution to [512], keep quantize:true,batch stays 1.
handoff failed in job error → training itself finished; the LoRA is still under thejob's output/<name>/ dir — copy it into models/loras/ manually and upsert the catalog.
long as the log tail moves, it's fine. The HF cache persists across runs.
Take artokun/train-character-lora from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.