litvc 1.2.1

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

use serde::Serialize;

/// Top-level ontology for the Lit version control system
#[derive(Debug, Serialize)]
pub struct LitOntology {
    #[serde(rename = "@context")]
    pub context: OntologyContext,
    #[serde(rename = "@type")]
    pub type_name: &'static str,
    pub name: &'static str,
    pub version: &'static str,
    pub description: &'static str,
    pub capabilities: Vec<Capability>,
    pub types: Vec<TypeDef>,
    pub commands: Vec<CommandDef>,
    pub workflows: Vec<Workflow>,
    pub protocols: Protocols,
    pub errors: ErrorOntology,
}

#[derive(Debug, Serialize)]
pub struct OntologyContext {
    pub lit: &'static str,
    pub schema: &'static str,
    pub vcs: &'static str,
    pub mcp: &'static str,
}

#[derive(Debug, Serialize)]
pub struct Capability {
    pub id: String,
    pub name: String,
    pub description: String,
}

#[derive(Debug, Serialize)]
pub struct TypeDef {
    pub id: String,
    pub name: String,
    pub description: String,
    pub properties: Vec<PropertyDef>,
}

#[derive(Debug, Serialize)]
pub struct PropertyDef {
    pub name: String,
    #[serde(rename = "type")]
    pub type_name: String,
    pub description: String,
    pub required: bool,
}

#[derive(Debug, Serialize)]
pub struct CommandDef {
    pub id: String,
    pub name: String,
    pub description: String,
    pub category: String,
    pub parameters: Vec<ParamDef>,
    pub returns: String,
    pub side_effects: Vec<String>,
    pub preconditions: Vec<String>,
    pub examples: Vec<Example>,
    /// Commands that commonly follow this one
    pub follows: Vec<String>,
    /// Commands that commonly precede this one
    pub preceded_by: Vec<String>,
    pub idempotent: bool,
    pub safe: bool,
}

