kneifftools / docs /How-To-User-Guides.md
kneiff's picture
refactor(captions)!: finalize Kneifftags migration
45f194e
|
Raw
History Blame Contribute Delete
54.5 kB

A newer version of the Gradio SDK is available: 6.22.0

Upgrade

Table Of Contents

  1. How-To User Guides
    1. Recipe Map
  2. First-Time Setup
    1. Install The Package
    2. Run The First Command
    3. Configure Local Environment Files
    4. Register A Persistent Storage Root
  3. Dataset Workflows
    1. Sync A Manifest Workbook
    2. Sync A Training Dataset
    3. Configure Caption Outputs
  4. LoRA Workflows
    1. Write SimpleTuner Artifacts
    2. Launch SimpleTuner Training
    3. Showcase Training Checkpoints
    4. Promote A Training Checkpoint
  5. Image Workflows
    1. Generate Solo And Duo T2I Runs
    2. Convert PNG Files To JPEG
    3. Prepare Image Sets
    4. Tag And Caption Images
  6. Maintainer Checks
    1. Sync Dependencies
    2. Run Tests
  7. Troubleshooting
    1. Environment Problems
    2. Command Problems
    3. Manifest And Config Problems

1. How-To User Guides

Recipe Map

Use this file when you want commands in order. Use References when you need exact names and Explanations when you need the system model.

Runtimeful dataset, training, ComfyUI, and LLM examples assume that KNF_STORAGE is exported or root --storage NAME_OR_PATH is present. An explicit workflow config path does not replace storage selection.

Related: use docs standards when adding new recipes so headings, callouts, and links stay consistent.


2. First-Time Setup

Install The Package

Use this recipe from the Kneiff repository root.

  1. Create or activate a Python environment:
python -m venv .venv
source .venv/bin/activate
.venv/bin/python -m pip install --upgrade pip
  1. Install the package for runtime use:
.venv/bin/python -m pip install -e "."
  1. Install the maintainer tools when you plan to edit the project:
.venv/bin/python -m pip install -e "." --group dev
  1. If you use uv, sync the locked environment:
uv sync --locked --all-extras

Related: use dependency surfaces for the difference between runtime dependencies and dependency groups.


Run The First Command

Run the CLI after installation:

knf --help

Check the top-level command groups:

knf dataset --help
knf train --help
knf img --help
knf comfy --help

Related: use public interfaces for the commands and import paths users can rely on.


Configure Local Environment Files

KNF_WORKERS controls dataset export, image inspection, and the workspace copy made by knf train prepare and a fresh knf train start. It is read from the selected AppRC storage config and defaults to eight workers. Set it with the TUI or the non-interactive config command:

knf --storage demo config set KNF_WORKERS 8 --scope storage

OpenAI-compatible image captioning reads BASE_URL or OPENAI_BASE_URL plus OPENAI_API_KEY or API_KEY from .env unless you pass --dotenv-path:

cat > .env <<'EOF'
BASE_URL=http://localhost:1234/v1
OPENAI_API_KEY=not-needed
EOF

Keep secrets and machine-local project roots out of committed files.


Register A Persistent Storage Root

Use knf project init when a training project root should become a switchable Kneiff project. It creates the Kneiff scaffold, registers the AppRC storage, and initializes the shallow conventional layout:

demo-project/
├── .env.apprc-storage              # Machine-local AppRC values, created on registration
├── .gitattributes                  # Git LFS tracking rules; does not install Git LFS
├── .gitignore                      # Ignores local and generated project outputs
├── .git/                           # New main-branch Git repository
├── default_tags.txt                # Project-owned seed: kneiff + identity tokens
├── vocabulary.knf.yaml
├── prompts.knf.yaml
├── configs/
│   ├── ANIMA.knf.yaml              # Sygred Anima training config and local model paths
│   └── F2K_9B.knf.yaml             # Flux2 Klein 9B training config
├── SOURCE/
│   ├── 0-FULLBODY/
│   └── 2-HEAD/
├── MANIFEST.knf.xlsx                # Editable, created by dataset sync
├── MANIFEST.yaml                    # Generated Git-review sidecar
├── HF/                              # Created empty and ignored
├── TRAINING/                        # Created empty and ignored
└── .old_manifests/
knf project init "D:\Training\demo-project" \
  --name demo \
  --activation-token Character_Token \
  --species-token species_token \
  --git-user-name kneiff \
  --yes
knf project use demo
knf project show
knf project validate
knf project list

AppRC uses the application name knf. The named-storage index lives at ~/.config/knf/knf.apprc.toml, the app-wide dotenv layer lives at ~/.config/knf/.env.apprc-app, and KNF_APPRC_TOML can override the index path. Each registered root has a machine-local .env.apprc-storage. On WSL/Linux, Windows drive paths are normalized before Kneiff stores or uses them.

When vocabulary.knf.yaml does not exist, knf project init requires both --activation-token and --species-token. Omit both options when adopting a root that already has its vocabulary. The command also creates configs/ANIMA.knf.yaml, the Sygred Anima Base v1.0 training template, and configs/F2K_9B.knf.yaml, the fully commented Flux2 Klein 9B template. The Flux2 config maps fullbody, head, and genitals to their SOURCE/ folders, uses black-forest-labs/FLUX.2-klein-base-9B with unset component paths, and keeps the rank-32, batch-2, 320-step training settings, with a 120-step fullbody/genitals warm-up. The Anima config continues to preserve its configured local model paths. default_tags.txt is a project-owned seed containing kneiff, the activation token, and the species token. Kneiff does not consume that file at runtime.

