> ## Documentation Index
> Fetch the complete documentation index at: https://comfyui-mcp.artokun.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# LoRA Training

> Train character LoRAs (FLUX.1-dev) via ostris ai-toolkit — locally in a GPU Docker image or on a rented RunPod pod — with a crash-safe job registry and streamed progress.

<Info>3 tools. Generated from the live MCP tool schemas — do not edit by hand; run `npm run docs:gen`.</Info>

<Tip>**You don't type these calls.** Ask your agent for what you want in ordinary English — it chooses the tool and fills in the arguments. The JSON on this page is what it sends. New here? Start with [Using the tools](/docs/using-tools).</Tip>

## train\_prepare\_dataset

Stage and curate the training DATASETS a LoRA run consumes — the images and their captions. Datasets are keyed by `name`; the jobs that train on them live in the separate `train_start` tool and are keyed by `id`. Driven by the `action` parameter:

* action:"prepare" — Stage training images + captions into a dataset dir the trainer consumes. Each item is an image (absolute `path`, OR a ComfyUI `ref` \{filename,subfolder?,type?} resolved against the connected ComfyUI's output/input dirs — how phone/panel pickers hand over selections) with an optional caption (a missing caption falls back to defaultCaption — typically the trigger word). Requires `name` + `items`. Returns the datasetPath to pass to train\_start (action:"start"). Character LoRA guidance: 10-30 varied images; caption what changes between images, keep the trigger word constant.
* action:"list" — List staged datasets, newest-first, with image/caption counts. Read-only, takes no other parameters. Pair with action:"detail" to see one dataset's images + captions.
* action:"detail" — Show ONE staged dataset by `name`: its dir (datasetPath — reusable as train\_start's datasetPath) and every image with its caption (null when uncaptioned). Images render via action:"file". Read-only.
* action:"update" — Edit a staged dataset by `name`: set/replace per-image captions (`setCaptions`) and/or delete individual images with their caption files (`deleteImages`). Refuses while a running/queued job trains from it. Returns per-file warnings for unknown files. This is the SURGICAL edit — it removes only the filenames you list, leaving the dataset itself in place.
* action:"delete" — DESTROY a whole staged DATASET by `name`: every image and every caption under it. Irreversible, and the images are typically hand-curated and unrecoverable — confirm with the user first. Refuses while a running/queued job trains from it. THIS DELETES A DATASET, NOT A TRAINING JOB: to delete a finished job's record and checkpoints use the separate `train_start` tool with action:"delete", which is keyed by `id` rather than `name`. To remove only SOME images, use action:"update" with `deleteImages`.
* action:"file" — Fetch an image under the training root (dataset image, job sample) by absolute `path` as an inline image — the tunnel-safe way for a phone/panel to render training files it can't reach over /view. Bounded: image files only, ≤ 2MB.
* action:"caption\_image" — Caption ONE image by absolute `path` with the user's own Claude subscription (one vision turn through the Agent SDK — not a paid API). Returns the bare caption and does NOT write it — review, then save with action:"update", or use action:"caption\_dataset" to write directly. Optional `guide` steers the style; optional `trigger` is prepended by the model.
* action:"caption\_dataset" — Caption a whole staged dataset by `name` (or the `only` subset) with the user's own Claude subscription and WRITE the captions into its .txt files (one vision turn per image, sequential). Captioning ALWAYS runs through Claude (Agent SDK) regardless of the panel's active backend, so it needs a logged-in Claude Code session (or ANTHROPIC\_API\_KEY). Use after gathering images, before train\_start (action:"start"). Per-file transient failures are reported without stopping the batch, but a persistent auth/credential failure stops immediately with an actionable error rather than failing every image. Optional `guide` steers all captions; optional `trigger` is prepended to each.

### Parameters

<ParamField path="action" type="enum" required>
  Which dataset operation to perform. "list" takes no other parameters; "prepare" requires `name` + `items`; "detail", "update", "delete" and "caption\_dataset" require `name`; "file" and "caption\_image" require `path`. NOTE "delete" here destroys a DATASET (images + captions) — deleting a training JOB is train\_start action:"delete". Options: `action:"prepare"`, `action:"list"`, `action:"detail"`, `action:"update"`, `action:"delete"`, `action:"file"`, `action:"caption_image"`, `action:"caption_dataset"`.
</ParamField>

<ParamField path="name" type="string">
  Dataset name — the staging dir name. REQUIRED for actions "prepare" (it is created), "detail", "update", "delete" and "caption\_dataset" (from action:"list"). This is a DATASET name, never a training job id.
</ParamField>

<ParamField path="items" type="object[]">
  action:"prepare" — the images to stage. REQUIRED for that action.
</ParamField>

<ParamField path="defaultCaption" type="string">
  action:"prepare" — fallback caption for items without one; usually the trigger word.
</ParamField>

<ParamField path="setCaptions" type="object">
  action:"update" — \{filename: caption} pairs to write (replaces existing captions).
</ParamField>

<ParamField path="deleteImages" type="string[]">
  action:"update" — image filenames to delete from the dataset (caption files go too). Removes only these files; action:"delete" removes the whole dataset.
</ParamField>

<ParamField path="path" type="string">
  Absolute path of a file under the training root. REQUIRED for action:"file" (a dataset image or job sample, from action:"detail"'s datasetPath or train\_start action:"status"'s samples) and for action:"caption\_image" (the image to caption).
</ParamField>

<ParamField path="guide" type="string">
  actions "caption\_image"/"caption\_dataset" — extra style guidance for the captioner (e.g. 'focus on outfits and backgrounds').
</ParamField>

<ParamField path="trigger" type="string">
  actions "caption\_image"/"caption\_dataset" — trigger word to prepend to the caption(s).
</ParamField>

<ParamField path="only" type="string[]">
  action:"caption\_dataset" — subset of filenames to caption (default: all images).
</ParamField>

### Example

<Note>No worked example yet — the call below is a skeleton generated from the required parameters. Real examples live in `scripts/tool-doc-examples.ts`; contributions welcome.</Note>

```json theme={null}
{
  "tool": "train_prepare_dataset",
  "arguments": {
    "action": "prepare",
    "name": "aria_character",
    "items": [
      {
        "path": "/photos/aria_01.png",
        "caption": "ohwx person, side profile, window light"
      }
    ],
    "defaultCaption": "ohwx person"
  }
}
```

***

## train\_start

Run and inspect LoRA training JOBS — launch a run, poll it, stop it, delete it, and read back the settings behind it. Jobs are keyed by `id`; the datasets they train on live in the separate `train_prepare_dataset` tool and are keyed by `name`. Driven by the `action` parameter:

* action:"start" — Start a LoRA training job: target 'local' builds the config and launches the GPU trainer container (docker run --gpus all); target 'pod' ssh-drives pod-native training on a connected RunPod pod (pod\_id, or the connector's currently connected pod). Requires `name` + `datasetPath`. Returns a job id for action:"status"/action:"cancel". Long-running — returns immediately; poll action:"status". On completion the LoRA is delivered per deliverTo (pod/local/both) and cataloged when local. Run train\_doctor first if unsure the image/docker/GPU (local) or bootstrap (pod) are ready.
* action:"status" — Check training progress: pass an `id` for one job (step/total, loss, recent samples, log tail, result paths when done) or OMIT `id` for all jobs newest-first. Read-only.
* action:"cancel" — STOP a RUNNING job (docker stop) by `id` and mark it cancelled. Nothing is erased: checkpoints already saved stay in the job's output dir; no LoRA is handed off to models/loras, so the run can be inspected afterwards. Returns ok:false when the container could not be confirmed stopped (the job reverts to running). This is the RECOVERABLE stop — use action:"delete" only when you also want the artifacts gone.
* action:"delete" — DESTROY a finished job by `id`: its record AND its output dir with checkpoints/samples, unless keep\_outputs is true. Irreversible — confirm with the user first. The delivered LoRA in models/loras is NOT removed. Running/queued jobs must be cancelled first (action:"cancel"). THIS DELETES A JOB, NOT A DATASET: to delete the staged images and captions a run consumed use the separate `train_prepare_dataset` tool with action:"delete", which is keyed by `name` rather than `id`.
* action:"list\_flows" — List the LoRA training flows and base models the local trainer supports (phase 1: character LoRA on FLUX.1-dev), with the default training params. Read-only, takes no other parameters — call this first to see what action:"start" accepts.
* action:"job\_config" — Show the effective settings a job ran with by `id` (steps/lr/rank/resolution/batch/saveEvery/sampleEvery/quantize), read back from the ai-toolkit config.yml it consumed, plus flow/model/trigger/datasetPath — everything needed to run the job again with tweaks. Read-only.
* action:"preview\_config" — Show the RAW ai-toolkit config.yml action:"start" WOULD write for these settings (the ostris-UI 'raw config' view) — no side effects, nothing is written or started. Requires `name` + `datasetPath`. Use it to review a run before launching; pass the same params to action:"start" to execute.

### Parameters

<ParamField path="action" type="enum" required>
  Which training-job operation to perform. "list\_flows" takes no other parameters; "status" takes an OPTIONAL `id` (omit for all jobs); "cancel", "delete" and "job\_config" require `id`; "start" and "preview\_config" require `name` + `datasetPath`. NOTE "delete" here destroys a training JOB — deleting a staged DATASET is train\_prepare\_dataset action:"delete". Options: `action:"start"`, `action:"status"`, `action:"cancel"`, `action:"delete"`, `action:"list_flows"`, `action:"job_config"`, `action:"preview_config"`.
</ParamField>

<ParamField path="id" type="string">
  Training job id, as returned by action:"start" (e.g. "t8f3k2ab") — NEVER a dataset name. REQUIRED and must be non-empty for actions "cancel", "delete" and "job\_config". OPTIONAL for action:"status": omit it (or pass an empty string) to list every job newest-first. Unused by "start", "list\_flows" and "preview\_config".
</ParamField>

<ParamField path="name" type="string">
  Job name — becomes the output .safetensors basename (e.g. 'aria\_character'). REQUIRED for actions "start" and "preview\_config". This names the RUN, not the dataset it reads.
</ParamField>

<ParamField path="flow" type="enum" default="character">
  action:"start" — training flow (see action:"list\_flows"). Options: `character`.
</ParamField>

<ParamField path="model" type="enum" default="flux1-dev">
  action:"start" — base model (see action:"list\_flows"). Options: `flux1-dev`.
</ParamField>

<ParamField path="datasetPath" type="string">
  Dataset dir from train\_prepare\_dataset (images + same-basename .txt captions). REQUIRED for actions "start" and "preview\_config".
</ParamField>

<ParamField path="trigger" type="string">
  Unique trigger word (e.g. 'ohwx person') — injected as trigger\_word and usable in prompts.
</ParamField>

<ParamField path="params" type="object">
  Training param overrides for actions "start" and "preview\_config" (steps/lr/rank/resolution/batchSize/saveEvery/sampleEvery/quantize). Omitted keys fall back to the defaults from action:"list\_flows". action:"preview\_config" enforces the SAME bounds action:"start" does, so a preview always reflects a run that could actually launch.
</ParamField>

<ParamField path="device" type="string">
  action:"start" — GPU selector, default cuda:0.
</ParamField>

<ParamField path="target" type="enum" default="local">
  action:"start" — 'local' = docker on this rig; 'pod' = pod-native over ssh on a RunPod pod. Options: `local`, `pod`.
</ParamField>

<ParamField path="pod_id" type="string">
  action:"start" — RunPod pod to train on (target 'pod'). Default: the connector's currently connected/watched pod.
</ParamField>

<ParamField path="deliverTo" type="enum" default="both">
  action:"start", pod jobs only: where the finished LoRA lands. Options: `pod`, `local`, `both`.
</ParamField>

<ParamField path="model_path" type="string">
  action:"start" — override the base model path AS THE TRAINER SEES IT (pod path for target 'pod', container path for 'local') — e.g. a pre-uploaded local HF snapshot dir when the default HF repo id is gated/unreachable.
</ParamField>

<ParamField path="keep_outputs" type="boolean">
  action:"delete" — keep the job's output dir (checkpoints/samples) and delete only the record.
</ParamField>

### Example

<Note>No worked example yet — the call below is a skeleton generated from the required parameters. Real examples live in `scripts/tool-doc-examples.ts`; contributions welcome.</Note>

```json theme={null}
{
  "tool": "train_start",
  "arguments": {
    "action": "start",
    "name": "aria_character",
    "datasetPath": "/home/me/.comfyui-mcp/training/datasets/aria_character",
    "trigger": "ohwx person"
  }
}
```

***

## train\_doctor

Preflight and set up the TRAINER ITSELF — the docker/GPU/venv machinery every training job needs. Touches no dataset and no job. Driven by the `action` parameter:

* action:"doctor" — Preflight the local trainer: docker daemon reachable, `--gpus all` GPU passthrough working (NVIDIA Container Toolkit), trainer image built. Read-only, takes no other parameters. Returns per-check booleans + setup hints. Also reports the training data root and whether HF\_TOKEN is set (needed to download FLUX.1-dev on first run), the native (dockerless) bootstrap status, and the connected pod. Run this first when a training start fails.
* action:"bootstrap" — Set up the NATIVE (dockerless) trainer on this machine (`target` 'local', the default) or on a pod (`target` 'pod', optional `pod_id`): clone ai-toolkit at the pinned commit, create its venv, install torch + requirements. One-time per machine/pod (\~10 min fresh, idempotent; a pod's /workspace persists it across restarts). Needed before a target 'pod' train\_start on a fresh pod (no docker there). Long-running.
* action:"build\_image" — Build the headless GPU trainer image (comfyui-mcp-trainer:latest) from docker/trainer/Dockerfile — one-time, several minutes (CUDA + torch + ai-toolkit). Requires a reachable docker daemon. `aiToolkitRef` pins the ai-toolkit commit/tag for reproducibility. The docker alternative to action:"bootstrap".

### Parameters

<ParamField path="action" type="enum" required>
  Which trainer-setup operation to perform. "doctor" is read-only and takes no other parameters; "bootstrap" takes `target` (+ `pod_id` for target 'pod'); "build\_image" takes an optional `aiToolkitRef`. None of them touches a dataset or a job. Options: `action:"doctor"`, `action:"bootstrap"`, `action:"build_image"`.
</ParamField>

<ParamField path="target" type="enum" default="local">
  action:"bootstrap" — where to install the native trainer. Default local. Options: `local`, `pod`.
</ParamField>

<ParamField path="pod_id" type="string">
  action:"bootstrap" — pod to bootstrap (target 'pod'). Default: the connected pod.
</ParamField>

<ParamField path="aiToolkitRef" type="string">
  action:"build\_image" — ai-toolkit git ref (commit/tag) to build against. Default: the Dockerfile's pinned ref.
</ParamField>

### Example

<Note>No worked example yet — the call below is a skeleton generated from the required parameters. Real examples live in `scripts/tool-doc-examples.ts`; contributions welcome.</Note>

```json theme={null}
{
  "tool": "train_doctor",
  "arguments": {
    "action": "doctor"
  }
}
```

***