#[derive(Debug, Serialize)]
pub struct ParamDef {
    pub name: String,
    #[serde(rename = "type")]
    pub type_name: String,
    pub description: String,
    pub required: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub default: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct Example {
    pub description: String,
    pub cli: String,
    pub json: serde_json::Value,
}

#[derive(Debug, Serialize)]
pub struct Workflow {
    pub id: String,
    pub name: String,
    pub description: String,
    pub steps: Vec<WorkflowStep>,
    pub agent_optimized: bool,
}

#[derive(Debug, Serialize)]
pub struct WorkflowStep {
    pub order: usize,
    pub command: String,
    pub description: String,
    pub optional: bool,
}

#[derive(Debug, Serialize)]
pub struct Protocols {
    pub cli: CliProtocol,
    pub rest: RestProtocol,
    pub mcp: McpProtocol,
    pub batch: BatchProtocol,
}

#[derive(Debug, Serialize)]
pub struct CliProtocol {
    pub binary: &'static str,
    pub global_flags: Vec<FlagDef>,
    pub output_formats: Vec<&'static str>,
    pub default_format: &'static str,
}

#[derive(Debug, Serialize)]
pub struct FlagDef {
    pub flag: String,
    pub description: String,
}

#[derive(Debug, Serialize)]
pub struct RestProtocol {
    pub base_path: &'static str,
    pub auth: Vec<&'static str>,
    pub content_type: &'static str,
}

#[derive(Debug, Serialize)]
pub struct McpProtocol {
    pub protocol_version: &'static str,
    pub transports: Vec<McpTransport>,
    pub tool_prefix: &'static str,
}

#[derive(Debug, Serialize)]
pub struct McpTransport {
    pub name: String,
    pub command: String,
    pub description: String,
}

#[derive(Debug, Serialize)]
pub struct BatchProtocol {
    pub format: &'static str,
    pub input: &'static str,
    pub flags: Vec<FlagDef>,
}

#[derive(Debug, Serialize)]
pub struct ErrorOntology {
    pub format: ErrorFormat,
    pub categories: Vec<ErrorCategory>,
}

#[derive(Debug, Serialize)]
pub struct ErrorFormat {
    pub json_envelope: serde_json::Value,
    pub fields: Vec<String>,
}

#[derive(Debug, Serialize)]
pub struct ErrorCategory {
    pub code: String,
    pub description: String,
    pub recoverable: bool,
    pub suggested_action: String,
}

/// Build and return the complete Lit ontology
pub fn get_ontology() -> LitOntology {
    LitOntology {
        context: OntologyContext {
            lit: "https://lit-vcs.dev/ontology/v1#",
            schema: "https://schema.org/",
            vcs: "https://lit-vcs.dev/ontology/vcs#",
            mcp: "https://modelcontextprotocol.io/schema/v1#",
        },
        type_name: "VersionControlSystem",
        name: "Lit",
        version: env!("CARGO_PKG_VERSION"),
        description: "Agentic-first distributed version control system. A complete Git replacement designed for AI agents first and humans second. Features post-quantum cryptography (ML-DSA-87, ML-KEM), FIPS 140-2 compliance, structured JSON I/O, batch mode, transactions, and MCP integration.",
        capabilities: build_capabilities(),
        types: build_types(),
        commands: build_commands(),
        workflows: build_workflows(),
        protocols: build_protocols(),
        errors: build_errors(),
    }
}

fn build_capabilities() -> Vec<Capability> {
    vec![
        cap("version-control", "Distributed Version Control", "Full DAG-based version control with branches, merges, commits, and tags"),
        cap("post-quantum-crypto", "Post-Quantum Cryptography", "ML-DSA-87 (Dilithium5) signatures and ML-KEM (Kyber) key encapsulation for quantum-resistant security"),
        cap("fips-compliance", "FIPS 140-2 Compliance", "SHA3-512, AES-256-GCM, HMAC-SHA256, PBKDF2 key derivation with secure zeroization"),
        cap("structured-io", "Structured I/O", "All commands produce structured JSON output by default, with human-readable alternative"),
        cap("batch-mode", "Batch Operations", "Execute multiple operations from JSONL stdin with atomic and dry-run modes"),
        cap("transactions", "Transaction Support", "Begin/commit/rollback with write-ahead log for crash recovery"),
        cap("agent-metadata", "Agent Metadata", "First-class metadata field on commits for agent_id, task_id, confidence, intent, tool_versions"),
        cap("search", "Full-Text Search", "Search file contents, commit messages, and agent metadata"),
        cap("snapshot", "Atomic Snapshots", "Single-command add-all + commit for agent workflows"),
        cap("integrity-verification", "Repository Verification", "Full integrity check of objects, refs, DAG connectivity, and index"),
        cap("mcp-server", "MCP Tool Server", "Model Context Protocol server for LLM agent integration (stdio and HTTP transports)"),
        cap("rest-api", "REST API Server", "HTTP API for remote repository operations with bearer token authentication"),
        cap("swarm-coordination", "Multi-Agent Swarm", "Agent registration, branch namespacing, and file lease system for concurrent agent collaboration"),
        cap("airgap-mode", "Air-Gap Mode", "Blocks all network protocols, allows only physical/local transports for secure environments"),
        cap("encryption-at-rest", "Encryption at Rest", "AES-256-GCM encryption for all repository objects and refs"),
    ]
}

fn build_types() -> Vec<TypeDef> {
    vec![
        TypeDef {
            id: "ObjectHash".to_string(),
            name: "Object Hash".to_string(),
            description:
                "192-character hex string: SHA3-512 (128 chars) + BLAKE3 (64 chars) concatenated"
                    .to_string(),
            properties: vec![
                prop(
                    "sha3_512",
                    "string",
                    "First 128 hex characters — SHA3-512 digest",
                    true,
                ),
                prop(
                    "blake3",
                    "string",
                    "Last 64 hex characters — BLAKE3 digest",
                    true,
                ),
            ],
        },
        TypeDef {
            id: "Commit".to_string(),
            name: "Commit Object".to_string(),
            description: "A snapshot of the repository state at a point in time".to_string(),
            properties: vec![
                prop("tree", "ObjectHash", "Hash of the root tree object", true),
                prop(
                    "parents",
                    "ObjectHash[]",
                    "Parent commit hashes (empty for initial commit)",
                    true,
                ),
                prop("author", "string", "Author identity", true),
                prop(
                    "timestamp",
                    "integer",
                    "Unix timestamp (seconds since epoch)",
                    true,
                ),
                prop("message", "string", "Commit message", true),
                prop(
                    "metadata",
                    "object|null",
                    "Optional JSON metadata (agent_id, task_id, confidence, etc.)",
                    false,
                ),
                prop(
                    "signature",
                    "PQSignature|null",
                    "Optional ML-DSA-87 signature",
                    false,
                ),
            ],
        },
        TypeDef {
            id: "Tree".to_string(),
            name: "Tree Object".to_string(),
            description: "A directory listing mapping names to object hashes".to_string(),
            properties: vec![prop(
                "entries",
                "TreeEntry[]",
                "List of entries (files and subdirectories)",
                true,
            )],
        },
        TypeDef {
            id: "Blob".to_string(),
            name: "Blob Object".to_string(),
            description: "File contents stored as a compressed byte sequence".to_string(),
            properties: vec![prop("data", "bytes", "Compressed file content", true)],
        },
        TypeDef {
            id: "Tag".to_string(),
            name: "Tag Object".to_string(),
            description: "A named reference to a specific commit, optionally signed".to_string(),
            properties: vec![
                prop("name", "string", "Tag name", true),
                prop("target", "ObjectHash", "The tagged commit hash", true),
                prop("tagger", "string", "Author of the tag", true),
                prop("message", "string", "Tag message", true),
                prop(
                    "signature",
                    "PQSignature|null",
                    "Optional ML-DSA-87 signature",
                    false,
                ),
            ],
        },
        TypeDef {
            id: "Branch".to_string(),
            name: "Branch Reference".to_string(),
            description: "A mutable named pointer to a commit hash, stored in .lit/refs/heads/"
                .to_string(),
            properties: vec![
                prop("name", "string", "Branch name", true),
                prop(
                    "target",
                    "ObjectHash",
                    "The commit hash this branch points to",
                    true,
                ),
            ],
        },
        TypeDef {
            id: "AgentMetadata".to_string(),
            name: "Agent Metadata".to_string(),
            description: "Structured metadata attached to commits by autonomous agents".to_string(),
            properties: vec![
                prop(
                    "agent_id",
                    "string",
                    "Unique identifier of the agent that created the commit",
                    false,
                ),
                prop(
                    "agent_model",
                    "string",
                    "Model name/version (e.g., 'claude-opus-4-20250514', 'gpt-4o')",
                    false,
                ),
                prop(
                    "task_id",
                    "string",
                    "Identifier for the task or work item being addressed",
                    false,
                ),
                prop(
                    "confidence",
                    "number",
                    "Agent's self-assessed confidence in the changes (0.0 - 1.0)",
                    false,
                ),
                prop(
                    "intent",
                    "string",
                    "Human-readable description of what the agent intended to do",
                    false,
                ),
                prop(
                    "tool_versions",
                    "object",
                    "Versions of tools used (e.g., compiler, linter)",
                    false,
                ),
                prop(
                    "parent_task",
                    "string",
                    "Reference to a parent task for hierarchical workflows",
                    false,
                ),
                prop(
                    "session_id",
                    "string",
                    "Conversation or session identifier",
                    false,
                ),
            ],
        },
        TypeDef {
            id: "FileLease".to_string(),
            name: "File Lease".to_string(),
            description: "Exclusive write lock on a file for swarm coordination".to_string(),
            properties: vec![
                prop("agent_id", "string", "The agent holding the lease", true),
                prop("path", "string", "File path the lease covers", true),
                prop(
                    "acquired_at",
                    "integer",
                    "Unix timestamp when lease was acquired",
                    true,
                ),
                prop(
                    "expires_at",
                    "integer",
                    "Unix timestamp when lease expires",
                    true,
                ),
            ],
        },
        TypeDef {
            id: "TreeEntry".to_string(),
            name: "Tree Entry".to_string(),
            description: "A single entry in a tree object, mapping a name to an object hash".to_string(),
            properties: vec![
                prop("mode", "string", "File mode: 100644 (normal), 100755 (executable), 040000 (directory)", true),
                prop("name", "string", "File or directory name", true),
                prop("hash", "ObjectHash", "Hash of the referenced blob or tree", true),
                prop("object_type", "string", "Object type: 'blob' or 'tree'", true),
            ],
        },
        TypeDef {
            id: "PQSignature".to_string(),
            name: "Post-Quantum Signature".to_string(),
            description: "ML-DSA-87 (Dilithium5) digital signature for quantum-resistant authentication".to_string(),
            properties: vec![
                prop("algorithm", "string", "Signature algorithm identifier (ML-DSA-87)", true),
                prop("signature", "bytes", "Raw signature bytes", true),
            ],
        },
        TypeDef {
            id: "PQKeyPair".to_string(),
            name: "Post-Quantum Key Pair".to_string(),
            description: "ML-DSA-87 key pair for signing and verification".to_string(),
            properties: vec![
                prop("public_key", "bytes", "Public key for verification", true),
                prop("secret_key", "bytes", "Secret key for signing (stored securely)", true),
            ],
        },
        TypeDef {
            id: "IndexEntry".to_string(),
            name: "Index Entry".to_string(),
            description: "A staged file in the index (staging area), mapping a path to its object hash".to_string(),
            properties: vec![
                prop("path", "string", "Relative file path", true),
                prop("hash", "string", "Object hash of the staged content", true),
                prop("mode", "string", "File mode (100644, 100755, etc.)", true),
            ],
        },
        TypeDef {
            id: "EncryptionConfig".to_string(),
            name: "Encryption Configuration".to_string(),
            description: "Repository encryption settings using AES-256-GCM with PBKDF2 key derivation".to_string(),
            properties: vec![
                prop("enabled", "boolean", "Whether encryption is active", true),
                prop("algorithm", "string", "Encryption algorithm (AES-256-GCM)", true),
                prop("salt", "bytes", "Random salt for key derivation", true),
                prop("kdf_iterations", "integer", "PBKDF2 iteration count", true),
            ],
        },
        TypeDef {
            id: "LfsPointer".to_string(),
            name: "LFS Pointer".to_string(),
            description: "Lightweight pointer replacing large file content, referencing the actual data stored separately".to_string(),
            properties: vec![
                prop("version", "string", "LFS pointer format version", true),
                prop("oid", "string", "Object identifier (sha3-blake3:hash)", true),
                prop("size", "integer", "Original file size in bytes", true),
            ],
        },
        TypeDef {
            id: "PackFile".to_string(),
            name: "Pack File".to_string(),
            description: "LITP-format pack file containing multiple compressed objects with CRC32 integrity".to_string(),
            properties: vec![
                prop("magic", "string", "File magic bytes: LITP", true),
                prop("version", "integer", "Pack format version", true),
                prop("object_count", "integer", "Number of objects in the pack", true),
            ],
        },
        TypeDef {
            id: "TransactionState".to_string(),
            name: "Transaction State".to_string(),
            description: "Write-ahead log state for transactional operations with rollback support".to_string(),
            properties: vec![
                prop("tx_id", "string", "Unique transaction identifier", true),
                prop("started_at", "integer", "Unix timestamp when transaction began", true),
                prop("operations", "object[]", "List of operations within the transaction", true),
            ],
        },
        TypeDef {
            id: "DiffHunk".to_string(),
            name: "Diff Hunk".to_string(),
            description: "A contiguous block of changes between two versions of a file".to_string(),
            properties: vec![
                prop("old_start", "integer", "Starting line number in original", true),
                prop("old_count", "integer", "Number of lines in original", true),
                prop("new_start", "integer", "Starting line number in modified", true),
                prop("new_count", "integer", "Number of lines in modified", true),
                prop("lines", "DiffLine[]", "Individual line changes", true),
            ],
        },
        TypeDef {
            id: "DiffLine".to_string(),
            name: "Diff Line".to_string(),
            description: "A single line in a diff hunk with its change kind".to_string(),
            properties: vec![
                prop("kind", "string", "Change type: context, add, or remove", true),
                prop("content", "string", "Line content", true),
            ],
        },
        TypeDef {
            id: "RemoteConfig".to_string(),
            name: "Remote Configuration".to_string(),
            description: "Named remote repository URL configuration stored in .lit/remotes".to_string(),
            properties: vec![
                prop("name", "string", "Remote name (e.g., 'origin')", true),
                prop("url", "string", "Remote repository URL", true),
            ],
        },
        TypeDef {
            id: "ReflogEntry".to_string(),
            name: "Reflog Entry".to_string(),
            description: "A single entry in a reference log, recording a ref state transition".to_string(),
            properties: vec![
                prop("index", "integer", "Entry index (0 = most recent)", true),
                prop("old_hash", "ObjectHash", "Previous ref target", true),
                prop("new_hash", "ObjectHash", "New ref target", true),
                prop("action", "string", "Action that caused the change (commit, checkout, merge, etc.)", true),
                prop("message", "string", "Description of the change", true),
                prop("timestamp", "integer", "Unix timestamp", true),
            ],
        },
    ]
}

fn build_commands() -> Vec<CommandDef> {
    vec![
        // Core VCS
        cmd("init", "Initialize Repository", "core", "Create a new Lit repository in the current or specified directory",
            vec![
                param("bare", "boolean", "Create a bare repository (no working tree)", false, None),
                param("path", "string", "Directory path (defaults to current directory)", false, None),
            ],
            "InitResponse", vec!["Creates .lit/ directory structure"], vec![],
            vec![ex("Initialize", "lit init", serde_json::json!({"bare": false}))],
            vec!["add", "config"], vec![], true, true),
        cmd("add", "Stage Files", "core", "Add file contents to the staging area (index)",
            vec![param("files", "string[]", "File paths to stage", true, None)],
            "AddResponse", vec!["Modifies .lit/index"], vec!["Repository must be initialized"],
            vec![ex("Stage files", "lit add src/main.rs", serde_json::json!({"files": ["src/main.rs"]}))],
            vec!["commit", "status"], vec!["init", "checkout"], false, true),
        cmd("commit", "Create Commit", "core", "Record staged changes as a new commit object",
            vec![
                param("message", "string", "Commit message describing the changes", true, None),
                param("author", "string", "Author name", false, None),
            ],
            "CommitResponse", vec!["Creates commit and tree objects", "Updates HEAD ref"], vec!["Files must be staged"],
            vec![ex("Commit", "lit commit -m 'fix bug'", serde_json::json!({"message": "fix bug"}))],
            vec!["push", "log", "status"], vec!["add"], false, false),
        cmd("status", "Show Status", "core", "Show the working tree status: branch, staged, modified, and untracked files",
            vec![],
            "StatusResponse", vec![], vec!["Repository must be initialized"],
            vec![ex("Check status", "lit status", serde_json::json!({}))],
            vec!["add", "commit", "diff"], vec![], true, true),
        cmd("log", "Show History", "core", "Display commit history from HEAD or a specified ref",
            vec![
                param("count", "integer", "Number of commits to show", false, Some("10")),
                param("oneline", "boolean", "Compact one-line format", false, Some("false")),
            ],
            "LogResponse", vec![], vec!["Repository must have commits"],
            vec![ex("Recent history", "lit log -n 5", serde_json::json!({"count": 5}))],
            vec!["show", "diff"], vec!["commit"], true, true),
        cmd("diff", "Show Changes", "core", "Show differences between working tree, index, and commits",
            vec![
                param("staged", "boolean", "Compare index to HEAD", false, Some("false")),
                param("stat", "boolean", "Show statistics only", false, Some("false")),
                param("ref1", "string", "First reference", false, None),
                param("ref2", "string", "Second reference", false, None),
            ],
            "DiffResponse", vec![], vec![],
            vec![ex("Working tree diff", "lit diff", serde_json::json!({}))],
            vec!["add", "commit"], vec![], true, true),
        cmd("show", "Show Object", "core", "Display contents of a commit, tree, or blob object",
            vec![param("object", "string", "Object hash or ref name", true, None)],
            "ShowResponse", vec![], vec![],
            vec![ex("Show commit", "lit show HEAD", serde_json::json!({"object": "HEAD"}))],
            vec![], vec!["log"], true, true),
        // Branching
        cmd("branch", "Manage Branches", "branching", "List, create, or delete branches",
            vec![
                param("name", "string", "Branch name to create", false, None),
                param("delete", "boolean", "Delete the named branch", false, Some("false")),
                param("all", "boolean", "List all branches", false, Some("false")),
            ],
            "BranchResponse", vec!["May create or delete refs"], vec![],
            vec![ex("List branches", "lit branch --all", serde_json::json!({"all": true}))],
            vec!["checkout"], vec![], true, true),
        cmd("checkout", "Switch Branch", "branching", "Switch to a different branch or restore working tree files",
            vec![
                param("target", "string", "Branch name or commit hash", true, None),
                param("b", "boolean", "Create and switch to new branch", false, Some("false")),
            ],
            "CheckoutResponse", vec!["Updates working tree", "Updates HEAD"], vec![],
            vec![ex("Switch branch", "lit checkout main", serde_json::json!({"target": "main"}))],
            vec!["add", "commit", "merge"], vec!["branch"], false, false),
        cmd("merge", "Merge Branches", "branching", "Merge another branch into the current branch",
            vec![
                param("branch", "string", "Branch to merge", true, None),
                param("strategy", "string", "Merge strategy (recursive, ours, theirs)", false, Some("recursive")),
            ],
            "MergeResponse", vec!["May create merge commit", "May produce conflicts"], vec!["Must be on a branch"],
            vec![ex("Merge feature", "lit merge feature-x", serde_json::json!({"branch": "feature-x"}))],
            vec!["resolve", "commit", "push"], vec!["checkout", "pull"], false, false),
        // Collaboration
        cmd("push", "Push Changes", "collaboration", "Upload local commits to a remote repository (LAN only)",
            vec![
                param("remote", "string", "Remote name", true, None),
                param("branch", "string", "Branch name", true, None),
                param("force", "boolean", "Force push", false, Some("false")),
            ],
            "PushResponse", vec!["Updates remote refs"], vec!["Remote must be configured"],
            vec![ex("Push to origin", "lit push origin main", serde_json::json!({"remote": "origin", "branch": "main"}))],
            vec![], vec!["commit", "merge"], false, false),
        cmd("pull", "Pull Changes", "collaboration", "Fetch and merge changes from a remote repository",
            vec![
                param("remote", "string", "Remote name", true, None),
                param("branch", "string", "Branch name", true, None),
            ],
            "PullResponse", vec!["Updates local refs and working tree"], vec!["Remote must be configured"],
            vec![ex("Pull from origin", "lit pull origin main", serde_json::json!({"remote": "origin", "branch": "main"}))],
            vec!["merge", "commit"], vec![], false, false),
        // Agent-optimized
        cmd("snapshot", "Atomic Snapshot", "agent", "Stage all files and commit in one atomic operation — the preferred agent workflow",
            vec![
                param("message", "string", "Commit message", true, None),
                param("author", "string", "Author name", false, None),
                param("metadata", "AgentMetadata", "Agent metadata JSON object", false, None),
            ],
            "SnapshotResponse", vec!["Stages all files", "Creates commit"], vec![],
            vec![ex("Agent snapshot", "lit snapshot -m 'implement feature X' --metadata '{\"agent_id\":\"claude-1\",\"confidence\":0.95}'",
                serde_json::json!({"message": "implement feature X", "metadata": {"agent_id": "claude-1", "confidence": 0.95}}))],
            vec!["push", "log"], vec![], false, false),
        cmd("batch", "Batch Operations", "agent", "Execute multiple operations from JSONL on stdin",
            vec![
                param("atomic", "boolean", "Stop on first failure, skip remaining", false, Some("false")),
                param("dry_run", "boolean", "Validate without executing", false, Some("false")),
            ],
            "BatchResponse", vec!["Depends on operations"], vec![],
            vec![ex("Batch", "echo '{\"command\":\"status\"}' | lit batch", serde_json::json!({"atomic": false}))],
            vec![], vec![], false, false),
        cmd("search", "Search Repository", "agent", "Full-text search across file contents, commit messages, or agent metadata",
            vec![
                param("query", "string", "Search query string", true, None),
                param("messages", "boolean", "Search commit messages", false, Some("false")),
                param("metadata", "string", "Search metadata (key=value)", false, None),
                param("max_results", "integer", "Maximum results to return", false, Some("100")),
            ],
            "SearchResponse", vec![], vec![],
            vec![ex("Search files", "lit search 'TODO'", serde_json::json!({"query": "TODO"}))],
            vec![], vec![], true, true),
        cmd("verify", "Verify Integrity", "agent", "Run full repository integrity check — objects, refs, DAG, index",
            vec![],
            "VerifyResponse", vec![], vec!["Repository must be initialized"],
            vec![ex("Verify", "lit verify", serde_json::json!({}))],
            vec![], vec![], true, true),
        // Swarm
        cmd("swarm register", "Register Agent", "swarm", "Register an agent for multi-agent coordination with branch namespacing",
            vec![param("agent_id", "string", "Unique agent identifier", true, None)],
            "SwarmResponse", vec!["Creates agent namespace in refs"], vec![],
            vec![ex("Register", "lit swarm register claude-1", serde_json::json!({"agent_id": "claude-1"}))],
            vec!["swarm lease-acquire"], vec![], true, false),
        cmd("swarm lease-acquire", "Acquire File Lease", "swarm", "Acquire exclusive write access to a file for a specified duration",
            vec![
                param("agent_id", "string", "Agent requesting the lease", true, None),
                param("path", "string", "File path to lease", true, None),
                param("duration", "integer", "Lease duration in seconds", false, Some("300")),
            ],
            "SwarmResponse", vec!["Creates lease file"], vec!["Agent must be registered"],
            vec![ex("Acquire lease", "lit swarm lease-acquire --agent claude-1 --path src/main.rs --duration 300",
                serde_json::json!({"agent_id": "claude-1", "path": "src/main.rs", "duration": 300}))],
            vec!["swarm lease-release"], vec!["swarm register"], false, false),
        cmd("swarm lease-release", "Release File Lease", "swarm", "Release an exclusive write lease on a file",
            vec![
                param("agent_id", "string", "Agent releasing the lease", true, None),
                param("path", "string", "File path to release", true, None),
            ],
            "SwarmResponse", vec!["Removes lease file"], vec!["Lease must be held by this agent"],
            vec![ex("Release lease", "lit swarm lease-release --agent claude-1 --path src/main.rs",
                serde_json::json!({"agent_id": "claude-1", "path": "src/main.rs"}))],
            vec![], vec!["swarm lease-acquire"], true, false),
        cmd("swarm list", "List Agents", "swarm", "List all registered agents in the swarm",
            vec![],
            "SwarmResponse", vec![], vec![],
            vec![ex("List agents", "lit swarm list", serde_json::json!({}))],
            vec![], vec!["swarm register"], true, true),
        cmd("swarm lease-list", "List Leases", "swarm", "List all active file leases across all agents",
            vec![],
            "SwarmResponse", vec![], vec![],
            vec![ex("List leases", "lit swarm lease-list", serde_json::json!({}))],
            vec![], vec![], true, true),
        // Remote & collaboration
        cmd("remote", "Manage Remotes", "collaboration", "Add, remove, or list remote repository URLs (LAN only)",
            vec![
                param("command", "string", "Subcommand: add, remove, list", true, None),
                param("name", "string", "Remote name (for add/remove)", false, None),
                param("url", "string", "Remote URL (for add)", false, None),
                param("verbose", "boolean", "Show URLs in list", false, Some("false")),
            ],
            "RemoteResponse", vec!["May modify .lit/remotes config"], vec![],
            vec![
                ex("List remotes", "lit remote list", serde_json::json!({"command": "list"})),
                ex("Add remote", "lit remote add origin smb://server/repo", serde_json::json!({"command": "add", "name": "origin", "url": "smb://server/repo"})),
            ],
            vec!["push", "pull", "fetch"], vec!["init", "clone"], true, true),
        cmd("clone", "Clone Repository", "collaboration", "Clone a remote repository into a new local directory (LAN only)",
            vec![
                param("url", "string", "Repository URL (must be LAN)", true, None),
                param("directory", "string", "Destination directory name", false, None),
            ],
            "CloneResponse", vec!["Creates new directory", "Downloads all objects and refs"], vec![],
            vec![ex("Clone", "lit clone smb://server/repo myrepo", serde_json::json!({"url": "smb://server/repo", "directory": "myrepo"}))],
            vec!["status", "log", "checkout"], vec![], false, false),
        cmd("fetch", "Fetch Remote", "collaboration", "Download objects and refs from a remote without merging",
            vec![
                param("remote", "string", "Remote name", true, None),
                param("branch", "string", "Specific branch to fetch (omit for all)", false, None),
            ],
            "FetchResponse", vec!["Updates remote-tracking refs"], vec!["Remote must be configured"],
            vec![ex("Fetch all", "lit fetch origin", serde_json::json!({"remote": "origin"}))],
            vec!["merge", "log"], vec![], false, true),
        // Configuration
        cmd("config", "Configuration", "configuration", "Show, get, or set repository and global configuration values",
            vec![
                param("command", "string", "Subcommand: show, get, set", true, None),
                param("key", "string", "Configuration key (for get/set)", false, None),
                param("value", "string", "Configuration value (for set)", false, None),
            ],
            "ConfigResponse", vec!["May modify .lit/config"], vec![],
            vec![
                ex("Show all config", "lit config show", serde_json::json!({"command": "show"})),
                ex("Get value", "lit config get core.bare", serde_json::json!({"command": "get", "key": "core.bare"})),
            ],
            vec![], vec!["init"], true, true),
        // Tagging
        cmd("tag", "Manage Tags", "branching", "Create, list, delete, sign, or verify tags. Supports annotated and post-quantum-signed tags (ML-DSA-87)",
            vec![
                param("name", "string", "Tag name", false, None),
                param("annotate", "boolean", "Create annotated tag", false, Some("false")),
                param("message", "string", "Tag message (implies annotated)", false, None),
                param("delete", "boolean", "Delete the named tag", false, Some("false")),
                param("sign", "boolean", "Sign tag with ML-DSA-87", false, Some("false")),
                param("verify", "boolean", "Verify tag signature", false, Some("false")),
                param("list", "boolean", "List all tags", false, Some("false")),
                param("commit", "string", "Target commit (defaults to HEAD)", false, None),
            ],
            "TagResponse", vec!["May create or delete refs/tags/"], vec![],
            vec![
                ex("Create annotated tag", "lit tag v1.0 -a -m 'Release 1.0'", serde_json::json!({"name": "v1.0", "annotate": true, "message": "Release 1.0"})),
                ex("List tags", "lit tag --list", serde_json::json!({"list": true})),
                ex("Sign tag", "lit tag v1.0 --sign -m 'Signed release'", serde_json::json!({"name": "v1.0", "sign": true, "message": "Signed release"})),
            ],
            vec!["push"], vec!["commit"], true, true),
        // History manipulation
        cmd("stash", "Stash Changes", "history", "Save, restore, list, or drop temporarily stashed changes",
            vec![
                param("command", "string", "Subcommand: push, pop, apply, list, drop", true, None),
                param("message", "string", "Stash message (for push)", false, None),
                param("index", "integer", "Stash index (for apply/drop)", false, None),
            ],
            "StashResponse", vec!["May modify .lit/stash and working tree"], vec![],
            vec![
                ex("Save changes", "lit stash push -m 'WIP'", serde_json::json!({"command": "push", "message": "WIP"})),
                ex("Restore latest", "lit stash pop", serde_json::json!({"command": "pop"})),
                ex("List stashes", "lit stash list", serde_json::json!({"command": "list"})),
            ],
            vec!["checkout", "commit"], vec![], false, false),
        cmd("reset", "Reset HEAD", "history", "Reset current HEAD to a specified state. Supports soft (HEAD only), mixed (HEAD + index), and hard (HEAD + index + working tree)",
            vec![
                param("target", "string", "Target commit hash or HEAD~N expression", true, None),
                param("soft", "boolean", "Keep changes in staging area", false, Some("false")),
                param("hard", "boolean", "Discard all changes (index + working tree)", false, Some("false")),
            ],
            "ResetResponse", vec!["Updates HEAD", "May modify index and working tree"], vec![],
            vec![
                ex("Soft reset", "lit reset HEAD~1 --soft", serde_json::json!({"target": "HEAD~1", "soft": true})),
                ex("Hard reset", "lit reset HEAD~3 --hard", serde_json::json!({"target": "HEAD~3", "hard": true})),
            ],
            vec!["status", "log"], vec!["log", "commit"], false, false),
        cmd("revert", "Revert Commit", "history", "Create a new inverse commit that undoes the changes from a specified commit",
            vec![param("target", "string", "Commit hash to revert", true, None)],
            "RevertResponse", vec!["Creates inverse commit"], vec!["Target commit must exist"],
            vec![ex("Revert commit", "lit revert abc123", serde_json::json!({"target": "abc123"}))],
            vec!["push", "log"], vec!["log"], false, false),
        cmd("cherry-pick", "Cherry-Pick Commit", "history", "Apply the changes from a specific commit onto the current branch",
            vec![param("target", "string", "Commit hash to cherry-pick", true, None)],
            "CherryPickResponse", vec!["Creates new commit with applied changes"], vec!["Target commit must exist"],
            vec![ex("Cherry-pick", "lit cherry-pick abc123", serde_json::json!({"target": "abc123"}))],
            vec!["push", "log"], vec!["log", "checkout"], false, false),
        cmd("rebase", "Rebase Branch", "history", "Reapply commits from the current branch onto a new base. Supports interactive mode with todo editing",
            vec![
                param("base", "string", "Base branch or commit to rebase onto", true, None),
                param("interactive", "boolean", "Interactive rebase with todo list", false, Some("false")),
                param("onto", "string", "Specific commit to rebase onto", false, None),
                param("abort", "boolean", "Abort an in-progress rebase", false, Some("false")),
                param("continue", "boolean", "Continue a paused rebase", false, Some("false")),
            ],
            "RebaseResponse", vec!["Rewrites commit history", "Updates HEAD"], vec!["Working tree must be clean"],
            vec![
                ex("Rebase onto main", "lit rebase main", serde_json::json!({"base": "main"})),
                ex("Interactive rebase", "lit rebase main --interactive", serde_json::json!({"base": "main", "interactive": true})),
            ],
            vec!["push --force", "log"], vec!["checkout"], false, false),
        cmd("blame", "Blame File", "history", "Show what revision and author last modified each line of a file",
            vec![param("file", "string", "File path to blame", true, None)],
            "BlameResponse", vec![], vec!["File must exist in repository"],
            vec![ex("Blame file", "lit blame src/main.rs", serde_json::json!({"file": "src/main.rs"}))],
            vec!["show", "log"], vec![], true, true),
        cmd("bisect", "Binary Search", "history", "Binary search through commit history to find the commit that introduced a bug",
            vec![
                param("command", "string", "Subcommand: start, good, bad, reset", true, None),
                param("commit", "string", "Commit hash (for good/bad)", false, None),
            ],
            "BisectResponse", vec!["Updates HEAD to test commits", "Saves state to .lit/bisect.json"], vec![],
            vec![
                ex("Start bisect", "lit bisect start", serde_json::json!({"command": "start"})),
                ex("Mark good", "lit bisect good abc123", serde_json::json!({"command": "good", "commit": "abc123"})),
            ],
            vec!["bisect good", "bisect bad", "bisect reset"], vec![], false, false),
        cmd("reflog", "Reference Log", "history", "Show the history of reference changes (HEAD updates, branch moves, etc.)",
            vec![
                param("ref_name", "string", "Reference name (default: HEAD)", false, Some("HEAD")),
                param("count", "integer", "Number of entries to show", false, Some("20")),
            ],
            "ReflogResponse", vec![], vec![],
            vec![ex("Show reflog", "lit reflog", serde_json::json!({}))],
            vec!["reset", "checkout"], vec![], true, true),
        cmd("resolve", "Resolve Conflicts", "branching", "Resolve merge conflicts using a specified strategy or finalize a merge after manual resolution",
            vec![
                param("file", "string", "Specific file to resolve", false, None),
                param("strategy", "string", "Resolution strategy: ours or theirs", false, None),
                param("all", "boolean", "Resolve all conflicting files", false, Some("false")),
                param("finish", "boolean", "Finalize merge after resolving all conflicts", false, Some("false")),
            ],
            "ResolveResponse", vec!["Modifies conflicting files", "May create merge commit"], vec!["Merge conflicts must exist"],
            vec![
                ex("Resolve all with ours", "lit resolve --all --strategy ours", serde_json::json!({"all": true, "strategy": "ours"})),
                ex("Finish merge", "lit resolve --continue", serde_json::json!({"finish": true})),
            ],
            vec!["commit", "push"], vec!["merge", "pull"], false, false),
        // Monitoring
        cmd("watch", "Watch Filesystem", "agent", "Monitor the working tree for file changes and emit a continuous stream of JSONL events",
            vec![
                param("debounce", "integer", "Debounce interval in milliseconds", false, Some("500")),
                param("filter", "string", "Glob pattern to filter watched files", false, None),
            ],
            "WatchResponse (continuous JSONL stream)", vec![], vec![],
            vec![ex("Watch with filter", "lit watch --filter '*.rs'", serde_json::json!({"filter": "*.rs"}))],
            vec!["snapshot"], vec![], true, true),
        // Transactions
        cmd("tx begin", "Begin Transaction", "agent", "Start a new transaction with write-ahead log for crash recovery",
            vec![],
            "TransactionResponse", vec!["Creates .lit/transaction.json and .lit/transaction.lock"], vec!["No other transaction active"],
            vec![ex("Begin transaction", "lit tx begin", serde_json::json!({}))],
            vec!["tx commit", "tx rollback"], vec![], false, false),
        cmd("tx commit", "Commit Transaction", "agent", "Commit the current transaction, finalizing all operations within it",
            vec![],
            "TransactionResponse", vec!["Removes transaction lock"], vec!["Transaction must be active"],
            vec![ex("Commit transaction", "lit tx commit", serde_json::json!({}))],
            vec![], vec!["tx begin"], false, false),
        cmd("tx rollback", "Rollback Transaction", "agent", "Rollback the current transaction, undoing all operations within it",
            vec![],
            "TransactionResponse", vec!["Restores pre-transaction state", "Removes transaction files"], vec!["Transaction must be active"],
            vec![ex("Rollback", "lit tx rollback", serde_json::json!({}))],
            vec![], vec!["tx begin"], false, false),
        // Server / API
        cmd("serve", "REST API Server", "server", "Start the Lit REST API server with optional bearer token authentication. Supports HTTP, stdio, and lit:// daemon modes",
            vec![
                param("port", "integer", "Port to listen on", false, Some("3000")),
                param("token", "string", "Bearer token for authentication (or LIT_API_TOKEN env)", false, None),
                param("stdio", "boolean", "Use stdio transport (for SSH pipe mode)", false, Some("false")),
                param("daemon", "boolean", "Run as lit:// protocol daemon (TCP, port 9418)", false, Some("false")),
            ],
            "ServeResponse", vec!["Starts long-running HTTP/TCP server"], vec!["Repository must be initialized"],
            vec![ex("Start server", "lit serve --port 3000 --token secret", serde_json::json!({"port": 3000, "token": "secret"}))],
            vec![], vec!["init"], false, false),
        cmd("mcp-serve", "MCP Tool Server", "server", "Start the Model Context Protocol (MCP) tool server for LLM agent integration. Exposes lit.* tools via JSON-RPC 2.0",
            vec![
                param("stdio", "boolean", "Use stdio transport (default)", false, Some("true")),
                param("port", "integer", "Use HTTP transport on specified port", false, None),
            ],
            "McpServeResponse", vec!["Starts long-running MCP server"], vec!["Repository must be initialized"],
            vec![
                ex("MCP stdio", "lit mcp-serve --stdio", serde_json::json!({"stdio": true})),
                ex("MCP HTTP", "lit mcp-serve --port 3001", serde_json::json!({"port": 3001})),
            ],
            vec![], vec!["init"], false, false),
        // Git interop
        cmd("import-git", "Import Git Repository", "interop", "Import a Git repository into Lit format, converting SHA-1 objects to SHA3-512+BLAKE3 composite hashes",
            vec![param("source", "string", "Path to Git repository (directory containing .git)", true, None)],
            "ImportGitResponse", vec!["Creates Lit objects from Git objects", "Creates Lit refs from Git refs"], vec!["Source must be a valid Git repository"],
            vec![ex("Import", "lit import-git /path/to/git-repo", serde_json::json!({"source": "/path/to/git-repo"}))],
            vec!["log", "status", "verify"], vec![], false, false),
        cmd("export-git", "Export to Git", "interop", "Export a Lit repository to Git format, converting composite hashes back to SHA-1",
            vec![param("destination", "string", "Destination path for the Git repository", true, None)],
            "ExportGitResponse", vec!["Creates bare Git repository at destination"], vec!["Lit repository must have commits"],
            vec![ex("Export", "lit export-git /path/to/output", serde_json::json!({"destination": "/path/to/output"}))],
            vec![], vec!["commit"], false, false),
        // Performance
        cmd("gc", "Garbage Collection", "performance", "Pack loose objects into pack files (LITP format) with CRC32 integrity, reducing disk usage and improving read performance",
            vec![],
            "GcResponse", vec!["Creates pack files", "Removes packed loose objects"], vec!["Repository must be initialized"],
            vec![ex("Run GC", "lit gc", serde_json::json!({}))],
            vec!["verify"], vec![], false, false),
        cmd("lfs track", "LFS Track Patterns", "performance", "Track file patterns for Large File Storage, writing rules to .litattributes",
            vec![param("patterns", "string[]", "Glob patterns to track (e.g., '*.bin', '*.dat')", true, None)],
            "LfsTrackResponse", vec!["Modifies .litattributes"], vec![],
            vec![ex("Track binaries", "lit lfs track '*.bin' '*.dat'", serde_json::json!({"patterns": ["*.bin", "*.dat"]}))],
            vec!["lfs migrate", "add"], vec!["init"], true, true),
        cmd("lfs migrate", "LFS Migrate", "performance", "Migrate existing large files to LFS pointer format, replacing content with lightweight references",
            vec![param("threshold", "integer", "Size threshold in bytes (default: 10MB)", false, Some("10485760"))],
            "LfsMigrateResponse", vec!["Replaces large blobs with LFS pointers"], vec!["LFS patterns must be configured"],
            vec![ex("Migrate large files", "lit lfs migrate --threshold 5242880", serde_json::json!({"threshold": 5242880}))],
            vec!["commit"], vec!["lfs track"], false, false),
        // Security
        cmd("rotate-key", "Rotate Encryption Key", "security", "Re-encrypt all repository objects and refs with a new passphrase. Prompts for old and new passphrases interactively",
            vec![],
            "RotateKeyResponse", vec!["Re-encrypts all objects, index, and refs"], vec!["Repository must be encrypted"],
            vec![ex("Rotate key", "lit rotate-key", serde_json::json!({}))],
            vec!["verify"], vec![], false, false),
        // Discovery
        cmd("ontology", "Show Ontology", "agent", "Output the complete Lit ontology as structured JSON for autonomous agent discovery. Includes all commands, types, workflows, protocols, and error categories",
            vec![],
            "OntologyResponse", vec![], vec![],
            vec![ex("Get ontology", "lit ontology", serde_json::json!({}))],
            vec![], vec![], true, true),
    ]
}

fn build_workflows() -> Vec<Workflow> {
    vec![
        Workflow {
            id: "agent-basic".to_string(),
            name: "Basic Agent Workflow".to_string(),
            description: "The simplest agent workflow: make changes, snapshot, push".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "status", "Check current repository state", false),
                wstep(
                    2,
                    "snapshot",
                    "Stage all changes and commit atomically",
                    false,
                ),
                wstep(3, "push", "Push to remote", true),
            ],
        },
        Workflow {
            id: "agent-branch".to_string(),
            name: "Agent Branch Workflow".to_string(),
            description: "Create a feature branch, make changes, merge back".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(
                    1,
                    "checkout -b",
                    "Create and switch to feature branch",
                    false,
                ),
                wstep(2, "snapshot", "Make changes and commit", false),
                wstep(3, "checkout", "Switch back to main branch", false),
                wstep(4, "merge", "Merge feature branch", false),
                wstep(5, "push", "Push merged changes", true),
            ],
        },
        Workflow {
            id: "agent-batch".to_string(),
            name: "Batch Operation Workflow".to_string(),
            description: "Submit multiple operations as JSONL for batch execution".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(
                    1,
                    "batch --dry-run",
                    "Validate operations without executing",
                    true,
                ),
                wstep(2, "batch --atomic", "Execute operations atomically", false),
            ],
        },
        Workflow {
            id: "agent-transaction".to_string(),
            name: "Transaction Workflow".to_string(),
            description: "Group operations with rollback support".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "tx begin", "Start a new transaction", false),
                wstep(
                    2,
                    "add/commit/...",
                    "Perform operations within the transaction",
                    false,
                ),
                wstep(
                    3,
                    "tx commit",
                    "Commit the transaction (or tx rollback to undo)",
                    false,
                ),
            ],
        },
        Workflow {
            id: "swarm-collaboration".to_string(),
            name: "Multi-Agent Collaboration".to_string(),
            description:
                "Multiple agents working on the same repository with lease-based coordination"
                    .to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "swarm register", "Register agent identity", false),
                wstep(
                    2,
                    "swarm lease-acquire",
                    "Acquire exclusive lease on files to edit",
                    false,
                ),
                wstep(3, "checkout -b", "Create agent-namespaced branch", false),
                wstep(4, "snapshot", "Make and commit changes", false),
                wstep(5, "swarm lease-release", "Release file leases", false),
                wstep(
                    6,
                    "push",
                    "Push agent branch for coordinator to merge",
                    false,
                ),
            ],
        },
        Workflow {
            id: "verify-and-fix".to_string(),
            name: "Verify and Fix".to_string(),
            description: "Check repository integrity and take corrective action if needed"
                .to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "verify", "Run full integrity check", false),
                wstep(
                    2,
                    "search",
                    "Search for related issues if verification fails",
                    true,
                ),
                wstep(3, "snapshot", "Commit fixes if any were applied", true),
            ],
        },
        Workflow {
            id: "git-migration".to_string(),
            name: "Git Migration".to_string(),
            description: "Import an existing Git repository into Lit format and verify integrity".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "import-git", "Import Git objects and refs into Lit", false),
                wstep(2, "verify", "Verify integrity of imported data", false),
                wstep(3, "log", "Review imported commit history", true),
                wstep(4, "branch --all", "List imported branches", true),
            ],
        },
        Workflow {
            id: "agent-code-review".to_string(),
            name: "Agent Code Review".to_string(),
            description: "Review changes on a branch, provide feedback via commits".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "log", "Review recent commit history", false),
                wstep(2, "diff", "Examine changes in detail", false),
                wstep(3, "blame", "Check authorship of specific files", true),
                wstep(4, "search", "Search for patterns or issues", true),
                wstep(5, "snapshot", "Commit review annotations as metadata", true),
            ],
        },
        Workflow {
            id: "agent-bisect".to_string(),
            name: "Automated Bug Bisection".to_string(),
            description: "Binary search through commit history to find the commit that introduced a regression".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "bisect start", "Begin bisection", false),
                wstep(2, "bisect bad", "Mark the known-bad commit", false),
                wstep(3, "bisect good", "Mark a known-good commit", false),
                wstep(4, "verify", "Test current commit (repeat until found)", false),
                wstep(5, "bisect reset", "End bisection session", false),
            ],
        },
        Workflow {
            id: "encrypted-repo".to_string(),
            name: "Encrypted Repository".to_string(),
            description: "Work with an encrypted repository using passphrase-based access".to_string(),
            agent_optimized: true,
            steps: vec![
                wstep(1, "init", "Initialize repository", false),
                wstep(2, "config set", "Configure encryption settings", false),
                wstep(3, "snapshot", "Create encrypted commits (passphrase via --passphrase or LIT_PASSPHRASE)", false),
                wstep(4, "rotate-key", "Periodically rotate encryption passphrase", true),
                wstep(5, "verify", "Verify encrypted integrity", true),
            ],
        },
    ]
}

