1use serde::Serialize;
8
9#[derive(Debug, Serialize)]
11pub struct LitOntology {
12 #[serde(rename = "@context")]
13 pub context: OntologyContext,
14 #[serde(rename = "@type")]
15 pub type_name: &'static str,
16 pub name: &'static str,
17 pub version: &'static str,
18 pub description: &'static str,
19 pub capabilities: Vec<Capability>,
20 pub types: Vec<TypeDef>,
21 pub commands: Vec<CommandDef>,
22 pub workflows: Vec<Workflow>,
23 pub protocols: Protocols,
24 pub errors: ErrorOntology,
25}
26
27#[derive(Debug, Serialize)]
28pub struct OntologyContext {
29 pub lit: &'static str,
30 pub schema: &'static str,
31 pub vcs: &'static str,
32 pub mcp: &'static str,
33}
34
35#[derive(Debug, Serialize)]
36pub struct Capability {
37 pub id: String,
38 pub name: String,
39 pub description: String,
40}
41
42#[derive(Debug, Serialize)]
43pub struct TypeDef {
44 pub id: String,
45 pub name: String,
46 pub description: String,
47 pub properties: Vec<PropertyDef>,
48}
49
50#[derive(Debug, Serialize)]
51pub struct PropertyDef {
52 pub name: String,
53 #[serde(rename = "type")]
54 pub type_name: String,
55 pub description: String,
56 pub required: bool,
57}
58
59#[derive(Debug, Serialize)]
60pub struct CommandDef {
61 pub id: String,
62 pub name: String,
63 pub description: String,
64 pub category: String,
65 pub parameters: Vec<ParamDef>,
66 pub returns: String,
67 pub side_effects: Vec<String>,
68 pub preconditions: Vec<String>,
69 pub examples: Vec<Example>,
70 pub follows: Vec<String>,
72 pub preceded_by: Vec<String>,
74 pub idempotent: bool,
75 pub safe: bool,
76}
77
78#[derive(Debug, Serialize)]
79pub struct ParamDef {
80 pub name: String,
81 #[serde(rename = "type")]
82 pub type_name: String,
83 pub description: String,
84 pub required: bool,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub default: Option<String>,
87}
88
89#[derive(Debug, Serialize)]
90pub struct Example {
91 pub description: String,
92 pub cli: String,
93 pub json: serde_json::Value,
94}
95
96#[derive(Debug, Serialize)]
97pub struct Workflow {
98 pub id: String,
99 pub name: String,
100 pub description: String,
101 pub steps: Vec<WorkflowStep>,
102 pub agent_optimized: bool,
103}
104
105#[derive(Debug, Serialize)]
106pub struct WorkflowStep {
107 pub order: usize,
108 pub command: String,
109 pub description: String,
110 pub optional: bool,
111}
112
113#[derive(Debug, Serialize)]
114pub struct Protocols {
115 pub cli: CliProtocol,
116 pub rest: RestProtocol,
117 pub mcp: McpProtocol,
118 pub batch: BatchProtocol,
119}
120
121#[derive(Debug, Serialize)]
122pub struct CliProtocol {
123 pub binary: &'static str,
124 pub global_flags: Vec<FlagDef>,
125 pub output_formats: Vec<&'static str>,
126 pub default_format: &'static str,
127}
128
129#[derive(Debug, Serialize)]
130pub struct FlagDef {
131 pub flag: String,
132 pub description: String,
133}
134
135#[derive(Debug, Serialize)]
136pub struct RestProtocol {
137 pub base_path: &'static str,
138 pub auth: Vec<&'static str>,
139 pub content_type: &'static str,
140}
141
142#[derive(Debug, Serialize)]
143pub struct McpProtocol {
144 pub protocol_version: &'static str,
145 pub transports: Vec<McpTransport>,
146 pub tool_prefix: &'static str,
147}
148
149#[derive(Debug, Serialize)]
150pub struct McpTransport {
151 pub name: String,
152 pub command: String,
153 pub description: String,
154}
155
156#[derive(Debug, Serialize)]
157pub struct BatchProtocol {
158 pub format: &'static str,
159 pub input: &'static str,
160 pub flags: Vec<FlagDef>,
161}
162
163#[derive(Debug, Serialize)]
164pub struct ErrorOntology {
165 pub format: ErrorFormat,
166 pub categories: Vec<ErrorCategory>,
167}
168
169#[derive(Debug, Serialize)]
170pub struct ErrorFormat {
171 pub json_envelope: serde_json::Value,
172 pub fields: Vec<String>,
173}
174
175#[derive(Debug, Serialize)]
176pub struct ErrorCategory {
177 pub code: String,
178 pub description: String,
179 pub recoverable: bool,
180 pub suggested_action: String,
181}
182
183pub fn get_ontology() -> LitOntology {
185 LitOntology {
186 context: OntologyContext {
187 lit: "https://lit-vcs.dev/ontology/v1#",
188 schema: "https://schema.org/",
189 vcs: "https://lit-vcs.dev/ontology/vcs#",
190 mcp: "https://modelcontextprotocol.io/schema/v1#",
191 },
192 type_name: "VersionControlSystem",
193 name: "Lit",
194 version: env!("CARGO_PKG_VERSION"),
195 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.",
196 capabilities: build_capabilities(),
197 types: build_types(),
198 commands: build_commands(),
199 workflows: build_workflows(),
200 protocols: build_protocols(),
201 errors: build_errors(),
202 }
203}
204
205fn build_capabilities() -> Vec<Capability> {
206 vec![
207 cap("version-control", "Distributed Version Control", "Full DAG-based version control with branches, merges, commits, and tags"),
208 cap("post-quantum-crypto", "Post-Quantum Cryptography", "ML-DSA-87 (Dilithium5) signatures and ML-KEM (Kyber) key encapsulation for quantum-resistant security"),
209 cap("fips-compliance", "FIPS 140-2 Compliance", "SHA3-512, AES-256-GCM, HMAC-SHA256, PBKDF2 key derivation with secure zeroization"),
210 cap("structured-io", "Structured I/O", "All commands produce structured JSON output by default, with human-readable alternative"),
211 cap("batch-mode", "Batch Operations", "Execute multiple operations from JSONL stdin with atomic and dry-run modes"),
212 cap("transactions", "Transaction Support", "Begin/commit/rollback with write-ahead log for crash recovery"),
213 cap("agent-metadata", "Agent Metadata", "First-class metadata field on commits for agent_id, task_id, confidence, intent, tool_versions"),
214 cap("search", "Full-Text Search", "Search file contents, commit messages, and agent metadata"),
215 cap("snapshot", "Atomic Snapshots", "Single-command add-all + commit for agent workflows"),
216 cap("integrity-verification", "Repository Verification", "Full integrity check of objects, refs, DAG connectivity, and index"),
217 cap("mcp-server", "MCP Tool Server", "Model Context Protocol server for LLM agent integration (stdio and HTTP transports)"),
218 cap("rest-api", "REST API Server", "HTTP API for remote repository operations with bearer token authentication"),
219 cap("swarm-coordination", "Multi-Agent Swarm", "Agent registration, branch namespacing, and file lease system for concurrent agent collaboration"),
220 cap("airgap-mode", "Air-Gap Mode", "Blocks all network protocols, allows only physical/local transports for secure environments"),
221 cap("encryption-at-rest", "Encryption at Rest", "AES-256-GCM encryption for all repository objects and refs"),
222 ]
223}
224
225fn build_types() -> Vec<TypeDef> {
226 vec![
227 TypeDef {
228 id: "ObjectHash".to_string(),
229 name: "Object Hash".to_string(),
230 description:
231 "192-character hex string: SHA3-512 (128 chars) + BLAKE3 (64 chars) concatenated"
232 .to_string(),
233 properties: vec![
234 prop(
235 "sha3_512",
236 "string",
237 "First 128 hex characters — SHA3-512 digest",
238 true,
239 ),
240 prop(
241 "blake3",
242 "string",
243 "Last 64 hex characters — BLAKE3 digest",
244 true,
245 ),
246 ],
247 },
248 TypeDef {
249 id: "Commit".to_string(),
250 name: "Commit Object".to_string(),
251 description: "A snapshot of the repository state at a point in time".to_string(),
252 properties: vec![
253 prop("tree", "ObjectHash", "Hash of the root tree object", true),
254 prop(
255 "parents",
256 "ObjectHash[]",
257 "Parent commit hashes (empty for initial commit)",
258 true,
259 ),
260 prop("author", "string", "Author identity", true),
261 prop(
262 "timestamp",
263 "integer",
264 "Unix timestamp (seconds since epoch)",
265 true,
266 ),
267 prop("message", "string", "Commit message", true),
268 prop(
269 "metadata",
270 "object|null",
271 "Optional JSON metadata (agent_id, task_id, confidence, etc.)",
272 false,
273 ),
274 prop(
275 "signature",
276 "PQSignature|null",
277 "Optional ML-DSA-87 signature",
278 false,
279 ),
280 ],
281 },
282 TypeDef {
283 id: "Tree".to_string(),
284 name: "Tree Object".to_string(),
285 description: "A directory listing mapping names to object hashes".to_string(),
286 properties: vec![prop(
287 "entries",
288 "TreeEntry[]",
289 "List of entries (files and subdirectories)",
290 true,
291 )],
292 },
293 TypeDef {
294 id: "Blob".to_string(),
295 name: "Blob Object".to_string(),
296 description: "File contents stored as a compressed byte sequence".to_string(),
297 properties: vec![prop("data", "bytes", "Compressed file content", true)],
298 },
299 TypeDef {
300 id: "Tag".to_string(),
301 name: "Tag Object".to_string(),
302 description: "A named reference to a specific commit, optionally signed".to_string(),
303 properties: vec![
304 prop("name", "string", "Tag name", true),
305 prop("target", "ObjectHash", "The tagged commit hash", true),
306 prop("tagger", "string", "Author of the tag", true),
307 prop("message", "string", "Tag message", true),
308 prop(
309 "signature",
310 "PQSignature|null",
311 "Optional ML-DSA-87 signature",
312 false,
313 ),
314 ],
315 },
316 TypeDef {
317 id: "Branch".to_string(),
318 name: "Branch Reference".to_string(),
319 description: "A mutable named pointer to a commit hash, stored in .lit/refs/heads/"
320 .to_string(),
321 properties: vec![
322 prop("name", "string", "Branch name", true),
323 prop(
324 "target",
325 "ObjectHash",
326 "The commit hash this branch points to",
327 true,
328 ),
329 ],
330 },
331 TypeDef {
332 id: "AgentMetadata".to_string(),
333 name: "Agent Metadata".to_string(),
334 description: "Structured metadata attached to commits by autonomous agents".to_string(),
335 properties: vec![
336 prop(
337 "agent_id",
338 "string",
339 "Unique identifier of the agent that created the commit",
340 false,
341 ),
342 prop(
343 "agent_model",
344 "string",
345 "Model name/version (e.g., 'claude-opus-4-20250514', 'gpt-4o')",
346 false,
347 ),
348 prop(
349 "task_id",
350 "string",
351 "Identifier for the task or work item being addressed",
352 false,
353 ),
354 prop(
355 "confidence",
356 "number",
357 "Agent's self-assessed confidence in the changes (0.0 - 1.0)",
358 false,
359 ),
360 prop(
361 "intent",
362 "string",
363 "Human-readable description of what the agent intended to do",
364 false,
365 ),
366 prop(
367 "tool_versions",
368 "object",
369 "Versions of tools used (e.g., compiler, linter)",
370 false,
371 ),
372 prop(
373 "parent_task",
374 "string",
375 "Reference to a parent task for hierarchical workflows",
376 false,
377 ),
378 prop(
379 "session_id",
380 "string",
381 "Conversation or session identifier",
382 false,
383 ),
384 ],
385 },
386 TypeDef {
387 id: "FileLease".to_string(),
388 name: "File Lease".to_string(),
389 description: "Exclusive write lock on a file for swarm coordination".to_string(),
390 properties: vec![
391 prop("agent_id", "string", "The agent holding the lease", true),
392 prop("path", "string", "File path the lease covers", true),
393 prop(
394 "acquired_at",
395 "integer",
396 "Unix timestamp when lease was acquired",
397 true,
398 ),
399 prop(
400 "expires_at",
401 "integer",
402 "Unix timestamp when lease expires",
403 true,
404 ),
405 ],
406 },
407 TypeDef {
408 id: "TreeEntry".to_string(),
409 name: "Tree Entry".to_string(),
410 description: "A single entry in a tree object, mapping a name to an object hash".to_string(),
411 properties: vec![
412 prop("mode", "string", "File mode: 100644 (normal), 100755 (executable), 040000 (directory)", true),
413 prop("name", "string", "File or directory name", true),
414 prop("hash", "ObjectHash", "Hash of the referenced blob or tree", true),
415 prop("object_type", "string", "Object type: 'blob' or 'tree'", true),
416 ],
417 },
418 TypeDef {
419 id: "PQSignature".to_string(),
420 name: "Post-Quantum Signature".to_string(),
421 description: "ML-DSA-87 (Dilithium5) digital signature for quantum-resistant authentication".to_string(),
422 properties: vec![
423 prop("algorithm", "string", "Signature algorithm identifier (ML-DSA-87)", true),
424 prop("signature", "bytes", "Raw signature bytes", true),
425 ],
426 },
427 TypeDef {
428 id: "PQKeyPair".to_string(),
429 name: "Post-Quantum Key Pair".to_string(),
430 description: "ML-DSA-87 key pair for signing and verification".to_string(),
431 properties: vec![
432 prop("public_key", "bytes", "Public key for verification", true),
433 prop("secret_key", "bytes", "Secret key for signing (stored securely)", true),
434 ],
435 },
436 TypeDef {
437 id: "IndexEntry".to_string(),
438 name: "Index Entry".to_string(),
439 description: "A staged file in the index (staging area), mapping a path to its object hash".to_string(),
440 properties: vec![
441 prop("path", "string", "Relative file path", true),
442 prop("hash", "string", "Object hash of the staged content", true),
443 prop("mode", "string", "File mode (100644, 100755, etc.)", true),
444 ],
445 },
446 TypeDef {
447 id: "EncryptionConfig".to_string(),
448 name: "Encryption Configuration".to_string(),
449 description: "Repository encryption settings using AES-256-GCM with PBKDF2 key derivation".to_string(),
450 properties: vec![
451 prop("enabled", "boolean", "Whether encryption is active", true),
452 prop("algorithm", "string", "Encryption algorithm (AES-256-GCM)", true),
453 prop("salt", "bytes", "Random salt for key derivation", true),
454 prop("kdf_iterations", "integer", "PBKDF2 iteration count", true),
455 ],
456 },
457 TypeDef {
458 id: "LfsPointer".to_string(),
459 name: "LFS Pointer".to_string(),
460 description: "Lightweight pointer replacing large file content, referencing the actual data stored separately".to_string(),
461 properties: vec![
462 prop("version", "string", "LFS pointer format version", true),
463 prop("oid", "string", "Object identifier (sha3-blake3:hash)", true),
464 prop("size", "integer", "Original file size in bytes", true),
465 ],
466 },
467 TypeDef {
468 id: "PackFile".to_string(),
469 name: "Pack File".to_string(),
470 description: "LITP-format pack file containing multiple compressed objects with CRC32 integrity".to_string(),
471 properties: vec![
472 prop("magic", "string", "File magic bytes: LITP", true),
473 prop("version", "integer", "Pack format version", true),
474 prop("object_count", "integer", "Number of objects in the pack", true),
475 ],
476 },
477 TypeDef {
478 id: "TransactionState".to_string(),
479 name: "Transaction State".to_string(),
480 description: "Write-ahead log state for transactional operations with rollback support".to_string(),
481 properties: vec![
482 prop("tx_id", "string", "Unique transaction identifier", true),
483 prop("started_at", "integer", "Unix timestamp when transaction began", true),
484 prop("operations", "object[]", "List of operations within the transaction", true),
485 ],
486 },
487 TypeDef {
488 id: "DiffHunk".to_string(),
489 name: "Diff Hunk".to_string(),
490 description: "A contiguous block of changes between two versions of a file".to_string(),
491 properties: vec![
492 prop("old_start", "integer", "Starting line number in original", true),
493 prop("old_count", "integer", "Number of lines in original", true),
494 prop("new_start", "integer", "Starting line number in modified", true),
495 prop("new_count", "integer", "Number of lines in modified", true),
496 prop("lines", "DiffLine[]", "Individual line changes", true),
497 ],
498 },
499 TypeDef {
500 id: "DiffLine".to_string(),
501 name: "Diff Line".to_string(),
502 description: "A single line in a diff hunk with its change kind".to_string(),
503 properties: vec![
504 prop("kind", "string", "Change type: context, add, or remove", true),
505 prop("content", "string", "Line content", true),
506 ],
507 },
508 TypeDef {
509 id: "RemoteConfig".to_string(),
510 name: "Remote Configuration".to_string(),
511 description: "Named remote repository URL configuration stored in .lit/remotes".to_string(),
512 properties: vec![
513 prop("name", "string", "Remote name (e.g., 'origin')", true),
514 prop("url", "string", "Remote repository URL", true),
515 ],
516 },
517 TypeDef {
518 id: "ReflogEntry".to_string(),
519 name: "Reflog Entry".to_string(),
520 description: "A single entry in a reference log, recording a ref state transition".to_string(),
521 properties: vec![
522 prop("index", "integer", "Entry index (0 = most recent)", true),
523 prop("old_hash", "ObjectHash", "Previous ref target", true),
524 prop("new_hash", "ObjectHash", "New ref target", true),
525 prop("action", "string", "Action that caused the change (commit, checkout, merge, etc.)", true),
526 prop("message", "string", "Description of the change", true),
527 prop("timestamp", "integer", "Unix timestamp", true),
528 ],
529 },
530 ]
531}
532
533fn build_commands() -> Vec<CommandDef> {
534 vec![
535 cmd("init", "Initialize Repository", "core", "Create a new Lit repository in the current or specified directory",
537 vec![
538 param("bare", "boolean", "Create a bare repository (no working tree)", false, None),
539 param("path", "string", "Directory path (defaults to current directory)", false, None),
540 ],
541 "InitResponse", vec!["Creates .lit/ directory structure"], vec![],
542 vec![ex("Initialize", "lit init", serde_json::json!({"bare": false}))],
543 vec!["add", "config"], vec![], true, true),
544 cmd("add", "Stage Files", "core", "Add file contents to the staging area (index)",
545 vec![param("files", "string[]", "File paths to stage", true, None)],
546 "AddResponse", vec!["Modifies .lit/index"], vec!["Repository must be initialized"],
547 vec![ex("Stage files", "lit add src/main.rs", serde_json::json!({"files": ["src/main.rs"]}))],
548 vec!["commit", "status"], vec!["init", "checkout"], false, true),
549 cmd("commit", "Create Commit", "core", "Record staged changes as a new commit object",
550 vec![
551 param("message", "string", "Commit message describing the changes", true, None),
552 param("author", "string", "Author name", false, None),
553 ],
554 "CommitResponse", vec!["Creates commit and tree objects", "Updates HEAD ref"], vec!["Files must be staged"],
555 vec![ex("Commit", "lit commit -m 'fix bug'", serde_json::json!({"message": "fix bug"}))],
556 vec!["push", "log", "status"], vec!["add"], false, false),
557 cmd("status", "Show Status", "core", "Show the working tree status: branch, staged, modified, and untracked files",
558 vec![],
559 "StatusResponse", vec![], vec!["Repository must be initialized"],
560 vec![ex("Check status", "lit status", serde_json::json!({}))],
561 vec!["add", "commit", "diff"], vec![], true, true),
562 cmd("log", "Show History", "core", "Display commit history from HEAD or a specified ref",
563 vec![
564 param("count", "integer", "Number of commits to show", false, Some("10")),
565 param("oneline", "boolean", "Compact one-line format", false, Some("false")),
566 ],
567 "LogResponse", vec![], vec!["Repository must have commits"],
568 vec![ex("Recent history", "lit log -n 5", serde_json::json!({"count": 5}))],
569 vec!["show", "diff"], vec!["commit"], true, true),
570 cmd("diff", "Show Changes", "core", "Show differences between working tree, index, and commits",
571 vec![
572 param("staged", "boolean", "Compare index to HEAD", false, Some("false")),
573 param("stat", "boolean", "Show statistics only", false, Some("false")),
574 param("ref1", "string", "First reference", false, None),
575 param("ref2", "string", "Second reference", false, None),
576 ],
577 "DiffResponse", vec![], vec![],
578 vec![ex("Working tree diff", "lit diff", serde_json::json!({}))],
579 vec!["add", "commit"], vec![], true, true),
580 cmd("show", "Show Object", "core", "Display contents of a commit, tree, or blob object",
581 vec![param("object", "string", "Object hash or ref name", true, None)],
582 "ShowResponse", vec![], vec![],
583 vec![ex("Show commit", "lit show HEAD", serde_json::json!({"object": "HEAD"}))],
584 vec![], vec!["log"], true, true),
585 cmd("branch", "Manage Branches", "branching", "List, create, or delete branches",
587 vec![
588 param("name", "string", "Branch name to create", false, None),
589 param("delete", "boolean", "Delete the named branch", false, Some("false")),
590 param("all", "boolean", "List all branches", false, Some("false")),
591 ],
592 "BranchResponse", vec!["May create or delete refs"], vec![],
593 vec![ex("List branches", "lit branch --all", serde_json::json!({"all": true}))],
594 vec!["checkout"], vec![], true, true),
595 cmd("checkout", "Switch Branch", "branching", "Switch to a different branch or restore working tree files",
596 vec![
597 param("target", "string", "Branch name or commit hash", true, None),
598 param("b", "boolean", "Create and switch to new branch", false, Some("false")),
599 ],
600 "CheckoutResponse", vec!["Updates working tree", "Updates HEAD"], vec![],
601 vec![ex("Switch branch", "lit checkout main", serde_json::json!({"target": "main"}))],
602 vec!["add", "commit", "merge"], vec!["branch"], false, false),
603 cmd("merge", "Merge Branches", "branching", "Merge another branch into the current branch",
604 vec![
605 param("branch", "string", "Branch to merge", true, None),
606 param("strategy", "string", "Merge strategy (recursive, ours, theirs)", false, Some("recursive")),
607 ],
608 "MergeResponse", vec!["May create merge commit", "May produce conflicts"], vec!["Must be on a branch"],
609 vec![ex("Merge feature", "lit merge feature-x", serde_json::json!({"branch": "feature-x"}))],
610 vec!["resolve", "commit", "push"], vec!["checkout", "pull"], false, false),
611 cmd("push", "Push Changes", "collaboration", "Upload local commits to a remote repository (LAN only)",
613 vec![
614 param("remote", "string", "Remote name", true, None),
615 param("branch", "string", "Branch name", true, None),
616 param("force", "boolean", "Force push", false, Some("false")),
617 ],
618 "PushResponse", vec!["Updates remote refs"], vec!["Remote must be configured"],
619 vec![ex("Push to origin", "lit push origin main", serde_json::json!({"remote": "origin", "branch": "main"}))],
620 vec![], vec!["commit", "merge"], false, false),
621 cmd("pull", "Pull Changes", "collaboration", "Fetch and merge changes from a remote repository",
622 vec![
623 param("remote", "string", "Remote name", true, None),
624 param("branch", "string", "Branch name", true, None),
625 ],
626 "PullResponse", vec!["Updates local refs and working tree"], vec!["Remote must be configured"],
627 vec![ex("Pull from origin", "lit pull origin main", serde_json::json!({"remote": "origin", "branch": "main"}))],
628 vec!["merge", "commit"], vec![], false, false),
629 cmd("snapshot", "Atomic Snapshot", "agent", "Stage all files and commit in one atomic operation — the preferred agent workflow",
631 vec![
632 param("message", "string", "Commit message", true, None),
633 param("author", "string", "Author name", false, None),
634 param("metadata", "AgentMetadata", "Agent metadata JSON object", false, None),
635 ],
636 "SnapshotResponse", vec!["Stages all files", "Creates commit"], vec![],
637 vec![ex("Agent snapshot", "lit snapshot -m 'implement feature X' --metadata '{\"agent_id\":\"claude-1\",\"confidence\":0.95}'",
638 serde_json::json!({"message": "implement feature X", "metadata": {"agent_id": "claude-1", "confidence": 0.95}}))],
639 vec!["push", "log"], vec![], false, false),
640 cmd("batch", "Batch Operations", "agent", "Execute multiple operations from JSONL on stdin",
641 vec![
642 param("atomic", "boolean", "Stop on first failure, skip remaining", false, Some("false")),
643 param("dry_run", "boolean", "Validate without executing", false, Some("false")),
644 ],
645 "BatchResponse", vec!["Depends on operations"], vec![],
646 vec![ex("Batch", "echo '{\"command\":\"status\"}' | lit batch", serde_json::json!({"atomic": false}))],
647 vec![], vec![], false, false),
648 cmd("search", "Search Repository", "agent", "Full-text search across file contents, commit messages, or agent metadata",
649 vec![
650 param("query", "string", "Search query string", true, None),
651 param("messages", "boolean", "Search commit messages", false, Some("false")),
652 param("metadata", "string", "Search metadata (key=value)", false, None),
653 param("max_results", "integer", "Maximum results to return", false, Some("100")),
654 ],
655 "SearchResponse", vec![], vec![],
656 vec![ex("Search files", "lit search 'TODO'", serde_json::json!({"query": "TODO"}))],
657 vec![], vec![], true, true),
658 cmd("verify", "Verify Integrity", "agent", "Run full repository integrity check — objects, refs, DAG, index",
659 vec![],
660 "VerifyResponse", vec![], vec!["Repository must be initialized"],
661 vec![ex("Verify", "lit verify", serde_json::json!({}))],
662 vec![], vec![], true, true),
663 cmd("swarm register", "Register Agent", "swarm", "Register an agent for multi-agent coordination with branch namespacing",
665 vec![param("agent_id", "string", "Unique agent identifier", true, None)],
666 "SwarmResponse", vec!["Creates agent namespace in refs"], vec![],
667 vec![ex("Register", "lit swarm register claude-1", serde_json::json!({"agent_id": "claude-1"}))],
668 vec!["swarm lease-acquire"], vec![], true, false),
669 cmd("swarm lease-acquire", "Acquire File Lease", "swarm", "Acquire exclusive write access to a file for a specified duration",
670 vec![
671 param("agent_id", "string", "Agent requesting the lease", true, None),
672 param("path", "string", "File path to lease", true, None),
673 param("duration", "integer", "Lease duration in seconds", false, Some("300")),
674 ],
675 "SwarmResponse", vec!["Creates lease file"], vec!["Agent must be registered"],
676 vec![ex("Acquire lease", "lit swarm lease-acquire --agent claude-1 --path src/main.rs --duration 300",
677 serde_json::json!({"agent_id": "claude-1", "path": "src/main.rs", "duration": 300}))],
678 vec!["swarm lease-release"], vec!["swarm register"], false, false),
679 cmd("swarm lease-release", "Release File Lease", "swarm", "Release an exclusive write lease on a file",
680 vec![
681 param("agent_id", "string", "Agent releasing the lease", true, None),
682 param("path", "string", "File path to release", true, None),
683 ],
684 "SwarmResponse", vec!["Removes lease file"], vec!["Lease must be held by this agent"],
685 vec![ex("Release lease", "lit swarm lease-release --agent claude-1 --path src/main.rs",
686 serde_json::json!({"agent_id": "claude-1", "path": "src/main.rs"}))],
687 vec![], vec!["swarm lease-acquire"], true, false),
688 cmd("swarm list", "List Agents", "swarm", "List all registered agents in the swarm",
689 vec![],
690 "SwarmResponse", vec![], vec![],
691 vec![ex("List agents", "lit swarm list", serde_json::json!({}))],
692 vec![], vec!["swarm register"], true, true),
693 cmd("swarm lease-list", "List Leases", "swarm", "List all active file leases across all agents",
694 vec![],
695 "SwarmResponse", vec![], vec![],
696 vec![ex("List leases", "lit swarm lease-list", serde_json::json!({}))],
697 vec![], vec![], true, true),
698 cmd("remote", "Manage Remotes", "collaboration", "Add, remove, or list remote repository URLs (LAN only)",
700 vec![
701 param("command", "string", "Subcommand: add, remove, list", true, None),
702 param("name", "string", "Remote name (for add/remove)", false, None),
703 param("url", "string", "Remote URL (for add)", false, None),
704 param("verbose", "boolean", "Show URLs in list", false, Some("false")),
705 ],
706 "RemoteResponse", vec!["May modify .lit/remotes config"], vec![],
707 vec![
708 ex("List remotes", "lit remote list", serde_json::json!({"command": "list"})),
709 ex("Add remote", "lit remote add origin smb://server/repo", serde_json::json!({"command": "add", "name": "origin", "url": "smb://server/repo"})),
710 ],
711 vec!["push", "pull", "fetch"], vec!["init", "clone"], true, true),
712 cmd("clone", "Clone Repository", "collaboration", "Clone a remote repository into a new local directory (LAN only)",
713 vec![
714 param("url", "string", "Repository URL (must be LAN)", true, None),
715 param("directory", "string", "Destination directory name", false, None),
716 ],
717 "CloneResponse", vec!["Creates new directory", "Downloads all objects and refs"], vec![],
718 vec![ex("Clone", "lit clone smb://server/repo myrepo", serde_json::json!({"url": "smb://server/repo", "directory": "myrepo"}))],
719 vec!["status", "log", "checkout"], vec![], false, false),
720 cmd("fetch", "Fetch Remote", "collaboration", "Download objects and refs from a remote without merging",
721 vec![
722 param("remote", "string", "Remote name", true, None),
723 param("branch", "string", "Specific branch to fetch (omit for all)", false, None),
724 ],
725 "FetchResponse", vec!["Updates remote-tracking refs"], vec!["Remote must be configured"],
726 vec![ex("Fetch all", "lit fetch origin", serde_json::json!({"remote": "origin"}))],
727 vec!["merge", "log"], vec![], false, true),
728 cmd("config", "Configuration", "configuration", "Show, get, or set repository and global configuration values",
730 vec![
731 param("command", "string", "Subcommand: show, get, set", true, None),
732 param("key", "string", "Configuration key (for get/set)", false, None),
733 param("value", "string", "Configuration value (for set)", false, None),
734 ],
735 "ConfigResponse", vec!["May modify .lit/config"], vec![],
736 vec![
737 ex("Show all config", "lit config show", serde_json::json!({"command": "show"})),
738 ex("Get value", "lit config get core.bare", serde_json::json!({"command": "get", "key": "core.bare"})),
739 ],
740 vec![], vec!["init"], true, true),
741 cmd("tag", "Manage Tags", "branching", "Create, list, delete, sign, or verify tags. Supports annotated and post-quantum-signed tags (ML-DSA-87)",
743 vec![
744 param("name", "string", "Tag name", false, None),
745 param("annotate", "boolean", "Create annotated tag", false, Some("false")),
746 param("message", "string", "Tag message (implies annotated)", false, None),
747 param("delete", "boolean", "Delete the named tag", false, Some("false")),
748 param("sign", "boolean", "Sign tag with ML-DSA-87", false, Some("false")),
749 param("verify", "boolean", "Verify tag signature", false, Some("false")),
750 param("list", "boolean", "List all tags", false, Some("false")),
751 param("commit", "string", "Target commit (defaults to HEAD)", false, None),
752 ],
753 "TagResponse", vec!["May create or delete refs/tags/"], vec![],
754 vec![
755 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"})),
756 ex("List tags", "lit tag --list", serde_json::json!({"list": true})),
757 ex("Sign tag", "lit tag v1.0 --sign -m 'Signed release'", serde_json::json!({"name": "v1.0", "sign": true, "message": "Signed release"})),
758 ],
759 vec!["push"], vec!["commit"], true, true),
760 cmd("stash", "Stash Changes", "history", "Save, restore, list, or drop temporarily stashed changes",
762 vec![
763 param("command", "string", "Subcommand: push, pop, apply, list, drop", true, None),
764 param("message", "string", "Stash message (for push)", false, None),
765 param("index", "integer", "Stash index (for apply/drop)", false, None),
766 ],
767 "StashResponse", vec!["May modify .lit/stash and working tree"], vec![],
768 vec![
769 ex("Save changes", "lit stash push -m 'WIP'", serde_json::json!({"command": "push", "message": "WIP"})),
770 ex("Restore latest", "lit stash pop", serde_json::json!({"command": "pop"})),
771 ex("List stashes", "lit stash list", serde_json::json!({"command": "list"})),
772 ],
773 vec!["checkout", "commit"], vec![], false, false),
774 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)",
775 vec![
776 param("target", "string", "Target commit hash or HEAD~N expression", true, None),
777 param("soft", "boolean", "Keep changes in staging area", false, Some("false")),
778 param("hard", "boolean", "Discard all changes (index + working tree)", false, Some("false")),
779 ],
780 "ResetResponse", vec!["Updates HEAD", "May modify index and working tree"], vec![],
781 vec![
782 ex("Soft reset", "lit reset HEAD~1 --soft", serde_json::json!({"target": "HEAD~1", "soft": true})),
783 ex("Hard reset", "lit reset HEAD~3 --hard", serde_json::json!({"target": "HEAD~3", "hard": true})),
784 ],
785 vec!["status", "log"], vec!["log", "commit"], false, false),
786 cmd("revert", "Revert Commit", "history", "Create a new inverse commit that undoes the changes from a specified commit",
787 vec![param("target", "string", "Commit hash to revert", true, None)],
788 "RevertResponse", vec!["Creates inverse commit"], vec!["Target commit must exist"],
789 vec![ex("Revert commit", "lit revert abc123", serde_json::json!({"target": "abc123"}))],
790 vec!["push", "log"], vec!["log"], false, false),
791 cmd("cherry-pick", "Cherry-Pick Commit", "history", "Apply the changes from a specific commit onto the current branch",
792 vec![param("target", "string", "Commit hash to cherry-pick", true, None)],
793 "CherryPickResponse", vec!["Creates new commit with applied changes"], vec!["Target commit must exist"],
794 vec![ex("Cherry-pick", "lit cherry-pick abc123", serde_json::json!({"target": "abc123"}))],
795 vec!["push", "log"], vec!["log", "checkout"], false, false),
796 cmd("rebase", "Rebase Branch", "history", "Reapply commits from the current branch onto a new base. Supports interactive mode with todo editing",
797 vec![
798 param("base", "string", "Base branch or commit to rebase onto", true, None),
799 param("interactive", "boolean", "Interactive rebase with todo list", false, Some("false")),
800 param("onto", "string", "Specific commit to rebase onto", false, None),
801 param("abort", "boolean", "Abort an in-progress rebase", false, Some("false")),
802 param("continue", "boolean", "Continue a paused rebase", false, Some("false")),
803 ],
804 "RebaseResponse", vec!["Rewrites commit history", "Updates HEAD"], vec!["Working tree must be clean"],
805 vec![
806 ex("Rebase onto main", "lit rebase main", serde_json::json!({"base": "main"})),
807 ex("Interactive rebase", "lit rebase main --interactive", serde_json::json!({"base": "main", "interactive": true})),
808 ],
809 vec!["push --force", "log"], vec!["checkout"], false, false),
810 cmd("blame", "Blame File", "history", "Show what revision and author last modified each line of a file",
811 vec![param("file", "string", "File path to blame", true, None)],
812 "BlameResponse", vec![], vec!["File must exist in repository"],
813 vec![ex("Blame file", "lit blame src/main.rs", serde_json::json!({"file": "src/main.rs"}))],
814 vec!["show", "log"], vec![], true, true),
815 cmd("bisect", "Binary Search", "history", "Binary search through commit history to find the commit that introduced a bug",
816 vec![
817 param("command", "string", "Subcommand: start, good, bad, reset", true, None),
818 param("commit", "string", "Commit hash (for good/bad)", false, None),
819 ],
820 "BisectResponse", vec!["Updates HEAD to test commits", "Saves state to .lit/bisect.json"], vec![],
821 vec![
822 ex("Start bisect", "lit bisect start", serde_json::json!({"command": "start"})),
823 ex("Mark good", "lit bisect good abc123", serde_json::json!({"command": "good", "commit": "abc123"})),
824 ],
825 vec!["bisect good", "bisect bad", "bisect reset"], vec![], false, false),
826 cmd("reflog", "Reference Log", "history", "Show the history of reference changes (HEAD updates, branch moves, etc.)",
827 vec![
828 param("ref_name", "string", "Reference name (default: HEAD)", false, Some("HEAD")),
829 param("count", "integer", "Number of entries to show", false, Some("20")),
830 ],
831 "ReflogResponse", vec![], vec![],
832 vec![ex("Show reflog", "lit reflog", serde_json::json!({}))],
833 vec!["reset", "checkout"], vec![], true, true),
834 cmd("resolve", "Resolve Conflicts", "branching", "Resolve merge conflicts using a specified strategy or finalize a merge after manual resolution",
835 vec![
836 param("file", "string", "Specific file to resolve", false, None),
837 param("strategy", "string", "Resolution strategy: ours or theirs", false, None),
838 param("all", "boolean", "Resolve all conflicting files", false, Some("false")),
839 param("finish", "boolean", "Finalize merge after resolving all conflicts", false, Some("false")),
840 ],
841 "ResolveResponse", vec!["Modifies conflicting files", "May create merge commit"], vec!["Merge conflicts must exist"],
842 vec![
843 ex("Resolve all with ours", "lit resolve --all --strategy ours", serde_json::json!({"all": true, "strategy": "ours"})),
844 ex("Finish merge", "lit resolve --continue", serde_json::json!({"finish": true})),
845 ],
846 vec!["commit", "push"], vec!["merge", "pull"], false, false),
847 cmd("watch", "Watch Filesystem", "agent", "Monitor the working tree for file changes and emit a continuous stream of JSONL events",
849 vec![
850 param("debounce", "integer", "Debounce interval in milliseconds", false, Some("500")),
851 param("filter", "string", "Glob pattern to filter watched files", false, None),
852 ],
853 "WatchResponse (continuous JSONL stream)", vec![], vec![],
854 vec![ex("Watch with filter", "lit watch --filter '*.rs'", serde_json::json!({"filter": "*.rs"}))],
855 vec!["snapshot"], vec![], true, true),
856 cmd("tx begin", "Begin Transaction", "agent", "Start a new transaction with write-ahead log for crash recovery",
858 vec![],
859 "TransactionResponse", vec!["Creates .lit/transaction.json and .lit/transaction.lock"], vec!["No other transaction active"],
860 vec![ex("Begin transaction", "lit tx begin", serde_json::json!({}))],
861 vec!["tx commit", "tx rollback"], vec![], false, false),
862 cmd("tx commit", "Commit Transaction", "agent", "Commit the current transaction, finalizing all operations within it",
863 vec![],
864 "TransactionResponse", vec!["Removes transaction lock"], vec!["Transaction must be active"],
865 vec![ex("Commit transaction", "lit tx commit", serde_json::json!({}))],
866 vec![], vec!["tx begin"], false, false),
867 cmd("tx rollback", "Rollback Transaction", "agent", "Rollback the current transaction, undoing all operations within it",
868 vec![],
869 "TransactionResponse", vec!["Restores pre-transaction state", "Removes transaction files"], vec!["Transaction must be active"],
870 vec![ex("Rollback", "lit tx rollback", serde_json::json!({}))],
871 vec![], vec!["tx begin"], false, false),
872 cmd("serve", "REST API Server", "server", "Start the Lit REST API server with optional bearer token authentication. Supports HTTP, stdio, and lit:// daemon modes",
874 vec![
875 param("port", "integer", "Port to listen on", false, Some("3000")),
876 param("token", "string", "Bearer token for authentication (or LIT_API_TOKEN env)", false, None),
877 param("stdio", "boolean", "Use stdio transport (for SSH pipe mode)", false, Some("false")),
878 param("daemon", "boolean", "Run as lit:// protocol daemon (TCP, port 9418)", false, Some("false")),
879 ],
880 "ServeResponse", vec!["Starts long-running HTTP/TCP server"], vec!["Repository must be initialized"],
881 vec![ex("Start server", "lit serve --port 3000 --token secret", serde_json::json!({"port": 3000, "token": "secret"}))],
882 vec![], vec!["init"], false, false),
883 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",
884 vec![
885 param("stdio", "boolean", "Use stdio transport (default)", false, Some("true")),
886 param("port", "integer", "Use HTTP transport on specified port", false, None),
887 ],
888 "McpServeResponse", vec!["Starts long-running MCP server"], vec!["Repository must be initialized"],
889 vec![
890 ex("MCP stdio", "lit mcp-serve --stdio", serde_json::json!({"stdio": true})),
891 ex("MCP HTTP", "lit mcp-serve --port 3001", serde_json::json!({"port": 3001})),
892 ],
893 vec![], vec!["init"], false, false),
894 cmd("import-git", "Import Git Repository", "interop", "Import a Git repository into Lit format, converting SHA-1 objects to SHA3-512+BLAKE3 composite hashes",
896 vec![param("source", "string", "Path to Git repository (directory containing .git)", true, None)],
897 "ImportGitResponse", vec!["Creates Lit objects from Git objects", "Creates Lit refs from Git refs"], vec!["Source must be a valid Git repository"],
898 vec![ex("Import", "lit import-git /path/to/git-repo", serde_json::json!({"source": "/path/to/git-repo"}))],
899 vec!["log", "status", "verify"], vec![], false, false),
900 cmd("export-git", "Export to Git", "interop", "Export a Lit repository to Git format, converting composite hashes back to SHA-1",
901 vec![param("destination", "string", "Destination path for the Git repository", true, None)],
902 "ExportGitResponse", vec!["Creates bare Git repository at destination"], vec!["Lit repository must have commits"],
903 vec![ex("Export", "lit export-git /path/to/output", serde_json::json!({"destination": "/path/to/output"}))],
904 vec![], vec!["commit"], false, false),
905 cmd("gc", "Garbage Collection", "performance", "Pack loose objects into pack files (LITP format) with CRC32 integrity, reducing disk usage and improving read performance",
907 vec![],
908 "GcResponse", vec!["Creates pack files", "Removes packed loose objects"], vec!["Repository must be initialized"],
909 vec![ex("Run GC", "lit gc", serde_json::json!({}))],
910 vec!["verify"], vec![], false, false),
911 cmd("lfs track", "LFS Track Patterns", "performance", "Track file patterns for Large File Storage, writing rules to .litattributes",
912 vec![param("patterns", "string[]", "Glob patterns to track (e.g., '*.bin', '*.dat')", true, None)],
913 "LfsTrackResponse", vec!["Modifies .litattributes"], vec![],
914 vec![ex("Track binaries", "lit lfs track '*.bin' '*.dat'", serde_json::json!({"patterns": ["*.bin", "*.dat"]}))],
915 vec!["lfs migrate", "add"], vec!["init"], true, true),
916 cmd("lfs migrate", "LFS Migrate", "performance", "Migrate existing large files to LFS pointer format, replacing content with lightweight references",
917 vec![param("threshold", "integer", "Size threshold in bytes (default: 10MB)", false, Some("10485760"))],
918 "LfsMigrateResponse", vec!["Replaces large blobs with LFS pointers"], vec!["LFS patterns must be configured"],
919 vec![ex("Migrate large files", "lit lfs migrate --threshold 5242880", serde_json::json!({"threshold": 5242880}))],
920 vec!["commit"], vec!["lfs track"], false, false),
921 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",
923 vec![],
924 "RotateKeyResponse", vec!["Re-encrypts all objects, index, and refs"], vec!["Repository must be encrypted"],
925 vec![ex("Rotate key", "lit rotate-key", serde_json::json!({}))],
926 vec!["verify"], vec![], false, false),
927 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",
929 vec![],
930 "OntologyResponse", vec![], vec![],
931 vec![ex("Get ontology", "lit ontology", serde_json::json!({}))],
932 vec![], vec![], true, true),
933 ]
934}
935
936fn build_workflows() -> Vec<Workflow> {
937 vec![
938 Workflow {
939 id: "agent-basic".to_string(),
940 name: "Basic Agent Workflow".to_string(),
941 description: "The simplest agent workflow: make changes, snapshot, push".to_string(),
942 agent_optimized: true,
943 steps: vec![
944 wstep(1, "status", "Check current repository state", false),
945 wstep(
946 2,
947 "snapshot",
948 "Stage all changes and commit atomically",
949 false,
950 ),
951 wstep(3, "push", "Push to remote", true),
952 ],
953 },
954 Workflow {
955 id: "agent-branch".to_string(),
956 name: "Agent Branch Workflow".to_string(),
957 description: "Create a feature branch, make changes, merge back".to_string(),
958 agent_optimized: true,
959 steps: vec![
960 wstep(
961 1,
962 "checkout -b",
963 "Create and switch to feature branch",
964 false,
965 ),
966 wstep(2, "snapshot", "Make changes and commit", false),
967 wstep(3, "checkout", "Switch back to main branch", false),
968 wstep(4, "merge", "Merge feature branch", false),
969 wstep(5, "push", "Push merged changes", true),
970 ],
971 },
972 Workflow {
973 id: "agent-batch".to_string(),
974 name: "Batch Operation Workflow".to_string(),
975 description: "Submit multiple operations as JSONL for batch execution".to_string(),
976 agent_optimized: true,
977 steps: vec![
978 wstep(
979 1,
980 "batch --dry-run",
981 "Validate operations without executing",
982 true,
983 ),
984 wstep(2, "batch --atomic", "Execute operations atomically", false),
985 ],
986 },
987 Workflow {
988 id: "agent-transaction".to_string(),
989 name: "Transaction Workflow".to_string(),
990 description: "Group operations with rollback support".to_string(),
991 agent_optimized: true,
992 steps: vec![
993 wstep(1, "tx begin", "Start a new transaction", false),
994 wstep(
995 2,
996 "add/commit/...",
997 "Perform operations within the transaction",
998 false,
999 ),
1000 wstep(
1001 3,
1002 "tx commit",
1003 "Commit the transaction (or tx rollback to undo)",
1004 false,
1005 ),
1006 ],
1007 },
1008 Workflow {
1009 id: "swarm-collaboration".to_string(),
1010 name: "Multi-Agent Collaboration".to_string(),
1011 description:
1012 "Multiple agents working on the same repository with lease-based coordination"
1013 .to_string(),
1014 agent_optimized: true,
1015 steps: vec![
1016 wstep(1, "swarm register", "Register agent identity", false),
1017 wstep(
1018 2,
1019 "swarm lease-acquire",
1020 "Acquire exclusive lease on files to edit",
1021 false,
1022 ),
1023 wstep(3, "checkout -b", "Create agent-namespaced branch", false),
1024 wstep(4, "snapshot", "Make and commit changes", false),
1025 wstep(5, "swarm lease-release", "Release file leases", false),
1026 wstep(
1027 6,
1028 "push",
1029 "Push agent branch for coordinator to merge",
1030 false,
1031 ),
1032 ],
1033 },
1034 Workflow {
1035 id: "verify-and-fix".to_string(),
1036 name: "Verify and Fix".to_string(),
1037 description: "Check repository integrity and take corrective action if needed"
1038 .to_string(),
1039 agent_optimized: true,
1040 steps: vec![
1041 wstep(1, "verify", "Run full integrity check", false),
1042 wstep(
1043 2,
1044 "search",
1045 "Search for related issues if verification fails",
1046 true,
1047 ),
1048 wstep(3, "snapshot", "Commit fixes if any were applied", true),
1049 ],
1050 },
1051 Workflow {
1052 id: "git-migration".to_string(),
1053 name: "Git Migration".to_string(),
1054 description: "Import an existing Git repository into Lit format and verify integrity".to_string(),
1055 agent_optimized: true,
1056 steps: vec![
1057 wstep(1, "import-git", "Import Git objects and refs into Lit", false),
1058 wstep(2, "verify", "Verify integrity of imported data", false),
1059 wstep(3, "log", "Review imported commit history", true),
1060 wstep(4, "branch --all", "List imported branches", true),
1061 ],
1062 },
1063 Workflow {
1064 id: "agent-code-review".to_string(),
1065 name: "Agent Code Review".to_string(),
1066 description: "Review changes on a branch, provide feedback via commits".to_string(),
1067 agent_optimized: true,
1068 steps: vec![
1069 wstep(1, "log", "Review recent commit history", false),
1070 wstep(2, "diff", "Examine changes in detail", false),
1071 wstep(3, "blame", "Check authorship of specific files", true),
1072 wstep(4, "search", "Search for patterns or issues", true),
1073 wstep(5, "snapshot", "Commit review annotations as metadata", true),
1074 ],
1075 },
1076 Workflow {
1077 id: "agent-bisect".to_string(),
1078 name: "Automated Bug Bisection".to_string(),
1079 description: "Binary search through commit history to find the commit that introduced a regression".to_string(),
1080 agent_optimized: true,
1081 steps: vec![
1082 wstep(1, "bisect start", "Begin bisection", false),
1083 wstep(2, "bisect bad", "Mark the known-bad commit", false),
1084 wstep(3, "bisect good", "Mark a known-good commit", false),
1085 wstep(4, "verify", "Test current commit (repeat until found)", false),
1086 wstep(5, "bisect reset", "End bisection session", false),
1087 ],
1088 },
1089 Workflow {
1090 id: "encrypted-repo".to_string(),
1091 name: "Encrypted Repository".to_string(),
1092 description: "Work with an encrypted repository using passphrase-based access".to_string(),
1093 agent_optimized: true,
1094 steps: vec![
1095 wstep(1, "init", "Initialize repository", false),
1096 wstep(2, "config set", "Configure encryption settings", false),
1097 wstep(3, "snapshot", "Create encrypted commits (passphrase via --passphrase or LIT_PASSPHRASE)", false),
1098 wstep(4, "rotate-key", "Periodically rotate encryption passphrase", true),
1099 wstep(5, "verify", "Verify encrypted integrity", true),
1100 ],
1101 },
1102 ]
1103}
1104
1105fn build_protocols() -> Protocols {
1106 Protocols {
1107 cli: CliProtocol {
1108 binary: "lit",
1109 global_flags: vec![
1110 flag("--json", "Output as JSON (default)"),
1111 flag("--human", "Output as human-readable text"),
1112 flag("--airgapped", "Enable air-gap mode (block network)"),
1113 flag(
1114 "--passphrase <PASSPHRASE>",
1115 "Encryption passphrase (or LIT_PASSPHRASE env)",
1116 ),
1117 flag(
1118 "--passphrase-file <PATH>",
1119 "Path to passphrase file (or LIT_PASSPHRASE_FILE env)",
1120 ),
1121 ],
1122 output_formats: vec!["json", "human"],
1123 default_format: "json",
1124 },
1125 rest: RestProtocol {
1126 base_path: "/api/v1",
1127 auth: vec!["Bearer token", "None (localhost only)"],
1128 content_type: "application/json",
1129 },
1130 mcp: McpProtocol {
1131 protocol_version: "2024-11-05",
1132 tool_prefix: "lit_",
1133 transports: vec![
1134 McpTransport {
1135 name: "stdio".to_string(),
1136 command: "lit mcp-serve --stdio".to_string(),
1137 description: "JSON-RPC 2.0 over stdin/stdout — standard MCP transport"
1138 .to_string(),
1139 },
1140 McpTransport {
1141 name: "http".to_string(),
1142 command: "lit mcp-serve --port 3001".to_string(),
1143 description: "JSON-RPC 2.0 over HTTP POST".to_string(),
1144 },
1145 ],
1146 },
1147 batch: BatchProtocol {
1148 format: "JSONL",
1149 input: "stdin",
1150 flags: vec![
1151 flag("--atomic", "Stop on first failure"),
1152 flag("--dry-run", "Validate without executing"),
1153 ],
1154 },
1155 }
1156}
1157
1158fn build_errors() -> ErrorOntology {
1159 ErrorOntology {
1160 format: ErrorFormat {
1161 json_envelope: serde_json::json!({
1162 "status": "error",
1163 "command": "<command_name>",
1164 "error": {
1165 "code": "<error_code>",
1166 "message": "<human_readable_message>",
1167 "suggestions": ["<recovery_hint>"]
1168 }
1169 }),
1170 fields: vec![
1171 "status".to_string(),
1172 "command".to_string(),
1173 "error.code".to_string(),
1174 "error.message".to_string(),
1175 "error.suggestions".to_string(),
1176 ],
1177 },
1178 categories: vec![
1179 errc(
1180 "REPO_NOT_FOUND",
1181 "Not a Lit repository",
1182 true,
1183 "Run 'lit init' to create one",
1184 ),
1185 errc(
1186 "REPO_CORRUPT",
1187 "Repository data is corrupt or inconsistent",
1188 false,
1189 "Run 'lit verify' to diagnose — may require re-clone",
1190 ),
1191 errc(
1192 "NO_COMMITS",
1193 "No commits in repository",
1194 true,
1195 "Create files and run 'lit snapshot -m \"initial\"'",
1196 ),
1197 errc(
1198 "MERGE_CONFLICT",
1199 "Merge conflict detected",
1200 true,
1201 "Use 'lit resolve' or 'lit resolve --all --strategy ours'",
1202 ),
1203 errc(
1204 "NOTHING_STAGED",
1205 "No files staged for commit",
1206 true,
1207 "Run 'lit add <files>' or use 'lit snapshot' instead",
1208 ),
1209 errc(
1210 "REF_NOT_FOUND",
1211 "Branch, tag, or ref does not exist",
1212 true,
1213 "Run 'lit branch --all' or 'lit tag --list' to list available refs",
1214 ),
1215 errc(
1216 "REF_CONFLICT",
1217 "Reference already exists or conflicts with another",
1218 true,
1219 "Use a different name or delete the existing ref first",
1220 ),
1221 errc(
1222 "OBJECT_NOT_FOUND",
1223 "Object hash not found in store",
1224 false,
1225 "The object may be corrupt or missing — run 'lit verify'",
1226 ),
1227 errc(
1228 "INDEX_LOCKED",
1229 "Index is locked by another operation",
1230 true,
1231 "Wait for the other operation to complete or remove .lit/index.lock",
1232 ),
1233 errc(
1234 "TX_IN_PROGRESS",
1235 "Another transaction is active",
1236 true,
1237 "Run 'lit tx rollback' to abort the existing transaction",
1238 ),
1239 errc(
1240 "LEASE_HELD",
1241 "File lease held by another agent",
1242 true,
1243 "Wait for lease expiration or coordinate with the holding agent",
1244 ),
1245 errc(
1246 "TRANSPORT_DENIED",
1247 "Network transport blocked or unavailable",
1248 true,
1249 "Disable --airgapped flag, use local file:// URLs, or check remote configuration",
1250 ),
1251 errc(
1252 "AUTH_FAILED",
1253 "Authentication failed for remote operation",
1254 true,
1255 "Check Bearer token (--token or LIT_API_TOKEN env) or verify credentials",
1256 ),
1257 errc(
1258 "CRYPTO_ERROR",
1259 "Encryption or decryption operation failed",
1260 true,
1261 "Verify passphrase is correct (--passphrase or LIT_PASSPHRASE env)",
1262 ),
1263 errc(
1264 "INVALID_INPUT",
1265 "Invalid argument or parameter value",
1266 true,
1267 "Check command help with 'lit <command> --help'",
1268 ),
1269 errc(
1270 "IO_ERROR",
1271 "File system read/write error",
1272 false,
1273 "Check file permissions and disk space",
1274 ),
1275 errc(
1276 "CONFIG_ERROR",
1277 "Configuration file is missing or malformed",
1278 true,
1279 "Run 'lit config show' to inspect or 'lit init' to recreate defaults",
1280 ),
1281 errc(
1282 "NOT_IMPLEMENTED",
1283 "Feature is not yet implemented",
1284 false,
1285 "This feature is planned for a future release",
1286 ),
1287 ],
1288 }
1289}
1290
1291fn cap(id: &str, name: &str, desc: &str) -> Capability {
1293 Capability {
1294 id: id.to_string(),
1295 name: name.to_string(),
1296 description: desc.to_string(),
1297 }
1298}
1299
1300fn prop(name: &str, type_name: &str, desc: &str, required: bool) -> PropertyDef {
1301 PropertyDef {
1302 name: name.to_string(),
1303 type_name: type_name.to_string(),
1304 description: desc.to_string(),
1305 required,
1306 }
1307}
1308
1309fn param(
1310 name: &str,
1311 type_name: &str,
1312 desc: &str,
1313 required: bool,
1314 default: Option<&str>,
1315) -> ParamDef {
1316 ParamDef {
1317 name: name.to_string(),
1318 type_name: type_name.to_string(),
1319 description: desc.to_string(),
1320 required,
1321 default: default.map(|s| s.to_string()),
1322 }
1323}
1324
1325fn ex(desc: &str, cli: &str, json: serde_json::Value) -> Example {
1326 Example {
1327 description: desc.to_string(),
1328 cli: cli.to_string(),
1329 json,
1330 }
1331}
1332
1333#[allow(clippy::too_many_arguments)]
1334fn cmd(
1335 id: &str,
1336 name: &str,
1337 category: &str,
1338 desc: &str,
1339 parameters: Vec<ParamDef>,
1340 returns: &str,
1341 side_effects: Vec<&str>,
1342 preconditions: Vec<&str>,
1343 examples: Vec<Example>,
1344 follows: Vec<&str>,
1345 preceded_by: Vec<&str>,
1346 idempotent: bool,
1347 safe: bool,
1348) -> CommandDef {
1349 CommandDef {
1350 id: id.to_string(),
1351 name: name.to_string(),
1352 category: category.to_string(),
1353 description: desc.to_string(),
1354 parameters,
1355 returns: returns.to_string(),
1356 side_effects: side_effects.into_iter().map(|s| s.to_string()).collect(),
1357 preconditions: preconditions.into_iter().map(|s| s.to_string()).collect(),
1358 examples,
1359 follows: follows.into_iter().map(|s| s.to_string()).collect(),
1360 preceded_by: preceded_by.into_iter().map(|s| s.to_string()).collect(),
1361 idempotent,
1362 safe,
1363 }
1364}
1365
1366fn wstep(order: usize, command: &str, description: &str, optional: bool) -> WorkflowStep {
1367 WorkflowStep {
1368 order,
1369 command: command.to_string(),
1370 description: description.to_string(),
1371 optional,
1372 }
1373}
1374
1375fn flag(f: &str, desc: &str) -> FlagDef {
1376 FlagDef {
1377 flag: f.to_string(),
1378 description: desc.to_string(),
1379 }
1380}
1381
1382fn errc(code: &str, desc: &str, recoverable: bool, action: &str) -> ErrorCategory {
1383 ErrorCategory {
1384 code: code.to_string(),
1385 description: desc.to_string(),
1386 recoverable,
1387 suggested_action: action.to_string(),
1388 }
1389}
1390
1391fn ontology_type_to_schema(type_name: &str) -> serde_json::Value {
1397 match type_name {
1398 "string" | "String" => serde_json::json!({ "type": "string" }),
1399 "boolean" | "bool" => serde_json::json!({ "type": "boolean" }),
1400 "integer" | "usize" | "i64" | "u64" | "i32" | "u32" => {
1401 serde_json::json!({ "type": "integer" })
1402 }
1403 "number" | "f64" | "f32" => serde_json::json!({ "type": "number" }),
1404 t if t.starts_with("array<") && t.ends_with('>') => {
1405 let inner = &t[6..t.len() - 1];
1406 serde_json::json!({
1407 "type": "array",
1408 "items": ontology_type_to_schema(inner)
1409 })
1410 }
1411 t if t.starts_with("optional<") && t.ends_with('>') => {
1412 let inner = &t[9..t.len() - 1];
1413 let mut schema = ontology_type_to_schema(inner);
1414 if let Some(obj) = schema.as_object_mut() {
1416 if let Some(serde_json::Value::String(ty)) = obj.get("type").cloned() {
1417 obj.insert("type".to_string(), serde_json::json!([ty, "null"]));
1418 }
1419 }
1420 schema
1421 }
1422 other => serde_json::json!({ "$ref": format!("#/$defs/{other}") }),
1424 }
1425}
1426
1427fn type_def_to_schema(td: &TypeDef) -> serde_json::Value {
1429 let mut properties = serde_json::Map::new();
1430 let mut required = Vec::new();
1431
1432 for prop in &td.properties {
1433 let mut prop_schema = ontology_type_to_schema(&prop.type_name);
1434 if let Some(obj) = prop_schema.as_object_mut() {
1435 obj.insert(
1436 "description".to_string(),
1437 serde_json::Value::String(prop.description.clone()),
1438 );
1439 }
1440 properties.insert(prop.name.clone(), prop_schema);
1441 if prop.required {
1442 required.push(serde_json::Value::String(prop.name.clone()));
1443 }
1444 }
1445
1446 serde_json::json!({
1447 "type": "object",
1448 "description": td.description,
1449 "properties": properties,
1450 "required": required,
1451 "additionalProperties": false
1452 })
1453}
1454
1455fn command_input_schema(cmd: &CommandDef) -> serde_json::Value {
1457 let mut properties = serde_json::Map::new();
1458 let mut required = Vec::new();
1459
1460 for param in &cmd.parameters {
1461 let mut param_schema = ontology_type_to_schema(¶m.type_name);
1462 if let Some(obj) = param_schema.as_object_mut() {
1463 obj.insert(
1464 "description".to_string(),
1465 serde_json::Value::String(param.description.clone()),
1466 );
1467 if let Some(ref default) = param.default {
1468 obj.insert(
1469 "default".to_string(),
1470 serde_json::Value::String(default.clone()),
1471 );
1472 }
1473 }
1474 properties.insert(param.name.clone(), param_schema);
1475 if param.required {
1476 required.push(serde_json::Value::String(param.name.clone()));
1477 }
1478 }
1479
1480 serde_json::json!({
1481 "type": "object",
1482 "description": format!("Input parameters for '{}'", cmd.name),
1483 "properties": properties,
1484 "required": required,
1485 "additionalProperties": false
1486 })
1487}
1488
1489pub fn generate_schemas() -> serde_json::Value {
1495 let ont = get_ontology();
1496
1497 let mut defs = serde_json::Map::new();
1499 for td in &ont.types {
1500 defs.insert(td.id.clone(), type_def_to_schema(td));
1501 }
1502
1503 let mut commands = serde_json::Map::new();
1505 for cmd in &ont.commands {
1506 commands.insert(
1507 cmd.id.clone(),
1508 serde_json::json!({
1509 "description": cmd.description,
1510 "category": cmd.category,
1511 "input": command_input_schema(cmd),
1512 "returns": cmd.returns,
1513 "idempotent": cmd.idempotent,
1514 "safe": cmd.safe,
1515 "side_effects": cmd.side_effects,
1516 "preconditions": cmd.preconditions,
1517 }),
1518 );
1519 }
1520
1521 serde_json::json!({
1522 "$schema": "https://json-schema.org/draft/2020-12/schema",
1523 "$id": "https://lit-vcs.dev/schema/v1",
1524 "title": "Lit VCS Schema",
1525 "description": "JSON Schema for the Lit version control system — types and command interfaces for agent discovery",
1526 "version": ont.version,
1527 "$defs": defs,
1528 "commands": commands
1529 })
1530}
1531
1532pub fn generate_command_schema(command_id: &str) -> Option<serde_json::Value> {
1536 let ont = get_ontology();
1537 ont.commands.iter().find(|c| c.id == command_id).map(|cmd| {
1538 serde_json::json!({
1539 "$schema": "https://json-schema.org/draft/2020-12/schema",
1540 "$id": format!("https://lit-vcs.dev/schema/v1/commands/{}", cmd.id),
1541 "title": format!("lit {}", cmd.name),
1542 "description": cmd.description,
1543 "input": command_input_schema(cmd),
1544 "returns": cmd.returns,
1545 "idempotent": cmd.idempotent,
1546 "safe": cmd.safe,
1547 })
1548 })
1549}