//! CLI argument definitions for Aphoria //! //! This module is split into submodules to keep file sizes manageable: //! - `extractors`: Extractor and shadow mode commands //! - `governance`: Governance and Audit commands //! - `lifecycle`: Lifecycle and Migration commands //! - `patterns`: Pattern and Eval commands //! - `scope`: Scope commands mod claims; mod extractors; mod governance; mod lifecycle; mod patterns; mod scope; mod verify; pub use claims::ClaimsCommands; pub use extractors::ExtractorCommands; pub use governance::{AuditCommands, GovernanceCommands}; pub use lifecycle::{LifecycleCommands, MigrationCommands}; pub use patterns::{EvalCommands, PatternCommands}; pub use scope::ScopeCommands; pub use verify::VerifyCommands; use std::path::PathBuf; use clap::{Parser, Subcommand}; /// A code-level truth linter powered by Episteme. /// /// Aphoria scans a codebase, extracts the decisions embedded in config and code, /// and checks them against authoritative sources. It finds the places where what /// your code *does* contradicts what the specs *say*. #[derive(Parser)] #[command(name = "aphoria")] #[command(version, about, long_about = None)] #[command( after_help = "Examples:\n aphoria scan Scan current directory\n aphoria scan --format sarif Output for IDE integration\n aphoria scan --strict Stricter conflict thresholds\n aphoria verify run Check code against claims\n aphoria coverage Show claim density per module\n aphoria explain Onboarding summary" )] pub struct Cli { /// Path to aphoria.toml configuration file #[arg(short, long, global = true)] pub config: Option, /// Enable verbose logging (shows internal tracing output) #[arg(short, long, global = true)] pub verbose: bool, #[command(subcommand)] pub command: Commands, } #[derive(Subcommand)] pub enum Commands { /// Scan a project for epistemic drift Scan { /// Path to the project root to scan #[arg(default_value = ".")] path: PathBuf, /// Output format: table, json, sarif, markdown #[arg(short, long, default_value = "table")] format: String, /// Exit with non-zero code if conflicts found #[arg(long)] exit_code: bool, /// Use stricter thresholds (FLAG at 0.3, BLOCK at 0.5) #[arg(long)] strict: bool, /// Persist claims to Episteme storage (enables diff/baseline features). /// Without this flag, scans are ephemeral and fast. #[arg(long)] persist: bool, /// Enable debug output showing conflict resolution traces. #[arg(long)] debug: bool, /// Enable write-back of observations to local Episteme (requires --persist). #[arg(long)] sync: bool, /// Scan only git-staged files (for pre-commit hooks). #[arg(long)] staged: bool, /// Preview what would be shared with the community corpus. #[arg(long)] community_preview: bool, /// Run performance benchmark with timing breakdown. #[arg(long)] benchmark: bool, /// Show all extracted claims in the output #[arg(long)] show_claims: bool, /// Show all observations with concept paths (for debugging extractor alignment) #[arg(long)] show_observations: bool, /// Show detailed authority tier breakdown for conflicts #[arg(long)] explain_authority: bool, /// Fetch remote org claims and show where your code diverges from org patterns. /// Requires hosted mode configuration (aphoria.toml with [hosted] section). #[arg(long)] suggest_convergence: bool, }, /// Manage acknowledgments (mark conflicts as intentional) Ack { #[command(subcommand)] command: AckCommands, }, /// Bless a code pattern as the authoritative standard Bless { /// The concept path to bless concept_path: String, /// The predicate (e.g., "enabled", "min_version") #[arg(short, long)] predicate: String, /// The value (e.g., "true", "1.2") #[arg(short = 'V', long)] value: String, /// Reason/description for this standard #[arg(short, long)] reason: String, }, /// Record an intentional configuration change as a policy update Update { /// The concept path being updated concept_path: String, /// The new value for this concept value: String, /// Reason for the update #[arg(short, long)] reason: String, }, /// Set the current scan as the baseline Baseline, /// Show changes since last baseline Diff, /// Show current scan status Status, /// Initialize Aphoria with authoritative corpus Init, /// Manage the authoritative corpus Corpus { #[command(subcommand)] command: CorpusCommands, }, /// Manage the research agent for filling corpus gaps Research { #[command(subcommand)] command: ResearchCommands, }, /// Manage federated policies (Trust Packs) Policy { #[command(subcommand)] command: PolicyCommands, }, /// Manage learned patterns and extractor promotion Extractors { #[command(subcommand)] command: ExtractorCommands, }, /// Evaluate LLM prompt effectiveness Eval { #[command(subcommand)] command: EvalCommands, }, /// Manage cross-project pattern learning Patterns { #[command(subcommand)] command: PatternCommands, }, /// Manage knowledge scopes and inheritance Scope { #[command(subcommand)] command: ScopeCommands, }, /// Manage knowledge lifecycle (deprecation, archival) Lifecycle { #[command(subcommand)] command: LifecycleCommands, }, /// Track migration progress for deprecated patterns Migrations { #[command(subcommand)] command: MigrationCommands, }, /// Manage approval workflows for pattern promotion Governance { #[command(subcommand)] command: GovernanceCommands, }, /// View and export audit trails for compliance Audit { #[command(subcommand)] command: AuditCommands, }, /// Manage human-authored claims (create, list, explain, update, supersede, deprecate) Claims { #[command(subcommand)] command: ClaimsCommands, }, /// Verify code against authored claims Verify { #[command(subcommand)] command: VerifyCommands, }, /// Show claim coverage metrics per module Coverage { /// Path to the project root #[arg(default_value = ".")] path: PathBuf, /// Output format: table, json, markdown #[arg(short, long, default_value = "table")] format: String, /// Sort modules by: name, density, unclaimed, observations #[arg(long, default_value = "name")] sort_by: String, }, /// Generate a narrative explanation of this project's claims (onboarding) Explain { /// Path to the project root #[arg(default_value = ".")] path: PathBuf, /// Write output to a file instead of stdout #[arg(short, long)] output: Option, /// Output format: markdown or json #[arg(long, default_value = "markdown")] format: String, }, /// Generate enhanced documentation from claims + verification Docs { #[command(subcommand)] command: DocsCommands, }, /// Manage curated Trust Packs (install, list) TrustPack { #[command(subcommand)] command: TrustPackCommands, }, /// Install Claude Code skills for Aphoria workflows InstallClaude { /// Preview what would be installed without copying #[arg(long)] dry_run: bool, /// Force reinstall even if files exist #[arg(short, long)] force: bool, }, } #[derive(Subcommand)] pub enum TrustPackCommands { /// Install a curated Trust Pack by name Install { /// Pack name (e.g., "security-hardening", "rfc-compliance", "owasp-top10") name: String, /// Custom registry URL (overrides built-in registry) #[arg(long)] registry: Option, }, /// List available curated Trust Packs List, } #[derive(Subcommand)] pub enum DocsCommands { /// Generate a claims overview document Generate { /// Path to the project root #[arg(default_value = ".")] path: PathBuf, /// Output path (default: stdout) #[arg(short, long)] output: Option, /// Output format: markdown or json #[arg(long, default_value = "markdown")] format: String, }, } #[derive(Subcommand)] pub enum AckCommands { /// Create a new acknowledgment for a conflict Add { /// The concept path to acknowledge concept_path: String, /// Reason for acknowledgment #[arg(short, long)] reason: String, /// Optional expiry for acknowledgment (e.g., "90d" or "2026-12-31") #[arg(long, alias = "expires-at")] expires: Option, }, /// Export acknowledgments to .aphoria/acks.toml for version control Export { /// Output path (default: .aphoria/acks.toml) #[arg(short, long)] output: Option, }, /// Import acknowledgments from .aphoria/acks.toml Import { /// Input path (default: .aphoria/acks.toml) #[arg(short, long)] input: Option, }, } #[derive(Subcommand)] pub enum CorpusCommands { /// Build the authoritative corpus from configured sources Build { /// Only include specific sources (comma-separated) #[arg(long)] only: Option, /// Run in offline mode (skip sources requiring network) #[arg(long)] offline: bool, /// Clear cache before building #[arg(long)] clear_cache: bool, }, /// List available corpus sources List, /// Import patterns from external sources to bootstrap the corpus Import { #[command(subcommand)] source: ImportSource, }, /// Export the corpus as a signed Trust Pack ExportPack { /// Name for the exported pack #[arg(long)] name: String, /// Output path for the .pack file #[arg(short, long)] output: PathBuf, /// Only include specific corpus sources (comma-separated) #[arg(long)] only: Option, /// Run in offline mode (skip sources requiring network) #[arg(long)] offline: bool, }, /// Create a new corpus item from structured data Create { /// Subject path (e.g., "ml/dependencies/basicsr/torchvision") #[arg(long)] subject: String, /// Predicate (e.g., "incompatible_with", "requires", "recommends") #[arg(long)] predicate: String, /// Value (string, number, or boolean) #[arg(long)] value: String, /// Full explanation/context for this claim #[arg(long)] explanation: String, /// Authority source (GitHub URL, paper citation, docs URL) #[arg(long)] authority: String, /// Category (compatibility, performance, security, architecture) #[arg(long)] category: String, /// Authority tier (0=regulatory, 1=clinical, 2=observational, 3=community) #[arg(long)] tier: u8, }, } #[derive(Subcommand)] pub enum ImportSource { /// Import patterns from wiki markdown documentation Wiki { /// Path to wiki directory containing markdown files path: PathBuf, }, } #[derive(Subcommand)] pub enum ResearchCommands { /// Run the research agent to fill corpus gaps Run { /// Minimum projects that must report a gap before researching #[arg(short, long, default_value = "3")] threshold: u32, /// Use strict quality validation #[arg(long)] strict: bool, /// Prune old gaps before researching #[arg(long)] prune: bool, /// Maximum age of gaps to consider in days #[arg(long, default_value = "90")] max_age: u64, }, /// Show research agent status and gap statistics Status, /// List gaps eligible for research Gaps { /// Minimum projects that must report a gap #[arg(short, long, default_value = "1")] threshold: u32, /// Show only gaps ready for research (seen in 3+ projects) #[arg(long)] ready: bool, }, } #[derive(Subcommand)] pub enum PolicyCommands { /// Export acknowledged conflicts as a Trust Pack Export { /// Name of the policy pack #[arg(long)] name: String, /// Output path for the pack file #[arg(short, long)] output: PathBuf, }, /// Import a Trust Pack into the local Episteme Import { /// Path to the .pack file file: PathBuf, }, /// Re-sign a Trust Pack with a new key Resign { /// Path to the .pack file to re-sign file: PathBuf, /// Output path for the re-signed pack #[arg(short, long)] output: PathBuf, /// Path to new signing key #[arg(long)] key: Option, /// Reason for re-signing (for audit trail) #[arg(long)] reason: Option, /// Preserve signature chain for audit trail #[arg(long, default_value = "true")] chain_signatures: bool, }, }