fn build_protocols() -> Protocols {
    Protocols {
        cli: CliProtocol {
            binary: "lit",
            global_flags: vec![
                flag("--json", "Output as JSON (default)"),
                flag("--human", "Output as human-readable text"),
                flag("--airgapped", "Enable air-gap mode (block network)"),
                flag(
                    "--passphrase <PASSPHRASE>",
                    "Encryption passphrase (or LIT_PASSPHRASE env)",
                ),
                flag(
                    "--passphrase-file <PATH>",
                    "Path to passphrase file (or LIT_PASSPHRASE_FILE env)",
                ),
            ],
            output_formats: vec!["json", "human"],
            default_format: "json",
        },
        rest: RestProtocol {
            base_path: "/api/v1",
            auth: vec!["Bearer token", "None (localhost only)"],
            content_type: "application/json",
        },
        mcp: McpProtocol {
            protocol_version: "2024-11-05",
            tool_prefix: "lit_",
            transports: vec![
                McpTransport {
                    name: "stdio".to_string(),
                    command: "lit mcp-serve --stdio".to_string(),
                    description: "JSON-RPC 2.0 over stdin/stdout — standard MCP transport"
                        .to_string(),
                },
                McpTransport {
                    name: "http".to_string(),
                    command: "lit mcp-serve --port 3001".to_string(),
                    description: "JSON-RPC 2.0 over HTTP POST".to_string(),
                },
            ],
        },
        batch: BatchProtocol {
            format: "JSONL",
            input: "stdin",
            flags: vec![
                flag("--atomic", "Stop on first failure"),
                flag("--dry-run", "Validate without executing"),
            ],
        },
    }
}

