File size: 54,521 Bytes
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae10cda
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
09df1fe
 
 
 
 
 
 
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
09df1fe
 
 
 
 
 
 
 
 
2857cf3
 
09df1fe
 
 
 
 
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
09df1fe
2857cf3
 
 
09df1fe
2857cf3
 
09df1fe
2857cf3
 
 
 
 
 
 
 
09df1fe
 
 
 
 
 
 
45f194e
 
 
09df1fe
 
 
 
 
2857cf3
 
09df1fe
 
 
2857cf3
 
09df1fe
 
 
2857cf3
 
09df1fe
 
 
 
 
 
 
 
 
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
09df1fe
 
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
09df1fe
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae10cda
 
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
ae10cda
 
 
 
 
 
 
2857cf3
 
 
 
 
 
 
 
 
 
 
ae10cda
 
 
 
 
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae10cda
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
<!-- ======================================================== -->
## Table Of Contents
<!-- ======================================================== -->

1. [How-To User Guides](#1-how-to-user-guides)
   1. [Recipe Map](#recipe-map)
2. [First-Time Setup](#2-first-time-setup)
   1. [Install The Package](#install-the-package)
   2. [Run The First Command](#run-the-first-command)
   3. [Configure Local Environment Files](#configure-local-environment-files)
   4. [Register A Persistent Storage Root](#register-a-persistent-storage-root)
3. [Dataset Workflows](#3-dataset-workflows)
   1. [Sync A Manifest Workbook](#sync-a-manifest-workbook)
   2. [Sync A Training Dataset](#sync-a-training-dataset)
   3. [Configure Caption Outputs](#configure-caption-outputs)
4. [LoRA Workflows](#4-lora-workflows)
   1. [Write SimpleTuner Artifacts](#write-simpletuner-artifacts)
   2. [Launch SimpleTuner Training](#launch-simpletuner-training)
   3. [Showcase Training Checkpoints](#showcase-training-checkpoints)
   4. [Promote A Training Checkpoint](#promote-a-training-checkpoint)
5. [Image Workflows](#5-image-workflows)
   1. [Generate Solo And Duo T2I Runs](#generate-solo-and-duo-t2i-runs)
   2. [Convert PNG Files To JPEG](#convert-png-files-to-jpeg)
   3. [Prepare Image Sets](#prepare-image-sets)
   4. [Tag And Caption Images](#tag-and-caption-images)
6. [Maintainer Checks](#6-maintainer-checks)
   1. [Sync Dependencies](#sync-dependencies)
   2. [Run Tests](#run-tests)
7. [Troubleshooting](#7-troubleshooting)
   1. [Environment Problems](#environment-problems)
   2. [Command Problems](#command-problems)
   3. [Manifest And Config Problems](#manifest-and-config-problems)

<br>

# 1. How-To User Guides

<!-- ======================================================== -->
## Recipe Map
<!-- ======================================================== -->

Use this file when you want commands in order. Use
[References](References.md) when you need exact names and
[Explanations](Explanations.md) when you need the system model.

> [!IMPORTANT]
> 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.

> [!NOTE]
> Related: use [docs standards](README.md#2-documentation-standards) when adding
> new recipes so headings, callouts, and links stay consistent.

<br>

# 2. First-Time Setup

<!-- ======================================================== -->
## Install The Package
<!-- ======================================================== -->

Use this recipe from the Kneiff repository root.

1. Create or activate a Python environment:

```bash
python -m venv .venv
source .venv/bin/activate
.venv/bin/python -m pip install --upgrade pip
```

2. Install the package for runtime use:

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

3. Install the maintainer tools when you plan to edit the project:

```bash
.venv/bin/python -m pip install -e "." --group dev
```

4. If you use `uv`, sync the locked environment:

```bash
uv sync --locked --all-extras
```

> [!NOTE]
> Related: use [dependency surfaces](References.md#dependency-surfaces) for the
> difference between runtime dependencies and dependency groups.

<br>

<!-- ======================================================== -->
## Run The First Command
<!-- ======================================================== -->

Run the CLI after installation:

```bash
knf --help
```

Check the top-level command groups:

```bash
knf dataset --help
knf train --help
knf img --help
knf comfy --help
```

> [!NOTE]
> Related: use [public interfaces](References.md#public-interfaces) for the
> commands and import paths users can rely on.

<br>

<!-- ======================================================== -->
## 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:

```bash
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`:

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

> [!CAUTION]
> Keep secrets and machine-local project roots out of committed files.

<br>

## 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:

```text
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/
```

```bash
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.

```yaml
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:

```bash
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:

```bash
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:

```bash
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:

```bash
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:

```bash
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.

<br>

# 3. Dataset Workflows

<!-- ======================================================== -->
## Sync A Manifest Workbook
<!-- ======================================================== -->

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

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

With storage selected, use the config selector instead:

```bash
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:

```bash
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.

> [!NOTE]
> Related: use [manifest-to-export model](Explanations.md#manifest-to-export-model)
> for the ownership boundary between source images, workbook rows, and exports.

<br>

<!-- ======================================================== -->
## Sync A Training Dataset
<!-- ======================================================== -->

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

```yaml
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:

```bash
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:

```bash
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:

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

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

```bash
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`](https://github.com/bghira/SimpleTuner/blob/main/documentation/DATALOADER.md#minimum_image_size),
[`maximum_image_size` and `target_downsample_size`](https://github.com/bghira/SimpleTuner/blob/main/documentation/DATALOADER.md#maximum_image_size-and-target_downsample_size),
and
[option](https://github.com/bghira/SimpleTuner/blob/main/documentation/OPTIONS.md)
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:

```bash
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:

```bash
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:

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

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

<br>

<!-- ======================================================== -->
## Configure Caption Outputs
<!-- ======================================================== -->

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

```yaml
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.

> [!WARNING]
> 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.

> [!IMPORTANT]
> `caption_outputs` no longer accepts per-subset mappings. Put subset-specific
> changes under `caption_outputs_overrides`.

<br>

# 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:

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

Prepare the generated SimpleTuner JSON files without launching:

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

> [!IMPORTANT]
> 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:

```yaml
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`:

```bash
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.

```yaml
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.

```yaml
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.

> [!NOTE]
> Related: use [LoRA workflow model](Explanations.md#lora-workflow-model) for
> how Kneiff translates one dataset config into SimpleTuner artifacts.

<br>

<!-- ======================================================== -->
## Launch SimpleTuner Training
<!-- ======================================================== -->

Launch SimpleTuner from the generated artifacts:

```bash
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`:

```dotenv
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:

```bash
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:

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

Resume a prepared or incomplete run without regenerating artifacts:

```bash
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
```

> [!IMPORTANT]
> `--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:

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

<br>

<!-- ======================================================== -->
## Showcase Training Checkpoints
<!-- ======================================================== -->

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

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

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

```bash
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:

```bash
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.

> [!IMPORTANT]
> `-t` requires an interactive terminal and cannot be combined with `--lora`.
> `COMFY_MODELS_DIR` must describe the filesystem used by the running ComfyUI
> server.

<br>

<!-- ======================================================== -->
## Promote A Training Checkpoint
<!-- ======================================================== -->

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

```bash
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:

```text
<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.

<br>

# 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`:

```bash
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:

```yaml
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:

```bash
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`.

> [!IMPORTANT]
> 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`.

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

<br>

<!-- ======================================================== -->
## Convert PNG Files To JPEG
<!-- ======================================================== -->

Convert every PNG below a directory into an output subdirectory:

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

Preview without writing files:

```bash
knf img png2jpg ./images --dry-run
```

<br>

<!-- ======================================================== -->
## Prepare Image Sets
<!-- ======================================================== -->

Concatenate images horizontally:

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

Rename files with an enumerated random suffix:

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

Upscale one file or a directory:

```bash
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.

> [!WARNING]
> Upscaling may download model weights and can use significant GPU memory.

<br>

<!-- ======================================================== -->
## Tag And Caption Images
<!-- ======================================================== -->

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

> [!IMPORTANT]
> 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.

```bash
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:

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

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

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

> [!NOTE]
> `--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:

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

Caption a directory and write sidecars:

```bash
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:

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

Generate a two-pass image prompt through LM Studio:

```bash
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:

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

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

```bash
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:

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

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

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

<br>

# 6. Maintainer Checks

<!-- ======================================================== -->
## Sync Dependencies
<!-- ======================================================== -->

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

```bash
just sync
```

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

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

> [!NOTE]
> Related: use [configuration model](Explanations.md#configuration-model)
> for why runtime installs and maintainer installs are documented separately.

<br>

<!-- ======================================================== -->
## Run Tests
<!-- ======================================================== -->

Run the focused CLI smoke tests:

```bash
.venv/bin/pytest tests/test_cli_smoke.py
```

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

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

> [!NOTE]
> Related: use [Development: verification](Development.md#verification) for
> the maintainer checklist before a commit.

<br>

# 7. Troubleshooting

<!-- ======================================================== -->
## Environment Problems
<!-- ======================================================== -->

Check the active Python and import location first:

```bash
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:

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

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

> [!NOTE]
> Related: use [failure model](Explanations.md#failure-model) for the normal
> order of checks when a command behaves differently across machines.

<br>

<!-- ======================================================== -->
## 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`.

```bash
just --list
ls .venv/bin
```

> [!NOTE]
> Related: use [command reference](References.md#command-reference) for the
> expected commands and their owners.

<br>

<!-- ======================================================== -->
## 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.

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

> [!NOTE]
> Related: use [configuration files](References.md#configuration-files) for the
> exact file owners and [caption sidecar model](Explanations.md#caption-sidecar-model)
> for output behavior.