# Command Restructure: Implementation Plan **Reference:** `command-restructure/CLI_AUDIT.md` **Scope:** 10 proposals, 3 implementation phases, estimated ~15 files touched --- ## Phase 1: Zero-Risk Quick Wins (1 commit) These four changes are purely additive -- no behavior changes, no renames, no removed commands. ### P1: Help Grouping **Goal:** Group the 29 visible commands into 5 semantic clusters in `--help` output. **File:** `src/cli/mod.rs` (lines 117-399, the `Commands` enum) **Changes:** Add `#[command(help_heading = "...")]` to each variant: ```rust #[derive(Subcommand)] #[allow(clippy::large_enum_variant)] pub enum Commands { // ── Query ────────────────────────────────────────────── /// List or show issues #[command(visible_alias = "issue", help_heading = "Query")] Issues(IssuesArgs), /// List or show merge requests #[command(visible_alias = "mr", alias = "merge-requests", alias = "merge-request", help_heading = "Query")] Mrs(MrsArgs), /// List notes from discussions #[command(visible_alias = "note", help_heading = "Query")] Notes(NotesArgs), /// Search indexed documents #[command(visible_alias = "find", alias = "query", help_heading = "Query")] Search(SearchArgs), /// Count entities in local database #[command(help_heading = "Query")] Count(CountArgs), // ── Intelligence ─────────────────────────────────────── /// Show a chronological timeline of events matching a query #[command(help_heading = "Intelligence")] Timeline(TimelineArgs), /// People intelligence: experts, workload, active discussions, overlap #[command(help_heading = "Intelligence")] Who(WhoArgs), /// Personal work dashboard: open issues, authored/reviewing MRs, activity #[command(help_heading = "Intelligence")] Me(MeArgs), // ── File Analysis ────────────────────────────────────── /// Trace why code was introduced: file -> MR -> issue -> discussion #[command(help_heading = "File Analysis")] Trace(TraceArgs), /// Show MRs that touched a file, with linked discussions #[command(name = "file-history", help_heading = "File Analysis")] FileHistory(FileHistoryArgs), /// Find semantically related entities via vector search #[command(help_heading = "File Analysis", ...)] Related { ... }, /// Detect discussion divergence from original intent #[command(help_heading = "File Analysis", ...)] Drift { ... }, // ── Data Pipeline ────────────────────────────────────── /// Run full sync pipeline: ingest -> generate-docs -> embed #[command(help_heading = "Data Pipeline")] Sync(SyncArgs), /// Ingest data from GitLab #[command(help_heading = "Data Pipeline")] Ingest(IngestArgs), /// Generate searchable documents from ingested data #[command(name = "generate-docs", help_heading = "Data Pipeline")] GenerateDocs(GenerateDocsArgs), /// Generate vector embeddings for documents via Ollama #[command(help_heading = "Data Pipeline")] Embed(EmbedArgs), // ── System ───────────────────────────────────────────── // (init, status, health, doctor, stats, auth, token, migrate, cron, // completions, robot-docs, version -- all get help_heading = "System") } ``` **Verification:** - `lore --help` shows grouped output - All existing commands still work identically - `lore robot-docs` output unchanged (robot-docs is hand-crafted, not derived from clap) **Files touched:** `src/cli/mod.rs` only --- ### P3: Singular/Plural Entity Type Fix **Goal:** Accept both `issue`/`issues`, `mr`/`mrs` everywhere entity types are value-parsed. **File:** `src/cli/args.rs` **Change 1 -- `CountArgs.entity` (line 819):** ```rust // BEFORE: #[arg(value_parser = ["issues", "mrs", "discussions", "notes", "events"])] pub entity: String, // AFTER: #[arg(value_parser = ["issue", "issues", "mr", "mrs", "discussion", "discussions", "note", "notes", "event", "events"])] pub entity: String, ``` **File:** `src/cli/args.rs` **Change 2 -- `SearchArgs.source_type` (line 369):** ```rust // BEFORE: #[arg(long = "type", value_parser = ["issue", "mr", "discussion", "note"], ...)] pub source_type: Option, // AFTER: #[arg(long = "type", value_parser = ["issue", "issues", "mr", "mrs", "discussion", "discussions", "note", "notes"], ...)] pub source_type: Option, ``` **File:** `src/cli/mod.rs` **Change 3 -- `Drift.entity_type` (line 287):** ```rust // BEFORE: #[arg(value_parser = ["issues"])] pub entity_type: String, // AFTER: #[arg(value_parser = ["issue", "issues"])] pub entity_type: String, ``` **Normalization layer:** In the handlers that consume these values, normalize to the canonical form (plural for entity names, singular for source_type) so downstream code doesn't need changes: **File:** `src/app/handlers.rs` In `handle_count` (~line 409): Normalize entity string before passing to `run_count`: ```rust let entity = match args.entity.as_str() { "issue" => "issues", "mr" => "mrs", "discussion" => "discussions", "note" => "notes", "event" => "events", other => other, }; ``` In `handle_search` (search handler): Normalize source_type: ```rust let source_type = args.source_type.as_deref().map(|t| match t { "issues" => "issue", "mrs" => "mr", "discussions" => "discussion", "notes" => "note", other => other, }); ``` In `handle_drift` (~line 225): Normalize entity_type: ```rust let entity_type = if entity_type == "issue" { "issues" } else { &entity_type }; ``` **Verification:** - `lore count issue` works (same as `lore count issues`) - `lore search --type issues 'foo'` works (same as `--type issue`) - `lore drift issue 42` works (same as `drift issues 42`) - All existing invocations unchanged **Files touched:** `src/cli/args.rs`, `src/cli/mod.rs`, `src/app/handlers.rs` --- ### P5: Fix `-f` Short Flag Collision **Goal:** Remove `-f` shorthand from `count --for` so `-f` consistently means `--force` across the CLI. **File:** `src/cli/args.rs` (line 823) ```rust // BEFORE: #[arg(short = 'f', long = "for", value_parser = ["issue", "mr"])] pub for_entity: Option, // AFTER: #[arg(long = "for", value_parser = ["issue", "mr"])] pub for_entity: Option, ``` **Also update the value_parser to accept both forms** (while we're here): ```rust #[arg(long = "for", value_parser = ["issue", "issues", "mr", "mrs"])] pub for_entity: Option, ``` And normalize in `handle_count`: ```rust let for_entity = args.for_entity.as_deref().map(|f| match f { "issues" => "issue", "mrs" => "mr", other => other, }); ``` **File:** `src/app/robot_docs.rs` (line 173) -- update the robot-docs entry: ```rust // BEFORE: "flags": ["", "-f/--for "], // AFTER: "flags": ["", "--for "], ``` **Verification:** - `lore count notes --for mr` still works - `lore count notes -f mr` now fails with a clear error (unknown flag `-f`) - `lore ingest -f` still works (means `--force`) **Files touched:** `src/cli/args.rs`, `src/app/robot_docs.rs` --- ### P9: Consistent `--open` Short Flag on `notes` **Goal:** Add `-o` shorthand to `notes --open`, matching `issues` and `mrs`. **File:** `src/cli/args.rs` (line 292) ```rust // BEFORE: #[arg(long, help_heading = "Actions")] pub open: bool, // AFTER: #[arg(short = 'o', long, help_heading = "Actions", overrides_with = "no_open")] pub open: bool, #[arg(long = "no-open", hide = true, overrides_with = "open")] pub no_open: bool, ``` **Verification:** - `lore notes -o` opens first result in browser - Matches behavior of `lore issues -o` and `lore mrs -o` **Files touched:** `src/cli/args.rs` --- ### Phase 1 Commit Summary **Files modified:** 1. `src/cli/mod.rs` -- help_heading on all Commands variants + drift value_parser 2. `src/cli/args.rs` -- singular/plural value_parsers, remove `-f` from count, add `-o` to notes 3. `src/app/handlers.rs` -- normalization of entity/source_type strings 4. `src/app/robot_docs.rs` -- update count flags documentation **Test plan:** ```bash cargo check --all-targets cargo clippy --all-targets -- -D warnings cargo fmt --check cargo test lore --help # Verify grouped output lore count issue # Verify singular accepted lore search --type issues 'x' # Verify plural accepted lore drift issue 42 # Verify singular accepted lore notes -o # Verify short flag works ``` --- ## Phase 2: Renames and Merges (2-3 commits) These changes rename commands and merge overlapping ones. Hidden aliases preserve backward compatibility. ### P2: Rename `stats` -> `index` **Goal:** Eliminate `status`/`stats`/`stat` confusion. `stats` becomes `index`. **File:** `src/cli/mod.rs` ```rust // BEFORE: /// Show document and index statistics #[command(visible_alias = "stat", help_heading = "System")] Stats(StatsArgs), // AFTER: /// Show document and index statistics #[command(visible_alias = "idx", alias = "stats", alias = "stat", help_heading = "System")] Index(StatsArgs), ``` Note: `alias = "stats"` and `alias = "stat"` are hidden aliases (not `visible_alias`) -- old invocations still work, but `--help` shows `index`. **File:** `src/main.rs` (line 257) ```rust // BEFORE: Some(Commands::Stats(args)) => handle_stats(cli.config.as_deref(), args, robot_mode).await, // AFTER: Some(Commands::Index(args)) => handle_stats(cli.config.as_deref(), args, robot_mode).await, ``` **File:** `src/app/robot_docs.rs` (line 181) ```rust // BEFORE: "stats": { "description": "Show document and index statistics", ... // AFTER: "index": { "description": "Show document and index statistics (formerly 'stats')", ... ``` Also update references in: - `robot_docs.rs` quick_start.lore_exclusive array (line 415): `"stats: Database statistics..."` -> `"index: Database statistics..."` - `robot_docs.rs` aliases.deprecated_commands: add `"stats": "index"`, `"stat": "index"` **File:** `src/cli/autocorrect.rs` Update `CANONICAL_SUBCOMMANDS` (line 366-area): ```rust // Replace "stats" with "index" in the canonical list // Add ("stats", "index") and ("stat", "index") to SUBCOMMAND_ALIASES ``` Update `COMMAND_FLAGS` (line 166-area): ```rust // BEFORE: ("stats", &["--check", ...]), // AFTER: ("index", &["--check", ...]), ``` **File:** `src/cli/robot.rs` -- update `expand_fields_preset` if any preset key is `"stats"` (currently no stats preset, so no change needed). **Verification:** - `lore index` works (shows document/index stats) - `lore stats` still works (hidden alias) - `lore stat` still works (hidden alias) - `lore index --check` works - `lore --help` shows `index` in System group, not `stats` - `lore robot-docs` shows `index` key in commands map **Files touched:** `src/cli/mod.rs`, `src/main.rs`, `src/app/robot_docs.rs`, `src/cli/autocorrect.rs` --- ### P4: Merge `health` into `doctor` **Goal:** One diagnostic command (`doctor`) with a `--quick` flag for the pre-flight check that `health` currently provides. **File:** `src/cli/mod.rs` ```rust // BEFORE: /// Quick health check: config, database, schema version #[command(after_help = "...")] Health, /// Check environment health #[command(after_help = "...")] Doctor, // AFTER: // Remove Health variant entirely. Add hidden alias: /// Check environment health (--quick for fast pre-flight) #[command( after_help = "...", alias = "health", // hidden backward compat help_heading = "System" )] Doctor { /// Fast pre-flight check only (config, DB, schema). Exit 0 = healthy. #[arg(long)] quick: bool, }, ``` **File:** `src/main.rs` ```rust // BEFORE: Some(Commands::Doctor) => handle_doctor(cli.config.as_deref(), robot_mode).await, ... Some(Commands::Health) => handle_health(cli.config.as_deref(), robot_mode).await, // AFTER: Some(Commands::Doctor { quick }) => { if quick { handle_health(cli.config.as_deref(), robot_mode).await } else { handle_doctor(cli.config.as_deref(), robot_mode).await } } // Health variant removed from enum, so no separate match arm ``` **File:** `src/app/robot_docs.rs` Merge the `health` and `doctor` entries: ```rust "doctor": { "description": "Environment health check. Use --quick for fast pre-flight (exit 0 = healthy, 19 = unhealthy).", "flags": ["--quick"], "example": "lore --robot doctor", "notes": { "quick_mode": "lore --robot doctor --quick — fast pre-flight check (formerly 'lore health'). Only checks config, DB, schema version. Returns exit 19 on failure.", "full_mode": "lore --robot doctor — full diagnostic: config, auth, database, Ollama" }, "response_schema": { "full": { ... }, // current doctor schema "quick": { ... } // current health schema } } ``` Remove the standalone `health` entry from the commands map. **File:** `src/cli/autocorrect.rs` - Remove `"health"` from `CANONICAL_SUBCOMMANDS` (clap's `alias` handles it) - Or keep it -- since clap treats aliases as valid subcommands, the autocorrect system will still resolve typos like `"helth"` to `"health"` which clap then maps to `doctor`. Either way works. **File:** `src/app/robot_docs.rs` -- update `workflows.pre_flight`: ```rust "pre_flight": [ "lore --robot doctor --quick" ], ``` Add to aliases.deprecated_commands: ```rust "health": "doctor --quick" ``` **Verification:** - `lore doctor` runs full diagnostic (unchanged behavior) - `lore doctor --quick` runs fast pre-flight (exit 0/19) - `lore health` still works (hidden alias, runs `doctor --quick`) - `lore --help` shows only `doctor` in System group - `lore robot-docs` shows merged entry **Files touched:** `src/cli/mod.rs`, `src/main.rs`, `src/app/robot_docs.rs`, `src/cli/autocorrect.rs` **Important edge case:** `lore health` via the hidden alias will invoke `Doctor { quick: false }` unless we handle it specially. Two options: **Option A (simpler):** Instead of making `health` an alias of `doctor`, keep both variants but hide `Health`: ```rust #[command(hide = true, help_heading = "System")] Health, ``` Then in `main.rs`, `Commands::Health` maps to `handle_health()` as before. This is less clean but zero-risk. **Option B (cleaner):** In the autocorrect layer, rewrite `health` -> `doctor --quick` before clap parsing: ```rust // In SUBCOMMAND_ALIASES or a new pre-clap rewrite: ("health", "doctor"), // plus inject "--quick" flag ``` This requires a small enhancement to autocorrect to support flag injection during alias resolution. **Recommendation:** Use Option A for initial implementation. It's one line (`hide = true`) and achieves the goal of removing `health` from `--help` while preserving full backward compatibility. The `doctor --quick` flag is additive. --- ### P7: Hide Pipeline Sub-stages **Goal:** Remove `ingest`, `generate-docs`, `embed` from `--help` while keeping them fully functional. **File:** `src/cli/mod.rs` ```rust // Add hide = true to each: /// Ingest data from GitLab #[command(hide = true)] Ingest(IngestArgs), /// Generate searchable documents from ingested data #[command(name = "generate-docs", hide = true)] GenerateDocs(GenerateDocsArgs), /// Generate vector embeddings for documents via Ollama #[command(hide = true)] Embed(EmbedArgs), ``` **File:** `src/cli/mod.rs` -- Update `Sync` help text to mention the individual stage commands: ```rust /// Run full sync pipeline: ingest -> generate-docs -> embed #[command(after_help = "\x1b[1mExamples:\x1b[0m lore sync # Full pipeline: ingest + docs + embed lore sync --no-embed # Skip embedding step ... \x1b[1mIndividual stages:\x1b[0m lore ingest # Fetch from GitLab only lore generate-docs # Rebuild documents only lore embed # Re-embed only", help_heading = "Data Pipeline" )] Sync(SyncArgs), ``` **File:** `src/app/robot_docs.rs` -- Add a `"hidden": true` field to the ingest/generate-docs/embed entries so agents know these are secondary: ```rust "ingest": { "hidden": true, "description": "Sync data from GitLab (prefer 'sync' for full pipeline)", ... ``` **Verification:** - `lore --help` no longer shows ingest, generate-docs, embed - `lore ingest`, `lore generate-docs`, `lore embed` all still work - `lore sync --help` mentions individual stage commands - `lore robot-docs` still includes all three (with `hidden: true`) **Files touched:** `src/cli/mod.rs`, `src/app/robot_docs.rs` --- ### Phase 2 Commit Summary **Commit A: Rename `stats` -> `index`** - `src/cli/mod.rs`, `src/main.rs`, `src/app/robot_docs.rs`, `src/cli/autocorrect.rs` **Commit B: Merge `health` into `doctor`, hide pipeline stages** - `src/cli/mod.rs`, `src/main.rs`, `src/app/robot_docs.rs`, `src/cli/autocorrect.rs` **Test plan:** ```bash cargo check --all-targets cargo clippy --all-targets -- -D warnings cargo fmt --check cargo test # Rename verification lore index # Works (new name) lore stats # Works (hidden alias) lore index --check # Works # Doctor merge verification lore doctor # Full diagnostic lore doctor --quick # Fast pre-flight lore health # Still works (hidden) # Hidden stages verification lore --help # ingest/generate-docs/embed gone lore ingest # Still works lore sync --help # Mentions individual stages ``` --- ## Phase 3: Structural Consolidation (requires careful design) These changes merge or absorb commands. More effort, more testing, but the biggest UX wins. ### P6: Consolidate `file-history` into `trace` **Goal:** `trace` absorbs `file-history`. One command for file-centric intelligence. **Approach:** Add `--mrs-only` flag to `trace`. When set, output matches `file-history` format (flat MR list, no issue/discussion linking). `file-history` becomes a hidden alias. **File:** `src/cli/args.rs` -- Add flag to `TraceArgs`: ```rust pub struct TraceArgs { pub path: String, #[arg(short = 'p', long, help_heading = "Filters")] pub project: Option, #[arg(long, help_heading = "Output")] pub discussions: bool, #[arg(long = "no-follow-renames", help_heading = "Filters")] pub no_follow_renames: bool, #[arg(short = 'n', long = "limit", default_value = "20", help_heading = "Output")] pub limit: usize, // NEW: absorb file-history behavior /// Show only MR list without issue/discussion linking (file-history mode) #[arg(long = "mrs-only", help_heading = "Output")] pub mrs_only: bool, /// Only show merged MRs (file-history mode) #[arg(long, help_heading = "Filters")] pub merged: bool, } ``` **File:** `src/cli/mod.rs` -- Hide `FileHistory`: ```rust /// Show MRs that touched a file, with linked discussions #[command(name = "file-history", hide = true, help_heading = "File Analysis")] FileHistory(FileHistoryArgs), ``` **File:** `src/app/handlers.rs` -- Route `trace --mrs-only` to the file-history handler: ```rust fn handle_trace( config_override: Option<&str>, args: TraceArgs, robot_mode: bool, ) -> Result<(), Box> { if args.mrs_only { // Delegate to file-history handler let fh_args = FileHistoryArgs { path: args.path, project: args.project, discussions: args.discussions, no_follow_renames: args.no_follow_renames, merged: args.merged, limit: args.limit, }; return handle_file_history(config_override, fh_args, robot_mode); } // ... existing trace logic ... } ``` **File:** `src/app/robot_docs.rs` -- Update trace entry, mark file-history as deprecated: ```rust "trace": { "description": "Trace why code was introduced: file -> MR -> issue -> discussion. Use --mrs-only for flat MR listing.", "flags": ["", "-p/--project", "--discussions", "--no-follow-renames", "-n/--limit", "--mrs-only", "--merged"], ... }, "file-history": { "hidden": true, "deprecated": "Use 'trace --mrs-only' instead", ... } ``` **Verification:** - `lore trace src/main.rs` works unchanged - `lore trace src/main.rs --mrs-only` produces file-history output - `lore trace src/main.rs --mrs-only --merged` filters to merged MRs - `lore file-history src/main.rs` still works (hidden command) - `lore --help` shows only `trace` in File Analysis group **Files touched:** `src/cli/args.rs`, `src/cli/mod.rs`, `src/app/handlers.rs`, `src/app/robot_docs.rs` --- ### P8: Make `count` a Flag on Entity Commands **Goal:** `lore issues --count` replaces `lore count issues`. Standalone `count` becomes hidden. **File:** `src/cli/args.rs` -- Add `--count` to `IssuesArgs`, `MrsArgs`, `NotesArgs`: ```rust // In IssuesArgs: /// Show count only (no listing) #[arg(long, help_heading = "Output", conflicts_with_all = ["iid", "open"])] pub count: bool, // In MrsArgs: /// Show count only (no listing) #[arg(long, help_heading = "Output", conflicts_with_all = ["iid", "open"])] pub count: bool, // In NotesArgs: /// Show count only (no listing) #[arg(long, help_heading = "Output", conflicts_with = "open")] pub count: bool, ``` **File:** `src/app/handlers.rs` -- In `handle_issues`, `handle_mrs`, `handle_notes`, check the count flag early: ```rust // In handle_issues (pseudocode): if args.count { let count_args = CountArgs { entity: "issues".to_string(), for_entity: None }; return handle_count(config_override, count_args, robot_mode).await; } ``` **File:** `src/cli/mod.rs` -- Hide `Count`: ```rust /// Count entities in local database #[command(hide = true, help_heading = "Query")] Count(CountArgs), ``` **File:** `src/app/robot_docs.rs` -- Mark count as hidden, add `--count` documentation to issues/mrs/notes entries. **Verification:** - `lore issues --count` returns issue count - `lore mrs --count` returns MR count - `lore notes --count` returns note count - `lore count issues` still works (hidden) - `lore count discussions --for mr` still works (no equivalent in the new pattern -- discussions/events/references still need the standalone `count` command) **Important note:** `count` supports entity types that don't have their own command (discussions, events, references). The standalone `count` must remain functional (just hidden). The `--count` flag on `issues`/`mrs`/`notes` handles the common cases only. **Files touched:** `src/cli/args.rs`, `src/cli/mod.rs`, `src/app/handlers.rs`, `src/app/robot_docs.rs` --- ### P10: Add `--sort` to `search` **Goal:** Allow sorting search results by score, created date, or updated date. **File:** `src/cli/args.rs` -- Add to `SearchArgs`: ```rust /// Sort results by field (score is default for ranked search) #[arg(long, value_parser = ["score", "created", "updated"], default_value = "score", help_heading = "Sorting")] pub sort: String, /// Sort ascending (default: descending) #[arg(long, help_heading = "Sorting", overrides_with = "no_asc")] pub asc: bool, #[arg(long = "no-asc", hide = true, overrides_with = "asc")] pub no_asc: bool, ``` **File:** `src/cli/commands/search.rs` -- Thread the sort parameter through to the search query. The search function currently returns results sorted by score. When `--sort created` or `--sort updated` is specified, apply an `ORDER BY` clause to the final result set. **File:** `src/app/robot_docs.rs` -- Add `--sort` and `--asc` to the search command's flags list. **Verification:** - `lore search 'auth' --sort score` (default, unchanged) - `lore search 'auth' --sort created --asc` (oldest first) - `lore search 'auth' --sort updated` (most recently updated first) **Files touched:** `src/cli/args.rs`, `src/cli/commands/search.rs`, `src/app/robot_docs.rs` --- ### Phase 3 Commit Summary **Commit C: Consolidate file-history into trace** - `src/cli/args.rs`, `src/cli/mod.rs`, `src/app/handlers.rs`, `src/app/robot_docs.rs` **Commit D: Add `--count` flag to entity commands** - `src/cli/args.rs`, `src/cli/mod.rs`, `src/app/handlers.rs`, `src/app/robot_docs.rs` **Commit E: Add `--sort` to search** - `src/cli/args.rs`, `src/cli/commands/search.rs`, `src/app/robot_docs.rs` **Test plan:** ```bash cargo check --all-targets cargo clippy --all-targets -- -D warnings cargo fmt --check cargo test # trace consolidation lore trace src/main.rs --mrs-only lore trace src/main.rs --mrs-only --merged --discussions lore file-history src/main.rs # backward compat # count flag lore issues --count lore mrs --count -s opened lore notes --count --for-issue 42 lore count discussions --for mr # still works # search sort lore search 'auth' --sort created --asc ``` --- ## Documentation Updates After all implementation is complete: ### CLAUDE.md / AGENTS.md Update the robot mode command reference to reflect: - `stats` -> `index` (with note that `stats` is a hidden alias) - `health` -> `doctor --quick` (with note that `health` is a hidden alias) - Remove `ingest`, `generate-docs`, `embed` from the primary command table (mention as "hidden, use `sync`") - Remove `file-history` from primary table (mention as "hidden, use `trace --mrs-only`") - Add `--count` flag to issues/mrs/notes documentation - Add `--sort` flag to search documentation - Add `--mrs-only` and `--merged` flags to trace documentation ### robot-docs Self-Discovery The `robot_docs.rs` changes above handle this. Key points: - New `"hidden": true` field on deprecated/hidden commands - Updated descriptions mentioning canonical alternatives - Updated flags lists - Updated workflows section --- ## File Impact Summary | File | Phase 1 | Phase 2 | Phase 3 | Total Changes | |------|---------|---------|---------|---------------| | `src/cli/mod.rs` | help_heading, drift value_parser | stats->index rename, hide health, hide pipeline stages | hide file-history, hide count | 4 passes | | `src/cli/args.rs` | singular/plural, remove `-f`, add `-o` | — | `--mrs-only`/`--merged` on trace, `--count` on entities, `--sort` on search | 2 passes | | `src/app/handlers.rs` | normalize entity strings | route doctor --quick | trace mrs-only delegation, count flag routing | 3 passes | | `src/app/robot_docs.rs` | update count flags | rename stats->index, merge health+doctor, add hidden field | update trace, file-history, count, search entries | 3 passes | | `src/cli/autocorrect.rs` | — | update CANONICAL_SUBCOMMANDS, SUBCOMMAND_ALIASES, COMMAND_FLAGS | — | 1 pass | | `src/main.rs` | — | stats->index variant rename, doctor variant change | — | 1 pass | | `src/cli/commands/search.rs` | — | — | sort parameter threading | 1 pass | --- ## Before / After Summary ### Command Count | Metric | Before | After | Delta | |--------|--------|-------|-------| | Visible top-level commands | 29 | 21 | -8 (-28%) | | Hidden commands (functional) | 4 | 12 | +8 (absorbed) | | Stub/unimplemented commands | 2 | 2 | 0 | | Total functional commands | 33 | 33 | 0 (nothing lost) | ### `lore --help` Output **Before (29 commands, flat list, ~50 lines of commands):** ``` Commands: issues List or show issues [aliases: issue] mrs List or show merge requests [aliases: mr] notes List notes from discussions [aliases: note] ingest Ingest data from GitLab count Count entities in local database status Show sync state [aliases: st] auth Verify GitLab authentication doctor Check environment health version Show version information init Initialize configuration and database search Search indexed documents [aliases: find] stats Show document and index statistics [aliases: stat] generate-docs Generate searchable documents from ingested data embed Generate vector embeddings for documents via Ollama sync Run full sync pipeline: ingest -> generate-docs -> embed migrate Run pending database migrations health Quick health check: config, database, schema version robot-docs Machine-readable command manifest for agent self-discovery completions Generate shell completions timeline Show a chronological timeline of events matching a query who People intelligence: experts, workload, active discussions, overlap me Personal work dashboard: open issues, authored/reviewing MRs, activity file-history Show MRs that touched a file, with linked discussions trace Trace why code was introduced: file -> MR -> issue -> discussion drift Detect discussion divergence from original intent related Find semantically related entities via vector search cron Manage cron-based automatic syncing token Manage stored GitLab token help Print this message or the help of the given subcommand(s) ``` **After (21 commands, grouped, ~35 lines of commands):** ``` Query: issues List or show issues [aliases: issue] mrs List or show merge requests [aliases: mr] notes List notes from discussions [aliases: note] search Search indexed documents [aliases: find] Intelligence: timeline Chronological timeline of events who People intelligence: experts, workload, overlap me Personal work dashboard File Analysis: trace Trace code provenance / file history related Find semantically related entities drift Detect discussion divergence Data Pipeline: sync Run full sync pipeline System: init Initialize configuration and database status Show sync state [aliases: st] doctor Check environment health (--quick for pre-flight) index Document and index statistics [aliases: idx] auth Verify GitLab authentication token Manage stored GitLab token migrate Run pending database migrations cron Manage automatic syncing robot-docs Agent self-discovery manifest completions Generate shell completions version Show version information ``` ### Flag Consistency | Issue | Before | After | |-------|--------|-------| | `-f` collision (force vs for) | `ingest -f`=force, `count -f`=for | `-f` removed from count; `-f` = force everywhere | | Singular/plural entity types | `count issues` but `search --type issue` | Both forms accepted everywhere | | `notes --open` missing `-o` | `notes --open` (no shorthand) | `notes -o` works (matches issues/mrs) | | `search` missing `--sort` | No sort override | `--sort score\|created\|updated` + `--asc` | ### Naming Confusion | Before | After | Resolution | |--------|-------|------------| | `status` vs `stats` vs `stat` (3 names, 2 commands) | `status` + `index` (2 names, 2 commands) | Eliminated near-homonym collision | | `health` vs `doctor` (2 commands, overlapping scope) | `doctor` + `doctor --quick` (1 command) | Progressive disclosure | | `trace` vs `file-history` (2 commands, overlapping function) | `trace` + `trace --mrs-only` (1 command) | Superset absorbs subset | ### Robot Ergonomics | Metric | Before | After | |--------|--------|-------| | Commands in robot-docs manifest | 29 | 21 visible + hidden section | | Agent decision space for "system check" | 4 commands | 2 commands (status, doctor) | | Agent decision space for "file query" | 3 commands + 2 who modes | 1 command (trace) + 2 who modes | | Entity type parse errors from singular/plural | Common | Eliminated | | Estimated token cost of robot-docs | Baseline | ~15% reduction (fewer entries, hidden flagged) | ### What Stays Exactly The Same - All 33 functional commands remain callable (nothing is removed) - All existing flags and their behavior are preserved - All response schemas are unchanged - All exit codes are unchanged - The autocorrect system continues to work - All hidden/deprecated commands emit their existing warnings ### What Breaks (Intentional) - `lore count -f mr` (the `-f` shorthand) -- must use `--for` instead - `lore --help` layout changes (commands are grouped, 8 commands hidden) - `lore robot-docs` output changes (new `hidden` field, renamed keys) - Any scripts parsing `--help` text (but `robot-docs` is the stable contract)