fn build_errors() -> ErrorOntology {
    ErrorOntology {
        format: ErrorFormat {
            json_envelope: serde_json::json!({
                "status": "error",
                "command": "<command_name>",
                "error": {
                    "code": "<error_code>",
                    "message": "<human_readable_message>",
                    "suggestions": ["<recovery_hint>"]
                }
            }),
            fields: vec![
                "status".to_string(),
                "command".to_string(),
                "error.code".to_string(),
                "error.message".to_string(),
                "error.suggestions".to_string(),
            ],
        },
        categories: vec![
            errc(
                "REPO_NOT_FOUND",
                "Not a Lit repository",
                true,
                "Run 'lit init' to create one",
            ),
            errc(
                "REPO_CORRUPT",
                "Repository data is corrupt or inconsistent",
                false,
                "Run 'lit verify' to diagnose — may require re-clone",
            ),
            errc(
                "NO_COMMITS",
                "No commits in repository",
                true,
                "Create files and run 'lit snapshot -m \"initial\"'",
            ),
            errc(
                "MERGE_CONFLICT",
                "Merge conflict detected",
                true,
                "Use 'lit resolve' or 'lit resolve --all --strategy ours'",
            ),
            errc(
                "NOTHING_STAGED",
                "No files staged for commit",
                true,
                "Run 'lit add <files>' or use 'lit snapshot' instead",
            ),
            errc(
                "REF_NOT_FOUND",
                "Branch, tag, or ref does not exist",
                true,
                "Run 'lit branch --all' or 'lit tag --list' to list available refs",
            ),
            errc(
                "REF_CONFLICT",
                "Reference already exists or conflicts with another",
                true,
                "Use a different name or delete the existing ref first",
            ),
            errc(
                "OBJECT_NOT_FOUND",
                "Object hash not found in store",
                false,
                "The object may be corrupt or missing — run 'lit verify'",
            ),
            errc(
                "INDEX_LOCKED",
                "Index is locked by another operation",
                true,
                "Wait for the other operation to complete or remove .lit/index.lock",
            ),
            errc(
                "TX_IN_PROGRESS",
                "Another transaction is active",
                true,
                "Run 'lit tx rollback' to abort the existing transaction",
            ),
            errc(
                "LEASE_HELD",
                "File lease held by another agent",
                true,
                "Wait for lease expiration or coordinate with the holding agent",
            ),
            errc(
                "TRANSPORT_DENIED",
                "Network transport blocked or unavailable",
                true,
                "Disable --airgapped flag, use local file:// URLs, or check remote configuration",
            ),
            errc(
                "AUTH_FAILED",
                "Authentication failed for remote operation",
                true,
                "Check Bearer token (--token or LIT_API_TOKEN env) or verify credentials",
            ),
            errc(
                "CRYPTO_ERROR",
                "Encryption or decryption operation failed",
                true,
                "Verify passphrase is correct (--passphrase or LIT_PASSPHRASE env)",
            ),
            errc(
                "INVALID_INPUT",
                "Invalid argument or parameter value",
                true,
                "Check command help with 'lit <command> --help'",
            ),
            errc(
                "IO_ERROR",
                "File system read/write error",
                false,
                "Check file permissions and disk space",
            ),
            errc(
                "CONFIG_ERROR",
                "Configuration file is missing or malformed",
                true,
                "Run 'lit config show' to inspect or 'lit init' to recreate defaults",
            ),
            errc(
                "NOT_IMPLEMENTED",
                "Feature is not yet implemented",
                false,
                "This feature is planned for a future release",
            ),
        ],
    }
}

