faces-cli 1.8.2 → 1.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -120,10 +120,23 @@
120
120
  "state.js"
121
121
  ]
122
122
  },
123
- "billing:balance": {
123
+ "auth:connect": {
124
124
  "aliases": [],
125
- "args": {},
126
- "description": "Show credit balance and payment method status",
125
+ "args": {
126
+ "provider": {
127
+ "description": "OAuth provider to connect",
128
+ "name": "provider",
129
+ "options": [
130
+ "openai"
131
+ ],
132
+ "required": true
133
+ }
134
+ },
135
+ "description": "Connect your ChatGPT account to Faces via device-code authorization (Subscription Connect plan)",
136
+ "examples": [
137
+ "<%= config.bin %> auth connect openai",
138
+ "<%= config.bin %> auth connect openai --json"
139
+ ],
127
140
  "flags": {
128
141
  "json": {
129
142
  "description": "Format output as json.",
@@ -159,7 +172,7 @@
159
172
  },
160
173
  "hasDynamicHelp": false,
161
174
  "hiddenAliases": [],
162
- "id": "billing:balance",
175
+ "id": "auth:connect",
163
176
  "pluginAlias": "faces-cli",
164
177
  "pluginName": "faces-cli",
165
178
  "pluginType": "core",
@@ -169,14 +182,18 @@
169
182
  "relativePath": [
170
183
  "dist",
171
184
  "commands",
172
- "billing",
173
- "balance.js"
185
+ "auth",
186
+ "connect.js"
174
187
  ]
175
188
  },
176
- "billing:card-setup": {
189
+ "auth:connections": {
177
190
  "aliases": [],
178
191
  "args": {},
179
- "description": "Get a Stripe card setup URL to save a payment method",
192
+ "description": "List connected OAuth provider accounts",
193
+ "examples": [
194
+ "<%= config.bin %> auth connections",
195
+ "<%= config.bin %> auth connections --json"
196
+ ],
180
197
  "flags": {
181
198
  "json": {
182
199
  "description": "Format output as json.",
@@ -212,7 +229,7 @@
212
229
  },
213
230
  "hasDynamicHelp": false,
214
231
  "hiddenAliases": [],
215
- "id": "billing:card-setup",
232
+ "id": "auth:connections",
216
233
  "pluginAlias": "faces-cli",
217
234
  "pluginName": "faces-cli",
218
235
  "pluginType": "core",
@@ -222,14 +239,26 @@
222
239
  "relativePath": [
223
240
  "dist",
224
241
  "commands",
225
- "billing",
226
- "card-setup.js"
242
+ "auth",
243
+ "connections.js"
227
244
  ]
228
245
  },
229
- "billing:llm-costs": {
246
+ "auth:disconnect": {
230
247
  "aliases": [],
231
- "args": {},
232
- "description": "List available LLMs and their per-token costs",
248
+ "args": {
249
+ "provider": {
250
+ "description": "OAuth provider to disconnect",
251
+ "name": "provider",
252
+ "options": [
253
+ "openai"
254
+ ],
255
+ "required": true
256
+ }
257
+ },
258
+ "description": "Disconnect a linked OAuth provider account",
259
+ "examples": [
260
+ "<%= config.bin %> auth disconnect openai"
261
+ ],
233
262
  "flags": {
234
263
  "json": {
235
264
  "description": "Format output as json.",
@@ -261,18 +290,11 @@
261
290
  "hasDynamicHelp": false,
262
291
  "multiple": false,
263
292
  "type": "option"
264
- },
265
- "provider": {
266
- "description": "Filter by provider (e.g. openai, anthropic)",
267
- "name": "provider",
268
- "hasDynamicHelp": false,
269
- "multiple": false,
270
- "type": "option"
271
293
  }
272
294
  },
273
295
  "hasDynamicHelp": false,
274
296
  "hiddenAliases": [],
275
- "id": "billing:llm-costs",
297
+ "id": "auth:disconnect",
276
298
  "pluginAlias": "faces-cli",
277
299
  "pluginName": "faces-cli",
278
300
  "pluginType": "core",
@@ -282,14 +304,14 @@
282
304
  "relativePath": [
283
305
  "dist",
284
306
  "commands",
285
- "billing",
286
- "llm-costs.js"
307
+ "auth",
308
+ "disconnect.js"
287
309
  ]
288
310
  },
289
- "billing:topup": {
311
+ "auth:login": {
290
312
  "aliases": [],
291
313
  "args": {},
292
- "description": "Top up credit balance using saved payment method",
314
+ "description": "Login and save JWT credentials",
293
315
  "flags": {
294
316
  "json": {
295
317
  "description": "Format output as json.",
@@ -322,17 +344,18 @@
322
344
  "multiple": false,
323
345
  "type": "option"
324
346
  },
325
- "amount": {
326
- "description": "Top-up amount in USD (min $1)",
327
- "name": "amount",
347
+ "email": {
348
+ "description": "Account email",
349
+ "name": "email",
328
350
  "required": true,
329
351
  "hasDynamicHelp": false,
330
352
  "multiple": false,
331
353
  "type": "option"
332
354
  },
333
- "payment-ref": {
334
- "description": "Payment reference (admin/test path)",
335
- "name": "payment-ref",
355
+ "password": {
356
+ "description": "Account password",
357
+ "name": "password",
358
+ "required": true,
336
359
  "hasDynamicHelp": false,
337
360
  "multiple": false,
338
361
  "type": "option"
@@ -340,7 +363,7 @@
340
363
  },
341
364
  "hasDynamicHelp": false,
342
365
  "hiddenAliases": [],
343
- "id": "billing:topup",
366
+ "id": "auth:login",
344
367
  "pluginAlias": "faces-cli",
345
368
  "pluginName": "faces-cli",
346
369
  "pluginType": "core",
@@ -350,14 +373,14 @@
350
373
  "relativePath": [
351
374
  "dist",
352
375
  "commands",
353
- "billing",
354
- "topup.js"
376
+ "auth",
377
+ "login.js"
355
378
  ]
356
379
  },
357
- "billing:usage": {
380
+ "auth:logout": {
358
381
  "aliases": [],
359
382
  "args": {},
360
- "description": "Aggregated usage analytics",
383
+ "description": "Clear saved credentials",
361
384
  "flags": {
362
385
  "json": {
363
386
  "description": "Format output as json.",
@@ -389,38 +412,11 @@
389
412
  "hasDynamicHelp": false,
390
413
  "multiple": false,
391
414
  "type": "option"
392
- },
393
- "group-by": {
394
- "description": "Group results",
395
- "name": "group-by",
396
- "hasDynamicHelp": false,
397
- "multiple": false,
398
- "options": [
399
- "api_key",
400
- "model",
401
- "llm",
402
- "date"
403
- ],
404
- "type": "option"
405
- },
406
- "from": {
407
- "description": "Start date (YYYY-MM-DD)",
408
- "name": "from",
409
- "hasDynamicHelp": false,
410
- "multiple": false,
411
- "type": "option"
412
- },
413
- "to": {
414
- "description": "End date (YYYY-MM-DD)",
415
- "name": "to",
416
- "hasDynamicHelp": false,
417
- "multiple": false,
418
- "type": "option"
419
415
  }
420
416
  },
421
417
  "hasDynamicHelp": false,
422
418
  "hiddenAliases": [],
423
- "id": "billing:usage",
419
+ "id": "auth:logout",
424
420
  "pluginAlias": "faces-cli",
425
421
  "pluginName": "faces-cli",
426
422
  "pluginType": "core",
@@ -430,27 +426,14 @@
430
426
  "relativePath": [
431
427
  "dist",
432
428
  "commands",
433
- "billing",
434
- "usage.js"
429
+ "auth",
430
+ "logout.js"
435
431
  ]
436
432
  },
437
- "auth:connect": {
433
+ "auth:refresh": {
438
434
  "aliases": [],
439
- "args": {
440
- "provider": {
441
- "description": "OAuth provider to connect",
442
- "name": "provider",
443
- "options": [
444
- "openai"
445
- ],
446
- "required": true
447
- }
448
- },
449
- "description": "Connect your ChatGPT account to Faces via device-code authorization (Subscription Connect plan)",
450
- "examples": [
451
- "<%= config.bin %> auth connect openai",
452
- "<%= config.bin %> auth connect openai --json"
453
- ],
435
+ "args": {},
436
+ "description": "Exchange current JWT for a fresh one",
454
437
  "flags": {
455
438
  "json": {
456
439
  "description": "Format output as json.",
@@ -486,7 +469,7 @@
486
469
  },
487
470
  "hasDynamicHelp": false,
488
471
  "hiddenAliases": [],
489
- "id": "auth:connect",
472
+ "id": "auth:refresh",
490
473
  "pluginAlias": "faces-cli",
491
474
  "pluginName": "faces-cli",
492
475
  "pluginType": "core",
@@ -497,17 +480,13 @@
497
480
  "dist",
498
481
  "commands",
499
482
  "auth",
500
- "connect.js"
483
+ "refresh.js"
501
484
  ]
502
485
  },
503
- "auth:connections": {
486
+ "auth:register": {
504
487
  "aliases": [],
505
488
  "args": {},
506
- "description": "List connected OAuth provider accounts",
507
- "examples": [
508
- "<%= config.bin %> auth connections",
509
- "<%= config.bin %> auth connections --json"
510
- ],
489
+ "description": "Create a new Faces account",
511
490
  "flags": {
512
491
  "json": {
513
492
  "description": "Format output as json.",
@@ -539,11 +518,54 @@
539
518
  "hasDynamicHelp": false,
540
519
  "multiple": false,
541
520
  "type": "option"
521
+ },
522
+ "email": {
523
+ "description": "Email address",
524
+ "name": "email",
525
+ "required": true,
526
+ "hasDynamicHelp": false,
527
+ "multiple": false,
528
+ "type": "option"
529
+ },
530
+ "password": {
531
+ "description": "Password",
532
+ "name": "password",
533
+ "required": true,
534
+ "hasDynamicHelp": false,
535
+ "multiple": false,
536
+ "type": "option"
537
+ },
538
+ "username": {
539
+ "description": "Username (lowercase, dashes, numbers)",
540
+ "name": "username",
541
+ "required": true,
542
+ "hasDynamicHelp": false,
543
+ "multiple": false,
544
+ "type": "option"
545
+ },
546
+ "invite-key": {
547
+ "description": "Invite key (if required)",
548
+ "name": "invite-key",
549
+ "hasDynamicHelp": false,
550
+ "multiple": false,
551
+ "type": "option"
552
+ },
553
+ "plan": {
554
+ "description": "Plan to subscribe to: \"free\" ($5 activation) or \"connect\" ($17/mo, no activation fee)",
555
+ "name": "plan",
556
+ "default": "free",
557
+ "hasDynamicHelp": false,
558
+ "multiple": false,
559
+ "options": [
560
+ "free",
561
+ "connect"
562
+ ],
563
+ "type": "option"
542
564
  }
543
565
  },
544
566
  "hasDynamicHelp": false,
545
567
  "hiddenAliases": [],
546
- "id": "auth:connections",
568
+ "id": "auth:register",
547
569
  "pluginAlias": "faces-cli",
548
570
  "pluginName": "faces-cli",
549
571
  "pluginType": "core",
@@ -554,25 +576,13 @@
554
576
  "dist",
555
577
  "commands",
556
578
  "auth",
557
- "connections.js"
579
+ "register.js"
558
580
  ]
559
581
  },
560
- "auth:disconnect": {
582
+ "auth:whoami": {
561
583
  "aliases": [],
562
- "args": {
563
- "provider": {
564
- "description": "OAuth provider to disconnect",
565
- "name": "provider",
566
- "options": [
567
- "openai"
568
- ],
569
- "required": true
570
- }
571
- },
572
- "description": "Disconnect a linked OAuth provider account",
573
- "examples": [
574
- "<%= config.bin %> auth disconnect openai"
575
- ],
584
+ "args": {},
585
+ "description": "Print current user profile and auth diagnostic",
576
586
  "flags": {
577
587
  "json": {
578
588
  "description": "Format output as json.",
@@ -608,7 +618,7 @@
608
618
  },
609
619
  "hasDynamicHelp": false,
610
620
  "hiddenAliases": [],
611
- "id": "auth:disconnect",
621
+ "id": "auth:whoami",
612
622
  "pluginAlias": "faces-cli",
613
623
  "pluginName": "faces-cli",
614
624
  "pluginType": "core",
@@ -619,13 +629,13 @@
619
629
  "dist",
620
630
  "commands",
621
631
  "auth",
622
- "disconnect.js"
632
+ "whoami.js"
623
633
  ]
624
634
  },
625
- "auth:login": {
635
+ "billing:balance": {
626
636
  "aliases": [],
627
637
  "args": {},
628
- "description": "Login and save JWT credentials",
638
+ "description": "Show credit balance and payment method status",
629
639
  "flags": {
630
640
  "json": {
631
641
  "description": "Format output as json.",
@@ -657,27 +667,11 @@
657
667
  "hasDynamicHelp": false,
658
668
  "multiple": false,
659
669
  "type": "option"
660
- },
661
- "email": {
662
- "description": "Account email",
663
- "name": "email",
664
- "required": true,
665
- "hasDynamicHelp": false,
666
- "multiple": false,
667
- "type": "option"
668
- },
669
- "password": {
670
- "description": "Account password",
671
- "name": "password",
672
- "required": true,
673
- "hasDynamicHelp": false,
674
- "multiple": false,
675
- "type": "option"
676
670
  }
677
671
  },
678
672
  "hasDynamicHelp": false,
679
673
  "hiddenAliases": [],
680
- "id": "auth:login",
674
+ "id": "billing:balance",
681
675
  "pluginAlias": "faces-cli",
682
676
  "pluginName": "faces-cli",
683
677
  "pluginType": "core",
@@ -687,14 +681,14 @@
687
681
  "relativePath": [
688
682
  "dist",
689
683
  "commands",
690
- "auth",
691
- "login.js"
684
+ "billing",
685
+ "balance.js"
692
686
  ]
693
687
  },
694
- "auth:logout": {
688
+ "billing:card-setup": {
695
689
  "aliases": [],
696
690
  "args": {},
697
- "description": "Clear saved credentials",
691
+ "description": "Get a Stripe card setup URL to save a payment method",
698
692
  "flags": {
699
693
  "json": {
700
694
  "description": "Format output as json.",
@@ -730,7 +724,7 @@
730
724
  },
731
725
  "hasDynamicHelp": false,
732
726
  "hiddenAliases": [],
733
- "id": "auth:logout",
727
+ "id": "billing:card-setup",
734
728
  "pluginAlias": "faces-cli",
735
729
  "pluginName": "faces-cli",
736
730
  "pluginType": "core",
@@ -740,14 +734,14 @@
740
734
  "relativePath": [
741
735
  "dist",
742
736
  "commands",
743
- "auth",
744
- "logout.js"
737
+ "billing",
738
+ "card-setup.js"
745
739
  ]
746
740
  },
747
- "auth:refresh": {
741
+ "billing:llm-costs": {
748
742
  "aliases": [],
749
743
  "args": {},
750
- "description": "Exchange current JWT for a fresh one",
744
+ "description": "List available LLMs and their per-token costs",
751
745
  "flags": {
752
746
  "json": {
753
747
  "description": "Format output as json.",
@@ -779,11 +773,18 @@
779
773
  "hasDynamicHelp": false,
780
774
  "multiple": false,
781
775
  "type": "option"
776
+ },
777
+ "provider": {
778
+ "description": "Filter by provider (e.g. openai, anthropic)",
779
+ "name": "provider",
780
+ "hasDynamicHelp": false,
781
+ "multiple": false,
782
+ "type": "option"
782
783
  }
783
784
  },
784
785
  "hasDynamicHelp": false,
785
786
  "hiddenAliases": [],
786
- "id": "auth:refresh",
787
+ "id": "billing:llm-costs",
787
788
  "pluginAlias": "faces-cli",
788
789
  "pluginName": "faces-cli",
789
790
  "pluginType": "core",
@@ -793,14 +794,14 @@
793
794
  "relativePath": [
794
795
  "dist",
795
796
  "commands",
796
- "auth",
797
- "refresh.js"
797
+ "billing",
798
+ "llm-costs.js"
798
799
  ]
799
800
  },
800
- "auth:register": {
801
+ "billing:topup": {
801
802
  "aliases": [],
802
803
  "args": {},
803
- "description": "Create a new Faces account",
804
+ "description": "Top up credit balance using saved payment method",
804
805
  "flags": {
805
806
  "json": {
806
807
  "description": "Format output as json.",
@@ -833,53 +834,25 @@
833
834
  "multiple": false,
834
835
  "type": "option"
835
836
  },
836
- "email": {
837
- "description": "Email address",
838
- "name": "email",
839
- "required": true,
840
- "hasDynamicHelp": false,
841
- "multiple": false,
842
- "type": "option"
843
- },
844
- "password": {
845
- "description": "Password",
846
- "name": "password",
847
- "required": true,
848
- "hasDynamicHelp": false,
849
- "multiple": false,
850
- "type": "option"
851
- },
852
- "username": {
853
- "description": "Username (lowercase, dashes, numbers)",
854
- "name": "username",
837
+ "amount": {
838
+ "description": "Top-up amount in USD (min $1)",
839
+ "name": "amount",
855
840
  "required": true,
856
841
  "hasDynamicHelp": false,
857
842
  "multiple": false,
858
843
  "type": "option"
859
844
  },
860
- "invite-key": {
861
- "description": "Invite key (if required)",
862
- "name": "invite-key",
863
- "hasDynamicHelp": false,
864
- "multiple": false,
865
- "type": "option"
866
- },
867
- "plan": {
868
- "description": "Plan to subscribe to: \"free\" ($5 activation) or \"connect\" ($17/mo, no activation fee)",
869
- "name": "plan",
870
- "default": "free",
845
+ "payment-ref": {
846
+ "description": "Payment reference (admin/test path)",
847
+ "name": "payment-ref",
871
848
  "hasDynamicHelp": false,
872
849
  "multiple": false,
873
- "options": [
874
- "free",
875
- "connect"
876
- ],
877
850
  "type": "option"
878
851
  }
879
852
  },
880
853
  "hasDynamicHelp": false,
881
854
  "hiddenAliases": [],
882
- "id": "auth:register",
855
+ "id": "billing:topup",
883
856
  "pluginAlias": "faces-cli",
884
857
  "pluginName": "faces-cli",
885
858
  "pluginType": "core",
@@ -889,14 +862,14 @@
889
862
  "relativePath": [
890
863
  "dist",
891
864
  "commands",
892
- "auth",
893
- "register.js"
865
+ "billing",
866
+ "topup.js"
894
867
  ]
895
868
  },
896
- "auth:whoami": {
869
+ "billing:usage": {
897
870
  "aliases": [],
898
871
  "args": {},
899
- "description": "Print current user profile and auth diagnostic",
872
+ "description": "Aggregated usage analytics",
900
873
  "flags": {
901
874
  "json": {
902
875
  "description": "Format output as json.",
@@ -928,11 +901,38 @@
928
901
  "hasDynamicHelp": false,
929
902
  "multiple": false,
930
903
  "type": "option"
904
+ },
905
+ "group-by": {
906
+ "description": "Group results",
907
+ "name": "group-by",
908
+ "hasDynamicHelp": false,
909
+ "multiple": false,
910
+ "options": [
911
+ "api_key",
912
+ "model",
913
+ "llm",
914
+ "date"
915
+ ],
916
+ "type": "option"
917
+ },
918
+ "from": {
919
+ "description": "Start date (YYYY-MM-DD)",
920
+ "name": "from",
921
+ "hasDynamicHelp": false,
922
+ "multiple": false,
923
+ "type": "option"
924
+ },
925
+ "to": {
926
+ "description": "End date (YYYY-MM-DD)",
927
+ "name": "to",
928
+ "hasDynamicHelp": false,
929
+ "multiple": false,
930
+ "type": "option"
931
931
  }
932
932
  },
933
933
  "hasDynamicHelp": false,
934
934
  "hiddenAliases": [],
935
- "id": "auth:whoami",
935
+ "id": "billing:usage",
936
936
  "pluginAlias": "faces-cli",
937
937
  "pluginName": "faces-cli",
938
938
  "pluginType": "core",
@@ -942,8 +942,8 @@
942
942
  "relativePath": [
943
943
  "dist",
944
944
  "commands",
945
- "auth",
946
- "whoami.js"
945
+ "billing",
946
+ "usage.js"
947
947
  ]
948
948
  },
949
949
  "catalog:backup": {
@@ -1261,21 +1261,10 @@
1261
1261
  "restore.js"
1262
1262
  ]
1263
1263
  },
1264
- "chat:chat": {
1264
+ "compile:all": {
1265
1265
  "aliases": [],
1266
- "args": {
1267
- "face_username": {
1268
- "description": "Face alias (alias@model, owner:alias@model for a published face, or a composite formula like \"(a | b)@model\"). Omit when using --formula.",
1269
- "name": "face_username",
1270
- "required": false
1271
- }
1272
- },
1273
- "description": "Chat via a face. Auto-routes to the correct API endpoint based on the model catalog.",
1274
- "examples": [
1275
- "<%= config.bin %> <%= command.id %> socrates -m \"What is virtue?\"",
1276
- "<%= config.bin %> <%= command.id %> \"(socrates | nietzsche)@claude-sonnet-4-6\" -m \"What is virtue?\"",
1277
- "<%= config.bin %> <%= command.id %> --formula \"socrates | nietzsche\" --llm claude-sonnet-4-6 -m \"What is virtue?\""
1278
- ],
1266
+ "args": {},
1267
+ "description": "Compile all uncompiled documents and threads across all faces",
1279
1268
  "flags": {
1280
1269
  "json": {
1281
1270
  "description": "Format output as json.",
@@ -1308,86 +1297,18 @@
1308
1297
  "multiple": false,
1309
1298
  "type": "option"
1310
1299
  },
1311
- "message": {
1312
- "char": "m",
1313
- "description": "User message (repeatable)",
1314
- "name": "message",
1315
- "required": false,
1316
- "hasDynamicHelp": false,
1317
- "multiple": true,
1318
- "type": "option"
1319
- },
1320
- "llm": {
1321
- "description": "LLM override (e.g. gpt-4o-mini, claude-sonnet-4-6)",
1322
- "name": "llm",
1323
- "hasDynamicHelp": false,
1324
- "multiple": false,
1325
- "type": "option"
1326
- },
1327
- "formula": {
1328
- "description": "Compose a run-time composite from your own faces, e.g. \"socrates | nietzsche\" (operators: | & ^ -). Requires --llm. The composite takes the name of its first operand; use face:create --formula for a named, persisted composite.",
1329
- "name": "formula",
1330
- "hasDynamicHelp": false,
1331
- "multiple": false,
1332
- "type": "option"
1333
- },
1334
- "system": {
1335
- "description": "System prompt / instructions",
1336
- "name": "system",
1337
- "hasDynamicHelp": false,
1338
- "multiple": false,
1339
- "type": "option"
1340
- },
1341
- "stream": {
1342
- "description": "Stream the response",
1343
- "name": "stream",
1344
- "allowNo": false,
1345
- "type": "boolean"
1346
- },
1347
- "max-tokens": {
1348
- "description": "Max tokens",
1349
- "name": "max-tokens",
1350
- "hasDynamicHelp": false,
1351
- "multiple": false,
1352
- "type": "option"
1353
- },
1354
- "temperature": {
1355
- "description": "Temperature (0.0-2.0)",
1356
- "name": "temperature",
1357
- "hasDynamicHelp": false,
1358
- "multiple": false,
1359
- "type": "option"
1360
- },
1361
- "file": {
1362
- "description": "Read message from file",
1363
- "name": "file",
1364
- "hasDynamicHelp": false,
1365
- "multiple": false,
1366
- "type": "option"
1367
- },
1368
- "responses": {
1369
- "description": "Force the OpenAI Responses API endpoint (escape hatch; routing is automatic otherwise)",
1370
- "name": "responses",
1371
- "allowNo": false,
1372
- "type": "boolean"
1373
- },
1374
- "medium": {
1375
- "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
1376
- "name": "medium",
1300
+ "timeout": {
1301
+ "description": "Per-item compile timeout in seconds (default: 600)",
1302
+ "name": "timeout",
1303
+ "default": 600,
1377
1304
  "hasDynamicHelp": false,
1378
1305
  "multiple": false,
1379
1306
  "type": "option"
1380
- },
1381
- "oauth-only": {
1382
- "description": "Prevent fallback to paid system key (use OAuth only)",
1383
- "name": "oauth-only",
1384
- "allowNo": false,
1385
- "type": "boolean"
1386
1307
  }
1387
1308
  },
1388
1309
  "hasDynamicHelp": false,
1389
1310
  "hiddenAliases": [],
1390
- "id": "chat:chat",
1311
+ "id": "compile:all",
1391
1312
  "pluginAlias": "faces-cli",
1392
1313
  "pluginName": "faces-cli",
1393
1314
  "pluginType": "core",
@@ -1397,20 +1318,20 @@
1397
1318
  "relativePath": [
1398
1319
  "dist",
1399
1320
  "commands",
1400
- "chat",
1401
- "chat.js"
1321
+ "compile",
1322
+ "all.js"
1402
1323
  ]
1403
1324
  },
1404
- "chat:messages": {
1325
+ "compile:import": {
1405
1326
  "aliases": [],
1406
1327
  "args": {
1407
- "face_model": {
1408
- "description": "Face model (e.g. myface, myface@claude-sonnet-4-6, or head:socrates@claude-sonnet-4-6)",
1409
- "name": "face_model",
1328
+ "face_id": {
1329
+ "description": "Face alias",
1330
+ "name": "face_id",
1410
1331
  "required": true
1411
1332
  }
1412
1333
  },
1413
- "description": "Anthropic Messages API proxy via a face (alias: chat:chat auto-routes Anthropic models here)",
1334
+ "description": "Import a YouTube video into a face via server-side download and transcription",
1414
1335
  "flags": {
1415
1336
  "json": {
1416
1337
  "description": "Format output as json.",
@@ -1443,53 +1364,55 @@
1443
1364
  "multiple": false,
1444
1365
  "type": "option"
1445
1366
  },
1446
- "message": {
1447
- "char": "m",
1448
- "description": "User message (repeatable)",
1449
- "name": "message",
1367
+ "url": {
1368
+ "description": "YouTube URL (youtube.com/watch?v=... or youtu.be/...)",
1369
+ "name": "url",
1450
1370
  "required": true,
1451
1371
  "hasDynamicHelp": false,
1452
- "multiple": true,
1453
- "type": "option"
1454
- },
1455
- "system": {
1456
- "description": "System prompt",
1457
- "name": "system",
1458
- "hasDynamicHelp": false,
1459
1372
  "multiple": false,
1460
1373
  "type": "option"
1461
1374
  },
1462
- "stream": {
1463
- "description": "Stream the response",
1464
- "name": "stream",
1465
- "allowNo": false,
1466
- "type": "boolean"
1467
- },
1468
- "max-tokens": {
1469
- "description": "Max tokens",
1470
- "name": "max-tokens",
1471
- "default": 1024,
1375
+ "type": {
1376
+ "description": "\"document\" for solo talks, lectures, monologues; \"thread\" for interviews or multi-speaker conversations",
1377
+ "name": "type",
1378
+ "default": "document",
1472
1379
  "hasDynamicHelp": false,
1473
1380
  "multiple": false,
1381
+ "options": [
1382
+ "document",
1383
+ "thread"
1384
+ ],
1474
1385
  "type": "option"
1475
1386
  },
1476
- "medium": {
1477
- "description": "What sort of writing this is e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
1478
- "name": "medium",
1387
+ "perspective": {
1388
+ "description": "\"first-person\" if the face is the speaker; \"third-person\" if the video is about the face",
1389
+ "name": "perspective",
1390
+ "default": "third-person",
1479
1391
  "hasDynamicHelp": false,
1480
1392
  "multiple": false,
1393
+ "options": [
1394
+ "first-person",
1395
+ "third-person"
1396
+ ],
1481
1397
  "type": "option"
1482
1398
  },
1483
- "oauth-only": {
1484
- "description": "Prevent fallback to paid system key (use OAuth only)",
1485
- "name": "oauth-only",
1399
+ "face-speaker": {
1400
+ "description": "For --type thread: AssemblyAI speaker label (e.g. \"A\") that corresponds to the face. Defaults to first detected speaker.",
1401
+ "name": "face-speaker",
1402
+ "hasDynamicHelp": false,
1403
+ "multiple": false,
1404
+ "type": "option"
1405
+ },
1406
+ "no-wait": {
1407
+ "description": "Return immediately after import starts (do not poll for transcription). Prints the ID for manual polling.",
1408
+ "name": "no-wait",
1486
1409
  "allowNo": false,
1487
1410
  "type": "boolean"
1488
1411
  }
1489
1412
  },
1490
1413
  "hasDynamicHelp": false,
1491
1414
  "hiddenAliases": [],
1492
- "id": "chat:messages",
1415
+ "id": "compile:import",
1493
1416
  "pluginAlias": "faces-cli",
1494
1417
  "pluginName": "faces-cli",
1495
1418
  "pluginType": "core",
@@ -1499,20 +1422,14 @@
1499
1422
  "relativePath": [
1500
1423
  "dist",
1501
1424
  "commands",
1502
- "chat",
1503
- "messages.js"
1425
+ "compile",
1426
+ "import.js"
1504
1427
  ]
1505
1428
  },
1506
- "chat:responses": {
1429
+ "compile:stats": {
1507
1430
  "aliases": [],
1508
- "args": {
1509
- "face_model": {
1510
- "description": "Face model (e.g. myface, myface@gpt-4o, or head:socrates@gpt-5.4)",
1511
- "name": "face_model",
1512
- "required": true
1513
- }
1514
- },
1515
- "description": "OpenAI Responses API proxy via a face (alias: chat:chat --responses)",
1431
+ "args": {},
1432
+ "description": "Show compilation stats per face",
1516
1433
  "flags": {
1517
1434
  "json": {
1518
1435
  "description": "Format output as json.",
@@ -1544,46 +1461,11 @@
1544
1461
  "hasDynamicHelp": false,
1545
1462
  "multiple": false,
1546
1463
  "type": "option"
1547
- },
1548
- "message": {
1549
- "char": "m",
1550
- "description": "User input message",
1551
- "name": "message",
1552
- "required": true,
1553
- "hasDynamicHelp": false,
1554
- "multiple": false,
1555
- "type": "option"
1556
- },
1557
- "instructions": {
1558
- "description": "System instructions",
1559
- "name": "instructions",
1560
- "hasDynamicHelp": false,
1561
- "multiple": false,
1562
- "type": "option"
1563
- },
1564
- "stream": {
1565
- "description": "Stream the response",
1566
- "name": "stream",
1567
- "allowNo": false,
1568
- "type": "boolean"
1569
- },
1570
- "medium": {
1571
- "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
1572
- "name": "medium",
1573
- "hasDynamicHelp": false,
1574
- "multiple": false,
1575
- "type": "option"
1576
- },
1577
- "oauth-only": {
1578
- "description": "Prevent fallback to paid system key (use OAuth only)",
1579
- "name": "oauth-only",
1580
- "allowNo": false,
1581
- "type": "boolean"
1582
1464
  }
1583
1465
  },
1584
1466
  "hasDynamicHelp": false,
1585
1467
  "hiddenAliases": [],
1586
- "id": "chat:responses",
1468
+ "id": "compile:stats",
1587
1469
  "pluginAlias": "faces-cli",
1588
1470
  "pluginName": "faces-cli",
1589
1471
  "pluginType": "core",
@@ -1593,27 +1475,20 @@
1593
1475
  "relativePath": [
1594
1476
  "dist",
1595
1477
  "commands",
1596
- "chat",
1597
- "responses.js"
1478
+ "compile",
1479
+ "stats.js"
1598
1480
  ]
1599
1481
  },
1600
- "chat:thread": {
1482
+ "compile:upload": {
1601
1483
  "aliases": [],
1602
1484
  "args": {
1603
- "face_username": {
1604
- "description": "Face alias (alias@model, or owner:alias@model for a published face) — required when starting a new thread",
1605
- "name": "face_username",
1606
- "required": false
1485
+ "alias": {
1486
+ "description": "Face alias",
1487
+ "name": "alias",
1488
+ "required": true
1607
1489
  }
1608
1490
  },
1609
- "description": "Multi-turn chat thread. Conversation history is stored under ~/.faces/threads/<id>.json resume any thread later with --id.",
1610
- "examples": [
1611
- "<%= config.bin %> <%= command.id %> socrates -m \"What is justice?\"",
1612
- "<%= config.bin %> <%= command.id %> --id t_abc123 -m \"Say more about that\"",
1613
- "<%= config.bin %> <%= command.id %> --list",
1614
- "<%= config.bin %> <%= command.id %> --id t_abc123 --show",
1615
- "<%= config.bin %> <%= command.id %> --id t_abc123 --delete"
1616
- ],
1491
+ "description": "Upload a file (text/PDF/Word .docx/audio/video) to compile into a face",
1617
1492
  "flags": {
1618
1493
  "json": {
1619
1494
  "description": "Format output as json.",
@@ -1646,97 +1521,62 @@
1646
1521
  "multiple": false,
1647
1522
  "type": "option"
1648
1523
  },
1649
- "id": {
1650
- "description": "Resume an existing thread by id",
1651
- "name": "id",
1652
- "hasDynamicHelp": false,
1653
- "multiple": false,
1654
- "type": "option"
1655
- },
1656
- "message": {
1657
- "char": "m",
1658
- "description": "User message",
1659
- "name": "message",
1660
- "hasDynamicHelp": false,
1661
- "multiple": false,
1662
- "type": "option"
1663
- },
1664
1524
  "file": {
1665
- "description": "Read message from file",
1525
+ "description": "File to upload",
1666
1526
  "name": "file",
1527
+ "required": true,
1667
1528
  "hasDynamicHelp": false,
1668
1529
  "multiple": false,
1669
1530
  "type": "option"
1670
1531
  },
1671
- "llm": {
1672
- "description": "LLM override (only honored when starting a new thread)",
1673
- "name": "llm",
1674
- "hasDynamicHelp": false,
1675
- "multiple": false,
1676
- "type": "option"
1677
- },
1678
- "system": {
1679
- "description": "System prompt (only honored when starting a new thread)",
1680
- "name": "system",
1532
+ "kind": {
1533
+ "description": "Upload kind: document or thread",
1534
+ "name": "kind",
1535
+ "default": "document",
1681
1536
  "hasDynamicHelp": false,
1682
1537
  "multiple": false,
1538
+ "options": [
1539
+ "document",
1540
+ "thread"
1541
+ ],
1683
1542
  "type": "option"
1684
1543
  },
1685
- "max-tokens": {
1686
- "description": "Max tokens",
1687
- "name": "max-tokens",
1544
+ "perspective": {
1545
+ "description": "Perspective (document only)",
1546
+ "name": "perspective",
1547
+ "default": "third-person",
1688
1548
  "hasDynamicHelp": false,
1689
1549
  "multiple": false,
1550
+ "options": [
1551
+ "first-person",
1552
+ "third-person"
1553
+ ],
1690
1554
  "type": "option"
1691
1555
  },
1692
- "temperature": {
1693
- "description": "Temperature (0.0-2.0, OpenAI/Chat Completions only)",
1694
- "name": "temperature",
1556
+ "medium": {
1557
+ "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not. Only valid with --kind document.",
1558
+ "name": "medium",
1695
1559
  "hasDynamicHelp": false,
1696
1560
  "multiple": false,
1697
1561
  "type": "option"
1698
1562
  },
1699
- "stream": {
1700
- "description": "Stream the response",
1701
- "name": "stream",
1702
- "allowNo": false,
1703
- "type": "boolean"
1704
- },
1705
- "medium": {
1706
- "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
1707
- "name": "medium",
1563
+ "face-speaker": {
1564
+ "description": "Speaker name to map to the face (thread only). If omitted, auto-detected from face name.",
1565
+ "name": "face-speaker",
1708
1566
  "hasDynamicHelp": false,
1709
1567
  "multiple": false,
1710
1568
  "type": "option"
1711
1569
  },
1712
- "oauth-only": {
1713
- "description": "Prevent fallback to paid system key",
1714
- "name": "oauth-only",
1715
- "allowNo": false,
1716
- "type": "boolean"
1717
- },
1718
- "list": {
1719
- "description": "List saved threads",
1720
- "name": "list",
1721
- "allowNo": false,
1722
- "type": "boolean"
1723
- },
1724
- "show": {
1725
- "description": "Show the thread transcript (requires --id)",
1726
- "name": "show",
1727
- "allowNo": false,
1728
- "type": "boolean"
1729
- },
1730
- "delete": {
1731
- "description": "Delete the thread (requires --id)",
1732
- "name": "delete",
1570
+ "no-wait": {
1571
+ "description": "Return immediately after upload (do not poll for transcription). Prints the ID for manual polling.",
1572
+ "name": "no-wait",
1733
1573
  "allowNo": false,
1734
1574
  "type": "boolean"
1735
1575
  }
1736
1576
  },
1737
1577
  "hasDynamicHelp": false,
1738
1578
  "hiddenAliases": [],
1739
- "id": "chat:thread",
1579
+ "id": "compile:upload",
1740
1580
  "pluginAlias": "faces-cli",
1741
1581
  "pluginName": "faces-cli",
1742
1582
  "pluginType": "core",
@@ -1746,14 +1586,14 @@
1746
1586
  "relativePath": [
1747
1587
  "dist",
1748
1588
  "commands",
1749
- "chat",
1750
- "thread.js"
1589
+ "compile",
1590
+ "upload.js"
1751
1591
  ]
1752
1592
  },
1753
- "compile:all": {
1593
+ "config:clear": {
1754
1594
  "aliases": [],
1755
1595
  "args": {},
1756
- "description": "Compile all uncompiled documents and threads across all faces",
1596
+ "description": "Delete all saved credentials and config",
1757
1597
  "flags": {
1758
1598
  "json": {
1759
1599
  "description": "Format output as json.",
@@ -1786,18 +1626,16 @@
1786
1626
  "multiple": false,
1787
1627
  "type": "option"
1788
1628
  },
1789
- "timeout": {
1790
- "description": "Per-item compile timeout in seconds (default: 600)",
1791
- "name": "timeout",
1792
- "default": 600,
1793
- "hasDynamicHelp": false,
1794
- "multiple": false,
1795
- "type": "option"
1629
+ "yes": {
1630
+ "description": "Skip confirmation",
1631
+ "name": "yes",
1632
+ "allowNo": false,
1633
+ "type": "boolean"
1796
1634
  }
1797
1635
  },
1798
1636
  "hasDynamicHelp": false,
1799
1637
  "hiddenAliases": [],
1800
- "id": "compile:all",
1638
+ "id": "config:clear",
1801
1639
  "pluginAlias": "faces-cli",
1802
1640
  "pluginName": "faces-cli",
1803
1641
  "pluginType": "core",
@@ -1807,20 +1645,25 @@
1807
1645
  "relativePath": [
1808
1646
  "dist",
1809
1647
  "commands",
1810
- "compile",
1811
- "all.js"
1648
+ "config",
1649
+ "clear.js"
1812
1650
  ]
1813
1651
  },
1814
- "compile:import": {
1652
+ "config:set": {
1815
1653
  "aliases": [],
1816
1654
  "args": {
1817
- "face_id": {
1818
- "description": "Face alias",
1819
- "name": "face_id",
1655
+ "key": {
1656
+ "description": "Config key",
1657
+ "name": "key",
1658
+ "required": true
1659
+ },
1660
+ "value": {
1661
+ "description": "Config value",
1662
+ "name": "value",
1820
1663
  "required": true
1821
1664
  }
1822
1665
  },
1823
- "description": "Import a YouTube video into a face via server-side download and transcription",
1666
+ "description": "Set a config value (e.g. base_url, api_key, token)",
1824
1667
  "flags": {
1825
1668
  "json": {
1826
1669
  "description": "Format output as json.",
@@ -1852,56 +1695,11 @@
1852
1695
  "hasDynamicHelp": false,
1853
1696
  "multiple": false,
1854
1697
  "type": "option"
1855
- },
1856
- "url": {
1857
- "description": "YouTube URL (youtube.com/watch?v=... or youtu.be/...)",
1858
- "name": "url",
1859
- "required": true,
1860
- "hasDynamicHelp": false,
1861
- "multiple": false,
1862
- "type": "option"
1863
- },
1864
- "type": {
1865
- "description": "\"document\" for solo talks, lectures, monologues; \"thread\" for interviews or multi-speaker conversations",
1866
- "name": "type",
1867
- "default": "document",
1868
- "hasDynamicHelp": false,
1869
- "multiple": false,
1870
- "options": [
1871
- "document",
1872
- "thread"
1873
- ],
1874
- "type": "option"
1875
- },
1876
- "perspective": {
1877
- "description": "\"first-person\" if the face is the speaker; \"third-person\" if the video is about the face",
1878
- "name": "perspective",
1879
- "default": "third-person",
1880
- "hasDynamicHelp": false,
1881
- "multiple": false,
1882
- "options": [
1883
- "first-person",
1884
- "third-person"
1885
- ],
1886
- "type": "option"
1887
- },
1888
- "face-speaker": {
1889
- "description": "For --type thread: AssemblyAI speaker label (e.g. \"A\") that corresponds to the face. Defaults to first detected speaker.",
1890
- "name": "face-speaker",
1891
- "hasDynamicHelp": false,
1892
- "multiple": false,
1893
- "type": "option"
1894
- },
1895
- "no-wait": {
1896
- "description": "Return immediately after import starts (do not poll for transcription). Prints the ID for manual polling.",
1897
- "name": "no-wait",
1898
- "allowNo": false,
1899
- "type": "boolean"
1900
1698
  }
1901
1699
  },
1902
1700
  "hasDynamicHelp": false,
1903
1701
  "hiddenAliases": [],
1904
- "id": "compile:import",
1702
+ "id": "config:set",
1905
1703
  "pluginAlias": "faces-cli",
1906
1704
  "pluginName": "faces-cli",
1907
1705
  "pluginType": "core",
@@ -1911,14 +1709,14 @@
1911
1709
  "relativePath": [
1912
1710
  "dist",
1913
1711
  "commands",
1914
- "compile",
1915
- "import.js"
1712
+ "config",
1713
+ "set.js"
1916
1714
  ]
1917
1715
  },
1918
- "compile:stats": {
1716
+ "config:show": {
1919
1717
  "aliases": [],
1920
1718
  "args": {},
1921
- "description": "Show compilation stats per face",
1719
+ "description": "Print current config (credentials are masked)",
1922
1720
  "flags": {
1923
1721
  "json": {
1924
1722
  "description": "Format output as json.",
@@ -1954,7 +1752,7 @@
1954
1752
  },
1955
1753
  "hasDynamicHelp": false,
1956
1754
  "hiddenAliases": [],
1957
- "id": "compile:stats",
1755
+ "id": "config:show",
1958
1756
  "pluginAlias": "faces-cli",
1959
1757
  "pluginName": "faces-cli",
1960
1758
  "pluginType": "core",
@@ -1964,20 +1762,25 @@
1964
1762
  "relativePath": [
1965
1763
  "dist",
1966
1764
  "commands",
1967
- "compile",
1968
- "stats.js"
1765
+ "config",
1766
+ "show.js"
1969
1767
  ]
1970
1768
  },
1971
- "compile:upload": {
1769
+ "chat:chat": {
1972
1770
  "aliases": [],
1973
1771
  "args": {
1974
- "alias": {
1975
- "description": "Face alias",
1976
- "name": "alias",
1977
- "required": true
1772
+ "face_username": {
1773
+ "description": "Face alias (alias@model, owner:alias@model for a published face, or a composite formula like \"(a | b)@model\"). Omit when using --formula.",
1774
+ "name": "face_username",
1775
+ "required": false
1978
1776
  }
1979
1777
  },
1980
- "description": "Upload a file (text/PDF/Word .docx/audio/video) to compile into a face",
1778
+ "description": "Chat via a face. Auto-routes to the correct API endpoint based on the model catalog.",
1779
+ "examples": [
1780
+ "<%= config.bin %> <%= command.id %> socrates -m \"What is virtue?\"",
1781
+ "<%= config.bin %> <%= command.id %> \"(socrates | nietzsche)@claude-sonnet-4-6\" -m \"What is virtue?\"",
1782
+ "<%= config.bin %> <%= command.id %> --formula \"socrates | nietzsche\" --llm claude-sonnet-4-6 -m \"What is virtue?\""
1783
+ ],
1981
1784
  "flags": {
1982
1785
  "json": {
1983
1786
  "description": "Format output as json.",
@@ -2010,62 +1813,86 @@
2010
1813
  "multiple": false,
2011
1814
  "type": "option"
2012
1815
  },
2013
- "file": {
2014
- "description": "File to upload",
2015
- "name": "file",
2016
- "required": true,
1816
+ "message": {
1817
+ "char": "m",
1818
+ "description": "User message (repeatable)",
1819
+ "name": "message",
1820
+ "required": false,
1821
+ "hasDynamicHelp": false,
1822
+ "multiple": true,
1823
+ "type": "option"
1824
+ },
1825
+ "llm": {
1826
+ "description": "LLM override (e.g. gpt-4o-mini, claude-sonnet-4-6)",
1827
+ "name": "llm",
2017
1828
  "hasDynamicHelp": false,
2018
1829
  "multiple": false,
2019
1830
  "type": "option"
2020
1831
  },
2021
- "kind": {
2022
- "description": "Upload kind: document or thread",
2023
- "name": "kind",
2024
- "default": "document",
1832
+ "formula": {
1833
+ "description": "Compose a run-time composite from your own faces, e.g. \"socrates | nietzsche\" (operators: | & ^ -). Requires --llm. The composite takes the name of its first operand; use face:create --formula for a named, persisted composite.",
1834
+ "name": "formula",
2025
1835
  "hasDynamicHelp": false,
2026
1836
  "multiple": false,
2027
- "options": [
2028
- "document",
2029
- "thread"
2030
- ],
2031
1837
  "type": "option"
2032
1838
  },
2033
- "perspective": {
2034
- "description": "Perspective (document only)",
2035
- "name": "perspective",
2036
- "default": "third-person",
1839
+ "system": {
1840
+ "description": "System prompt / instructions",
1841
+ "name": "system",
2037
1842
  "hasDynamicHelp": false,
2038
1843
  "multiple": false,
2039
- "options": [
2040
- "first-person",
2041
- "third-person"
2042
- ],
2043
1844
  "type": "option"
2044
1845
  },
2045
- "medium": {
2046
- "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not. Only valid with --kind document.",
2047
- "name": "medium",
1846
+ "stream": {
1847
+ "description": "Stream the response",
1848
+ "name": "stream",
1849
+ "allowNo": false,
1850
+ "type": "boolean"
1851
+ },
1852
+ "max-tokens": {
1853
+ "description": "Max tokens",
1854
+ "name": "max-tokens",
2048
1855
  "hasDynamicHelp": false,
2049
1856
  "multiple": false,
2050
1857
  "type": "option"
2051
1858
  },
2052
- "face-speaker": {
2053
- "description": "Speaker name to map to the face (thread only). If omitted, auto-detected from face name.",
2054
- "name": "face-speaker",
1859
+ "temperature": {
1860
+ "description": "Temperature (0.0-2.0)",
1861
+ "name": "temperature",
2055
1862
  "hasDynamicHelp": false,
2056
1863
  "multiple": false,
2057
1864
  "type": "option"
2058
1865
  },
2059
- "no-wait": {
2060
- "description": "Return immediately after upload (do not poll for transcription). Prints the ID for manual polling.",
2061
- "name": "no-wait",
1866
+ "file": {
1867
+ "description": "Read message from file",
1868
+ "name": "file",
1869
+ "hasDynamicHelp": false,
1870
+ "multiple": false,
1871
+ "type": "option"
1872
+ },
1873
+ "responses": {
1874
+ "description": "Force the OpenAI Responses API endpoint (escape hatch; routing is automatic otherwise)",
1875
+ "name": "responses",
1876
+ "allowNo": false,
1877
+ "type": "boolean"
1878
+ },
1879
+ "medium": {
1880
+ "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
1881
+ "name": "medium",
1882
+ "hasDynamicHelp": false,
1883
+ "multiple": false,
1884
+ "type": "option"
1885
+ },
1886
+ "oauth-only": {
1887
+ "description": "Prevent fallback to paid system key (use OAuth only)",
1888
+ "name": "oauth-only",
2062
1889
  "allowNo": false,
2063
1890
  "type": "boolean"
2064
1891
  }
2065
1892
  },
2066
1893
  "hasDynamicHelp": false,
2067
1894
  "hiddenAliases": [],
2068
- "id": "compile:upload",
1895
+ "id": "chat:chat",
2069
1896
  "pluginAlias": "faces-cli",
2070
1897
  "pluginName": "faces-cli",
2071
1898
  "pluginType": "core",
@@ -2075,14 +1902,20 @@
2075
1902
  "relativePath": [
2076
1903
  "dist",
2077
1904
  "commands",
2078
- "compile",
2079
- "upload.js"
1905
+ "chat",
1906
+ "chat.js"
2080
1907
  ]
2081
1908
  },
2082
- "config:clear": {
1909
+ "chat:messages": {
2083
1910
  "aliases": [],
2084
- "args": {},
2085
- "description": "Delete all saved credentials and config",
1911
+ "args": {
1912
+ "face_model": {
1913
+ "description": "Face model (e.g. myface, myface@claude-sonnet-4-6, or head:socrates@claude-sonnet-4-6)",
1914
+ "name": "face_model",
1915
+ "required": true
1916
+ }
1917
+ },
1918
+ "description": "Anthropic Messages API proxy via a face (alias: chat:chat auto-routes Anthropic models here)",
2086
1919
  "flags": {
2087
1920
  "json": {
2088
1921
  "description": "Format output as json.",
@@ -2115,16 +1948,53 @@
2115
1948
  "multiple": false,
2116
1949
  "type": "option"
2117
1950
  },
2118
- "yes": {
2119
- "description": "Skip confirmation",
2120
- "name": "yes",
1951
+ "message": {
1952
+ "char": "m",
1953
+ "description": "User message (repeatable)",
1954
+ "name": "message",
1955
+ "required": true,
1956
+ "hasDynamicHelp": false,
1957
+ "multiple": true,
1958
+ "type": "option"
1959
+ },
1960
+ "system": {
1961
+ "description": "System prompt",
1962
+ "name": "system",
1963
+ "hasDynamicHelp": false,
1964
+ "multiple": false,
1965
+ "type": "option"
1966
+ },
1967
+ "stream": {
1968
+ "description": "Stream the response",
1969
+ "name": "stream",
1970
+ "allowNo": false,
1971
+ "type": "boolean"
1972
+ },
1973
+ "max-tokens": {
1974
+ "description": "Max tokens",
1975
+ "name": "max-tokens",
1976
+ "default": 1024,
1977
+ "hasDynamicHelp": false,
1978
+ "multiple": false,
1979
+ "type": "option"
1980
+ },
1981
+ "medium": {
1982
+ "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
1983
+ "name": "medium",
1984
+ "hasDynamicHelp": false,
1985
+ "multiple": false,
1986
+ "type": "option"
1987
+ },
1988
+ "oauth-only": {
1989
+ "description": "Prevent fallback to paid system key (use OAuth only)",
1990
+ "name": "oauth-only",
2121
1991
  "allowNo": false,
2122
1992
  "type": "boolean"
2123
1993
  }
2124
1994
  },
2125
1995
  "hasDynamicHelp": false,
2126
1996
  "hiddenAliases": [],
2127
- "id": "config:clear",
1997
+ "id": "chat:messages",
2128
1998
  "pluginAlias": "faces-cli",
2129
1999
  "pluginName": "faces-cli",
2130
2000
  "pluginType": "core",
@@ -2134,25 +2004,20 @@
2134
2004
  "relativePath": [
2135
2005
  "dist",
2136
2006
  "commands",
2137
- "config",
2138
- "clear.js"
2007
+ "chat",
2008
+ "messages.js"
2139
2009
  ]
2140
2010
  },
2141
- "config:set": {
2011
+ "chat:responses": {
2142
2012
  "aliases": [],
2143
2013
  "args": {
2144
- "key": {
2145
- "description": "Config key",
2146
- "name": "key",
2147
- "required": true
2148
- },
2149
- "value": {
2150
- "description": "Config value",
2151
- "name": "value",
2014
+ "face_model": {
2015
+ "description": "Face model (e.g. myface, myface@gpt-4o, or head:socrates@gpt-5.4)",
2016
+ "name": "face_model",
2152
2017
  "required": true
2153
2018
  }
2154
2019
  },
2155
- "description": "Set a config value (e.g. base_url, api_key, token)",
2020
+ "description": "OpenAI Responses API proxy via a face (alias: chat:chat --responses)",
2156
2021
  "flags": {
2157
2022
  "json": {
2158
2023
  "description": "Format output as json.",
@@ -2184,11 +2049,46 @@
2184
2049
  "hasDynamicHelp": false,
2185
2050
  "multiple": false,
2186
2051
  "type": "option"
2052
+ },
2053
+ "message": {
2054
+ "char": "m",
2055
+ "description": "User input message",
2056
+ "name": "message",
2057
+ "required": true,
2058
+ "hasDynamicHelp": false,
2059
+ "multiple": false,
2060
+ "type": "option"
2061
+ },
2062
+ "instructions": {
2063
+ "description": "System instructions",
2064
+ "name": "instructions",
2065
+ "hasDynamicHelp": false,
2066
+ "multiple": false,
2067
+ "type": "option"
2068
+ },
2069
+ "stream": {
2070
+ "description": "Stream the response",
2071
+ "name": "stream",
2072
+ "allowNo": false,
2073
+ "type": "boolean"
2074
+ },
2075
+ "medium": {
2076
+ "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
2077
+ "name": "medium",
2078
+ "hasDynamicHelp": false,
2079
+ "multiple": false,
2080
+ "type": "option"
2081
+ },
2082
+ "oauth-only": {
2083
+ "description": "Prevent fallback to paid system key (use OAuth only)",
2084
+ "name": "oauth-only",
2085
+ "allowNo": false,
2086
+ "type": "boolean"
2187
2087
  }
2188
2088
  },
2189
2089
  "hasDynamicHelp": false,
2190
2090
  "hiddenAliases": [],
2191
- "id": "config:set",
2091
+ "id": "chat:responses",
2192
2092
  "pluginAlias": "faces-cli",
2193
2093
  "pluginName": "faces-cli",
2194
2094
  "pluginType": "core",
@@ -2198,14 +2098,27 @@
2198
2098
  "relativePath": [
2199
2099
  "dist",
2200
2100
  "commands",
2201
- "config",
2202
- "set.js"
2101
+ "chat",
2102
+ "responses.js"
2203
2103
  ]
2204
2104
  },
2205
- "config:show": {
2105
+ "chat:thread": {
2206
2106
  "aliases": [],
2207
- "args": {},
2208
- "description": "Print current config (credentials are masked)",
2107
+ "args": {
2108
+ "face_username": {
2109
+ "description": "Face alias (alias@model, or owner:alias@model for a published face) — required when starting a new thread",
2110
+ "name": "face_username",
2111
+ "required": false
2112
+ }
2113
+ },
2114
+ "description": "Multi-turn chat thread. Conversation history is stored under ~/.faces/threads/<id>.json — resume any thread later with --id.",
2115
+ "examples": [
2116
+ "<%= config.bin %> <%= command.id %> socrates -m \"What is justice?\"",
2117
+ "<%= config.bin %> <%= command.id %> --id t_abc123 -m \"Say more about that\"",
2118
+ "<%= config.bin %> <%= command.id %> --list",
2119
+ "<%= config.bin %> <%= command.id %> --id t_abc123 --show",
2120
+ "<%= config.bin %> <%= command.id %> --id t_abc123 --delete"
2121
+ ],
2209
2122
  "flags": {
2210
2123
  "json": {
2211
2124
  "description": "Format output as json.",
@@ -2237,11 +2150,98 @@
2237
2150
  "hasDynamicHelp": false,
2238
2151
  "multiple": false,
2239
2152
  "type": "option"
2153
+ },
2154
+ "id": {
2155
+ "description": "Resume an existing thread by id",
2156
+ "name": "id",
2157
+ "hasDynamicHelp": false,
2158
+ "multiple": false,
2159
+ "type": "option"
2160
+ },
2161
+ "message": {
2162
+ "char": "m",
2163
+ "description": "User message",
2164
+ "name": "message",
2165
+ "hasDynamicHelp": false,
2166
+ "multiple": false,
2167
+ "type": "option"
2168
+ },
2169
+ "file": {
2170
+ "description": "Read message from file",
2171
+ "name": "file",
2172
+ "hasDynamicHelp": false,
2173
+ "multiple": false,
2174
+ "type": "option"
2175
+ },
2176
+ "llm": {
2177
+ "description": "LLM override (only honored when starting a new thread)",
2178
+ "name": "llm",
2179
+ "hasDynamicHelp": false,
2180
+ "multiple": false,
2181
+ "type": "option"
2182
+ },
2183
+ "system": {
2184
+ "description": "System prompt (only honored when starting a new thread)",
2185
+ "name": "system",
2186
+ "hasDynamicHelp": false,
2187
+ "multiple": false,
2188
+ "type": "option"
2189
+ },
2190
+ "max-tokens": {
2191
+ "description": "Max tokens",
2192
+ "name": "max-tokens",
2193
+ "hasDynamicHelp": false,
2194
+ "multiple": false,
2195
+ "type": "option"
2196
+ },
2197
+ "temperature": {
2198
+ "description": "Temperature (0.0-2.0, OpenAI/Chat Completions only)",
2199
+ "name": "temperature",
2200
+ "hasDynamicHelp": false,
2201
+ "multiple": false,
2202
+ "type": "option"
2203
+ },
2204
+ "stream": {
2205
+ "description": "Stream the response",
2206
+ "name": "stream",
2207
+ "allowNo": false,
2208
+ "type": "boolean"
2209
+ },
2210
+ "medium": {
2211
+ "description": "What sort of writing this is — e.g. email, text message, social post, essay, academic paper, blog post, legal document, thread reply, conversation (dialogue: transcripts, interviews, calls), lecture (sustained speech nobody interrupts: talks, sermons, keynotes). Common synonyms fold automatically. Omit it if you do not know: a wrong declaration is worse than none, because a declaration is trusted and an absence is not.",
2212
+ "name": "medium",
2213
+ "hasDynamicHelp": false,
2214
+ "multiple": false,
2215
+ "type": "option"
2216
+ },
2217
+ "oauth-only": {
2218
+ "description": "Prevent fallback to paid system key",
2219
+ "name": "oauth-only",
2220
+ "allowNo": false,
2221
+ "type": "boolean"
2222
+ },
2223
+ "list": {
2224
+ "description": "List saved threads",
2225
+ "name": "list",
2226
+ "allowNo": false,
2227
+ "type": "boolean"
2228
+ },
2229
+ "show": {
2230
+ "description": "Show the thread transcript (requires --id)",
2231
+ "name": "show",
2232
+ "allowNo": false,
2233
+ "type": "boolean"
2234
+ },
2235
+ "delete": {
2236
+ "description": "Delete the thread (requires --id)",
2237
+ "name": "delete",
2238
+ "allowNo": false,
2239
+ "type": "boolean"
2240
2240
  }
2241
2241
  },
2242
2242
  "hasDynamicHelp": false,
2243
2243
  "hiddenAliases": [],
2244
- "id": "config:show",
2244
+ "id": "chat:thread",
2245
2245
  "pluginAlias": "faces-cli",
2246
2246
  "pluginName": "faces-cli",
2247
2247
  "pluginType": "core",
@@ -2251,14 +2251,14 @@
2251
2251
  "relativePath": [
2252
2252
  "dist",
2253
2253
  "commands",
2254
- "config",
2255
- "show.js"
2254
+ "chat",
2255
+ "thread.js"
2256
2256
  ]
2257
2257
  },
2258
- "keys:create": {
2258
+ "face:attributes": {
2259
2259
  "aliases": [],
2260
2260
  "args": {},
2261
- "description": "Create a new API key (JWT required). The new key is saved to ~/.faces/config.json as api_key by default; pass --no-save to skip.",
2261
+ "description": "List all supported attribute keys",
2262
2262
  "flags": {
2263
2263
  "json": {
2264
2264
  "description": "Format output as json.",
@@ -2290,53 +2290,11 @@
2290
2290
  "hasDynamicHelp": false,
2291
2291
  "multiple": false,
2292
2292
  "type": "option"
2293
- },
2294
- "name": {
2295
- "description": "Key name/label",
2296
- "name": "name",
2297
- "required": true,
2298
- "hasDynamicHelp": false,
2299
- "multiple": false,
2300
- "type": "option"
2301
- },
2302
- "expires-days": {
2303
- "description": "Expiry in days (omit for no expiry)",
2304
- "name": "expires-days",
2305
- "hasDynamicHelp": false,
2306
- "multiple": false,
2307
- "type": "option"
2308
- },
2309
- "budget": {
2310
- "description": "Spend budget in USD",
2311
- "name": "budget",
2312
- "hasDynamicHelp": false,
2313
- "multiple": false,
2314
- "type": "option"
2315
- },
2316
- "face": {
2317
- "description": "Allowed face alias (repeatable)",
2318
- "name": "face",
2319
- "hasDynamicHelp": false,
2320
- "multiple": true,
2321
- "type": "option"
2322
- },
2323
- "model": {
2324
- "description": "Allowed model name (repeatable)",
2325
- "name": "model",
2326
- "hasDynamicHelp": false,
2327
- "multiple": true,
2328
- "type": "option"
2329
- },
2330
- "save": {
2331
- "description": "Save the new key to ~/.faces/config.json as api_key (default: true; use --no-save to skip)",
2332
- "name": "save",
2333
- "allowNo": true,
2334
- "type": "boolean"
2335
2293
  }
2336
2294
  },
2337
2295
  "hasDynamicHelp": false,
2338
2296
  "hiddenAliases": [],
2339
- "id": "keys:create",
2297
+ "id": "face:attributes",
2340
2298
  "pluginAlias": "faces-cli",
2341
2299
  "pluginName": "faces-cli",
2342
2300
  "pluginType": "core",
@@ -2346,14 +2304,14 @@
2346
2304
  "relativePath": [
2347
2305
  "dist",
2348
2306
  "commands",
2349
- "keys",
2350
- "create.js"
2307
+ "face",
2308
+ "attributes.js"
2351
2309
  ]
2352
2310
  },
2353
- "keys:list": {
2311
+ "face:create": {
2354
2312
  "aliases": [],
2355
2313
  "args": {},
2356
- "description": "List all API keys (JWT required)",
2314
+ "description": "Create a new face",
2357
2315
  "flags": {
2358
2316
  "json": {
2359
2317
  "description": "Format output as json.",
@@ -2385,11 +2343,86 @@
2385
2343
  "hasDynamicHelp": false,
2386
2344
  "multiple": false,
2387
2345
  "type": "option"
2346
+ },
2347
+ "name": {
2348
+ "description": "Display name",
2349
+ "name": "name",
2350
+ "required": true,
2351
+ "hasDynamicHelp": false,
2352
+ "multiple": false,
2353
+ "type": "option"
2354
+ },
2355
+ "alias": {
2356
+ "description": "Unique alias slug",
2357
+ "name": "alias",
2358
+ "required": true,
2359
+ "hasDynamicHelp": false,
2360
+ "multiple": false,
2361
+ "type": "option"
2362
+ },
2363
+ "description": {
2364
+ "description": "Plain-text description / bio (max 1500 chars)",
2365
+ "name": "description",
2366
+ "hasDynamicHelp": false,
2367
+ "multiple": false,
2368
+ "type": "option"
2369
+ },
2370
+ "tag": {
2371
+ "description": "Tag label (repeatable, lowercase)",
2372
+ "name": "tag",
2373
+ "hasDynamicHelp": false,
2374
+ "multiple": true,
2375
+ "type": "option"
2376
+ },
2377
+ "default-model": {
2378
+ "description": "Default LLM for chat (e.g. gpt-4o-mini, claude-sonnet-4-6)",
2379
+ "name": "default-model",
2380
+ "hasDynamicHelp": false,
2381
+ "multiple": false,
2382
+ "type": "option"
2383
+ },
2384
+ "formula": {
2385
+ "description": "Boolean formula over owned concrete face aliases (e.g. \"a | b\", \"(a | b) - c\"). Creates a composite face.",
2386
+ "name": "formula",
2387
+ "hasDynamicHelp": false,
2388
+ "multiple": false,
2389
+ "type": "option"
2390
+ },
2391
+ "attr": {
2392
+ "description": "Attribute KEY=VALUE (repeatable)",
2393
+ "name": "attr",
2394
+ "hasDynamicHelp": false,
2395
+ "multiple": true,
2396
+ "type": "option"
2397
+ },
2398
+ "tool": {
2399
+ "description": "Tool name to enable (repeatable)",
2400
+ "name": "tool",
2401
+ "hasDynamicHelp": false,
2402
+ "multiple": true,
2403
+ "type": "option"
2404
+ },
2405
+ "profile-addendum": {
2406
+ "description": "Per-face system prompt, injected after the persona profile and before any per-request system prompt (max 100,000 chars).",
2407
+ "name": "profile-addendum",
2408
+ "hasDynamicHelp": false,
2409
+ "multiple": false,
2410
+ "type": "option"
2411
+ },
2412
+ "profile-addendum-file": {
2413
+ "description": "Read the per-face system prompt from a file (alternative to --profile-addendum).",
2414
+ "exclusive": [
2415
+ "profile-addendum"
2416
+ ],
2417
+ "name": "profile-addendum-file",
2418
+ "hasDynamicHelp": false,
2419
+ "multiple": false,
2420
+ "type": "option"
2388
2421
  }
2389
2422
  },
2390
2423
  "hasDynamicHelp": false,
2391
2424
  "hiddenAliases": [],
2392
- "id": "keys:list",
2425
+ "id": "face:create",
2393
2426
  "pluginAlias": "faces-cli",
2394
2427
  "pluginName": "faces-cli",
2395
2428
  "pluginType": "core",
@@ -2399,20 +2432,20 @@
2399
2432
  "relativePath": [
2400
2433
  "dist",
2401
2434
  "commands",
2402
- "keys",
2403
- "list.js"
2435
+ "face",
2436
+ "create.js"
2404
2437
  ]
2405
2438
  },
2406
- "keys:revoke": {
2439
+ "face:delete": {
2407
2440
  "aliases": [],
2408
2441
  "args": {
2409
- "key_id": {
2410
- "description": "Key ID",
2411
- "name": "key_id",
2442
+ "face_id": {
2443
+ "description": "Face alias",
2444
+ "name": "face_id",
2412
2445
  "required": true
2413
2446
  }
2414
2447
  },
2415
- "description": "Revoke an API key (JWT required)",
2448
+ "description": "Delete a face permanently",
2416
2449
  "flags": {
2417
2450
  "json": {
2418
2451
  "description": "Format output as json.",
@@ -2454,7 +2487,7 @@
2454
2487
  },
2455
2488
  "hasDynamicHelp": false,
2456
2489
  "hiddenAliases": [],
2457
- "id": "keys:revoke",
2490
+ "id": "face:delete",
2458
2491
  "pluginAlias": "faces-cli",
2459
2492
  "pluginName": "faces-cli",
2460
2493
  "pluginType": "core",
@@ -2464,20 +2497,14 @@
2464
2497
  "relativePath": [
2465
2498
  "dist",
2466
2499
  "commands",
2467
- "keys",
2468
- "revoke.js"
2500
+ "face",
2501
+ "delete.js"
2469
2502
  ]
2470
2503
  },
2471
- "keys:update": {
2504
+ "face:diff": {
2472
2505
  "aliases": [],
2473
- "args": {
2474
- "key_id": {
2475
- "description": "Key ID",
2476
- "name": "key_id",
2477
- "required": true
2478
- }
2479
- },
2480
- "description": "Update API key metadata (JWT required)",
2506
+ "args": {},
2507
+ "description": "Compare owned faces pairwise across all centroid components",
2481
2508
  "flags": {
2482
2509
  "json": {
2483
2510
  "description": "Format output as json.",
@@ -2510,30 +2537,18 @@
2510
2537
  "multiple": false,
2511
2538
  "type": "option"
2512
2539
  },
2513
- "name": {
2514
- "description": "New key name",
2515
- "name": "name",
2516
- "hasDynamicHelp": false,
2517
- "multiple": false,
2518
- "type": "option"
2519
- },
2520
- "budget": {
2521
- "description": "New spend budget in USD",
2522
- "name": "budget",
2540
+ "face": {
2541
+ "description": "Face alias to include (repeatable, min 2)",
2542
+ "name": "face",
2543
+ "required": true,
2523
2544
  "hasDynamicHelp": false,
2524
- "multiple": false,
2545
+ "multiple": true,
2525
2546
  "type": "option"
2526
- },
2527
- "reset-spent": {
2528
- "description": "Reset spent amount to zero",
2529
- "name": "reset-spent",
2530
- "allowNo": false,
2531
- "type": "boolean"
2532
2547
  }
2533
2548
  },
2534
2549
  "hasDynamicHelp": false,
2535
2550
  "hiddenAliases": [],
2536
- "id": "keys:update",
2551
+ "id": "face:diff",
2537
2552
  "pluginAlias": "faces-cli",
2538
2553
  "pluginName": "faces-cli",
2539
2554
  "pluginType": "core",
@@ -2543,24 +2558,20 @@
2543
2558
  "relativePath": [
2544
2559
  "dist",
2545
2560
  "commands",
2546
- "keys",
2547
- "update.js"
2561
+ "face",
2562
+ "diff.js"
2548
2563
  ]
2549
2564
  },
2550
- "style:delete": {
2565
+ "face:edit": {
2551
2566
  "aliases": [],
2552
2567
  "args": {
2553
- "alias": {
2568
+ "face_id": {
2554
2569
  "description": "Face alias",
2555
- "name": "alias",
2570
+ "name": "face_id",
2556
2571
  "required": true
2557
2572
  }
2558
2573
  },
2559
- "description": "Delete a face's captured style. The material it was learned from is kept, so the style can be captured again without re-uploading. This never deletes documents or threads: remove those with compile:doc:delete or compile:thread:delete.",
2560
- "examples": [
2561
- "<%= config.bin %> <%= command.id %> alice",
2562
- "<%= config.bin %> <%= command.id %> alice --yes"
2563
- ],
2574
+ "description": "Edit a face's metadata",
2564
2575
  "flags": {
2565
2576
  "json": {
2566
2577
  "description": "Format output as json.",
@@ -2593,16 +2604,86 @@
2593
2604
  "multiple": false,
2594
2605
  "type": "option"
2595
2606
  },
2596
- "yes": {
2597
- "description": "Skip confirmation",
2598
- "name": "yes",
2607
+ "name": {
2608
+ "description": "New display name",
2609
+ "name": "name",
2610
+ "hasDynamicHelp": false,
2611
+ "multiple": false,
2612
+ "type": "option"
2613
+ },
2614
+ "description": {
2615
+ "description": "Plain-text description / bio (max 1500 chars)",
2616
+ "name": "description",
2617
+ "hasDynamicHelp": false,
2618
+ "multiple": false,
2619
+ "type": "option"
2620
+ },
2621
+ "tag": {
2622
+ "description": "Replace all tags (repeatable, lowercase)",
2623
+ "name": "tag",
2624
+ "hasDynamicHelp": false,
2625
+ "multiple": true,
2626
+ "type": "option"
2627
+ },
2628
+ "default-model": {
2629
+ "description": "Default LLM for chat (e.g. gpt-4o-mini, claude-sonnet-4-6)",
2630
+ "name": "default-model",
2631
+ "hasDynamicHelp": false,
2632
+ "multiple": false,
2633
+ "type": "option"
2634
+ },
2635
+ "formula": {
2636
+ "description": "New boolean formula (synthetic faces only)",
2637
+ "name": "formula",
2638
+ "hasDynamicHelp": false,
2639
+ "multiple": false,
2640
+ "type": "option"
2641
+ },
2642
+ "attr": {
2643
+ "description": "Update attribute KEY=VALUE (repeatable)",
2644
+ "name": "attr",
2645
+ "hasDynamicHelp": false,
2646
+ "multiple": true,
2647
+ "type": "option"
2648
+ },
2649
+ "tool": {
2650
+ "description": "Tool names to set (replaces list, repeatable)",
2651
+ "name": "tool",
2652
+ "hasDynamicHelp": false,
2653
+ "multiple": true,
2654
+ "type": "option"
2655
+ },
2656
+ "profile-addendum": {
2657
+ "description": "Replace the per-face system prompt (max 100,000 chars).",
2658
+ "name": "profile-addendum",
2659
+ "hasDynamicHelp": false,
2660
+ "multiple": false,
2661
+ "type": "option"
2662
+ },
2663
+ "profile-addendum-file": {
2664
+ "description": "Replace the per-face system prompt from a file.",
2665
+ "exclusive": [
2666
+ "profile-addendum"
2667
+ ],
2668
+ "name": "profile-addendum-file",
2669
+ "hasDynamicHelp": false,
2670
+ "multiple": false,
2671
+ "type": "option"
2672
+ },
2673
+ "clear-profile-addendum": {
2674
+ "description": "Remove the per-face system prompt.",
2675
+ "exclusive": [
2676
+ "profile-addendum",
2677
+ "profile-addendum-file"
2678
+ ],
2679
+ "name": "clear-profile-addendum",
2599
2680
  "allowNo": false,
2600
2681
  "type": "boolean"
2601
2682
  }
2602
2683
  },
2603
2684
  "hasDynamicHelp": false,
2604
2685
  "hiddenAliases": [],
2605
- "id": "style:delete",
2686
+ "id": "face:edit",
2606
2687
  "pluginAlias": "faces-cli",
2607
2688
  "pluginName": "faces-cli",
2608
2689
  "pluginType": "core",
@@ -2612,26 +2693,20 @@
2612
2693
  "relativePath": [
2613
2694
  "dist",
2614
2695
  "commands",
2615
- "style",
2616
- "delete.js"
2696
+ "face",
2697
+ "edit.js"
2617
2698
  ]
2618
2699
  },
2619
- "style:make": {
2700
+ "face:get": {
2620
2701
  "aliases": [],
2621
2702
  "args": {
2622
- "alias": {
2703
+ "face_id": {
2623
2704
  "description": "Face alias",
2624
- "name": "alias",
2705
+ "name": "face_id",
2625
2706
  "required": true
2626
2707
  }
2627
2708
  },
2628
- "description": "Capture how a face writes, from its own material, and install it. This is style, not knowledge: compile teaches a face what it knows, style teaches it how it sounds. Name the sources to learn from with --source, or take everything ready with --all.",
2629
- "examples": [
2630
- "<%= config.bin %> <%= command.id %> alice --all",
2631
- "<%= config.bin %> <%= command.id %> alice --source 1a2b3c4d --source 5e6f7a8b",
2632
- "<%= config.bin %> <%= command.id %> alice --source 1a2b3c4d:essay",
2633
- "<%= config.bin %> <%= command.id %> alice --all --medium essay --no-wait"
2634
- ],
2709
+ "description": "Get details for a face, by alias or owner:alias. A published or shared face is reachable under the same owner:alias address chat uses; it is shown with a note that you do not own it.",
2635
2710
  "flags": {
2636
2711
  "json": {
2637
2712
  "description": "Format output as json.",
@@ -2663,71 +2738,24 @@
2663
2738
  "hasDynamicHelp": false,
2664
2739
  "multiple": false,
2665
2740
  "type": "option"
2666
- },
2667
- "source": {
2668
- "description": "A document or thread to learn from, by id (repeatable). Append :<medium> to declare what it is, e.g. --source 1a2b3c4d:essay, when the source does not already say.",
2669
- "name": "source",
2670
- "hasDynamicHelp": false,
2671
- "multiple": true,
2672
- "type": "option"
2673
- },
2674
- "all": {
2675
- "description": "Use every source on the face that is ready. Anything skipped is listed.",
2676
- "name": "all",
2677
- "allowNo": false,
2678
- "type": "boolean"
2679
- },
2680
- "medium": {
2681
- "description": "Medium for selected sources that do not already declare one. It does not override a source that does. Each medium is analysed on its own, so an essay never teaches a rule about email.",
2682
- "name": "medium",
2683
- "hasDynamicHelp": false,
2684
- "multiple": false,
2685
- "type": "option"
2686
- },
2687
- "model": {
2688
- "description": "Analyst model (default: gpt-5.6-terra)",
2689
- "name": "model",
2690
- "hasDynamicHelp": false,
2691
- "multiple": false,
2692
- "type": "option"
2693
- },
2694
- "allow-paid": {
2695
- "description": "Permit a build that bills. Without this a build is free or it does not run. Needed for any model outside the free tier, and to allow the paid route when a free quota is exhausted.",
2696
- "name": "allow-paid",
2697
- "allowNo": false,
2698
- "type": "boolean"
2699
- },
2700
- "compile": {
2701
- "description": "Compile any named source that is not compiled yet, before capturing style. On by default. --no-compile captures style from what is already compiled and never bills for compilation.",
2702
- "name": "compile",
2703
- "allowNo": true,
2704
- "type": "boolean"
2705
- },
2706
- "best-of": {
2707
- "description": "Generate N candidates and keep the best (1-5, default 1)",
2708
- "name": "best-of",
2709
- "hasDynamicHelp": false,
2710
- "multiple": false,
2711
- "type": "option"
2712
- },
2713
- "no-wait": {
2714
- "description": "Start the build and return the job id without polling.",
2715
- "name": "no-wait",
2716
- "allowNo": false,
2717
- "type": "boolean"
2718
- },
2719
- "timeout": {
2720
- "description": "How long to wait, in seconds (default: 3600)",
2721
- "name": "timeout",
2722
- "default": 3600,
2741
+ },
2742
+ "include": {
2743
+ "description": "Include extra fields: tags, teams (comma-separated)",
2744
+ "name": "include",
2723
2745
  "hasDynamicHelp": false,
2724
2746
  "multiple": false,
2725
2747
  "type": "option"
2748
+ },
2749
+ "full": {
2750
+ "description": "Print the full profile_addendum instead of a truncated preview",
2751
+ "name": "full",
2752
+ "allowNo": false,
2753
+ "type": "boolean"
2726
2754
  }
2727
2755
  },
2728
2756
  "hasDynamicHelp": false,
2729
2757
  "hiddenAliases": [],
2730
- "id": "style:make",
2758
+ "id": "face:get",
2731
2759
  "pluginAlias": "faces-cli",
2732
2760
  "pluginName": "faces-cli",
2733
2761
  "pluginType": "core",
@@ -2737,24 +2765,14 @@
2737
2765
  "relativePath": [
2738
2766
  "dist",
2739
2767
  "commands",
2740
- "style",
2741
- "make.js"
2768
+ "face",
2769
+ "get.js"
2742
2770
  ]
2743
2771
  },
2744
- "style:revert": {
2772
+ "face:list": {
2745
2773
  "aliases": [],
2746
- "args": {
2747
- "alias": {
2748
- "description": "Face alias",
2749
- "name": "alias",
2750
- "required": true
2751
- }
2752
- },
2753
- "description": "Go back to the style a face had before the last style:make. A face holds one style per medium, so name which one with --medium when it has more than one. Two versions are kept per medium, so this goes back exactly one step. It changes how the face writes immediately, so it asks first.",
2754
- "examples": [
2755
- "<%= config.bin %> <%= command.id %> alice --yes",
2756
- "<%= config.bin %> <%= command.id %> alice --medium email --yes"
2757
- ],
2774
+ "args": {},
2775
+ "description": "List faces. By default lists owned faces; use --public to include published faces from other accounts.",
2758
2776
  "flags": {
2759
2777
  "json": {
2760
2778
  "description": "Format output as json.",
@@ -2787,23 +2805,63 @@
2787
2805
  "multiple": false,
2788
2806
  "type": "option"
2789
2807
  },
2790
- "medium": {
2791
- "description": "Which style to step back, when the face has more than one. See faces style:versions <alias>.",
2792
- "name": "medium",
2808
+ "tag": {
2809
+ "description": "Filter by tag (repeatable, AND logic)",
2810
+ "name": "tag",
2811
+ "hasDynamicHelp": false,
2812
+ "multiple": true,
2813
+ "type": "option"
2814
+ },
2815
+ "team": {
2816
+ "description": "Filter by team ID (repeatable, OR logic)",
2817
+ "name": "team",
2818
+ "hasDynamicHelp": false,
2819
+ "multiple": true,
2820
+ "type": "option"
2821
+ },
2822
+ "include": {
2823
+ "description": "Include extra fields: tags, teams (comma-separated)",
2824
+ "name": "include",
2793
2825
  "hasDynamicHelp": false,
2794
2826
  "multiple": false,
2795
2827
  "type": "option"
2796
2828
  },
2797
- "yes": {
2798
- "description": "Skip confirmation",
2799
- "name": "yes",
2829
+ "public": {
2830
+ "description": "Include published faces from other accounts (open to everybody)",
2831
+ "name": "public",
2832
+ "allowNo": false,
2833
+ "type": "boolean"
2834
+ },
2835
+ "shared": {
2836
+ "description": "Include faces other accounts have shared with YOU in particular",
2837
+ "name": "shared",
2838
+ "allowNo": false,
2839
+ "type": "boolean"
2840
+ },
2841
+ "system": {
2842
+ "description": "Show only the curated system faces (published faces owned by 'head')",
2843
+ "name": "system",
2800
2844
  "allowNo": false,
2801
2845
  "type": "boolean"
2846
+ },
2847
+ "from-users": {
2848
+ "description": "Only published faces from these owners (repeatable/comma-separated)",
2849
+ "name": "from-users",
2850
+ "hasDynamicHelp": false,
2851
+ "multiple": true,
2852
+ "type": "option"
2853
+ },
2854
+ "not-from-users": {
2855
+ "description": "Exclude published faces from these owners (repeatable/comma-separated)",
2856
+ "name": "not-from-users",
2857
+ "hasDynamicHelp": false,
2858
+ "multiple": true,
2859
+ "type": "option"
2802
2860
  }
2803
2861
  },
2804
2862
  "hasDynamicHelp": false,
2805
2863
  "hiddenAliases": [],
2806
- "id": "style:revert",
2864
+ "id": "face:list",
2807
2865
  "pluginAlias": "faces-cli",
2808
2866
  "pluginName": "faces-cli",
2809
2867
  "pluginType": "core",
@@ -2813,24 +2871,22 @@
2813
2871
  "relativePath": [
2814
2872
  "dist",
2815
2873
  "commands",
2816
- "style",
2817
- "revert.js"
2874
+ "face",
2875
+ "list.js"
2818
2876
  ]
2819
2877
  },
2820
- "style:status": {
2878
+ "face:lock": {
2821
2879
  "aliases": [],
2822
2880
  "args": {
2823
- "job_id": {
2824
- "description": "Build job id",
2825
- "name": "job_id",
2826
- "required": false
2881
+ "face_id": {
2882
+ "description": "Face alias",
2883
+ "name": "face_id",
2884
+ "required": true
2827
2885
  }
2828
2886
  },
2829
- "description": "Read a style build. Give a job id for one build, or --face to list a face's recent builds. Listing is how you find a job id you no longer have.",
2887
+ "description": "Lock a face (read-only). A locked face still reads and chats normally, but it and everything it owns (documents, threads, voiceprint) cannot be changed until unlocked.",
2830
2888
  "examples": [
2831
- "<%= config.bin %> <%= command.id %> 7a8b9c0d",
2832
- "<%= config.bin %> <%= command.id %> --face alice",
2833
- "<%= config.bin %> <%= command.id %> 7a8b9c0d --wait"
2889
+ "<%= config.bin %> <%= command.id %> socrates"
2834
2890
  ],
2835
2891
  "flags": {
2836
2892
  "json": {
@@ -2863,40 +2919,11 @@
2863
2919
  "hasDynamicHelp": false,
2864
2920
  "multiple": false,
2865
2921
  "type": "option"
2866
- },
2867
- "face": {
2868
- "description": "List recent builds for this face instead of reading one job",
2869
- "name": "face",
2870
- "hasDynamicHelp": false,
2871
- "multiple": false,
2872
- "type": "option"
2873
- },
2874
- "limit": {
2875
- "description": "How many builds to list with --face (default: 10)",
2876
- "name": "limit",
2877
- "default": 10,
2878
- "hasDynamicHelp": false,
2879
- "multiple": false,
2880
- "type": "option"
2881
- },
2882
- "wait": {
2883
- "description": "Block until the job finishes",
2884
- "name": "wait",
2885
- "allowNo": false,
2886
- "type": "boolean"
2887
- },
2888
- "timeout": {
2889
- "description": "How long to wait with --wait, in seconds (default: 3600)",
2890
- "name": "timeout",
2891
- "default": 3600,
2892
- "hasDynamicHelp": false,
2893
- "multiple": false,
2894
- "type": "option"
2895
2922
  }
2896
2923
  },
2897
2924
  "hasDynamicHelp": false,
2898
2925
  "hiddenAliases": [],
2899
- "id": "style:status",
2926
+ "id": "face:lock",
2900
2927
  "pluginAlias": "faces-cli",
2901
2928
  "pluginName": "faces-cli",
2902
2929
  "pluginType": "core",
@@ -2906,30 +2933,20 @@
2906
2933
  "relativePath": [
2907
2934
  "dist",
2908
2935
  "commands",
2909
- "style",
2910
- "status.js"
2936
+ "face",
2937
+ "lock.js"
2911
2938
  ]
2912
2939
  },
2913
- "style:upload": {
2940
+ "face:neighbors": {
2914
2941
  "aliases": [],
2915
2942
  "args": {
2916
- "alias": {
2943
+ "face_id": {
2917
2944
  "description": "Face alias",
2918
- "name": "alias",
2919
- "required": true
2920
- },
2921
- "file": {
2922
- "description": "Corpus file",
2923
- "name": "file",
2945
+ "name": "face_id",
2924
2946
  "required": true
2925
2947
  }
2926
2948
  },
2927
- "description": "Load a corpus of a person's own writing (a mail export, a message archive) as source material for style capture. This only stores the material: nothing is compiled and nothing is billed. Capture the style afterwards with style:make.",
2928
- "examples": [
2929
- "<%= config.bin %> <%= command.id %> alice ./mail.jsonl",
2930
- "<%= config.bin %> <%= command.id %> alice ./thread.json --type thread_json",
2931
- "<%= config.bin %> <%= command.id %> alice ./mail.jsonl --messages-per-room 100 --strict"
2932
- ],
2949
+ "description": "Find the most similar or dissimilar owned faces to a given face",
2933
2950
  "flags": {
2934
2951
  "json": {
2935
2952
  "description": "Format output as json.",
@@ -2962,36 +2979,38 @@
2962
2979
  "multiple": false,
2963
2980
  "type": "option"
2964
2981
  },
2965
- "type": {
2966
- "description": "email_jsonl: one message per line, split across several rooms. thread_json: a JSON array that becomes a single room.",
2967
- "name": "type",
2968
- "default": "email_jsonl",
2982
+ "k": {
2983
+ "description": "Number of results (1–20)",
2984
+ "name": "k",
2985
+ "default": 5,
2969
2986
  "hasDynamicHelp": false,
2970
2987
  "multiple": false,
2971
- "options": [
2972
- "email_jsonl",
2973
- "thread_json"
2974
- ],
2975
2988
  "type": "option"
2976
2989
  },
2977
- "messages-per-room": {
2978
- "description": "How many messages per room when the type is email_jsonl (1-1000, default: 50)",
2979
- "name": "messages-per-room",
2980
- "default": 50,
2990
+ "component": {
2991
+ "description": "What to rank on: `face` for overall similarity, or a component position such as 1. Which positions are comparable varies; the API names them if you pick a wrong one.",
2992
+ "name": "component",
2993
+ "default": "face",
2981
2994
  "hasDynamicHelp": false,
2982
2995
  "multiple": false,
2983
2996
  "type": "option"
2984
2997
  },
2985
- "strict": {
2986
- "description": "Reject the whole upload if any message is invalid. By default invalid messages are skipped and reported, because a corpus is statistical and a few bad lines are not worth losing the rest.",
2987
- "name": "strict",
2988
- "allowNo": false,
2989
- "type": "boolean"
2998
+ "direction": {
2999
+ "description": "nearest (most similar) or furthest (most dissimilar)",
3000
+ "name": "direction",
3001
+ "default": "nearest",
3002
+ "hasDynamicHelp": false,
3003
+ "multiple": false,
3004
+ "options": [
3005
+ "nearest",
3006
+ "furthest"
3007
+ ],
3008
+ "type": "option"
2990
3009
  }
2991
3010
  },
2992
3011
  "hasDynamicHelp": false,
2993
3012
  "hiddenAliases": [],
2994
- "id": "style:upload",
3013
+ "id": "face:neighbors",
2995
3014
  "pluginAlias": "faces-cli",
2996
3015
  "pluginName": "faces-cli",
2997
3016
  "pluginType": "core",
@@ -3001,11 +3020,11 @@
3001
3020
  "relativePath": [
3002
3021
  "dist",
3003
3022
  "commands",
3004
- "style",
3005
- "upload.js"
3023
+ "face",
3024
+ "neighbors.js"
3006
3025
  ]
3007
3026
  },
3008
- "style:versions": {
3027
+ "face:publish": {
3009
3028
  "aliases": [],
3010
3029
  "args": {
3011
3030
  "alias": {
@@ -3014,10 +3033,9 @@
3014
3033
  "required": true
3015
3034
  }
3016
3035
  },
3017
- "description": "List the styles captured for a face, and which one it writes in now. A face holds one style per medium, so more than one can be in use at once: an email style and an essay style are separate and do not replace each other. Two versions are kept per medium, which is what style:revert has to go back to.",
3036
+ "description": "Publish a face so EVERY account can chat with it. This is a global override: while it is on, everyone can reach the face regardless of who it is shared with. You still pay only to compile it; whoever chats pays for their own inference.",
3018
3037
  "examples": [
3019
- "<%= config.bin %> <%= command.id %> alice",
3020
- "<%= config.bin %> <%= command.id %> alice --json"
3038
+ "<%= config.bin %> <%= command.id %> alice --yes"
3021
3039
  ],
3022
3040
  "flags": {
3023
3041
  "json": {
@@ -3050,11 +3068,17 @@
3050
3068
  "hasDynamicHelp": false,
3051
3069
  "multiple": false,
3052
3070
  "type": "option"
3071
+ },
3072
+ "yes": {
3073
+ "description": "Skip confirmation",
3074
+ "name": "yes",
3075
+ "allowNo": false,
3076
+ "type": "boolean"
3053
3077
  }
3054
3078
  },
3055
3079
  "hasDynamicHelp": false,
3056
3080
  "hiddenAliases": [],
3057
- "id": "style:versions",
3081
+ "id": "face:publish",
3058
3082
  "pluginAlias": "faces-cli",
3059
3083
  "pluginName": "faces-cli",
3060
3084
  "pluginType": "core",
@@ -3064,20 +3088,26 @@
3064
3088
  "relativePath": [
3065
3089
  "dist",
3066
3090
  "commands",
3067
- "style",
3068
- "versions.js"
3091
+ "face",
3092
+ "publish.js"
3069
3093
  ]
3070
3094
  },
3071
- "team:add": {
3095
+ "face:share": {
3072
3096
  "aliases": [],
3073
3097
  "args": {
3074
- "team_id": {
3075
- "description": "Team ID",
3076
- "name": "team_id",
3098
+ "alias": {
3099
+ "description": "Face alias",
3100
+ "name": "alias",
3077
3101
  "required": true
3078
3102
  }
3079
3103
  },
3080
- "description": "Add face(s) to a team. A team may only contain faces this account owns: a published or shared face can be chatted with but cannot be a member.",
3104
+ "description": "Share a face so named accounts can chat with it. Sharing grants chat and nothing else: no reading its documents, no compiling, no re-sharing, and never its profile addendum. --add keeps the current list; --with replaces it.",
3105
+ "examples": [
3106
+ "<%= config.bin %> <%= command.id %> alice --list",
3107
+ "<%= config.bin %> <%= command.id %> alice --add dana",
3108
+ "<%= config.bin %> <%= command.id %> alice --with dana --with sam@example.com",
3109
+ "<%= config.bin %> <%= command.id %> alice --none --yes"
3110
+ ],
3081
3111
  "flags": {
3082
3112
  "json": {
3083
3113
  "description": "Format output as json.",
@@ -3110,18 +3140,54 @@
3110
3140
  "multiple": false,
3111
3141
  "type": "option"
3112
3142
  },
3113
- "face": {
3114
- "description": "Face alias to add (repeatable)",
3115
- "name": "face",
3116
- "required": true,
3143
+ "list": {
3144
+ "description": "Show who the face is shared with, and change nothing",
3145
+ "name": "list",
3146
+ "allowNo": false,
3147
+ "type": "boolean"
3148
+ },
3149
+ "add": {
3150
+ "description": "Add an account, keeping everyone already on the list — username or email (repeatable)",
3151
+ "exclusive": [
3152
+ "with",
3153
+ "none"
3154
+ ],
3155
+ "name": "add",
3156
+ "hasDynamicHelp": false,
3157
+ "multiple": true,
3158
+ "type": "option"
3159
+ },
3160
+ "with": {
3161
+ "description": "Set the list to exactly these accounts, dropping anyone else (repeatable)",
3162
+ "exclusive": [
3163
+ "add",
3164
+ "none"
3165
+ ],
3166
+ "name": "with",
3117
3167
  "hasDynamicHelp": false,
3118
3168
  "multiple": true,
3119
3169
  "type": "option"
3170
+ },
3171
+ "none": {
3172
+ "description": "Revoke everyone",
3173
+ "exclusive": [
3174
+ "add",
3175
+ "with"
3176
+ ],
3177
+ "name": "none",
3178
+ "allowNo": false,
3179
+ "type": "boolean"
3180
+ },
3181
+ "yes": {
3182
+ "description": "Skip the confirmation shown when someone would lose access",
3183
+ "name": "yes",
3184
+ "allowNo": false,
3185
+ "type": "boolean"
3120
3186
  }
3121
3187
  },
3122
3188
  "hasDynamicHelp": false,
3123
3189
  "hiddenAliases": [],
3124
- "id": "team:add",
3190
+ "id": "face:share",
3125
3191
  "pluginAlias": "faces-cli",
3126
3192
  "pluginName": "faces-cli",
3127
3193
  "pluginType": "core",
@@ -3131,14 +3197,25 @@
3131
3197
  "relativePath": [
3132
3198
  "dist",
3133
3199
  "commands",
3134
- "team",
3135
- "add.js"
3200
+ "face",
3201
+ "share.js"
3136
3202
  ]
3137
3203
  },
3138
- "team:create": {
3204
+ "face:sources": {
3139
3205
  "aliases": [],
3140
- "args": {},
3141
- "description": "Create a new team",
3206
+ "args": {
3207
+ "alias": {
3208
+ "description": "Face alias",
3209
+ "name": "alias",
3210
+ "required": true
3211
+ }
3212
+ },
3213
+ "description": "List every source compiled into a face: documents and threads together, one row each. Exits 4 if the face does not exist, which is a different answer from a face that has no sources. Content is never printed; read a single source with compile:doc:get or compile:thread:get.",
3214
+ "examples": [
3215
+ "<%= config.bin %> <%= command.id %> alice",
3216
+ "<%= config.bin %> <%= command.id %> alice --type thread",
3217
+ "<%= config.bin %> <%= command.id %> alice --json"
3218
+ ],
3142
3219
  "flags": {
3143
3220
  "json": {
3144
3221
  "description": "Format output as json.",
@@ -3171,46 +3248,21 @@
3171
3248
  "multiple": false,
3172
3249
  "type": "option"
3173
3250
  },
3174
- "name": {
3175
- "description": "Team name",
3176
- "name": "name",
3177
- "required": true,
3178
- "hasDynamicHelp": false,
3179
- "multiple": false,
3180
- "type": "option"
3181
- },
3182
- "description": {
3183
- "description": "Plain-text team description (max 1500 chars)",
3184
- "name": "description",
3185
- "hasDynamicHelp": false,
3186
- "multiple": false,
3187
- "type": "option"
3188
- },
3189
- "protocol": {
3190
- "description": "Protocol content (mermaid diagram or markdown, max 1000 words)",
3191
- "name": "protocol",
3192
- "hasDynamicHelp": false,
3193
- "multiple": false,
3194
- "type": "option"
3195
- },
3196
- "protocol-file": {
3197
- "description": "Read protocol from file",
3198
- "name": "protocol-file",
3251
+ "type": {
3252
+ "description": "Show only one kind of source",
3253
+ "name": "type",
3199
3254
  "hasDynamicHelp": false,
3200
3255
  "multiple": false,
3201
- "type": "option"
3202
- },
3203
- "tag": {
3204
- "description": "Tag label (repeatable, lowercase)",
3205
- "name": "tag",
3206
- "hasDynamicHelp": false,
3207
- "multiple": true,
3256
+ "options": [
3257
+ "doc",
3258
+ "thread"
3259
+ ],
3208
3260
  "type": "option"
3209
3261
  }
3210
3262
  },
3211
3263
  "hasDynamicHelp": false,
3212
3264
  "hiddenAliases": [],
3213
- "id": "team:create",
3265
+ "id": "face:sources",
3214
3266
  "pluginAlias": "faces-cli",
3215
3267
  "pluginName": "faces-cli",
3216
3268
  "pluginType": "core",
@@ -3220,20 +3272,14 @@
3220
3272
  "relativePath": [
3221
3273
  "dist",
3222
3274
  "commands",
3223
- "team",
3224
- "create.js"
3275
+ "face",
3276
+ "sources.js"
3225
3277
  ]
3226
3278
  },
3227
- "team:delete": {
3279
+ "face:stats": {
3228
3280
  "aliases": [],
3229
- "args": {
3230
- "team_id": {
3231
- "description": "Team ID",
3232
- "name": "team_id",
3233
- "required": true
3234
- }
3235
- },
3236
- "description": "Delete a team",
3281
+ "args": {},
3282
+ "description": "Compile and chat stats for all owned faces",
3237
3283
  "flags": {
3238
3284
  "json": {
3239
3285
  "description": "Format output as json.",
@@ -3265,17 +3311,11 @@
3265
3311
  "hasDynamicHelp": false,
3266
3312
  "multiple": false,
3267
3313
  "type": "option"
3268
- },
3269
- "yes": {
3270
- "description": "Skip confirmation",
3271
- "name": "yes",
3272
- "allowNo": false,
3273
- "type": "boolean"
3274
3314
  }
3275
3315
  },
3276
3316
  "hasDynamicHelp": false,
3277
3317
  "hiddenAliases": [],
3278
- "id": "team:delete",
3318
+ "id": "face:stats",
3279
3319
  "pluginAlias": "faces-cli",
3280
3320
  "pluginName": "faces-cli",
3281
3321
  "pluginType": "core",
@@ -3285,20 +3325,20 @@
3285
3325
  "relativePath": [
3286
3326
  "dist",
3287
3327
  "commands",
3288
- "team",
3289
- "delete.js"
3328
+ "face",
3329
+ "stats.js"
3290
3330
  ]
3291
3331
  },
3292
- "team:edit": {
3332
+ "face:teams": {
3293
3333
  "aliases": [],
3294
3334
  "args": {
3295
- "team_id": {
3296
- "description": "Team ID",
3297
- "name": "team_id",
3335
+ "alias": {
3336
+ "description": "Face alias",
3337
+ "name": "alias",
3298
3338
  "required": true
3299
3339
  }
3300
3340
  },
3301
- "description": "Edit a team",
3341
+ "description": "Set a face's team memberships (replaces all)",
3302
3342
  "flags": {
3303
3343
  "json": {
3304
3344
  "description": "Format output as json.",
@@ -3331,38 +3371,18 @@
3331
3371
  "multiple": false,
3332
3372
  "type": "option"
3333
3373
  },
3334
- "name": {
3335
- "description": "New team name",
3336
- "name": "name",
3337
- "hasDynamicHelp": false,
3338
- "multiple": false,
3339
- "type": "option"
3340
- },
3341
- "description": {
3342
- "description": "New description (max 1500 chars)",
3343
- "name": "description",
3344
- "hasDynamicHelp": false,
3345
- "multiple": false,
3346
- "type": "option"
3347
- },
3348
- "protocol": {
3349
- "description": "New protocol content",
3350
- "name": "protocol",
3351
- "hasDynamicHelp": false,
3352
- "multiple": false,
3353
- "type": "option"
3354
- },
3355
- "protocol-file": {
3356
- "description": "Read protocol from file",
3357
- "name": "protocol-file",
3374
+ "team": {
3375
+ "description": "Team ID (repeatable, replaces all memberships)",
3376
+ "name": "team",
3377
+ "required": true,
3358
3378
  "hasDynamicHelp": false,
3359
- "multiple": false,
3379
+ "multiple": true,
3360
3380
  "type": "option"
3361
3381
  }
3362
3382
  },
3363
3383
  "hasDynamicHelp": false,
3364
3384
  "hiddenAliases": [],
3365
- "id": "team:edit",
3385
+ "id": "face:teams",
3366
3386
  "pluginAlias": "faces-cli",
3367
3387
  "pluginName": "faces-cli",
3368
3388
  "pluginType": "core",
@@ -3372,20 +3392,23 @@
3372
3392
  "relativePath": [
3373
3393
  "dist",
3374
3394
  "commands",
3375
- "team",
3376
- "edit.js"
3395
+ "face",
3396
+ "teams.js"
3377
3397
  ]
3378
3398
  },
3379
- "team:get": {
3399
+ "face:unlock": {
3380
3400
  "aliases": [],
3381
3401
  "args": {
3382
- "team_id": {
3383
- "description": "Team ID",
3384
- "name": "team_id",
3402
+ "face_id": {
3403
+ "description": "Face alias",
3404
+ "name": "face_id",
3385
3405
  "required": true
3386
3406
  }
3387
3407
  },
3388
- "description": "Get a team by ID",
3408
+ "description": "Unlock a face (make it writable again). Thaws the face and everything it owns (documents, threads, voiceprint).",
3409
+ "examples": [
3410
+ "<%= config.bin %> <%= command.id %> socrates"
3411
+ ],
3389
3412
  "flags": {
3390
3413
  "json": {
3391
3414
  "description": "Format output as json.",
@@ -3421,7 +3444,7 @@
3421
3444
  },
3422
3445
  "hasDynamicHelp": false,
3423
3446
  "hiddenAliases": [],
3424
- "id": "team:get",
3447
+ "id": "face:unlock",
3425
3448
  "pluginAlias": "faces-cli",
3426
3449
  "pluginName": "faces-cli",
3427
3450
  "pluginType": "core",
@@ -3431,14 +3454,20 @@
3431
3454
  "relativePath": [
3432
3455
  "dist",
3433
3456
  "commands",
3434
- "team",
3435
- "get.js"
3457
+ "face",
3458
+ "unlock.js"
3436
3459
  ]
3437
3460
  },
3438
- "team:list": {
3461
+ "face:unpublish": {
3439
3462
  "aliases": [],
3440
- "args": {},
3441
- "description": "List your teams",
3463
+ "args": {
3464
+ "alias": {
3465
+ "description": "Face alias",
3466
+ "name": "alias",
3467
+ "required": true
3468
+ }
3469
+ },
3470
+ "description": "Stop publishing a face. Anyone it is individually shared with keeps their access — publishing is an override on top of sharing, not a replacement for it.",
3442
3471
  "flags": {
3443
3472
  "json": {
3444
3473
  "description": "Format output as json.",
@@ -3474,7 +3503,7 @@
3474
3503
  },
3475
3504
  "hasDynamicHelp": false,
3476
3505
  "hiddenAliases": [],
3477
- "id": "team:list",
3506
+ "id": "face:unpublish",
3478
3507
  "pluginAlias": "faces-cli",
3479
3508
  "pluginName": "faces-cli",
3480
3509
  "pluginType": "core",
@@ -3484,20 +3513,24 @@
3484
3513
  "relativePath": [
3485
3514
  "dist",
3486
3515
  "commands",
3487
- "team",
3488
- "list.js"
3516
+ "face",
3517
+ "unpublish.js"
3489
3518
  ]
3490
3519
  },
3491
- "team:members": {
3520
+ "face:unshare": {
3492
3521
  "aliases": [],
3493
3522
  "args": {
3494
- "team_id": {
3495
- "description": "Team ID",
3496
- "name": "team_id",
3523
+ "alias": {
3524
+ "description": "Face alias",
3525
+ "name": "alias",
3497
3526
  "required": true
3498
3527
  }
3499
3528
  },
3500
- "description": "List members of a team",
3529
+ "description": "Revoke access to a shared face. Takes effect immediately — there is no grace period.",
3530
+ "examples": [
3531
+ "<%= config.bin %> <%= command.id %> alice --from dana --yes",
3532
+ "<%= config.bin %> <%= command.id %> alice --all --yes"
3533
+ ],
3501
3534
  "flags": {
3502
3535
  "json": {
3503
3536
  "description": "Format output as json.",
@@ -3529,11 +3562,36 @@
3529
3562
  "hasDynamicHelp": false,
3530
3563
  "multiple": false,
3531
3564
  "type": "option"
3565
+ },
3566
+ "from": {
3567
+ "description": "Account to revoke (repeatable)",
3568
+ "exclusive": [
3569
+ "all"
3570
+ ],
3571
+ "name": "from",
3572
+ "hasDynamicHelp": false,
3573
+ "multiple": true,
3574
+ "type": "option"
3575
+ },
3576
+ "all": {
3577
+ "description": "Revoke everyone",
3578
+ "exclusive": [
3579
+ "from"
3580
+ ],
3581
+ "name": "all",
3582
+ "allowNo": false,
3583
+ "type": "boolean"
3584
+ },
3585
+ "yes": {
3586
+ "description": "Skip confirmation",
3587
+ "name": "yes",
3588
+ "allowNo": false,
3589
+ "type": "boolean"
3532
3590
  }
3533
3591
  },
3534
3592
  "hasDynamicHelp": false,
3535
3593
  "hiddenAliases": [],
3536
- "id": "team:members",
3594
+ "id": "face:unshare",
3537
3595
  "pluginAlias": "faces-cli",
3538
3596
  "pluginName": "faces-cli",
3539
3597
  "pluginType": "core",
@@ -3543,25 +3601,14 @@
3543
3601
  "relativePath": [
3544
3602
  "dist",
3545
3603
  "commands",
3546
- "team",
3547
- "members.js"
3604
+ "face",
3605
+ "unshare.js"
3548
3606
  ]
3549
3607
  },
3550
- "team:remove": {
3608
+ "keys:create": {
3551
3609
  "aliases": [],
3552
- "args": {
3553
- "team_id": {
3554
- "description": "Team ID",
3555
- "name": "team_id",
3556
- "required": true
3557
- },
3558
- "alias": {
3559
- "description": "Face alias to remove",
3560
- "name": "alias",
3561
- "required": true
3562
- }
3563
- },
3564
- "description": "Remove a face from a team",
3610
+ "args": {},
3611
+ "description": "Create a new API key (JWT required). The new key is saved to ~/.faces/config.json as api_key by default; pass --no-save to skip.",
3565
3612
  "flags": {
3566
3613
  "json": {
3567
3614
  "description": "Format output as json.",
@@ -3593,11 +3640,53 @@
3593
3640
  "hasDynamicHelp": false,
3594
3641
  "multiple": false,
3595
3642
  "type": "option"
3643
+ },
3644
+ "name": {
3645
+ "description": "Key name/label",
3646
+ "name": "name",
3647
+ "required": true,
3648
+ "hasDynamicHelp": false,
3649
+ "multiple": false,
3650
+ "type": "option"
3651
+ },
3652
+ "expires-days": {
3653
+ "description": "Expiry in days (omit for no expiry)",
3654
+ "name": "expires-days",
3655
+ "hasDynamicHelp": false,
3656
+ "multiple": false,
3657
+ "type": "option"
3658
+ },
3659
+ "budget": {
3660
+ "description": "Spend budget in USD",
3661
+ "name": "budget",
3662
+ "hasDynamicHelp": false,
3663
+ "multiple": false,
3664
+ "type": "option"
3665
+ },
3666
+ "face": {
3667
+ "description": "Allowed face alias (repeatable)",
3668
+ "name": "face",
3669
+ "hasDynamicHelp": false,
3670
+ "multiple": true,
3671
+ "type": "option"
3672
+ },
3673
+ "model": {
3674
+ "description": "Allowed model name (repeatable)",
3675
+ "name": "model",
3676
+ "hasDynamicHelp": false,
3677
+ "multiple": true,
3678
+ "type": "option"
3679
+ },
3680
+ "save": {
3681
+ "description": "Save the new key to ~/.faces/config.json as api_key (default: true; use --no-save to skip)",
3682
+ "name": "save",
3683
+ "allowNo": true,
3684
+ "type": "boolean"
3596
3685
  }
3597
3686
  },
3598
3687
  "hasDynamicHelp": false,
3599
3688
  "hiddenAliases": [],
3600
- "id": "team:remove",
3689
+ "id": "keys:create",
3601
3690
  "pluginAlias": "faces-cli",
3602
3691
  "pluginName": "faces-cli",
3603
3692
  "pluginType": "core",
@@ -3607,14 +3696,14 @@
3607
3696
  "relativePath": [
3608
3697
  "dist",
3609
3698
  "commands",
3610
- "team",
3611
- "remove.js"
3699
+ "keys",
3700
+ "create.js"
3612
3701
  ]
3613
3702
  },
3614
- "face:attributes": {
3703
+ "keys:list": {
3615
3704
  "aliases": [],
3616
3705
  "args": {},
3617
- "description": "List all supported attribute keys",
3706
+ "description": "List all API keys (JWT required)",
3618
3707
  "flags": {
3619
3708
  "json": {
3620
3709
  "description": "Format output as json.",
@@ -3650,7 +3739,7 @@
3650
3739
  },
3651
3740
  "hasDynamicHelp": false,
3652
3741
  "hiddenAliases": [],
3653
- "id": "face:attributes",
3742
+ "id": "keys:list",
3654
3743
  "pluginAlias": "faces-cli",
3655
3744
  "pluginName": "faces-cli",
3656
3745
  "pluginType": "core",
@@ -3660,14 +3749,20 @@
3660
3749
  "relativePath": [
3661
3750
  "dist",
3662
3751
  "commands",
3663
- "face",
3664
- "attributes.js"
3752
+ "keys",
3753
+ "list.js"
3665
3754
  ]
3666
3755
  },
3667
- "face:create": {
3756
+ "keys:revoke": {
3668
3757
  "aliases": [],
3669
- "args": {},
3670
- "description": "Create a new face",
3758
+ "args": {
3759
+ "key_id": {
3760
+ "description": "Key ID",
3761
+ "name": "key_id",
3762
+ "required": true
3763
+ }
3764
+ },
3765
+ "description": "Revoke an API key (JWT required)",
3671
3766
  "flags": {
3672
3767
  "json": {
3673
3768
  "description": "Format output as json.",
@@ -3700,85 +3795,16 @@
3700
3795
  "multiple": false,
3701
3796
  "type": "option"
3702
3797
  },
3703
- "name": {
3704
- "description": "Display name",
3705
- "name": "name",
3706
- "required": true,
3707
- "hasDynamicHelp": false,
3708
- "multiple": false,
3709
- "type": "option"
3710
- },
3711
- "alias": {
3712
- "description": "Unique alias slug",
3713
- "name": "alias",
3714
- "required": true,
3715
- "hasDynamicHelp": false,
3716
- "multiple": false,
3717
- "type": "option"
3718
- },
3719
- "description": {
3720
- "description": "Plain-text description / bio (max 1500 chars)",
3721
- "name": "description",
3722
- "hasDynamicHelp": false,
3723
- "multiple": false,
3724
- "type": "option"
3725
- },
3726
- "tag": {
3727
- "description": "Tag label (repeatable, lowercase)",
3728
- "name": "tag",
3729
- "hasDynamicHelp": false,
3730
- "multiple": true,
3731
- "type": "option"
3732
- },
3733
- "default-model": {
3734
- "description": "Default LLM for chat (e.g. gpt-4o-mini, claude-sonnet-4-6)",
3735
- "name": "default-model",
3736
- "hasDynamicHelp": false,
3737
- "multiple": false,
3738
- "type": "option"
3739
- },
3740
- "formula": {
3741
- "description": "Boolean formula over owned concrete face aliases (e.g. \"a | b\", \"(a | b) - c\"). Creates a composite face.",
3742
- "name": "formula",
3743
- "hasDynamicHelp": false,
3744
- "multiple": false,
3745
- "type": "option"
3746
- },
3747
- "attr": {
3748
- "description": "Attribute KEY=VALUE (repeatable)",
3749
- "name": "attr",
3750
- "hasDynamicHelp": false,
3751
- "multiple": true,
3752
- "type": "option"
3753
- },
3754
- "tool": {
3755
- "description": "Tool name to enable (repeatable)",
3756
- "name": "tool",
3757
- "hasDynamicHelp": false,
3758
- "multiple": true,
3759
- "type": "option"
3760
- },
3761
- "profile-addendum": {
3762
- "description": "Per-face system prompt, injected after the persona profile and before any per-request system prompt (max 100,000 chars).",
3763
- "name": "profile-addendum",
3764
- "hasDynamicHelp": false,
3765
- "multiple": false,
3766
- "type": "option"
3767
- },
3768
- "profile-addendum-file": {
3769
- "description": "Read the per-face system prompt from a file (alternative to --profile-addendum).",
3770
- "exclusive": [
3771
- "profile-addendum"
3772
- ],
3773
- "name": "profile-addendum-file",
3774
- "hasDynamicHelp": false,
3775
- "multiple": false,
3776
- "type": "option"
3798
+ "yes": {
3799
+ "description": "Skip confirmation",
3800
+ "name": "yes",
3801
+ "allowNo": false,
3802
+ "type": "boolean"
3777
3803
  }
3778
3804
  },
3779
3805
  "hasDynamicHelp": false,
3780
3806
  "hiddenAliases": [],
3781
- "id": "face:create",
3807
+ "id": "keys:revoke",
3782
3808
  "pluginAlias": "faces-cli",
3783
3809
  "pluginName": "faces-cli",
3784
3810
  "pluginType": "core",
@@ -3788,20 +3814,20 @@
3788
3814
  "relativePath": [
3789
3815
  "dist",
3790
3816
  "commands",
3791
- "face",
3792
- "create.js"
3817
+ "keys",
3818
+ "revoke.js"
3793
3819
  ]
3794
3820
  },
3795
- "face:delete": {
3821
+ "keys:update": {
3796
3822
  "aliases": [],
3797
3823
  "args": {
3798
- "face_id": {
3799
- "description": "Face alias",
3800
- "name": "face_id",
3824
+ "key_id": {
3825
+ "description": "Key ID",
3826
+ "name": "key_id",
3801
3827
  "required": true
3802
3828
  }
3803
3829
  },
3804
- "description": "Delete a face permanently",
3830
+ "description": "Update API key metadata (JWT required)",
3805
3831
  "flags": {
3806
3832
  "json": {
3807
3833
  "description": "Format output as json.",
@@ -3834,16 +3860,30 @@
3834
3860
  "multiple": false,
3835
3861
  "type": "option"
3836
3862
  },
3837
- "yes": {
3838
- "description": "Skip confirmation",
3839
- "name": "yes",
3863
+ "name": {
3864
+ "description": "New key name",
3865
+ "name": "name",
3866
+ "hasDynamicHelp": false,
3867
+ "multiple": false,
3868
+ "type": "option"
3869
+ },
3870
+ "budget": {
3871
+ "description": "New spend budget in USD",
3872
+ "name": "budget",
3873
+ "hasDynamicHelp": false,
3874
+ "multiple": false,
3875
+ "type": "option"
3876
+ },
3877
+ "reset-spent": {
3878
+ "description": "Reset spent amount to zero",
3879
+ "name": "reset-spent",
3840
3880
  "allowNo": false,
3841
3881
  "type": "boolean"
3842
3882
  }
3843
3883
  },
3844
3884
  "hasDynamicHelp": false,
3845
3885
  "hiddenAliases": [],
3846
- "id": "face:delete",
3886
+ "id": "keys:update",
3847
3887
  "pluginAlias": "faces-cli",
3848
3888
  "pluginName": "faces-cli",
3849
3889
  "pluginType": "core",
@@ -3853,14 +3893,24 @@
3853
3893
  "relativePath": [
3854
3894
  "dist",
3855
3895
  "commands",
3856
- "face",
3857
- "delete.js"
3896
+ "keys",
3897
+ "update.js"
3858
3898
  ]
3859
3899
  },
3860
- "face:diff": {
3900
+ "style:delete": {
3861
3901
  "aliases": [],
3862
- "args": {},
3863
- "description": "Compare owned faces pairwise across all centroid components",
3902
+ "args": {
3903
+ "alias": {
3904
+ "description": "Face alias",
3905
+ "name": "alias",
3906
+ "required": true
3907
+ }
3908
+ },
3909
+ "description": "Delete a face's captured style. The material it was learned from is kept, so the style can be captured again without re-uploading. This never deletes documents or threads: remove those with compile:doc:delete or compile:thread:delete.",
3910
+ "examples": [
3911
+ "<%= config.bin %> <%= command.id %> alice",
3912
+ "<%= config.bin %> <%= command.id %> alice --yes"
3913
+ ],
3864
3914
  "flags": {
3865
3915
  "json": {
3866
3916
  "description": "Format output as json.",
@@ -3893,18 +3943,16 @@
3893
3943
  "multiple": false,
3894
3944
  "type": "option"
3895
3945
  },
3896
- "face": {
3897
- "description": "Face alias to include (repeatable, min 2)",
3898
- "name": "face",
3899
- "required": true,
3900
- "hasDynamicHelp": false,
3901
- "multiple": true,
3902
- "type": "option"
3946
+ "yes": {
3947
+ "description": "Skip confirmation",
3948
+ "name": "yes",
3949
+ "allowNo": false,
3950
+ "type": "boolean"
3903
3951
  }
3904
3952
  },
3905
3953
  "hasDynamicHelp": false,
3906
3954
  "hiddenAliases": [],
3907
- "id": "face:diff",
3955
+ "id": "style:delete",
3908
3956
  "pluginAlias": "faces-cli",
3909
3957
  "pluginName": "faces-cli",
3910
3958
  "pluginType": "core",
@@ -3914,20 +3962,26 @@
3914
3962
  "relativePath": [
3915
3963
  "dist",
3916
3964
  "commands",
3917
- "face",
3918
- "diff.js"
3965
+ "style",
3966
+ "delete.js"
3919
3967
  ]
3920
3968
  },
3921
- "face:edit": {
3969
+ "style:make": {
3922
3970
  "aliases": [],
3923
3971
  "args": {
3924
- "face_id": {
3972
+ "alias": {
3925
3973
  "description": "Face alias",
3926
- "name": "face_id",
3974
+ "name": "alias",
3927
3975
  "required": true
3928
3976
  }
3929
3977
  },
3930
- "description": "Edit a face's metadata",
3978
+ "description": "Capture how a face writes, from its own material, and install it. This is style, not knowledge: compile teaches a face what it knows, style teaches it how it sounds. Name the sources to learn from with --source, or take everything ready with --all.",
3979
+ "examples": [
3980
+ "<%= config.bin %> <%= command.id %> alice --all",
3981
+ "<%= config.bin %> <%= command.id %> alice --source 1a2b3c4d --source 5e6f7a8b",
3982
+ "<%= config.bin %> <%= command.id %> alice --source 1a2b3c4d:essay",
3983
+ "<%= config.bin %> <%= command.id %> alice --all --medium essay --no-wait"
3984
+ ],
3931
3985
  "flags": {
3932
3986
  "json": {
3933
3987
  "description": "Format output as json.",
@@ -3952,94 +4006,78 @@
3952
4006
  "multiple": false,
3953
4007
  "type": "option"
3954
4008
  },
3955
- "api-key": {
3956
- "description": "API key",
3957
- "env": "FACES_API_KEY",
3958
- "name": "api-key",
3959
- "hasDynamicHelp": false,
3960
- "multiple": false,
3961
- "type": "option"
3962
- },
3963
- "name": {
3964
- "description": "New display name",
3965
- "name": "name",
3966
- "hasDynamicHelp": false,
3967
- "multiple": false,
3968
- "type": "option"
3969
- },
3970
- "description": {
3971
- "description": "Plain-text description / bio (max 1500 chars)",
3972
- "name": "description",
4009
+ "api-key": {
4010
+ "description": "API key",
4011
+ "env": "FACES_API_KEY",
4012
+ "name": "api-key",
3973
4013
  "hasDynamicHelp": false,
3974
4014
  "multiple": false,
3975
4015
  "type": "option"
3976
4016
  },
3977
- "tag": {
3978
- "description": "Replace all tags (repeatable, lowercase)",
3979
- "name": "tag",
4017
+ "source": {
4018
+ "description": "A document or thread to learn from, by id (repeatable). Append :<medium> to declare what it is, e.g. --source 1a2b3c4d:essay, when the source does not already say.",
4019
+ "name": "source",
3980
4020
  "hasDynamicHelp": false,
3981
4021
  "multiple": true,
3982
4022
  "type": "option"
3983
4023
  },
3984
- "default-model": {
3985
- "description": "Default LLM for chat (e.g. gpt-4o-mini, claude-sonnet-4-6)",
3986
- "name": "default-model",
4024
+ "all": {
4025
+ "description": "Use every source on the face that is ready. Anything skipped is listed.",
4026
+ "name": "all",
4027
+ "allowNo": false,
4028
+ "type": "boolean"
4029
+ },
4030
+ "medium": {
4031
+ "description": "Medium for selected sources that do not already declare one. It does not override a source that does. Each medium is analysed on its own, so an essay never teaches a rule about email.",
4032
+ "name": "medium",
3987
4033
  "hasDynamicHelp": false,
3988
4034
  "multiple": false,
3989
4035
  "type": "option"
3990
4036
  },
3991
- "formula": {
3992
- "description": "New boolean formula (synthetic faces only)",
3993
- "name": "formula",
4037
+ "model": {
4038
+ "description": "Analyst model (default: gpt-5.6-terra)",
4039
+ "name": "model",
3994
4040
  "hasDynamicHelp": false,
3995
4041
  "multiple": false,
3996
4042
  "type": "option"
3997
4043
  },
3998
- "attr": {
3999
- "description": "Update attribute KEY=VALUE (repeatable)",
4000
- "name": "attr",
4001
- "hasDynamicHelp": false,
4002
- "multiple": true,
4003
- "type": "option"
4044
+ "allow-paid": {
4045
+ "description": "Permit a build that bills. Without this a build is free or it does not run. Needed for any model outside the free tier, and to allow the paid route when a free quota is exhausted.",
4046
+ "name": "allow-paid",
4047
+ "allowNo": false,
4048
+ "type": "boolean"
4004
4049
  },
4005
- "tool": {
4006
- "description": "Tool names to set (replaces list, repeatable)",
4007
- "name": "tool",
4008
- "hasDynamicHelp": false,
4009
- "multiple": true,
4010
- "type": "option"
4050
+ "compile": {
4051
+ "description": "Compile any named source that is not compiled yet, before capturing style. On by default. --no-compile captures style from what is already compiled and never bills for compilation.",
4052
+ "name": "compile",
4053
+ "allowNo": true,
4054
+ "type": "boolean"
4011
4055
  },
4012
- "profile-addendum": {
4013
- "description": "Replace the per-face system prompt (max 100,000 chars).",
4014
- "name": "profile-addendum",
4056
+ "best-of": {
4057
+ "description": "Generate N candidates and keep the best (1-5, default 1)",
4058
+ "name": "best-of",
4015
4059
  "hasDynamicHelp": false,
4016
4060
  "multiple": false,
4017
4061
  "type": "option"
4018
4062
  },
4019
- "profile-addendum-file": {
4020
- "description": "Replace the per-face system prompt from a file.",
4021
- "exclusive": [
4022
- "profile-addendum"
4023
- ],
4024
- "name": "profile-addendum-file",
4063
+ "no-wait": {
4064
+ "description": "Start the build and return the job id without polling.",
4065
+ "name": "no-wait",
4066
+ "allowNo": false,
4067
+ "type": "boolean"
4068
+ },
4069
+ "timeout": {
4070
+ "description": "How long to wait, in seconds (default: 3600)",
4071
+ "name": "timeout",
4072
+ "default": 3600,
4025
4073
  "hasDynamicHelp": false,
4026
4074
  "multiple": false,
4027
4075
  "type": "option"
4028
- },
4029
- "clear-profile-addendum": {
4030
- "description": "Remove the per-face system prompt.",
4031
- "exclusive": [
4032
- "profile-addendum",
4033
- "profile-addendum-file"
4034
- ],
4035
- "name": "clear-profile-addendum",
4036
- "allowNo": false,
4037
- "type": "boolean"
4038
4076
  }
4039
4077
  },
4040
4078
  "hasDynamicHelp": false,
4041
4079
  "hiddenAliases": [],
4042
- "id": "face:edit",
4080
+ "id": "style:make",
4043
4081
  "pluginAlias": "faces-cli",
4044
4082
  "pluginName": "faces-cli",
4045
4083
  "pluginType": "core",
@@ -4049,20 +4087,24 @@
4049
4087
  "relativePath": [
4050
4088
  "dist",
4051
4089
  "commands",
4052
- "face",
4053
- "edit.js"
4090
+ "style",
4091
+ "make.js"
4054
4092
  ]
4055
4093
  },
4056
- "face:get": {
4094
+ "style:revert": {
4057
4095
  "aliases": [],
4058
4096
  "args": {
4059
- "face_id": {
4097
+ "alias": {
4060
4098
  "description": "Face alias",
4061
- "name": "face_id",
4099
+ "name": "alias",
4062
4100
  "required": true
4063
4101
  }
4064
4102
  },
4065
- "description": "Get details for a face, by alias or owner:alias. A published or shared face is reachable under the same owner:alias address chat uses; it is shown with a note that you do not own it.",
4103
+ "description": "Go back to the style a face had before the last style:make. Two versions are kept per medium, so this is a toggle: running it again returns to where you started. A face holds one style per medium, so name which one with --medium when it has more than one. It changes how the face writes immediately, so it asks first.",
4104
+ "examples": [
4105
+ "<%= config.bin %> <%= command.id %> alice --yes",
4106
+ "<%= config.bin %> <%= command.id %> alice --medium email --yes"
4107
+ ],
4066
4108
  "flags": {
4067
4109
  "json": {
4068
4110
  "description": "Format output as json.",
@@ -4095,23 +4137,23 @@
4095
4137
  "multiple": false,
4096
4138
  "type": "option"
4097
4139
  },
4098
- "include": {
4099
- "description": "Include extra fields: tags, teams (comma-separated)",
4100
- "name": "include",
4140
+ "medium": {
4141
+ "description": "Which style to step back, when the face has more than one. See faces style:versions <alias>.",
4142
+ "name": "medium",
4101
4143
  "hasDynamicHelp": false,
4102
4144
  "multiple": false,
4103
4145
  "type": "option"
4104
4146
  },
4105
- "full": {
4106
- "description": "Print the full profile_addendum instead of a truncated preview",
4107
- "name": "full",
4147
+ "yes": {
4148
+ "description": "Skip confirmation",
4149
+ "name": "yes",
4108
4150
  "allowNo": false,
4109
4151
  "type": "boolean"
4110
4152
  }
4111
4153
  },
4112
4154
  "hasDynamicHelp": false,
4113
4155
  "hiddenAliases": [],
4114
- "id": "face:get",
4156
+ "id": "style:revert",
4115
4157
  "pluginAlias": "faces-cli",
4116
4158
  "pluginName": "faces-cli",
4117
4159
  "pluginType": "core",
@@ -4121,14 +4163,25 @@
4121
4163
  "relativePath": [
4122
4164
  "dist",
4123
4165
  "commands",
4124
- "face",
4125
- "get.js"
4166
+ "style",
4167
+ "revert.js"
4126
4168
  ]
4127
4169
  },
4128
- "face:list": {
4170
+ "style:status": {
4129
4171
  "aliases": [],
4130
- "args": {},
4131
- "description": "List faces. By default lists owned faces; use --public to include published faces from other accounts.",
4172
+ "args": {
4173
+ "job_id": {
4174
+ "description": "Build job id",
4175
+ "name": "job_id",
4176
+ "required": false
4177
+ }
4178
+ },
4179
+ "description": "Read a style build. Give a job id for one build, or --face to list a face's recent builds. Listing is how you find a job id you no longer have.",
4180
+ "examples": [
4181
+ "<%= config.bin %> <%= command.id %> 7a8b9c0d",
4182
+ "<%= config.bin %> <%= command.id %> --face alice",
4183
+ "<%= config.bin %> <%= command.id %> 7a8b9c0d --wait"
4184
+ ],
4132
4185
  "flags": {
4133
4186
  "json": {
4134
4187
  "description": "Format output as json.",
@@ -4161,63 +4214,39 @@
4161
4214
  "multiple": false,
4162
4215
  "type": "option"
4163
4216
  },
4164
- "tag": {
4165
- "description": "Filter by tag (repeatable, AND logic)",
4166
- "name": "tag",
4167
- "hasDynamicHelp": false,
4168
- "multiple": true,
4169
- "type": "option"
4170
- },
4171
- "team": {
4172
- "description": "Filter by team ID (repeatable, OR logic)",
4173
- "name": "team",
4217
+ "face": {
4218
+ "description": "List recent builds for this face instead of reading one job",
4219
+ "name": "face",
4174
4220
  "hasDynamicHelp": false,
4175
- "multiple": true,
4221
+ "multiple": false,
4176
4222
  "type": "option"
4177
4223
  },
4178
- "include": {
4179
- "description": "Include extra fields: tags, teams (comma-separated)",
4180
- "name": "include",
4224
+ "limit": {
4225
+ "description": "How many builds to list with --face (default: 10)",
4226
+ "name": "limit",
4227
+ "default": 10,
4181
4228
  "hasDynamicHelp": false,
4182
4229
  "multiple": false,
4183
4230
  "type": "option"
4184
4231
  },
4185
- "public": {
4186
- "description": "Include published faces from other accounts (open to everybody)",
4187
- "name": "public",
4188
- "allowNo": false,
4189
- "type": "boolean"
4190
- },
4191
- "shared": {
4192
- "description": "Include faces other accounts have shared with YOU in particular",
4193
- "name": "shared",
4194
- "allowNo": false,
4195
- "type": "boolean"
4196
- },
4197
- "system": {
4198
- "description": "Show only the curated system faces (published faces owned by 'head')",
4199
- "name": "system",
4232
+ "wait": {
4233
+ "description": "Block until the job finishes",
4234
+ "name": "wait",
4200
4235
  "allowNo": false,
4201
4236
  "type": "boolean"
4202
4237
  },
4203
- "from-users": {
4204
- "description": "Only published faces from these owners (repeatable/comma-separated)",
4205
- "name": "from-users",
4206
- "hasDynamicHelp": false,
4207
- "multiple": true,
4208
- "type": "option"
4209
- },
4210
- "not-from-users": {
4211
- "description": "Exclude published faces from these owners (repeatable/comma-separated)",
4212
- "name": "not-from-users",
4238
+ "timeout": {
4239
+ "description": "How long to wait with --wait, in seconds (default: 3600)",
4240
+ "name": "timeout",
4241
+ "default": 3600,
4213
4242
  "hasDynamicHelp": false,
4214
- "multiple": true,
4243
+ "multiple": false,
4215
4244
  "type": "option"
4216
4245
  }
4217
4246
  },
4218
4247
  "hasDynamicHelp": false,
4219
4248
  "hiddenAliases": [],
4220
- "id": "face:list",
4249
+ "id": "style:status",
4221
4250
  "pluginAlias": "faces-cli",
4222
4251
  "pluginName": "faces-cli",
4223
4252
  "pluginType": "core",
@@ -4227,22 +4256,29 @@
4227
4256
  "relativePath": [
4228
4257
  "dist",
4229
4258
  "commands",
4230
- "face",
4231
- "list.js"
4259
+ "style",
4260
+ "status.js"
4232
4261
  ]
4233
4262
  },
4234
- "face:lock": {
4263
+ "style:upload": {
4235
4264
  "aliases": [],
4236
4265
  "args": {
4237
- "face_id": {
4266
+ "alias": {
4238
4267
  "description": "Face alias",
4239
- "name": "face_id",
4268
+ "name": "alias",
4269
+ "required": true
4270
+ },
4271
+ "file": {
4272
+ "description": "Corpus file",
4273
+ "name": "file",
4240
4274
  "required": true
4241
4275
  }
4242
4276
  },
4243
- "description": "Lock a face (read-only). A locked face still reads and chats normally, but it and everything it owns (documents, threads, voiceprint) cannot be changed until unlocked.",
4277
+ "description": "Load a corpus of a person's own writing (a mail export, a message archive) as source material for style capture. This only stores the material: nothing is compiled and nothing is billed. Capture the style afterwards with style:make.",
4244
4278
  "examples": [
4245
- "<%= config.bin %> <%= command.id %> socrates"
4279
+ "<%= config.bin %> <%= command.id %> alice ./mail.jsonl",
4280
+ "<%= config.bin %> <%= command.id %> alice ./thread.json --type thread_json",
4281
+ "<%= config.bin %> <%= command.id %> alice ./mail.jsonl --messages-per-room 100 --strict"
4246
4282
  ],
4247
4283
  "flags": {
4248
4284
  "json": {
@@ -4275,11 +4311,37 @@
4275
4311
  "hasDynamicHelp": false,
4276
4312
  "multiple": false,
4277
4313
  "type": "option"
4314
+ },
4315
+ "type": {
4316
+ "description": "email_jsonl: one message per line, split across several rooms. thread_json: a JSON array that becomes a single room.",
4317
+ "name": "type",
4318
+ "default": "email_jsonl",
4319
+ "hasDynamicHelp": false,
4320
+ "multiple": false,
4321
+ "options": [
4322
+ "email_jsonl",
4323
+ "thread_json"
4324
+ ],
4325
+ "type": "option"
4326
+ },
4327
+ "messages-per-room": {
4328
+ "description": "How many messages per room when the type is email_jsonl (1-1000, default: 50)",
4329
+ "name": "messages-per-room",
4330
+ "default": 50,
4331
+ "hasDynamicHelp": false,
4332
+ "multiple": false,
4333
+ "type": "option"
4334
+ },
4335
+ "strict": {
4336
+ "description": "Reject the whole upload if any message is invalid. By default invalid messages are skipped and reported, because a corpus is statistical and a few bad lines are not worth losing the rest.",
4337
+ "name": "strict",
4338
+ "allowNo": false,
4339
+ "type": "boolean"
4278
4340
  }
4279
4341
  },
4280
4342
  "hasDynamicHelp": false,
4281
4343
  "hiddenAliases": [],
4282
- "id": "face:lock",
4344
+ "id": "style:upload",
4283
4345
  "pluginAlias": "faces-cli",
4284
4346
  "pluginName": "faces-cli",
4285
4347
  "pluginType": "core",
@@ -4289,20 +4351,24 @@
4289
4351
  "relativePath": [
4290
4352
  "dist",
4291
4353
  "commands",
4292
- "face",
4293
- "lock.js"
4354
+ "style",
4355
+ "upload.js"
4294
4356
  ]
4295
4357
  },
4296
- "face:neighbors": {
4358
+ "style:versions": {
4297
4359
  "aliases": [],
4298
4360
  "args": {
4299
- "face_id": {
4361
+ "alias": {
4300
4362
  "description": "Face alias",
4301
- "name": "face_id",
4363
+ "name": "alias",
4302
4364
  "required": true
4303
4365
  }
4304
4366
  },
4305
- "description": "Find the most similar or dissimilar owned faces to a given face",
4367
+ "description": "List the styles captured for a face, and which one it writes in now. A face holds one style per medium, so more than one can be in use at once: an email style and an essay style are separate and do not replace each other. Two versions are kept per medium, which is what style:revert has to go back to.",
4368
+ "examples": [
4369
+ "<%= config.bin %> <%= command.id %> alice",
4370
+ "<%= config.bin %> <%= command.id %> alice --json"
4371
+ ],
4306
4372
  "flags": {
4307
4373
  "json": {
4308
4374
  "description": "Format output as json.",
@@ -4334,39 +4400,11 @@
4334
4400
  "hasDynamicHelp": false,
4335
4401
  "multiple": false,
4336
4402
  "type": "option"
4337
- },
4338
- "k": {
4339
- "description": "Number of results (1–20)",
4340
- "name": "k",
4341
- "default": 5,
4342
- "hasDynamicHelp": false,
4343
- "multiple": false,
4344
- "type": "option"
4345
- },
4346
- "component": {
4347
- "description": "What to rank on: `face` for overall similarity, or a component position such as 1. Which positions are comparable varies; the API names them if you pick a wrong one.",
4348
- "name": "component",
4349
- "default": "face",
4350
- "hasDynamicHelp": false,
4351
- "multiple": false,
4352
- "type": "option"
4353
- },
4354
- "direction": {
4355
- "description": "nearest (most similar) or furthest (most dissimilar)",
4356
- "name": "direction",
4357
- "default": "nearest",
4358
- "hasDynamicHelp": false,
4359
- "multiple": false,
4360
- "options": [
4361
- "nearest",
4362
- "furthest"
4363
- ],
4364
- "type": "option"
4365
4403
  }
4366
4404
  },
4367
4405
  "hasDynamicHelp": false,
4368
4406
  "hiddenAliases": [],
4369
- "id": "face:neighbors",
4407
+ "id": "style:versions",
4370
4408
  "pluginAlias": "faces-cli",
4371
4409
  "pluginName": "faces-cli",
4372
4410
  "pluginType": "core",
@@ -4376,22 +4414,23 @@
4376
4414
  "relativePath": [
4377
4415
  "dist",
4378
4416
  "commands",
4379
- "face",
4380
- "neighbors.js"
4417
+ "style",
4418
+ "versions.js"
4381
4419
  ]
4382
4420
  },
4383
- "face:publish": {
4421
+ "team:add": {
4384
4422
  "aliases": [],
4385
4423
  "args": {
4386
- "alias": {
4387
- "description": "Face alias",
4388
- "name": "alias",
4424
+ "team_id": {
4425
+ "description": "Team ID",
4426
+ "name": "team_id",
4389
4427
  "required": true
4390
4428
  }
4391
4429
  },
4392
- "description": "Publish a face so EVERY account can chat with it. This is a global override: while it is on, everyone can reach the face regardless of who it is shared with. You still pay only to compile it; whoever chats pays for their own inference.",
4430
+ "description": "Add face(s) to a team. Any face this account can reach may join: your own, a published one, or one shared with you. Name someone else's as owner:alias, the same address chat uses.",
4393
4431
  "examples": [
4394
- "<%= config.bin %> <%= command.id %> alice --yes"
4432
+ "<%= config.bin %> <%= command.id %> TEAM_ID --face alice --face bob",
4433
+ "<%= config.bin %> <%= command.id %> TEAM_ID --face head:socrates"
4395
4434
  ],
4396
4435
  "flags": {
4397
4436
  "json": {
@@ -4425,16 +4464,18 @@
4425
4464
  "multiple": false,
4426
4465
  "type": "option"
4427
4466
  },
4428
- "yes": {
4429
- "description": "Skip confirmation",
4430
- "name": "yes",
4431
- "allowNo": false,
4432
- "type": "boolean"
4467
+ "face": {
4468
+ "description": "Face alias to add (repeatable)",
4469
+ "name": "face",
4470
+ "required": true,
4471
+ "hasDynamicHelp": false,
4472
+ "multiple": true,
4473
+ "type": "option"
4433
4474
  }
4434
4475
  },
4435
4476
  "hasDynamicHelp": false,
4436
4477
  "hiddenAliases": [],
4437
- "id": "face:publish",
4478
+ "id": "team:add",
4438
4479
  "pluginAlias": "faces-cli",
4439
4480
  "pluginName": "faces-cli",
4440
4481
  "pluginType": "core",
@@ -4444,26 +4485,14 @@
4444
4485
  "relativePath": [
4445
4486
  "dist",
4446
4487
  "commands",
4447
- "face",
4448
- "publish.js"
4488
+ "team",
4489
+ "add.js"
4449
4490
  ]
4450
4491
  },
4451
- "face:share": {
4492
+ "team:create": {
4452
4493
  "aliases": [],
4453
- "args": {
4454
- "alias": {
4455
- "description": "Face alias",
4456
- "name": "alias",
4457
- "required": true
4458
- }
4459
- },
4460
- "description": "Share a face so named accounts can chat with it. Sharing grants chat and nothing else: no reading its documents, no compiling, no re-sharing, and never its profile addendum. --add keeps the current list; --with replaces it.",
4461
- "examples": [
4462
- "<%= config.bin %> <%= command.id %> alice --list",
4463
- "<%= config.bin %> <%= command.id %> alice --add dana",
4464
- "<%= config.bin %> <%= command.id %> alice --with dana --with sam@example.com",
4465
- "<%= config.bin %> <%= command.id %> alice --none --yes"
4466
- ],
4494
+ "args": {},
4495
+ "description": "Create a new team",
4467
4496
  "flags": {
4468
4497
  "json": {
4469
4498
  "description": "Format output as json.",
@@ -4496,54 +4525,46 @@
4496
4525
  "multiple": false,
4497
4526
  "type": "option"
4498
4527
  },
4499
- "list": {
4500
- "description": "Show who the face is shared with, and change nothing",
4501
- "name": "list",
4502
- "allowNo": false,
4503
- "type": "boolean"
4528
+ "name": {
4529
+ "description": "Team name",
4530
+ "name": "name",
4531
+ "required": true,
4532
+ "hasDynamicHelp": false,
4533
+ "multiple": false,
4534
+ "type": "option"
4504
4535
  },
4505
- "add": {
4506
- "description": "Add an account, keeping everyone already on the list — username or email (repeatable)",
4507
- "exclusive": [
4508
- "with",
4509
- "none"
4510
- ],
4511
- "name": "add",
4536
+ "description": {
4537
+ "description": "Plain-text team description (max 1500 chars)",
4538
+ "name": "description",
4512
4539
  "hasDynamicHelp": false,
4513
- "multiple": true,
4540
+ "multiple": false,
4514
4541
  "type": "option"
4515
4542
  },
4516
- "with": {
4517
- "description": "Set the list to exactly these accounts, dropping anyone else (repeatable)",
4518
- "exclusive": [
4519
- "add",
4520
- "none"
4521
- ],
4522
- "name": "with",
4543
+ "protocol": {
4544
+ "description": "Protocol content (mermaid diagram or markdown, max 1000 words)",
4545
+ "name": "protocol",
4523
4546
  "hasDynamicHelp": false,
4524
- "multiple": true,
4547
+ "multiple": false,
4525
4548
  "type": "option"
4526
4549
  },
4527
- "none": {
4528
- "description": "Revoke everyone",
4529
- "exclusive": [
4530
- "add",
4531
- "with"
4532
- ],
4533
- "name": "none",
4534
- "allowNo": false,
4535
- "type": "boolean"
4550
+ "protocol-file": {
4551
+ "description": "Read protocol from file",
4552
+ "name": "protocol-file",
4553
+ "hasDynamicHelp": false,
4554
+ "multiple": false,
4555
+ "type": "option"
4536
4556
  },
4537
- "yes": {
4538
- "description": "Skip the confirmation shown when someone would lose access",
4539
- "name": "yes",
4540
- "allowNo": false,
4541
- "type": "boolean"
4557
+ "tag": {
4558
+ "description": "Tag label (repeatable, lowercase)",
4559
+ "name": "tag",
4560
+ "hasDynamicHelp": false,
4561
+ "multiple": true,
4562
+ "type": "option"
4542
4563
  }
4543
4564
  },
4544
4565
  "hasDynamicHelp": false,
4545
4566
  "hiddenAliases": [],
4546
- "id": "face:share",
4567
+ "id": "team:create",
4547
4568
  "pluginAlias": "faces-cli",
4548
4569
  "pluginName": "faces-cli",
4549
4570
  "pluginType": "core",
@@ -4553,25 +4574,20 @@
4553
4574
  "relativePath": [
4554
4575
  "dist",
4555
4576
  "commands",
4556
- "face",
4557
- "share.js"
4577
+ "team",
4578
+ "create.js"
4558
4579
  ]
4559
4580
  },
4560
- "face:sources": {
4581
+ "team:delete": {
4561
4582
  "aliases": [],
4562
4583
  "args": {
4563
- "alias": {
4564
- "description": "Face alias",
4565
- "name": "alias",
4584
+ "team_id": {
4585
+ "description": "Team ID",
4586
+ "name": "team_id",
4566
4587
  "required": true
4567
4588
  }
4568
4589
  },
4569
- "description": "List every source compiled into a face: documents and threads together, one row each. Exits 4 if the face does not exist, which is a different answer from a face that has no sources. Content is never printed; read a single source with compile:doc:get or compile:thread:get.",
4570
- "examples": [
4571
- "<%= config.bin %> <%= command.id %> alice",
4572
- "<%= config.bin %> <%= command.id %> alice --type thread",
4573
- "<%= config.bin %> <%= command.id %> alice --json"
4574
- ],
4590
+ "description": "Delete a team",
4575
4591
  "flags": {
4576
4592
  "json": {
4577
4593
  "description": "Format output as json.",
@@ -4604,21 +4620,16 @@
4604
4620
  "multiple": false,
4605
4621
  "type": "option"
4606
4622
  },
4607
- "type": {
4608
- "description": "Show only one kind of source",
4609
- "name": "type",
4610
- "hasDynamicHelp": false,
4611
- "multiple": false,
4612
- "options": [
4613
- "doc",
4614
- "thread"
4615
- ],
4616
- "type": "option"
4623
+ "yes": {
4624
+ "description": "Skip confirmation",
4625
+ "name": "yes",
4626
+ "allowNo": false,
4627
+ "type": "boolean"
4617
4628
  }
4618
4629
  },
4619
4630
  "hasDynamicHelp": false,
4620
4631
  "hiddenAliases": [],
4621
- "id": "face:sources",
4632
+ "id": "team:delete",
4622
4633
  "pluginAlias": "faces-cli",
4623
4634
  "pluginName": "faces-cli",
4624
4635
  "pluginType": "core",
@@ -4628,14 +4639,20 @@
4628
4639
  "relativePath": [
4629
4640
  "dist",
4630
4641
  "commands",
4631
- "face",
4632
- "sources.js"
4642
+ "team",
4643
+ "delete.js"
4633
4644
  ]
4634
4645
  },
4635
- "face:stats": {
4646
+ "team:edit": {
4636
4647
  "aliases": [],
4637
- "args": {},
4638
- "description": "Compile and chat stats for all owned faces",
4648
+ "args": {
4649
+ "team_id": {
4650
+ "description": "Team ID",
4651
+ "name": "team_id",
4652
+ "required": true
4653
+ }
4654
+ },
4655
+ "description": "Edit a team",
4639
4656
  "flags": {
4640
4657
  "json": {
4641
4658
  "description": "Format output as json.",
@@ -4667,11 +4684,39 @@
4667
4684
  "hasDynamicHelp": false,
4668
4685
  "multiple": false,
4669
4686
  "type": "option"
4687
+ },
4688
+ "name": {
4689
+ "description": "New team name",
4690
+ "name": "name",
4691
+ "hasDynamicHelp": false,
4692
+ "multiple": false,
4693
+ "type": "option"
4694
+ },
4695
+ "description": {
4696
+ "description": "New description (max 1500 chars)",
4697
+ "name": "description",
4698
+ "hasDynamicHelp": false,
4699
+ "multiple": false,
4700
+ "type": "option"
4701
+ },
4702
+ "protocol": {
4703
+ "description": "New protocol content",
4704
+ "name": "protocol",
4705
+ "hasDynamicHelp": false,
4706
+ "multiple": false,
4707
+ "type": "option"
4708
+ },
4709
+ "protocol-file": {
4710
+ "description": "Read protocol from file",
4711
+ "name": "protocol-file",
4712
+ "hasDynamicHelp": false,
4713
+ "multiple": false,
4714
+ "type": "option"
4670
4715
  }
4671
4716
  },
4672
4717
  "hasDynamicHelp": false,
4673
4718
  "hiddenAliases": [],
4674
- "id": "face:stats",
4719
+ "id": "team:edit",
4675
4720
  "pluginAlias": "faces-cli",
4676
4721
  "pluginName": "faces-cli",
4677
4722
  "pluginType": "core",
@@ -4681,20 +4726,20 @@
4681
4726
  "relativePath": [
4682
4727
  "dist",
4683
4728
  "commands",
4684
- "face",
4685
- "stats.js"
4729
+ "team",
4730
+ "edit.js"
4686
4731
  ]
4687
4732
  },
4688
- "face:teams": {
4733
+ "team:get": {
4689
4734
  "aliases": [],
4690
4735
  "args": {
4691
- "alias": {
4692
- "description": "Face alias",
4693
- "name": "alias",
4736
+ "team_id": {
4737
+ "description": "Team ID",
4738
+ "name": "team_id",
4694
4739
  "required": true
4695
4740
  }
4696
4741
  },
4697
- "description": "Set a face's team memberships (replaces all)",
4742
+ "description": "Get a team by ID",
4698
4743
  "flags": {
4699
4744
  "json": {
4700
4745
  "description": "Format output as json.",
@@ -4719,26 +4764,18 @@
4719
4764
  "multiple": false,
4720
4765
  "type": "option"
4721
4766
  },
4722
- "api-key": {
4723
- "description": "API key",
4724
- "env": "FACES_API_KEY",
4725
- "name": "api-key",
4726
- "hasDynamicHelp": false,
4727
- "multiple": false,
4728
- "type": "option"
4729
- },
4730
- "team": {
4731
- "description": "Team ID (repeatable, replaces all memberships)",
4732
- "name": "team",
4733
- "required": true,
4767
+ "api-key": {
4768
+ "description": "API key",
4769
+ "env": "FACES_API_KEY",
4770
+ "name": "api-key",
4734
4771
  "hasDynamicHelp": false,
4735
- "multiple": true,
4772
+ "multiple": false,
4736
4773
  "type": "option"
4737
4774
  }
4738
4775
  },
4739
4776
  "hasDynamicHelp": false,
4740
4777
  "hiddenAliases": [],
4741
- "id": "face:teams",
4778
+ "id": "team:get",
4742
4779
  "pluginAlias": "faces-cli",
4743
4780
  "pluginName": "faces-cli",
4744
4781
  "pluginType": "core",
@@ -4748,23 +4785,14 @@
4748
4785
  "relativePath": [
4749
4786
  "dist",
4750
4787
  "commands",
4751
- "face",
4752
- "teams.js"
4788
+ "team",
4789
+ "get.js"
4753
4790
  ]
4754
4791
  },
4755
- "face:unlock": {
4792
+ "team:list": {
4756
4793
  "aliases": [],
4757
- "args": {
4758
- "face_id": {
4759
- "description": "Face alias",
4760
- "name": "face_id",
4761
- "required": true
4762
- }
4763
- },
4764
- "description": "Unlock a face (make it writable again). Thaws the face and everything it owns (documents, threads, voiceprint).",
4765
- "examples": [
4766
- "<%= config.bin %> <%= command.id %> socrates"
4767
- ],
4794
+ "args": {},
4795
+ "description": "List your teams",
4768
4796
  "flags": {
4769
4797
  "json": {
4770
4798
  "description": "Format output as json.",
@@ -4800,7 +4828,7 @@
4800
4828
  },
4801
4829
  "hasDynamicHelp": false,
4802
4830
  "hiddenAliases": [],
4803
- "id": "face:unlock",
4831
+ "id": "team:list",
4804
4832
  "pluginAlias": "faces-cli",
4805
4833
  "pluginName": "faces-cli",
4806
4834
  "pluginType": "core",
@@ -4810,20 +4838,24 @@
4810
4838
  "relativePath": [
4811
4839
  "dist",
4812
4840
  "commands",
4813
- "face",
4814
- "unlock.js"
4841
+ "team",
4842
+ "list.js"
4815
4843
  ]
4816
4844
  },
4817
- "face:unpublish": {
4845
+ "team:members": {
4818
4846
  "aliases": [],
4819
4847
  "args": {
4820
- "alias": {
4821
- "description": "Face alias",
4822
- "name": "alias",
4848
+ "team_id": {
4849
+ "description": "Team ID",
4850
+ "name": "team_id",
4823
4851
  "required": true
4824
4852
  }
4825
4853
  },
4826
- "description": "Stop publishing a face. Anyone it is individually shared with keeps their access publishing is an override on top of sharing, not a replacement for it.",
4854
+ "description": "List members of a team. A member you do not own can stop being reachable if its owner revokes access or deletes it; those are listed with the reason rather than dropped.",
4855
+ "examples": [
4856
+ "<%= config.bin %> <%= command.id %> TEAM_ID",
4857
+ "<%= config.bin %> <%= command.id %> TEAM_ID --json"
4858
+ ],
4827
4859
  "flags": {
4828
4860
  "json": {
4829
4861
  "description": "Format output as json.",
@@ -4859,7 +4891,7 @@
4859
4891
  },
4860
4892
  "hasDynamicHelp": false,
4861
4893
  "hiddenAliases": [],
4862
- "id": "face:unpublish",
4894
+ "id": "team:members",
4863
4895
  "pluginAlias": "faces-cli",
4864
4896
  "pluginName": "faces-cli",
4865
4897
  "pluginType": "core",
@@ -4869,24 +4901,25 @@
4869
4901
  "relativePath": [
4870
4902
  "dist",
4871
4903
  "commands",
4872
- "face",
4873
- "unpublish.js"
4904
+ "team",
4905
+ "members.js"
4874
4906
  ]
4875
4907
  },
4876
- "face:unshare": {
4908
+ "team:remove": {
4877
4909
  "aliases": [],
4878
4910
  "args": {
4911
+ "team_id": {
4912
+ "description": "Team ID",
4913
+ "name": "team_id",
4914
+ "required": true
4915
+ },
4879
4916
  "alias": {
4880
- "description": "Face alias",
4917
+ "description": "Face alias to remove",
4881
4918
  "name": "alias",
4882
4919
  "required": true
4883
4920
  }
4884
4921
  },
4885
- "description": "Revoke access to a shared face. Takes effect immediately — there is no grace period.",
4886
- "examples": [
4887
- "<%= config.bin %> <%= command.id %> alice --from dana --yes",
4888
- "<%= config.bin %> <%= command.id %> alice --all --yes"
4889
- ],
4922
+ "description": "Remove a face from a team",
4890
4923
  "flags": {
4891
4924
  "json": {
4892
4925
  "description": "Format output as json.",
@@ -4918,36 +4951,11 @@
4918
4951
  "hasDynamicHelp": false,
4919
4952
  "multiple": false,
4920
4953
  "type": "option"
4921
- },
4922
- "from": {
4923
- "description": "Account to revoke (repeatable)",
4924
- "exclusive": [
4925
- "all"
4926
- ],
4927
- "name": "from",
4928
- "hasDynamicHelp": false,
4929
- "multiple": true,
4930
- "type": "option"
4931
- },
4932
- "all": {
4933
- "description": "Revoke everyone",
4934
- "exclusive": [
4935
- "from"
4936
- ],
4937
- "name": "all",
4938
- "allowNo": false,
4939
- "type": "boolean"
4940
- },
4941
- "yes": {
4942
- "description": "Skip confirmation",
4943
- "name": "yes",
4944
- "allowNo": false,
4945
- "type": "boolean"
4946
4954
  }
4947
4955
  },
4948
4956
  "hasDynamicHelp": false,
4949
4957
  "hiddenAliases": [],
4950
- "id": "face:unshare",
4958
+ "id": "team:remove",
4951
4959
  "pluginAlias": "faces-cli",
4952
4960
  "pluginName": "faces-cli",
4953
4961
  "pluginType": "core",
@@ -4957,8 +4965,8 @@
4957
4965
  "relativePath": [
4958
4966
  "dist",
4959
4967
  "commands",
4960
- "face",
4961
- "unshare.js"
4968
+ "team",
4969
+ "remove.js"
4962
4970
  ]
4963
4971
  },
4964
4972
  "billing:subscription:activate": {
@@ -6542,16 +6550,16 @@
6542
6550
  "sync.js"
6543
6551
  ]
6544
6552
  },
6545
- "team:tag:add": {
6553
+ "face:tag:add": {
6546
6554
  "aliases": [],
6547
6555
  "args": {
6548
- "team_id": {
6549
- "description": "Team ID",
6550
- "name": "team_id",
6556
+ "alias": {
6557
+ "description": "Face alias",
6558
+ "name": "alias",
6551
6559
  "required": true
6552
6560
  }
6553
6561
  },
6554
- "description": "Add tags to a team (appends, idempotent)",
6562
+ "description": "Add tags to a face (appends, idempotent)",
6555
6563
  "flags": {
6556
6564
  "json": {
6557
6565
  "description": "Format output as json.",
@@ -6595,7 +6603,7 @@
6595
6603
  },
6596
6604
  "hasDynamicHelp": false,
6597
6605
  "hiddenAliases": [],
6598
- "id": "team:tag:add",
6606
+ "id": "face:tag:add",
6599
6607
  "pluginAlias": "faces-cli",
6600
6608
  "pluginName": "faces-cli",
6601
6609
  "pluginType": "core",
@@ -6605,21 +6613,15 @@
6605
6613
  "relativePath": [
6606
6614
  "dist",
6607
6615
  "commands",
6608
- "team",
6616
+ "face",
6609
6617
  "tag",
6610
6618
  "add.js"
6611
6619
  ]
6612
6620
  },
6613
- "team:tag:list": {
6621
+ "face:tag:all": {
6614
6622
  "aliases": [],
6615
- "args": {
6616
- "team_id": {
6617
- "description": "Team ID",
6618
- "name": "team_id",
6619
- "required": true
6620
- }
6621
- },
6622
- "description": "List tags on a team",
6623
+ "args": {},
6624
+ "description": "List all tags across all your faces",
6623
6625
  "flags": {
6624
6626
  "json": {
6625
6627
  "description": "Format output as json.",
@@ -6655,7 +6657,7 @@
6655
6657
  },
6656
6658
  "hasDynamicHelp": false,
6657
6659
  "hiddenAliases": [],
6658
- "id": "team:tag:list",
6660
+ "id": "face:tag:all",
6659
6661
  "pluginAlias": "faces-cli",
6660
6662
  "pluginName": "faces-cli",
6661
6663
  "pluginType": "core",
@@ -6665,26 +6667,21 @@
6665
6667
  "relativePath": [
6666
6668
  "dist",
6667
6669
  "commands",
6668
- "team",
6670
+ "face",
6669
6671
  "tag",
6670
- "list.js"
6672
+ "all.js"
6671
6673
  ]
6672
6674
  },
6673
- "team:tag:remove": {
6675
+ "face:tag:list": {
6674
6676
  "aliases": [],
6675
6677
  "args": {
6676
- "team_id": {
6677
- "description": "Team ID",
6678
- "name": "team_id",
6679
- "required": true
6680
- },
6681
- "tag": {
6682
- "description": "Tag to remove",
6683
- "name": "tag",
6678
+ "alias": {
6679
+ "description": "Face alias",
6680
+ "name": "alias",
6684
6681
  "required": true
6685
6682
  }
6686
6683
  },
6687
- "description": "Remove a tag from a team",
6684
+ "description": "List tags on a face",
6688
6685
  "flags": {
6689
6686
  "json": {
6690
6687
  "description": "Format output as json.",
@@ -6720,7 +6717,7 @@
6720
6717
  },
6721
6718
  "hasDynamicHelp": false,
6722
6719
  "hiddenAliases": [],
6723
- "id": "team:tag:remove",
6720
+ "id": "face:tag:list",
6724
6721
  "pluginAlias": "faces-cli",
6725
6722
  "pluginName": "faces-cli",
6726
6723
  "pluginType": "core",
@@ -6730,21 +6727,26 @@
6730
6727
  "relativePath": [
6731
6728
  "dist",
6732
6729
  "commands",
6733
- "team",
6730
+ "face",
6734
6731
  "tag",
6735
- "remove.js"
6732
+ "list.js"
6736
6733
  ]
6737
6734
  },
6738
- "team:tag:set": {
6735
+ "face:tag:remove": {
6739
6736
  "aliases": [],
6740
6737
  "args": {
6741
- "team_id": {
6742
- "description": "Team ID",
6743
- "name": "team_id",
6738
+ "alias": {
6739
+ "description": "Face alias",
6740
+ "name": "alias",
6741
+ "required": true
6742
+ },
6743
+ "tag": {
6744
+ "description": "Tag to remove",
6745
+ "name": "tag",
6744
6746
  "required": true
6745
6747
  }
6746
6748
  },
6747
- "description": "Replace all tags on a team",
6749
+ "description": "Remove a tag from a face",
6748
6750
  "flags": {
6749
6751
  "json": {
6750
6752
  "description": "Format output as json.",
@@ -6776,19 +6778,11 @@
6776
6778
  "hasDynamicHelp": false,
6777
6779
  "multiple": false,
6778
6780
  "type": "option"
6779
- },
6780
- "tag": {
6781
- "description": "Tag to set (repeatable, replaces all)",
6782
- "name": "tag",
6783
- "required": true,
6784
- "hasDynamicHelp": false,
6785
- "multiple": true,
6786
- "type": "option"
6787
6781
  }
6788
6782
  },
6789
6783
  "hasDynamicHelp": false,
6790
6784
  "hiddenAliases": [],
6791
- "id": "team:tag:set",
6785
+ "id": "face:tag:remove",
6792
6786
  "pluginAlias": "faces-cli",
6793
6787
  "pluginName": "faces-cli",
6794
6788
  "pluginType": "core",
@@ -6798,12 +6792,12 @@
6798
6792
  "relativePath": [
6799
6793
  "dist",
6800
6794
  "commands",
6801
- "team",
6795
+ "face",
6802
6796
  "tag",
6803
- "set.js"
6797
+ "remove.js"
6804
6798
  ]
6805
6799
  },
6806
- "face:tag:add": {
6800
+ "face:tag:set": {
6807
6801
  "aliases": [],
6808
6802
  "args": {
6809
6803
  "alias": {
@@ -6812,7 +6806,7 @@
6812
6806
  "required": true
6813
6807
  }
6814
6808
  },
6815
- "description": "Add tags to a face (appends, idempotent)",
6809
+ "description": "Replace all tags on a face",
6816
6810
  "flags": {
6817
6811
  "json": {
6818
6812
  "description": "Format output as json.",
@@ -6846,7 +6840,7 @@
6846
6840
  "type": "option"
6847
6841
  },
6848
6842
  "tag": {
6849
- "description": "Tag to add (repeatable)",
6843
+ "description": "Tag to set (repeatable, replaces all)",
6850
6844
  "name": "tag",
6851
6845
  "required": true,
6852
6846
  "hasDynamicHelp": false,
@@ -6856,7 +6850,7 @@
6856
6850
  },
6857
6851
  "hasDynamicHelp": false,
6858
6852
  "hiddenAliases": [],
6859
- "id": "face:tag:add",
6853
+ "id": "face:tag:set",
6860
6854
  "pluginAlias": "faces-cli",
6861
6855
  "pluginName": "faces-cli",
6862
6856
  "pluginType": "core",
@@ -6868,13 +6862,19 @@
6868
6862
  "commands",
6869
6863
  "face",
6870
6864
  "tag",
6871
- "add.js"
6865
+ "set.js"
6872
6866
  ]
6873
6867
  },
6874
- "face:tag:all": {
6868
+ "team:tag:add": {
6875
6869
  "aliases": [],
6876
- "args": {},
6877
- "description": "List all tags across all your faces",
6870
+ "args": {
6871
+ "team_id": {
6872
+ "description": "Team ID",
6873
+ "name": "team_id",
6874
+ "required": true
6875
+ }
6876
+ },
6877
+ "description": "Add tags to a team (appends, idempotent)",
6878
6878
  "flags": {
6879
6879
  "json": {
6880
6880
  "description": "Format output as json.",
@@ -6906,11 +6906,19 @@
6906
6906
  "hasDynamicHelp": false,
6907
6907
  "multiple": false,
6908
6908
  "type": "option"
6909
+ },
6910
+ "tag": {
6911
+ "description": "Tag to add (repeatable)",
6912
+ "name": "tag",
6913
+ "required": true,
6914
+ "hasDynamicHelp": false,
6915
+ "multiple": true,
6916
+ "type": "option"
6909
6917
  }
6910
6918
  },
6911
6919
  "hasDynamicHelp": false,
6912
6920
  "hiddenAliases": [],
6913
- "id": "face:tag:all",
6921
+ "id": "team:tag:add",
6914
6922
  "pluginAlias": "faces-cli",
6915
6923
  "pluginName": "faces-cli",
6916
6924
  "pluginType": "core",
@@ -6920,21 +6928,21 @@
6920
6928
  "relativePath": [
6921
6929
  "dist",
6922
6930
  "commands",
6923
- "face",
6931
+ "team",
6924
6932
  "tag",
6925
- "all.js"
6933
+ "add.js"
6926
6934
  ]
6927
6935
  },
6928
- "face:tag:list": {
6936
+ "team:tag:list": {
6929
6937
  "aliases": [],
6930
6938
  "args": {
6931
- "alias": {
6932
- "description": "Face alias",
6933
- "name": "alias",
6939
+ "team_id": {
6940
+ "description": "Team ID",
6941
+ "name": "team_id",
6934
6942
  "required": true
6935
6943
  }
6936
6944
  },
6937
- "description": "List tags on a face",
6945
+ "description": "List tags on a team",
6938
6946
  "flags": {
6939
6947
  "json": {
6940
6948
  "description": "Format output as json.",
@@ -6970,7 +6978,7 @@
6970
6978
  },
6971
6979
  "hasDynamicHelp": false,
6972
6980
  "hiddenAliases": [],
6973
- "id": "face:tag:list",
6981
+ "id": "team:tag:list",
6974
6982
  "pluginAlias": "faces-cli",
6975
6983
  "pluginName": "faces-cli",
6976
6984
  "pluginType": "core",
@@ -6980,17 +6988,17 @@
6980
6988
  "relativePath": [
6981
6989
  "dist",
6982
6990
  "commands",
6983
- "face",
6991
+ "team",
6984
6992
  "tag",
6985
6993
  "list.js"
6986
6994
  ]
6987
6995
  },
6988
- "face:tag:remove": {
6996
+ "team:tag:remove": {
6989
6997
  "aliases": [],
6990
6998
  "args": {
6991
- "alias": {
6992
- "description": "Face alias",
6993
- "name": "alias",
6999
+ "team_id": {
7000
+ "description": "Team ID",
7001
+ "name": "team_id",
6994
7002
  "required": true
6995
7003
  },
6996
7004
  "tag": {
@@ -6999,7 +7007,7 @@
6999
7007
  "required": true
7000
7008
  }
7001
7009
  },
7002
- "description": "Remove a tag from a face",
7010
+ "description": "Remove a tag from a team",
7003
7011
  "flags": {
7004
7012
  "json": {
7005
7013
  "description": "Format output as json.",
@@ -7035,7 +7043,7 @@
7035
7043
  },
7036
7044
  "hasDynamicHelp": false,
7037
7045
  "hiddenAliases": [],
7038
- "id": "face:tag:remove",
7046
+ "id": "team:tag:remove",
7039
7047
  "pluginAlias": "faces-cli",
7040
7048
  "pluginName": "faces-cli",
7041
7049
  "pluginType": "core",
@@ -7045,21 +7053,21 @@
7045
7053
  "relativePath": [
7046
7054
  "dist",
7047
7055
  "commands",
7048
- "face",
7056
+ "team",
7049
7057
  "tag",
7050
7058
  "remove.js"
7051
7059
  ]
7052
7060
  },
7053
- "face:tag:set": {
7061
+ "team:tag:set": {
7054
7062
  "aliases": [],
7055
7063
  "args": {
7056
- "alias": {
7057
- "description": "Face alias",
7058
- "name": "alias",
7064
+ "team_id": {
7065
+ "description": "Team ID",
7066
+ "name": "team_id",
7059
7067
  "required": true
7060
7068
  }
7061
7069
  },
7062
- "description": "Replace all tags on a face",
7070
+ "description": "Replace all tags on a team",
7063
7071
  "flags": {
7064
7072
  "json": {
7065
7073
  "description": "Format output as json.",
@@ -7103,7 +7111,7 @@
7103
7111
  },
7104
7112
  "hasDynamicHelp": false,
7105
7113
  "hiddenAliases": [],
7106
- "id": "face:tag:set",
7114
+ "id": "team:tag:set",
7107
7115
  "pluginAlias": "faces-cli",
7108
7116
  "pluginName": "faces-cli",
7109
7117
  "pluginType": "core",
@@ -7113,11 +7121,11 @@
7113
7121
  "relativePath": [
7114
7122
  "dist",
7115
7123
  "commands",
7116
- "face",
7124
+ "team",
7117
7125
  "tag",
7118
7126
  "set.js"
7119
7127
  ]
7120
7128
  }
7121
7129
  },
7122
- "version": "1.8.2"
7130
+ "version": "1.8.4"
7123
7131
  }