For a new root, the command runs git init --initial-branch main and sets the repository-local user.name from --git-user-name (default kneiff). It never sets an email, touches global Git config, creates a commit, configures a remote, or installs Git LFS. Existing repositories retain their Git identity and remotes. The generated .gitattributes declares LFS tracking rules for images, models, archives, and workbooks, while .gitignore ignores .env.apprc-storage, HF/, TRAINING/, and other machine-local/generated paths. HF/ and TRAINING/ are created empty without placeholder files.

The initializer registers the root in AppRC's knf.apprc.toml and AppRC creates the root .env.apprc-storage. Existing project-owned files are never replaced. It is the only project initializer.

There is no separate kneiff.project.yaml. The selected AppRC storage is the project identity, and Kneiff derives the shallow paths above in code. vocabulary.knf.yaml overlays the packaged generic JTP vocabulary with the project's activation token, species token, and project-only axes. Each declared axis requires an explicit values list and each value requires a canonical tag. prompts.knf.yaml is an optional version-1 project overlay on Kneiff's packaged core prompt catalog. Package rows provide the portable character reference, NOOB negative default, and fixed validation controls; project rows provide project-specific scenes. Every row requires a nonempty uses list such as showcase, training_validation, or negative_control. Only the core catalog may own negative_control rows. Both loaders reject misspelled or unsupported schema fields. Add project-specific ComfyUI overrides only when needed as workflows/showcase_<preset>.workflow.json.

To control positive and negative prefixes during knf comfy showcase, set defaults.showcase_model_prompts in prompts.knf.yaml. The built-in model family keys are anima, flux2, pony, noob, z-image, and krea2. Settings apply only to showcase generation and are not added to training-validation prompts. A row's negative_prompt or negative_prompts.<field> supplies the negative base; the model's negative_prefix prepends once after that selection. negative_prefix: "" deliberately disables only the model prefix. The old model-level negative_prompt key is rejected. Set ignore_positive_prefix: true on a row to submit its raw caption without any showcase positive prefix. A project workflow named workflows/showcase_<id>.workflow.json uses <id> as its model key unless it belongs to a built-in family.

defaults:
  showcase_model_prompts:
    anima:
      positive_prefix: "masterpiece, best quality, "
      negative_prefix: "worst quality, lowres, "
    flux2:
      negative_prefix: ""
    pony:
      positive_prefix: "score_9, score_8_up, score_7_up, "
      negative_prefix: "score_4, score_3, score_2, score_1, "
    noob:
      positive_prefix: "masterpiece, best quality, newest, "
      negative_prefix: "worst quality, lowres, "
prompts:
  - id: character_reference
    uses: [showcase]
    negative_prompt: "blurry anatomy"
    ignore_positive_prefix: true
    captions: {nlg: "A character reference image."}

knf project use NAME persists the default KNF_STORAGE selector in app-wide AppRC config. A shell KNF_STORAGE value or root --storage NAME_OR_PATH option overrides it for a specific command:

knf --storage demo dataset plan chroma

knf project list validates every registered root. knf project show reports the selected root, identity, validation status, default Anima and Flux2 configs, default tags, Git files and repository state, starter source directories, and every conventional project path. knf project validate checks the fixed starter files and source directories, parses both generated configs through the export and SimpleTuner loaders, then parses the vocabulary, packaged core catalog, optional project overlay, and workflow overrides and reports their counts.