// Builder helpers
fn cap(id: &str, name: &str, desc: &str) -> Capability {
    Capability {
        id: id.to_string(),
        name: name.to_string(),
        description: desc.to_string(),
    }
}

fn prop(name: &str, type_name: &str, desc: &str, required: bool) -> PropertyDef {
    PropertyDef {
        name: name.to_string(),
        type_name: type_name.to_string(),
        description: desc.to_string(),
        required,
    }
}

fn param(
    name: &str,
    type_name: &str,
    desc: &str,
    required: bool,
    default: Option<&str>,
) -> ParamDef {
    ParamDef {
        name: name.to_string(),
        type_name: type_name.to_string(),
        description: desc.to_string(),
        required,
        default: default.map(|s| s.to_string()),
    }
}

fn ex(desc: &str, cli: &str, json: serde_json::Value) -> Example {
    Example {
        description: desc.to_string(),
        cli: cli.to_string(),
        json,
    }
}

#[allow(clippy::too_many_arguments)]
fn cmd(
    id: &str,
    name: &str,
    category: &str,
    desc: &str,
    parameters: Vec<ParamDef>,
    returns: &str,
    side_effects: Vec<&str>,
    preconditions: Vec<&str>,
    examples: Vec<Example>,
    follows: Vec<&str>,
    preceded_by: Vec<&str>,
    idempotent: bool,
    safe: bool,
) -> CommandDef {
    CommandDef {
        id: id.to_string(),
        name: name.to_string(),
        category: category.to_string(),
        description: desc.to_string(),
        parameters,
        returns: returns.to_string(),
        side_effects: side_effects.into_iter().map(|s| s.to_string()).collect(),
        preconditions: preconditions.into_iter().map(|s| s.to_string()).collect(),
        examples,
        follows: follows.into_iter().map(|s| s.to_string()).collect(),
        preceded_by: preceded_by.into_iter().map(|s| s.to_string()).collect(),
        idempotent,
        safe,
    }
}

