Skip to main content

lit/ontology/
mod.rs

1//! Lit Ontology — machine-readable capability schema for autonomous agent discovery.
2//!
3//! Provides a structured representation of all Lit commands, types, workflows,
4//! and interaction protocols so that autonomous agents can discover and use Lit
5//! without prior training or documentation.
6
7use serde::Serialize;
8
9/// Top-level ontology for the Lit version control system
10#[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    /// Commands that commonly follow this one
71    pub follows: Vec<String>,
72    /// Commands that commonly precede this one
73    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
183/// Build and return the complete Lit ontology
184pub 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        // Core VCS
536        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        // Branching
586        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        // Collaboration
612        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        // Agent-optimized
630        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        // Swarm
664        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        // Remote & collaboration
699        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        // Configuration
729        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        // Tagging
742        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        // History manipulation
761        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        // Monitoring
848        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        // Transactions
857        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        // Server / API
873        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        // Git interop
895        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        // Performance
906        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        // Security
922        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        // Discovery
928        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
1291// Builder helpers
1292fn 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
1391// ============================================================================
1392// JSON Schema Generation
1393// ============================================================================
1394
1395/// Map an ontology type string to a JSON Schema type
1396fn 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            // Make nullable by allowing null
1415            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        // Named types become $ref
1423        other => serde_json::json!({ "$ref": format!("#/$defs/{other}") }),
1424    }
1425}
1426
1427/// Generate a JSON Schema for a single `TypeDef`
1428fn 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
1455/// Generate a JSON Schema for a single command's input parameters
1456fn 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(&param.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
1489/// Generate the full JSON Schema document for the Lit ontology.
1490///
1491/// Produces a standard JSON Schema (draft 2020-12) with:
1492/// - `$defs` containing a schema for every ontology type
1493/// - `commands` containing input schemas for every command
1494pub fn generate_schemas() -> serde_json::Value {
1495    let ont = get_ontology();
1496
1497    // Build $defs from types
1498    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    // Build command schemas
1504    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
1532/// Generate a JSON Schema for a single command by its ID.
1533///
1534/// Returns `None` if the command is not found.
1535pub 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}