An explicit configs/*.knf.yaml path must remain inside the selected project root. Kneiff rejects paths from another project; select that project with --storage instead. Inspect AppRC paths and edit native config values with the generated commands:

knf --storage demo config show
knf config paths
knf config doctor
knf --storage demo config edit

knf config edit opens the Textual TUI. knf config app init creates the app-wide dotenv file; knf config storage add, list, and remove manage the named-storage index. Use knf config set KEY VALUE --scope app or --scope storage for a non-interactive override.

Keep project-local settings such as KNF_WORKERS in the project root .env.apprc-storage, managed by AppRC. The storage-local file cannot select its own root because AppRC must resolve KNF_STORAGE before it knows which file to load. Use knf project use, the shell environment, or root --storage for selection. Set COMFY_MODELS_DIR in .env.apprc-storage, the shell, or --env-file when using knf comfy showcase with LoRA discovery. Root --env-file options must appear before the command group and may be repeated:

COMFY_MODELS_DIR="/path/to/comfyui-models"
knf --storage demo --env-file ./comfy.env comfy showcase

Set COMFY_LORAS_DIR_1 when the interactive LoRA picker should open in a specific subdirectory below $COMFY_MODELS_DIR/models/loras. knf comfy upscale has built-in defaults, but you can override its model choices when your ComfyUI install uses different filenames:

COMFY_LORAS_DIR_1="/path/to/comfyui-models/models/loras/project/version"
COMFY_UPSCALE_MODEL="4x-UltraSharpV2.pth"
COMFY_UPSCALE_REFINER_UNET="krea2_turbo_fp8_scaled.safetensors"
COMFY_UPSCALE_REFINER_CLIP="qwen3vl_4b_fp8_scaled.safetensors"

COMFY_UPSCALE_REFINER_CLIP_TYPE defaults to krea2, and COMFY_UPSCALE_REFINER_VAE defaults to qwen_image_vae.safetensors. If a default is not installed, interactive terminals open a picker from ComfyUI's reported options; scripts should set the matching COMFY_* value, pass -z for the legacy Z-Image quality workflow, or pass --fast.

Set LM Studio prompt-generation settings in .env.apprc-storage, the shell, or --env-file when using knf llm prompt. LM Studio must already be running with its OpenAI-compatible local server enabled:

KNF_LMSTUDIO_BASE_URL="http://127.0.0.1:1234/v1"
KNF_LMSTUDIO_MODEL="qwen/qwen3-14b"
KNF_PROMPTGEN_DRAFT_TEMPERATURE=0.7
KNF_PROMPTGEN_REVIEW_TEMPERATURE=0.2

Use KNF_LMSTUDIO_DRAFT_MODEL and KNF_LMSTUDIO_REVIEW_MODEL when the two passes should use different local models. KNF_LMSTUDIO_CUDA_DEVICE_NAME resolves a visible GPU name fragment, such as RTX 4070 Ti Super, for future Kneiff-managed launch helpers; it cannot change the GPU used by an already running LM Studio server. When prompt exchange saving is enabled, knf llm prompt writes raw transcripts under the selected storage root at .llm_promptgen/. Set KNF_PROMPTGEN_EXCHANGE_DIR only when you want to override that location. knf llm prompt saves user-facing JSON and review-text prompt results below .llm_promptgen/results/ in the selected storage by default. Pass --no-export to skip those result files for one run. The former --export opt-in is removed because export is now the default.

When a command needs a config, pass either an explicit config path or a selector such as chroma, Chroma, or CHROMA. Selectors match direct child configs/*.knf.yaml files in the active storage root. If no selector is passed, Kneiff auto-selects only when exactly one config is available. If multiple configs are available in an interactive terminal, use the arrow-key picker. Batch-capable commands let you press Space to toggle configs, a to toggle all, and Enter to confirm; single-config commands still select the highlighted config with Enter. In scripts, pass explicit config paths or selectors so non-interactive runs keep failing with the available-config list.


3. Dataset Workflows

Sync A Manifest Workbook

Refresh only MANIFEST.knf.xlsx and generated MANIFEST.yaml from SOURCE/:

knf dataset sync path/to/project/configs/example.knf.yaml --manifest-only

With storage selected, use the config selector instead:

knf dataset sync example --manifest-only

Kneiff creates or updates fixed A-H workbook sheets. Every image occupies exactly 13 rows: Relative_path, Subject, Appearance, Composition, Pose and behavior, Face, Anatomy, Sexual content, Scene, Presentation, Fallback, SFW, and Notes. The thumbnail in column A and the derived tag, json, nlg, chroma, and prose outputs in columns D-H are merged across the block. Each column-C User Input cell remains independent.

MANIFEST.yaml is generated beside the workbook so Git can show manifest changes clearly. Keep editing MANIFEST.knf.xlsx; the YAML sidecar is rewritten from the workbook sync output.

When configs/*.knf.yaml files are present, run a dataset sync:

knf dataset plan path/to/project/configs/example.knf.yaml
knf dataset sync path/to/project/configs/example.knf.yaml
knf dataset sync alpha beta

Sync stages and validates MANIFEST.knf.xlsx, schema-version-2 MANIFEST.yaml, and a legacy project vocabulary before activating any of them. The sidecar stores logical records and user input but no derived captions. A first migration archives the previous file set below .old_manifests/ and restores it if activation fails. Existing _resolution_plan sheets remain available; the retired _caption_previews sheet is replaced by the five merged output columns.

The selected AppRC storage defines the project root. The direct-child configs/<id>.knf.yaml supplies the config id and workflow settings; source images are read from SOURCE/, manifest rows stay relative to SOURCE/, and the export root is HF/<id>/. Each exported dataset also gets a kneiff-training-image-grid.jpg contact sheet, Hugging Face metadata.jsonl, a generated dataset-card README.md, and publish-safe .hfignore and .gitignore files in its export root. SimpleTuner files are generated by knf train prepare, not by dataset sync.

Related: use manifest-to-export model for the ownership boundary between source images, workbook rows, and exports.


Sync A Training Dataset

Use a configs/*.knf.yaml file to map source folders to export subsets:

mappings:
  identity:
    - "0-IDENTITY"
  details:
    - "1-DETAILS"
image_resize:
  min_pixel_area: 768
  max_pixel_area: 1536
augmentations:
  mirrored_extra: true
  mirrored_transform: flip_only
  seed: 12345
export_sfw_subset: true
publishing:
  huggingface:
    repo_id: account/dataset-name
    pretty_name: Example LoRA Dataset
    version: v1.0
    optimized_for_model: Chroma1-HD
    license: cc-by-4.0
    tags: [image-captioning, diffusion-training, lora]
    provenance: TODO
    adult_content: false
    notes: TODO

Keep filesystem paths out of this file. The config must live directly at <project>/configs/<config-id>.knf.yaml; Kneiff derives SOURCE/, MANIFEST.knf.xlsx, HF/<config-id>/, and numbered TRAINING/ paths. The keys source_root, manifest_path, export_root, and allow_export_inside_source are rejected.

augmentations.mirrored_extra adds fixed mirrored image/caption pairs during export. Use mirrored_transform: flip_only for exact horizontal mirrors, or mirrored_transform: augmented for the legacy mirror plus kneifftools crop, rotation, and color jitter. SimpleTuner runtime crop settings live separately under training.simpletuner.dataset.

Inspect the resolved paths before writing:

knf dataset plan path/to/project/configs/example.knf.yaml
knf dataset plan example
knf dataset plan alpha beta

The plan output uses Config: <id> for the selected CONFIG identity and Config path: ... for the resolved configs/<id>.knf.yaml file.

Sync from the explicit config:

knf dataset sync path/to/project/configs/example.knf.yaml
knf dataset sync example
knf dataset sync alpha beta

Successful syncs write kneiff-training-image-grid.jpg in the export root so you can quickly inspect the non-mirrored training images by subset. Sync also writes Hugging Face metadata.jsonl, a generated README.md, .hfignore, and .gitignore files. Metadata rows use relative file_name values and follow the configured SimpleTuner training subsets when training is enabled. Exported image and caption files are diffed against HF/<id>/.kneiff-export-state.json, so unchanged files are skipped while README and metadata artifacts still refresh. If that state file is missing or invalid, the next sync rewrites planned files and preserves files outside the current plan. Use --rebuild when you explicitly want to clear the export root.

Regenerate only the dataset card from existing export artifacts:

knf dataset readme path/to/project/configs/example.knf.yaml

Regenerate only that non-mirrored grid from the existing export directory:

knf dataset grid path/to/project/configs/example.knf.yaml
knf dataset grid path/to/project/configs/example.knf.yaml --output /tmp/training-grid.jpg

When SimpleTuner training is enabled, training.simpletuner.subsets must be a non-empty explicit mapping. Sync reports include Train prob and Train % columns. Train % matches the configured data_backend_sampling mode: auto-weighting uses exported image count times probability, while uniform uses probability only. The generated sfw subset is excluded unless it is explicitly listed under training.simpletuner.subsets. Sync also reports source and planned export resolution buckets plus a source-resolution plan showing Kneiff export processing and predicted SimpleTuner behavior from the current config. The report starts with kept vs KICKED health counts and prints a kicked-out image table whenever any input would be filtered by the trainer. Oversized inputs stay kept when SimpleTuner can downsample them through maximum_image_size and target_downsample_size; KICKED is reserved for true trainer filters such as minimum_image_size, minimum_aspect_ratio, maximum_aspect_ratio, unsupported crop prediction, or an unconfigured backend. This matches SimpleTuner's upstream minimum_image_size, maximum_image_size and target_downsample_size, and option documentation. Resolution tables always include totals and preserve the smallest buckets before aggregating other. Real sync runs list changed image files with their source size, output size, and resize scale; add --verbose to show all changed images and all uncapped resolution buckets.

Use --dry-run to validate and count outputs without writing files:

knf dataset sync path/to/project/configs/example.knf.yaml --dry-run

Use knf dataset describe when you want the same dry-run counts table without the sync summary or any file writes:

knf dataset describe path/to/project/configs/example.knf.yaml

Use --rebuild only when you are ready to delete and recreate generated public export files. Add --yes to confirm that rebuild prompt in unattended runs:

knf dataset sync path/to/project/configs/example.knf.yaml --rebuild
knf dataset sync path/to/project/configs/example.knf.yaml --rebuild --yes

--rebuild deletes existing contents under the config-derived export root. Review HF/<id>/ before confirming a destructive rebuild.


Configure Caption Outputs

Use caption_outputs for global sidecar defaults and caption_outputs_overrides for per-subset changes:

caption_outputs:
  mode: hybrid_txt
  formats: [tags, natural]
  tag_scope: supplemental
caption_outputs_overrides:
  identity:
    formats: [tags, natural, json]
  sfw:
    mode: separate_txt
    formats: [tags, natural, chroma, nlg]
caption:
  subject_sex: null  # Set male or female only when the project needs it.

Supported caption formats are:

Format Output
tags Kneifftags tag profile.
natural Kneifftags natural-language profile.
json Compact category-to-tag JSON derived from the shared analysis.
nlg Kneifftags controlled NLG profile.
chroma Kneifftags Chroma profile.
hybrid Kneifftags hybrid natural-and-tag profile.

Only the listed format names are accepted. Replace removed tag and prose config values with tags and natural. The workbook headers remain tag and prose because they are part of the fixed workbook layout.

Every caption for one image is rendered from the same Kneifftags analysis. Unknown inputs are preserved in fallback output and reported as warnings. Category mismatches and ambiguous inputs also remain visible in diagnostics. Active Kneifftags errors block migration or export.

Rows marked SFW reject explicit or NSFW labels, explicit anatomy, penis state and appearance, sexual actions, sexual fluids, and the exact tags anus, balls, and genitals.

Set tag_scope: supplemental to keep identity and tag-only facts while omitting tags already expressed in natural text inside a joined caption. Set tag_scope: all when you need the full tag tail. Standalone tags and chroma files always use the complete tag set.

Use formats: [nlg] for Flux2/Z-Image Qwen-style character LoRA captions. Caption-text compatibility does not make LoRA weights cross-model-compatible; train and load LoRAs within the target model family.

Project-only tags from vocabulary.knf.yaml are entered in the matching fixed workbook field. Use Fallback when no fixed semantic field applies. A project extension can define categories, groups, aliases, output tags, natural/NLG phrases, and safety metadata; Kneifftags owns their validation and rendering. Project character and species defaults are namespace-qualified so a built-in tag with the same spelling cannot replace project identity.

caption_outputs no longer accepts per-subset mappings. Put subset-specific changes under caption_outputs_overrides.


4. LoRA Workflows

Write SimpleTuner Artifacts

LoRA training settings live under training.simpletuner in the same configs/*.knf.yaml file used for dataset sync.

List prepared and completed training runs:

knf train runs example
knf train runs /abs/path/to/project/configs/example.knf.yaml

Prepare the generated SimpleTuner JSON files without launching:

knf train prepare example
knf train prepare alpha beta --testrun
knf train prepare /abs/path/to/project/configs/example.knf.yaml

Run knf dataset sync CONFIG before preparing training artifacts. knf train prepare requires a populated HF/<config-id>/ export with files in every enabled training.simpletuner.subsets entry, and it does not run dataset sync or create an empty export root. There is no project-specific subset fallback.

The config-derived export root stays the public dataset folder. knf train prepare writes SimpleTuner state under TRAINING/<config-id>_<run>/, including dataset/, simpletuner-config.json, simpletuner-multidatabackend.json, _simpletuner-output/, and kneiff-training-run.json. Generated JSON reserves paths below .simpletuner-cache/; SimpleTuner creates cache content when it runs. When validation prompts are enabled, preparation also writes simpletuner-validation-prompts.json. These are Kneiff-owned fixed paths; training configs cannot rename or redirect them. Fresh preparation chooses the next free run number by scanning existing TRAINING/<config-id>_<N>/ workspaces and root validation-grid files. Training preparation and review output include a SimpleTuner-only resolution health summary for the copied dataset, including kicked-out image paths when any copied image would be filtered; random aspect crop modes list possible buckets instead of exact counts. knf train start may create .kneiff-simpletuner/ later when the launcher bootstraps model conversions. That directory and its generated component directories and metadata files must not be symlinks. The only generated link is chroma-text-encoder/text_encoder/model.safetensors, and an existing link is accepted only when it still points to the configured Chroma text encoder.

Every numbered workspace must contain a valid kneiff-training-run.json, and its dataset, JSON artifacts, cache, prompt library, and output paths must match the fixed locations in that workspace. The marker requires schema_version: 1, normalized absolute paths, explicit typed optional fields, exact SHA-256 digests, and a nonempty unique subset list matching direct dataset/ children from the generated data-backend JSON. Kneiff does not coerce, backfill, or rewrite pre-layout training runs. Archive or remove an unsupported workspace and prepare a new run.

Use training.simpletuner.curriculum when different subset mixes should train at different points inside the same run. Phase steps are included in training.simpletuner.trainer.max_train_steps; this example trains the identity subset for the first 400 steps and starts every configured image subset at step 400:

training:
  simpletuner:
    curriculum:
      enabled: true
      phases:
        - name: focused_start
          start_step: 0
          subsets: [identity]
        - name: full_mix
          start_step: 400
          subsets: all

Apply a short smoke-test profile from training.simpletuner.trainer_testrun:

knf train prepare path/to/project/configs/example.knf.yaml --testrun

Delay scheduled intermediary validation until an exact optimizer step with training.simpletuner.validation_schedule.start_step. With a start step of 550 and trainer.validation_step_interval: 100, it renders at steps 550, 650, 750, and so on. The step-0 base-model benchmark and the end-of-run validation remain available. Omit this setting or use start_step: 0 to retain SimpleTuner's normal interval schedule. A delayed schedule requires a positive step interval and cannot be combined with trainer.validation_epoch_interval. Kneiff saves the chosen step in the prepared run, so reviews, resumes, and extensions keep that schedule even if the source YAML is changed later.

training:
  simpletuner:
    validation_schedule:
      start_step: 550
    trainer:
      validation_step_interval: 100

When training.simpletuner.validation_prompts is configured, knf train prepare writes the fixed simpletuner-validation-prompts.json beside the generated SimpleTuner config and points user_prompt_library at that file. The clean wrapper supports direct custom prompts plus manifest-generated prompts in one library.

Use custom for prompt text that should be copied directly into the prompt library, from_prompts for curated captions from the selected project's resolved core-plus-overlay catalog marked with training_validation, and from_manifest for an activation prompt plus one sampled prompt per configured export subset. default_negative_controls independently adds the fixed wolf and two fixed human controls and is enabled by default. Set root styles once to supply every enabled source; each source may override it with caption_styles. Controls and manifest sampling require exactly one effective style. Training config cannot redirect the project prompt source. Custom prompts may include {activation_token}, which resolves to the selected project's character token when the prompt library is written. Prompt catalogs live under kneiff.prompts; SimpleTuner validation artifacts live under kneiff.training.lora. Use positive_prefix to prepend model-specific quality or safety tags to every generated and custom validation prompt. Packaged controls and manifest sampling support tags, natural, chroma, and nlg. Generated sfw fanout rows are not added as validation prompts unless sfw is an explicit mapping subset.

training:
  simpletuner:
    validation_prompts:
      styles: [nlg]
      positive_prefix: "masterpiece, best quality, score_7, safe, "
      custom:
        custom_portrait: "{activation_token}. A close-up portrait validation prompt."
      from_prompts: {}

Add from_manifest with caption_styles: [tags] when sampled dataset prompts are also needed. Set default_negative_controls.enabled: false to omit the packaged control suite. The generated section contains fixed wolf, residential-street, and office-worker negative controls, an activation control, and one subset prompt per mapping. Project prompt entries are ordered after core rows by prompt row, caption style, and caption variant; generated prompt keys receive a runtime index prefix for stable file explorer ordering. negative_control_species is not configurable.

Kneiff ships LoRA config templates as package resources under kneiff.training.lora.templates: complete.yaml, chroma.yaml, z-image.yaml, flux2-klein-4b.yaml, flux2-klein-9b.yaml, anima.yaml, and sdxl.yaml. The complete template is a reference for supported settings, sdxl.yaml is a full commented Pony/SDXL starting config, and the remaining model-specific templates are compact overlays with only model-specific caption, model, validation, and crop recommendations.

Related: use LoRA workflow model for how Kneiff translates one dataset config into SimpleTuner artifacts.


Launch SimpleTuner Training

Launch SimpleTuner from the generated artifacts:

knf train start example --cuda-device 1
knf train start alpha beta --yes
knf train start /abs/path/to/project/configs/example.knf.yaml --cuda-device 1

Set KNF_SIMPLETUNER_EXECUTABLE in the app-wide .env.apprc-app file when Kneiff should use a specific SimpleTuner environment instead of the first simpletuner command on PATH:

KNF_SIMPLETUNER_EXECUTABLE=~/repos/SimpleTuner/.venv/bin/simpletuner

The configured value must be an absolute path or begin with ~, point to an existing console script, and declare its Python interpreter directly in its shebang. An unset or blank value preserves the PATH lookup. Kneiff uses the selected interpreter to start the workspace's copied patch runner in an isolated child process. It never imports SimpleTuner into the Kneiff process or temporarily replaces the Kneiff process's working directory and environment.

Interactive terminals show a review menu before launch. Use json to inspect the generated SimpleTuner files, diff to compare against the previous run, and start to launch. Run-index-only path changes inside TRAINING/<config-id>_<N>/ are hidden from the diff so real generated-config changes are easier to spot. Use --yes or --no-review when running unattended.

After a successful run, Kneiff scans SimpleTuner's validation_images, keeps only the trained-model half of paired split validation outputs, leaves the first-run single-image renders intact, and writes TRAINING/<config-id>_<run>-kneiff-validation-progress-grid.jpg. When prompt-library metadata is available, each validation column shows the prompt key plus up to ten wrapped lines of full prompt text at both the top and bottom of the grid. For SDXL/Pony LoRAs, the same successful run also writes pytorch_lora_weights.comfyui.safetensors beside each pytorch_lora_weights.safetensors checkpoint so ComfyUI can load the exported adapter directly.

Regenerate only that grid from existing validation images:

knf train grid path/to/project/configs/example.knf.yaml 1
knf train grid path/to/project/configs/example.knf.yaml 1 --output /tmp/validation-grid.jpg

Run the testrun profile and regenerate artifacts first:

knf train start example --testrun --cuda-device 1

Resume a prepared or incomplete run without regenerating artifacts:

knf train start example --resume 1 --cuda-device 1
knf train start alpha beta --resume 2
knf train start alpha --resume
knf train start /abs/path/to/project/configs/example.knf.yaml --resume

--resume launches existing generated JSON files from the selected run workspace. It does not regenerate artifacts from the current YAML config. The workspace-local dataset/ copy must still exist and contain files for every active image backend. If it is missing or stale, run knf dataset sync CONFIG and prepare a new run. Pass a run number to skip the interactive prompt. Bare --resume opens an interactive picker for not_started and incomplete runs. Running knf train start without a selector in an interactive terminal first lists those resumable runs, then the configs that would start new runs.

Use --fallback-cuda-device when the launch wrapper should record a fallback device for the child process environment:

knf train start path/to/project/configs/example.knf.yaml --cuda-device 1 --fallback-cuda-device 0

Showcase Training Checkpoints

Set COMFY_MODELS_DIR to the ComfyUI models root. Its models/loras directory must be writable:

COMFY_MODELS_DIR="/path/to/comfyui-models"

Open the shared run-first picker for numeric checkpoint files from direct training-run _simpletuner-output trees:

knf comfy showcase -t

Pass one or more positive step numbers to include only exact checkpoint directories. Every requested step must exist in at least one run:

knf comfy showcase -t 400
knf comfy showcase -t 400 800 --workflow anima

The picker first lists direct TRAINING/<config-id>_<run>/ directories. Opening a run shows only its checkpoint-<step> LoRAs. ../ Other TRAINING runs returns to the run list without losing checked files, so a showcase can compare several runs. Root-level final exports are hidden because they have no numeric checkpoint step. ComfyUI-native *.comfyui.safetensors files appear first, followed by every remaining .safetensors file. Kneiff excludes caches, dataset copies, symlinks, and files outside direct _simpletuner-output trees.

Use Space to toggle LoRAs or a to select all candidates. Enter selects the checked LoRAs, or only the highlighted LoRA when nothing is checked. Each selected file is hard-linked into a unique directory below models/loras/.kneiff-training/ when possible and copied when the two paths use different filesystems. Kneiff removes those temporary directories after the run, including when workflow resolution or showcase generation fails. Omit --workflow to infer the shared workflow from the first selected training-relative path and open the workflow picker when the path has no unique match.

The run and file lists keep the active row in a terminal-height-bounded viewport. Above/below indicators show omitted rows, and each rendered row is kept to one terminal line so arrow-key navigation replaces the prior frame instead of flooding a short terminal.

Kneiff prints each prompt source on its own row, followed by the inspected workflow settings and the dated ComfyUI output directory. Interactive terminals show one progress bar across every selected LoRA and eligible prompt.

Every successful showcase downloads the reported images, assembles one timestamped JPEG in a temporary directory, and uploads it into the same dated ComfyUI output subfolder as the individual SaveImage results. Prompts are the columns and LoRAs are the rows, so selecting several checkpoints produces one comparison grid. Prompt IDs and up to ten wrapped lines of full prompt text appear above and below the images. Kneiff does not persist showcase grids below the project's TRAINING directory.

-t requires an interactive terminal and cannot be combined with --lora. COMFY_MODELS_DIR must describe the filesystem used by the running ComfyUI server.


Promote A Training Checkpoint

Install one reviewed numeric checkpoint as a release copy below the configured ComfyUI LoRA library:

knf train promote
knf train promote --name Rook-Preview

knf train promote uses the same run-first TRAINING picker, then lets you browse existing directories under $COMFY_MODELS_DIR/models/loras. It asks for a mandatory release version in v<major>.<minor> form, shows the exact target, and requires confirmation before copying. The target name is:

<name>-<MODEL_ID>-v<major>.<minor>-<step>.safetensors

name comes from custom_tokens.character.text unless --name / -n overrides it. MODEL_ID is the uppercase compact model ID inferred from the generated simpletuner-config.json, and step comes from the selected checkpoint-<step> directory. The source in TRAINING is never moved or overwritten; an existing destination filename is refused.


5. Image Workflows

Generate Solo And Duo T2I Runs

Run LM Studio's OpenAI-compatible server and ComfyUI, then configure the filesystem and model paths in the selected project's .env.apprc-storage:

COMFY_MODELS_DIR="/path/to/comfyui-models"
COMFY_LORAS_DIR_1="project/primary"
COMFY_LORAS_DIR_2="project/partner"

COMFY_T2I_MODEL_SOLO="diffusion_models/Krea2/krea2_turbo_fp8.safetensors"
COMFY_T2I_LORA_SOLO="primary-krea2.safetensors"
COMFY_I2I_MODEL_SOLO="diffusion_models/F2K_9B/flux-2-klein-9b.safetensors"
COMFY_I2I_LORA="primary-flux2.safetensors"

COMFY_T2I_MODEL_DUO="diffusion_models/Anima/anima-base-v1.0.safetensors"
COMFY_T2I_LORA_DUO_1="primary-anima.safetensors"
COMFY_T2I_LORA_DUO_2="partner-anima.safetensors"

COMFY_I2I_MODEL_DUO="diffusion_models/F2K_9B/flux-2-klein-9b.safetensors"
COMFY_I2I_LORA_1="primary-flux2.safetensors"
COMFY_I2I_LORA_2="partner-flux2.safetensors"

Strength keys default to 1.0. Add COMFY_T2I_LORA_STRENGTH_SOLO, COMFY_I2I_LORA_STRENGTH, COMFY_T2I_LORA_STRENGTH_DUO_1, COMFY_T2I_LORA_STRENGTH_DUO_2, COMFY_I2I_LORA_STRENGTH_1, or COMFY_I2I_LORA_STRENGTH_2 when a model needs another value.

For duo runs, declare participant 2 in the project vocabulary. The canonical custom_tokens.character entry remains participant 1:

additional_activation_tokens:
  - Sygred_Lightfeet

When --pipeline is omitted, knf comfy t2i solo opens an arrow-key picker for Krea2 only, Krea2 plus Flux2 Klein cleanup, or Anima plus Flux2 Klein cleanup. Non-interactive scripts must pass the choice. Krea2 only produces nine finals by default; either Flux profile and duo produce nine baselines plus 27 cleanup candidates:

knf comfy t2i solo --pipeline krea2 "full-body portrait in a sunlit workshop"
knf comfy t2i solo --pipeline anima-flux2 "full-body portrait in a sunlit workshop"
knf comfy t2i duo "two characters talking beside a forest stream"

Use --num-prompts, --num-images, and --num-cleanups on Flux profiles or duo to change branch counts. Solo Flux cleanup accepts --i2i-model, --i2i-lora, and --i2i-lora-strength for one run. Krea2-only rejects those cleanup options. --seed controls image branches only; LM prompt text remains sampled. Before each pass, Kneiff derives project identity facts, project-specific visual concepts, and scene-relevant curated prompt references from the selected vocabulary and prompt catalog. The LLM uses references only for persistent identity and prompt grammar, not their scene-specific content. Every run prints its random or explicit root seed and records the derived context plus exact raw and effective prompts in readable run.knf.yaml.

Kneiff sends run-relative output paths to ComfyUI and uploads run.knf.yaml through the same server-managed output mechanism used by the showcase grid. No client-side ComfyUI output path is required. Set optional COMFY_OUTPUT_DIR or pass --output-dir only to keep an additional local mirror. Any Flux cleanup also requires qwen_3_8b_fp8mixed.safetensors below ComfyUI's text encoders and full_encoder_small_decoder.safetensors below its VAE models, matching the current official distilled 9B edit workflow.

All baseline prompts are queued before Flux cleanup begins. Ctrl-C deletes only pending prompt IDs created by this run and interrupts the active prompt only when ComfyUI confirms that it belongs to the same run. Completed files and the manifest remain available after failure or interruption. Krea2-only prints Cleanup: not selected.

LM Studio and ComfyUI may allocate GPU memory concurrently. An OOM can come from either server; the command prints both URLs before generation starts.


Convert PNG Files To JPEG

Convert every PNG below a directory into an output subdirectory:

knf img png2jpg ./images --out-subdir jpg --quality 95

Preview without writing files:

knf img png2jpg ./images --dry-run

Prepare Image Sets

Concatenate images horizontally:

knf img concat ./a.png ./b.png --output contact-sheet.png --width 2000

Rename files with an enumerated random suffix:

knf img rename ./images/*.png --base-name sample --mode enum --start 1

Upscale one file or a directory:

knf img upscale ./images --out-dir ./upscaled

Interactive png2jpg and local-upscale batches replace repetitive success lines with one Rich progress bar. Local upscale starts with a spinner while it resolves and loads model weights, then adds the discovered image count. Redirected execution keeps the existing plain per-file output.

Upscaling may download model weights and can use significant GPU memory.


Tag And Caption Images

Print e621-style tags from RedRocket/JTP-3:

The current RedRocket/JTP-3 main snapshot requires the Python package pyvips and native libvips. Install Python dependencies with uv sync or .venv/bin/python -m pip install -e .. On Fedora WSL, install the native package with sudo dnf install vips. Current main uses calibrated upstream tag selection; --threshold is only for legacy pinned revisions.

knf img tag ./images --recursive

For one image, knf img tag prints only the selected tag line. For multiple images or directory inputs, each line is PATH<TAB>TAGS.

Write .txt tag sidecars instead:

knf img tag ./images --recursive --txt

Use legacy comma-separated tag text when another workflow expects it:

knf img tag ./images --recursive --txt --comma

--csv-stdout is a probability CSV export mode, not selected-tag text output.

Common knf img tag options:

Option Use
--txt Write .txt sidecars next to images instead of printing selected tags.
--comma, -c Use legacy comma-separated selected-tag text. Without this, tags are e621-style whitespace-separated tokens.
--csv-stdout Print probability CSV output from JTP-3. Do not combine it with --txt or --comma.
--threshold, -t Set the symmetric tag threshold for legacy pinned JTP-3 revisions. Current main uses calibrated upstream tag selection and rejects non-default thresholds.
--device, -d Select the Torch device, for example cuda, cuda:1, or cpu.
--batch-size, -b Set images per inference batch.
--workers, -w Set upstream image-loader workers. Omit it for JTP-3's automatic default.
--seqlen, -S Set NaFlex sequence length. The default is 1024; JTP-3 accepts 64 to 2048.
--prefix, -p Force tag text to the beginning of selected-tag output.
--repo-id, --revision Use a different Hugging Face model repository or pinned revision.

Caption one image through an OpenAI-compatible server:

knf img caption ./image.png --server --model-name local-model

Caption a directory and write sidecars:

knf img caption ./images --server --model-name local-model --out-suffix .cap.txt

Directory captioning counts only images eligible after the existing-sidecar and --overwrite policy. Caught server or image-open failures still advance the attempt count and remain visible as diagnostics. Full server instruction dumps are hidden behind an interactive bar but remain present when stdout is redirected. Single-image captioning does not create a progress display.

knf img concat, knf img rename, and knf img tag do not show Kneiff bars. Concatenation and renaming finish as short result-oriented operations; JTP-3 is one upstream subprocess and does not expose reliable per-image completions.

Use the BLIP/Qwen path instead of a local server:

knf img caption ./images --blip --model-name Qwen/Qwen2-VL-2B-Instruct

Generate a two-pass image prompt through LM Studio:

knf llm prompt "Character_Token resting against a tree, rear view, looking back"

knf llm prompt prints a human review view by default with the first version, second version, and review comments. Use --verbose or --format json for the full structured JSON payload with dataset-shaped fields, final prompt text, assumptions, missing input, review issues, and model ids. Use --text for a copy-friendly prompt:

knf llm prompt "front-view portrait, smiling" --text

The explicit review format is also available when scripts should spell out the human output mode:

knf llm prompt "front-view portrait, smiling" --format review

Prompt results are saved automatically below .llm_promptgen/results/ in the selected storage. Suppress those files when you only want terminal output:

knf llm prompt "front-view portrait, smiling" --no-export

Force known fields with repeated --field FIELD=VALUE options:

knf llm prompt "resting against a tree" \
  --field character=Character_Token \
  --field view=rear_view \
  --field pose_body=standing,leaning

6. Maintainer Checks

Sync Dependencies

Use just sync to install the full maintainer environment from uv.lock:

just sync

Use plain pip when you only need the package and do not want uv:

.venv/bin/python -m pip install -e "."

Related: use configuration model for why runtime installs and maintainer installs are documented separately.


Run Tests

Run the focused CLI smoke tests:

.venv/bin/pytest tests/test_cli_smoke.py

Run the usual quality tools before finishing a Python code change:

.venv/bin/ruff format .
.venv/bin/ruff check .
.venv/bin/pyright
.venv/bin/pytest

Related: use Development: verification for the maintainer checklist before a commit.


7. Troubleshooting

Environment Problems

Check the active Python and import location first:

python --version
python -c "import sys; print(sys.executable)"
python -c "import kneiff; print(kneiff.__file__)"

If knf is missing, reinstall from the Kneiff repository root:

.venv/bin/python -m pip install -e "."

For image captioning, confirm the local .env contains BASE_URL or OPENAI_BASE_URL.

Related: use failure model for the normal order of checks when a command behaves differently across machines.


Command Problems

When a just recipe fails:

  1. Run just --list.
  2. Run the underlying command manually.
  3. Check whether the virtual environment is active.
  4. Check whether the command exists in .venv/bin.
just --list
ls .venv/bin

Related: use command reference for the expected commands and their owners.


Manifest And Config Problems

When dataset sync fails:

  1. Confirm the config file is named configs/<dataset-id>.knf.yaml.
  2. Confirm the manifest uses the canonical Relative_path column.
  3. Confirm mappings names source folders relative to SOURCE/.
  4. Confirm caption_outputs_overrides names only configured subsets, plus sfw when export_sfw_subset: true.
  5. Confirm YAML keys are unique. Duplicate keys are rejected, including nested keys such as training.simpletuner.trainer.caption_dropout_probability.
  6. Run sync in --dry-run mode.
knf dataset sync path/to/project/configs/example.knf.yaml --dry-run

Related: use configuration files for the exact file owners and caption sidecar model for output behavior.