fn wstep(order: usize, command: &str, description: &str, optional: bool) -> WorkflowStep {
    WorkflowStep {
        order,
        command: command.to_string(),
        description: description.to_string(),
        optional,
    }
}

fn flag(f: &str, desc: &str) -> FlagDef {
    FlagDef {
        flag: f.to_string(),
        description: desc.to_string(),
    }
}

fn errc(code: &str, desc: &str, recoverable: bool, action: &str) -> ErrorCategory {
    ErrorCategory {
        code: code.to_string(),
        description: desc.to_string(),
        recoverable,
        suggested_action: action.to_string(),
    }
}

// ============================================================================
// JSON Schema Generation
// ============================================================================

/// Map an ontology type string to a JSON Schema type
fn ontology_type_to_schema(type_name: &str) -> serde_json::Value {
    match type_name {
        "string" | "String" => serde_json::json!({ "type": "string" }),
        "boolean" | "bool" => serde_json::json!({ "type": "boolean" }),
        "integer" | "usize" | "i64" | "u64" | "i32" | "u32" => {
            serde_json::json!({ "type": "integer" })
        }
        "number" | "f64" | "f32" => serde_json::json!({ "type": "number" }),
        t if t.starts_with("array<") && t.ends_with('>') => {
            let inner = &t[6..t.len() - 1];
            serde_json::json!({
                "type": "array",
                "items": ontology_type_to_schema(inner)
            })
        }
        t if t.starts_with("optional<") && t.ends_with('>') => {
            let inner = &t[9..t.len() - 1];
            let mut schema = ontology_type_to_schema(inner);
            // Make nullable by allowing null
            if let Some(obj) = schema.as_object_mut() {
                if let Some(serde_json::Value::String(ty)) = obj.get("type").cloned() {
                    obj.insert("type".to_string(), serde_json::json!([ty, "null"]));
                }
            }
            schema
        }
        // Named types become $ref
        other => serde_json::json!({ "$ref": format!("#/$defs/{other}") }),
    }
}

