Skip to main content

obsidian_cli_inspector/
cli.rs

1use clap::{Parser, Subcommand};
2use std::path::PathBuf;
3
4const LONG_ABOUT: &str = "\
5Obsidian CLI Inspector - A local-first, read-only CLI/TUI for Obsidian vaults
6
7ABOUT:
8  This tool helps you inspect, query, and navigate your Obsidian vault from the terminal.
9  All data is stored locally in a SQLite database for fast, offline access.
10
11USE CASES:
12  • Search: Find notes quickly with full-text search across your entire vault
13  • Link Analysis: Discover backlinks, forward links, and unresolved references
14  • Tag Management: Filter and organize notes by tags with AND/OR logic
15  • Graph Exploration: Visualize note relationships and connection depths
16  • Content Quality: Identify bloated notes that may need refactoring
17  • Related Notes: Get AI-style suggestions for notes you might want to link
18  • Scripting: Integrate with shell scripts and automation workflows
19  • Interactive TUI: Browse your vault in a terminal user interface
20
21WORKFLOW:
22  1. Run 'init' to set up the database
23  2. Run 'index' to scan and parse your vault
24  3. Use query commands (search, backlinks, tags, etc.)
25  4. Re-run 'index' periodically to catch changes
26
27EXAMPLES:
28  # Initialize and index your vault
29  obsidian-cli-inspector init
30  obsidian-cli-inspector index
31
32  # Search for notes containing 'rust'
33  obsidian-cli-inspector search rust --limit 10
34
35  # Find all notes linking to 'Project Ideas'
36  obsidian-cli-inspector backlinks \"Project Ideas\"
37
38  # List all notes tagged with 'work'
39  obsidian-cli-inspector tags work
40
41  # Find large notes that might need splitting
42  obsidian-cli-inspector bloat --threshold 100000
43
44  # Launch interactive mode
45  obsidian-cli-inspector tui
46
47CONFIG:
48  Place config at ~/.config/obsidian-cli-inspector/config.toml
49  Specify vault path and database location there.
50";
51
52#[derive(Parser)]
53#[command(name = "obsidian-cli-inspector")]
54#[command(author, version)]
55#[command(about = "Local-first CLI/TUI for indexing and querying Obsidian vaults")]
56#[command(long_about = LONG_ABOUT)]
57pub struct Cli {
58    /// Path to config file
59    #[arg(short, long, value_name = "FILE")]
60    pub config: Option<PathBuf>,
61
62    #[command(subcommand)]
63    pub command: Commands,
64}
65
66#[derive(Subcommand)]
67pub enum Commands {
68    /// Initialize or reinitialize the database
69    Init {
70        /// Force reinitialization (drops existing data)
71        #[arg(short, long)]
72        force: bool,
73    },
74
75    /// Index the vault (scan and parse all files)
76    Index {
77        /// Perform a dry run without writing to database
78        #[arg(short = 'n', long)]
79        dry_run: bool,
80
81        /// Force full re-index (ignores change detection)
82        #[arg(short, long)]
83        force: bool,
84
85        /// Show verbose output
86        #[arg(short, long)]
87        verbose: bool,
88    },
89
90    /// Search notes using full-text search
91    Search {
92        /// Search query
93        query: String,
94
95        /// Maximum number of results
96        #[arg(short, long, default_value = "20")]
97        limit: usize,
98    },
99
100    /// List backlinks to a note
101    Backlinks {
102        /// Note path or title
103        note: String,
104    },
105
106    /// List forward links from a note
107    Links {
108        /// Note path or title
109        note: String,
110    },
111
112    /// List all unresolved links in the vault
113    UnresolvedLinks,
114
115    /// List notes by tag
116    Tags {
117        /// Tag name (without #)
118        tag: Option<String>,
119
120        /// List all tags if no tag specified
121        #[arg(short, long)]
122        all: bool,
123    },
124
125    /// Suggest related notes not directly linked
126    Suggest {
127        /// Note path or title
128        note: String,
129
130        /// Maximum number of suggestions
131        #[arg(short, long, default_value = "10")]
132        limit: usize,
133    },
134
135    /// Detect bloated notes and suggest refactoring
136    Bloat {
137        /// Minimum size threshold in bytes
138        #[arg(short, long, default_value = "50000")]
139        threshold: usize,
140
141        /// Maximum number of notes to analyze
142        #[arg(short, long, default_value = "10")]
143        limit: usize,
144    },
145
146    /// Show statistics about the vault
147    Stats,
148
149    /// Launch interactive TUI
150    Tui,
151
152    /// Display vault graph information
153    Graph {
154        /// Note path or title (if not specified, shows overall graph)
155        note: Option<String>,
156
157        /// Maximum traversal depth
158        #[arg(short, long, default_value = "2")]
159        depth: usize,
160    },
161
162    /// Describe file metadata (without displaying paragraphs)
163    Describe {
164        /// File path or title to describe
165        filename: String,
166    },
167
168    /// Diagnose orphan notes (no incoming + no outgoing links)
169    DiagnoseOrphans {
170        /// Exclude template notes
171        #[arg(long)]
172        exclude_templates: bool,
173
174        /// Exclude daily notes
175        #[arg(long)]
176        exclude_daily: bool,
177    },
178
179    /// Diagnose broken links (unresolved and ambiguous)
180    DiagnoseBrokenLinks,
181}