minni 0.1.0

Local memory, task, and codebase indexing tool for AI agents
Documentation
pub mod context;
pub mod doctor;
pub mod eval;
pub mod index;
pub mod init;
pub mod journal;
pub mod refs;
pub mod research;
pub mod search;
pub mod status;
pub mod task;

use clap::{Parser, Subcommand};
use std::path::PathBuf;

#[derive(Parser)]
#[command(name = "minni")]
#[command(
    author,
    version,
    about = "Local memory and codebase indexing for AI agents"
)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
    /// Initialize minni in the current directory
    Init,

    /// Index the codebase for semantic search
    Index {
        /// Path to index (defaults to current directory)
        #[arg(short, long)]
        path: Option<PathBuf>,

        /// Force re-index all files
        #[arg(short, long)]
        force: bool,
    },

    /// Search for code snippets
    Search {
        /// Search query (natural language or code)
        query: String,

        /// Maximum number of results
        #[arg(short, long, default_value = "10")]
        limit: usize,

        /// Output results as JSON
        #[arg(long)]
        json: bool,

        /// Filter by file path (substring match)
        #[arg(long)]
        path: Option<String>,

        /// Filter by language (exact match, case-insensitive)
        #[arg(long)]
        lang: Option<String>,

        /// Filter by chunk type (function, class, file, block)
        #[arg(long, value_name = "TYPE")]
        chunk_type: Option<String>,

        /// Filter by symbol name (substring match, case-insensitive)
        #[arg(long)]
        symbol: Option<String>,

        /// Lines of context before the match
        #[arg(long)]
        before: Option<usize>,

        /// Lines of context after the match
        #[arg(long)]
        after: Option<usize>,

        /// Lines of context before and after the match
        #[arg(long)]
        context: Option<usize>,
    },

    /// Experimental deep research retrieval (deterministic, citation-oriented)
    Research {
        /// Research question
        question: String,

        /// Number of deterministic query passes
        #[arg(long, default_value = "3")]
        passes: usize,

        /// Maximum number of aggregated findings
        #[arg(short, long, default_value = "8")]
        limit: usize,

        /// Output structured JSON
        #[arg(long)]
        json: bool,
    },

    /// Manage session contexts
    Context {
        #[command(subcommand)]
        command: ContextCommands,
    },

    /// Automatic journaling of project activity
    Journal {
        #[command(subcommand)]
        command: JournalCommands,
    },

    /// Evaluate search quality against a benchmark query file
    Eval {
        /// Path to benchmark query file (default: eval/queries.json)
        #[arg(short, long, value_name = "FILE")]
        file: Option<PathBuf>,

        /// Output results as JSON
        #[arg(long)]
        json: bool,

        /// Fail (exit non-zero) if aggregate MRR drops below this value
        #[arg(long, value_name = "THRESHOLD")]
        min_mrr: Option<f64>,
    },

    /// Show symbol definitions, importers, and dependencies
    Refs {
        /// Symbol name to look up
        symbol: String,

        /// Output as JSON
        #[arg(long)]
        json: bool,
    },

    /// Show minni status for current project
    Status,

    /// Run diagnostic checks and report setup health
    Doctor,

    /// Manage implementation tasks within a context
    Task {
        #[command(subcommand)]
        command: TaskCommands,
    },
}

#[derive(Subcommand, Clone)]
pub enum JournalCommands {
    /// Show recent journal entries
    Show {
        /// Number of entries to show
        #[arg(short, long, default_value = "10")]
        count: usize,
    },

    /// Add a note to the journal
    Note {
        /// Note message
        message: String,
    },

    /// Record current git commit (called by hook)
    Record,

    /// Clear all journal entries
    Clear,

    /// Install git hooks for auto-journaling
    HooksInstall,

    /// Remove git hooks
    HooksUninstall,

    /// Show context for resuming a session
    Resume,
}

#[derive(Subcommand, Clone)]
pub enum ContextCommands {
    /// Save current session context
    Save {
        /// Name for this context
        #[arg(short, long)]
        name: Option<String>,

        /// Description of what was being worked on
        #[arg(short, long)]
        description: Option<String>,
    },

    /// Load a saved context
    Load {
        /// Context ID or name to load
        id: String,
    },

    /// List all saved contexts
    List {
        /// Show full details
        #[arg(short, long)]
        verbose: bool,
    },

    /// Delete a saved context
    Delete {
        /// Context ID or name to delete
        id: String,
    },

    /// Snapshot current state (files, conversation, tasks)
    Snapshot {
        /// Name for this snapshot
        #[arg(short, long)]
        name: Option<String>,

        /// Include git diff
        #[arg(long)]
        include_diff: bool,

        /// Include conversation from stdin
        #[arg(long)]
        conversation: bool,
    },

    /// Export context for sharing between AI assistants
    Export {
        /// Context ID or name
        id: String,

        /// Output file path (default: context.json)
        #[arg(short, long)]
        output: Option<String>,
    },

    /// Import context from another session
    Import {
        /// Input file path
        file: String,

        /// Optional new name
        #[arg(short, long)]
        name: Option<String>,
    },

    /// Show detailed context information
    Show {
        /// Context ID or name
        id: String,
    },

    /// Add information to the current context
    Add {
        /// Key for this context item
        key: String,

        /// Value to store
        value: String,
    },
}

#[derive(Subcommand, Clone)]
pub enum TaskCommands {
    /// Add a new task to a context
    Add {
        /// Context name (e.g. ORI-9999)
        context: String,
        #[arg(short, long)]
        title: String,
        #[arg(short, long)]
        description: Option<String>,
        #[arg(short, long, default_value = "medium")]
        priority: String,
    },
    /// Update a task's fields
    Update {
        context: String,
        /// Task sequence number
        seq: i64,
        #[arg(long)]
        title: Option<String>,
        #[arg(long)]
        description: Option<String>,
        #[arg(long)]
        status: Option<String>,
        #[arg(long)]
        priority: Option<String>,
    },
    /// List all tasks in a context
    List {
        context: String,
        #[arg(long)]
        json: bool,
    },
    /// Show full detail for a single task
    Show {
        context: String,
        seq: i64,
        #[arg(long)]
        json: bool,
    },
    /// Manage todo items on a task (see task 003)
    Todo {
        context: String,
        seq: i64,
        text: Option<String>,
        #[arg(long)]
        done: Option<i64>,
    },
    /// Export a task to a Markdown file (see task 004)
    Export { context: String, seq: i64 },
}