/// Generate a JSON Schema for a single `TypeDef`
fn type_def_to_schema(td: &TypeDef) -> serde_json::Value {
    let mut properties = serde_json::Map::new();
    let mut required = Vec::new();

    for prop in &td.properties {
        let mut prop_schema = ontology_type_to_schema(&prop.type_name);
        if let Some(obj) = prop_schema.as_object_mut() {
            obj.insert(
                "description".to_string(),
                serde_json::Value::String(prop.description.clone()),
            );
        }
        properties.insert(prop.name.clone(), prop_schema);
        if prop.required {
            required.push(serde_json::Value::String(prop.name.clone()));
        }
    }

    serde_json::json!({
        "type": "object",
        "description": td.description,
        "properties": properties,
        "required": required,
        "additionalProperties": false
    })
}

/// Generate a JSON Schema for a single command's input parameters
fn command_input_schema(cmd: &CommandDef) -> serde_json::Value {
    let mut properties = serde_json::Map::new();
    let mut required = Vec::new();

    for param in &cmd.parameters {
        let mut param_schema = ontology_type_to_schema(&param.type_name);
        if let Some(obj) = param_schema.as_object_mut() {
            obj.insert(
                "description".to_string(),
                serde_json::Value::String(param.description.clone()),
            );
            if let Some(ref default) = param.default {
                obj.insert(
                    "default".to_string(),
                    serde_json::Value::String(default.clone()),
                );
            }
        }
        properties.insert(param.name.clone(), param_schema);
        if param.required {
            required.push(serde_json::Value::String(param.name.clone()));
        }
    }

    serde_json::json!({
        "type": "object",
        "description": format!("Input parameters for '{}'", cmd.name),
        "properties": properties,
        "required": required,
        "additionalProperties": false
    })
}

/// Generate the full JSON Schema document for the Lit ontology.
///
/// Produces a standard JSON Schema (draft 2020-12) with:
/// - `$defs` containing a schema for every ontology type
/// - `commands` containing input schemas for every command
pub fn generate_schemas() -> serde_json::Value {
    let ont = get_ontology();

    // Build $defs from types
    let mut defs = serde_json::Map::new();
    for td in &ont.types {
        defs.insert(td.id.clone(), type_def_to_schema(td));
    }

    // Build command schemas
    let mut commands = serde_json::Map::new();
    for cmd in &ont.commands {
        commands.insert(
            cmd.id.clone(),
            serde_json::json!({
                "description": cmd.description,
                "category": cmd.category,
                "input": command_input_schema(cmd),
                "returns": cmd.returns,
                "idempotent": cmd.idempotent,
                "safe": cmd.safe,
                "side_effects": cmd.side_effects,
                "preconditions": cmd.preconditions,
            }),
        );
    }

    serde_json::json!({
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "$id": "https://lit-vcs.dev/schema/v1",
        "title": "Lit VCS Schema",
        "description": "JSON Schema for the Lit version control system — types and command interfaces for agent discovery",
        "version": ont.version,
        "$defs": defs,
        "commands": commands
    })
}

/// Generate a JSON Schema for a single command by its ID.
///
/// Returns `None` if the command is not found.
pub fn generate_command_schema(command_id: &str) -> Option<serde_json::Value> {
    let ont = get_ontology();
    ont.commands.iter().find(|c| c.id == command_id).map(|cmd| {
        serde_json::json!({
            "$schema": "https://json-schema.org/draft/2020-12/schema",
            "$id": format!("https://lit-vcs.dev/schema/v1/commands/{}", cmd.id),
            "title": format!("lit {}", cmd.name),
            "description": cmd.description,
            "input": command_input_schema(cmd),
            "returns": cmd.returns,
            "idempotent": cmd.idempotent,
            "safe": cmd.safe,
        })
    })
}