# MarketAlly.GitCommitEditor API Reference Complete API documentation for developers and AI assistants. --- ## Table of Contents - [Services](#services) - [IGitMessageImproverService](#igitmessageimproverservice) - [IRepositoryManager](#irepositorymanager) - [ICommitAnalysisService](#icommitanalysisservice) - [ISuggestionService](#isuggestionservice) - [ICommitRewriteService](#icommitrewriteservice) - [IGitPushService](#igitpushservice) - [IHistoryHealthService](#ihistoryhealthservice) - [ICommitMessageAnalyzer](#icommitmessageanalyzer) - [ICleanupExecutor](#icleanupexecutor) - [Models](#models) - [ManagedRepo](#managedrepo) - [CommitAnalysis](#commitanalysis) - [MessageQualityScore](#messagequalityscore) - [QualityIssue](#qualityissue) - [CommitContext](#commitcontext) - [RewriteOperation](#rewriteoperation) - [RewriteSafetyInfo](#rewritesafetyinfo) - [BatchResult](#batchresult) - [BatchRewriteResult](#batchrewriteresult) - [BranchInfo](#branchinfo) - [Result Types](#result-types) - [History Health Models](#history-health-models) - [HistoryHealthReport](#historyhealthreport) - [HealthScore](#healthscore) - [HealthIssue](#healthissue) - [CleanupOperation](#cleanupoperation) - [CleanupSuggestions](#cleanupsuggestions) - [Options](#options) - [GitImproverOptions](#gitimproveroptions) - [CommitMessageRules](#commitmessagerules) - [AiOptions](#aioptions) - [HistoryAnalysisOptions](#historyanalysisoptions) - [CleanupExecutionOptions](#cleanupexecutionoptions) - [Enumerations](#enumerations) - [Extensions](#extensions) - [Usage Patterns](#usage-patterns) - [Error Handling](#error-handling) --- ## Services ### IGitMessageImproverService The main facade interface that composes all functionality. This is the primary entry point for most use cases. **Implements:** `IRepositoryManager`, `ICommitAnalysisService`, `ISuggestionService`, `ICommitRewriteService`, `IGitPushService`, `IHistoryHealthService`, `IDisposable` ```csharp public interface IGitMessageImproverService : IDisposable { // State Management Task LoadStateAsync(CancellationToken ct = default); string GenerateSummaryReport(); // All methods from composed interfaces (see below) } ``` #### Factory Method ```csharp // Create service without DI container public static Task CreateAsync(GitImproverOptions options); ``` #### Additional Methods on Implementation ```csharp // Branch management Task CheckoutBranchAsync(ManagedRepo repo, string branchName); IEnumerable GetBackupBranches(string repoPath); bool DeleteBranch(string repoPath, string branchName); int DeleteAllBackupBranches(string repoPath); // Safety checks RewriteSafetyInfo GetRewriteSafetyInfo(string repoPath, IEnumerable commits); // Batch rewrite with safety Task ExecuteBatchRewriteAsync( string repoPath, IEnumerable commits, bool createBackup = true, IProgress<(int Current, int Total, string CommitHash)>? progress = null, CancellationToken ct = default); ``` --- ### IRepositoryManager Manages git repository discovery and registration. ```csharp public interface IRepositoryManager { /// Gets all registered repositories. IReadOnlyList Repos { get; } /// Scans WorkspaceRoot for git repos and registers new ones. Task> ScanAndRegisterReposAsync(CancellationToken ct = default); /// Manually register a repository by path. Task RegisterRepoAsync(string repoPath); /// Unregister a repository by ID or path. Task UnregisterRepoAsync(string repoIdOrPath); /// Get all branches (local and remote) for a repository. IEnumerable GetBranches(string repoPath); } ``` --- ### ICommitAnalysisService Provides commit message quality analysis. ```csharp public interface ICommitAnalysisService { /// Analyze commits across all registered repositories. /// If true, only return commits with quality issues. /// Reports (RepoName, CommitCount) as repos are processed. Task> AnalyzeAllReposAsync( bool onlyNeedsImprovement = true, IProgress<(string Repo, int Processed)>? progress = null, CancellationToken ct = default); /// Analyze commits in a single repository. IEnumerable AnalyzeRepo(ManagedRepo repo); /// Analyze a specific commit by hash. CommitAnalysis AnalyzeCommit(string repoPath, string commitHash); /// Update and persist repo analysis statistics. Task UpdateRepoAnalysisAsync( ManagedRepo repo, int totalCommits, int commitsNeedingImprovement, CancellationToken ct = default); } ``` --- ### ISuggestionService Generates AI-powered commit message suggestions. ```csharp public interface ISuggestionService { /// Generate AI suggestions for multiple commits. /// Result with success/failure counts and individual failures. Task GenerateSuggestionsAsync( IEnumerable analyses, IProgress? progress = null, CancellationToken ct = default); /// Generate AI suggestion for a single commit. Task GenerateSuggestionAsync( CommitAnalysis analysis, CancellationToken ct = default); } ``` **Throws:** `ApiKeyNotConfiguredException` if AI provider API key is not set. --- ### ICommitRewriteService Handles commit message rewriting operations. ```csharp public interface ICommitRewriteService { /// History of all rewrite operations. IReadOnlyList History { get; } /// Create RewriteOperation objects for commits with suggestions. IReadOnlyList PreviewChanges(IEnumerable analyses); /// Apply commit message changes. /// If true, validate but don't modify commits. Task ApplyChangesAsync( IEnumerable operations, bool dryRun = true, IProgress<(int Processed, int Total)>? progress = null, CancellationToken ct = default); /// Apply suggested message for a single commit. Task ApplyChangeAsync( CommitAnalysis analysis, CancellationToken ct = default); /// Undo a commit amend by resetting to original commit. bool UndoCommitAmend(string repoPath, string originalCommitHash); } ``` --- ### IGitPushService Handles git push operations and remote tracking. ```csharp public interface IGitPushService { /// Check if a commit exists on the remote tracking branch. bool IsCommitPushed(string repoPath, string commitHash); /// Get tracking information for current branch. TrackingInfo GetTrackingInfo(string repoPath); /// Push current branch to remote. GitPushResult Push(string repoPath); /// Force push current branch to remote (overwrites remote history). GitPushResult ForcePush(string repoPath); } ``` --- ### IHistoryHealthService Service for analyzing and reporting on git repository history health. ```csharp public interface IHistoryHealthService { /// Analyzes repository history health and generates a comprehensive report. Task AnalyzeHistoryHealthAsync( string repoPath, HistoryAnalysisOptions? options = null, IProgress? progress = null, CancellationToken ct = default); /// Analyzes history health for a managed repository. Task AnalyzeHistoryHealthAsync( ManagedRepo repo, HistoryAnalysisOptions? options = null, IProgress? progress = null, CancellationToken ct = default); /// Exports a health report to the specified format (Json, Markdown, Html, Console). Task ExportHealthReportAsync( HistoryHealthReport report, ReportFormat format, CancellationToken ct = default); /// Exports a health report to a file. Task ExportHealthReportToFileAsync( HistoryHealthReport report, ReportFormat format, string outputPath, CancellationToken ct = default); /// Executes a single cleanup operation. Task ExecuteCleanupAsync( ManagedRepo repo, CleanupOperation operation, CleanupExecutionOptions? options = null, IProgress? progress = null, CancellationToken ct = default); /// Executes all cleanup operations from suggestions. Task ExecuteAllCleanupsAsync( ManagedRepo repo, CleanupSuggestions suggestions, CleanupExecutionOptions? options = null, IProgress? progress = null, CancellationToken ct = default); /// Creates a backup branch before cleanup operations. Task CreateBackupBranchAsync( ManagedRepo repo, string? branchName = null, CancellationToken ct = default); } ``` --- ### ICommitMessageAnalyzer Analyzes commit message quality against configured rules. ```csharp public interface ICommitMessageAnalyzer { /// Analyze message without change context. MessageQualityScore Analyze(string message); /// Analyze message with context about actual changes. /// Enables detection of vague messages for significant changes. MessageQualityScore Analyze(string message, CommitContext context); } ``` --- ### ICleanupExecutor Executes cleanup operations on git repositories. ```csharp public interface ICleanupExecutor { /// Executes a single cleanup operation. Task ExecuteAsync( ManagedRepo repo, CleanupOperation operation, CleanupExecutionOptions? options = null, IProgress? progress = null, CancellationToken ct = default); /// Executes multiple cleanup operations in sequence. Task ExecuteBatchAsync( ManagedRepo repo, IEnumerable operations, CleanupExecutionOptions? options = null, IProgress? progress = null, CancellationToken ct = default); /// Previews what a cleanup operation will do without executing it. Task PreviewAsync( ManagedRepo repo, CleanupOperation operation, CancellationToken ct = default); /// Creates a backup branch before cleanup operations. Task CreateBackupBranchAsync( ManagedRepo repo, string? branchName = null, CancellationToken ct = default); } ``` --- ## Models ### ManagedRepo Represents a registered git repository. ```csharp public sealed class ManagedRepo { public string Id { get; } // GUID public string Name { get; set; } // Directory name public string Path { get; set; } // Full path public string? RemoteUrl { get; set; } // Origin URL public string? CurrentBranch { get; set; } public DateTimeOffset? LastScannedAt { get; set; } public DateTimeOffset? LastAnalyzedAt { get; set; } public int TotalCommits { get; set; } public int CommitsNeedingImprovement { get; set; } } ``` --- ### CommitAnalysis Complete analysis of a single commit. ```csharp public sealed class CommitAnalysis { public string RepoId { get; } public string RepoName { get; } public string RepoPath { get; } public string CommitHash { get; } public string ShortHash { get; } // First 7 characters public string OriginalMessage { get; } public string? SuggestedMessage { get; set; } // Populated by AI public DateTimeOffset CommitDate { get; } public string Author { get; } public string AuthorEmail { get; } public MessageQualityScore Quality { get; } public IReadOnlyList FilesChanged { get; } public string? DiffSummary { get; } public IReadOnlyDictionary FileDiffs { get; } // Path -> Diff public int LinesAdded { get; } public int LinesDeleted { get; } public bool IsLatestCommit { get; } public AnalysisStatus Status { get; set; } // Pending, Analyzed, Applied, Failed, Skipped } ``` --- ### MessageQualityScore Quality assessment with detailed issues. ```csharp public sealed class MessageQualityScore { public int OverallScore { get; } // 0-100 public IReadOnlyList Issues { get; } public bool NeedsImprovement { get; } // Score < 70 or has Error severity } ``` --- ### QualityIssue Individual quality problem found in a message. ```csharp public sealed class QualityIssue { public required string Code { get; init; } // e.g., "SUBJECT_TOO_SHORT" public required string Message { get; init; } // Human-readable description public required IssueSeverity Severity { get; init; } public int ScoreImpact { get; init; } // Points deducted } ``` **Issue Codes:** - `SUBJECT_TOO_SHORT` - Subject line below minimum length - `SUBJECT_TOO_LONG` - Subject line exceeds maximum length - `BODY_TOO_SHORT` - Body below minimum length (if required) - `MISSING_CONVENTIONAL_TYPE` - Missing conventional commit type prefix - `BANNED_PHRASE` - Contains banned/vague phrase - `MISSING_ISSUE_REFERENCE` - Missing issue/ticket reference (if required) - `VAGUE_FOR_CHANGES` - Message too vague for significant code changes --- ### CommitContext Context about commit changes for smarter analysis. ```csharp public sealed class CommitContext { public int FilesChanged { get; init; } public int LinesAdded { get; init; } public int LinesDeleted { get; init; } public IReadOnlyList FileNames { get; init; } public int TotalLinesChanged { get; } // Added + Deleted public bool HasSignificantChanges { get; } // Files > 0 or Lines > 0 public static CommitContext Empty { get; } } ``` --- ### RewriteOperation Represents a commit rewrite operation. ```csharp public sealed class RewriteOperation { public string Id { get; } // GUID public string RepoId { get; set; } public string RepoPath { get; set; } public string CommitHash { get; set; } public string? NewCommitHash { get; set; } // After rewrite public string OriginalMessage { get; set; } public string NewMessage { get; set; } public bool IsLatestCommit { get; set; } public OperationStatus Status { get; set; } // Pending, Applied, Failed, Undone public string? ErrorMessage { get; set; } public DateTimeOffset CreatedAt { get; } public DateTimeOffset? AppliedAt { get; set; } } ``` --- ### RewriteSafetyInfo Safety information for batch rewrite operations. ```csharp public sealed class RewriteSafetyInfo { public bool HasUncommittedChanges { get; init; } public bool HasPushedCommits { get; init; } public int PushedCommitCount { get; init; } public int LocalOnlyCommitCount { get; init; } public int TotalCommitCount { get; init; } public bool HasRemoteTracking { get; init; } public string? RemoteTrackingBranch { get; init; } public int? AheadOfRemote { get; init; } public int? BehindRemote { get; init; } public bool BackupBranchCreated { get; init; } public string? BackupBranchName { get; init; } // Computed properties public bool CanProceedSafely { get; } // !HasUncommittedChanges && !HasPushedCommits public bool CanProceedWithWarnings { get; } // !HasUncommittedChanges // Methods public IReadOnlyList GetWarnings(); public string GetSummary(); } ``` --- ### BatchResult Result of batch operations (ApplyChangesAsync). ```csharp public sealed class BatchResult { public int TotalProcessed { get; init; } public int Successful { get; init; } public int Failed { get; init; } public int Skipped { get; init; } public IReadOnlyList Operations { get; init; } } ``` --- ### BatchRewriteResult Result of ExecuteBatchRewriteAsync. ```csharp public sealed class BatchRewriteResult { public bool Success { get; init; } public int SuccessCount { get; init; } public int FailedCount { get; init; } public int SkippedCount { get; init; } public string? ErrorMessage { get; init; } public bool RequiresForcePush { get; init; } public string? BackupBranchName { get; init; } public IReadOnlyList Operations { get; init; } public static BatchRewriteResult Failure(string error); } ``` --- ### BranchInfo Information about a git branch. ```csharp public sealed class BranchInfo { public string Name { get; init; } // e.g., "main" public string FullName { get; init; } // e.g., "refs/heads/main" public bool IsRemote { get; init; } public bool IsCurrentHead { get; init; } public string? LastCommitSha { get; init; } public DateTimeOffset? LastCommitDate { get; init; } public string? RemoteName { get; init; } // e.g., "origin" } ``` --- ### Result Types ```csharp // Push operation result public sealed record GitPushResult(bool Success, string Message) { public static GitPushResult Ok(string message = "Push successful"); public static GitPushResult Fail(string message); } // Branch tracking information public sealed record TrackingInfo(string? UpstreamBranch, int? AheadBy, int? BehindBy) { public static TrackingInfo None { get; } public bool HasUpstream { get; } public bool IsInSync { get; } // AheadBy == 0 && BehindBy == 0 } // AI suggestion result public sealed record SuggestionResult( CommitAnalysis? Analysis, string? Suggestion, string? ErrorMessage = null, string? RawResponse = null, bool ReturnedOriginal = false, int InputTokens = 0, int OutputTokens = 0, decimal EstimatedCost = 0) { public bool Success { get; } public int TotalTokens { get; } public static SuggestionResult Ok(CommitAnalysis analysis, string suggestion, ...); public static SuggestionResult Succeeded(string suggestion, ...); public static SuggestionResult Fail(CommitAnalysis analysis, string error); public static SuggestionResult Failed(string error, string? rawResponse = null); } // Batch suggestion result public sealed class BatchSuggestionResult { public IReadOnlyList Analyses { get; init; } public int SuccessCount { get; init; } public int FailedCount { get; init; } public IReadOnlyList Failures { get; init; } } ``` --- ## History Health Models ### HistoryHealthReport Complete health report with scoring, issues, and recommendations. ```csharp public sealed class HistoryHealthReport { public required string RepoId { get; init; } public required string RepoName { get; init; } public required string RepoPath { get; init; } public required string CurrentBranch { get; init; } public DateTimeOffset GeneratedAt { get; init; } public int CommitsAnalyzed { get; init; } // Summary score public required HealthScore Score { get; init; } // Detailed metrics public required DuplicateCommitMetrics DuplicateMetrics { get; init; } public required MergeCommitMetrics MergeMetrics { get; init; } public required BranchComplexityMetrics BranchMetrics { get; init; } public required MessageQualityDistribution MessageDistribution { get; init; } public required AuthorshipMetrics AuthorshipMetrics { get; init; } // Issues and recommendations public IReadOnlyList Issues { get; init; } public IReadOnlyList Recommendations { get; init; } // Cleanup opportunities public CleanupSuggestions? CleanupSuggestions { get; init; } // Convenience properties public int CriticalIssueCount { get; } public int ErrorCount { get; } public int WarningCount { get; } } ``` --- ### HealthScore ```csharp public sealed class HealthScore { public int OverallScore { get; init; } // 0-100 public HealthGrade Grade { get; init; } // Excellent, Good, Fair, Poor, Critical public int MessageQualityScore { get; init; } public int DuplicateScore { get; init; } public int MergeHealthScore { get; init; } public int BranchComplexityScore { get; init; } } ``` --- ### HealthIssue ```csharp public sealed class HealthIssue { public required string Code { get; init; } public required string Category { get; init; } public required HealthIssueSeverity Severity { get; init; } // Info, Warning, Error, Critical public required string Title { get; init; } public required string Description { get; init; } public int ImpactScore { get; init; } public IReadOnlyList AffectedCommits { get; init; } } ``` --- ### CleanupOperation ```csharp public sealed class CleanupOperation { public required string Id { get; init; } public required string Title { get; init; } public required string Description { get; init; } public required CleanupType Type { get; init; } public required CleanupAutomationLevel AutomationLevel { get; init; } public EstimatedEffort Effort { get; init; } public RiskLevel Risk { get; init; } public int ExpectedScoreImprovement { get; init; } public IReadOnlyList AffectedCommits { get; init; } public string? GitCommand { get; init; } public CleanupOperationStatus Status { get; set; } } ``` --- ### CleanupSuggestions ```csharp public sealed class CleanupSuggestions { public IReadOnlyList AutomatedOperations { get; init; } public IReadOnlyList SemiAutomatedOperations { get; init; } public IReadOnlyList ManualOperations { get; init; } public int TotalOperations { get; } public int TotalExpectedImprovement { get; } } ``` --- ## Options ### GitImproverOptions Main configuration object. ```csharp public sealed class GitImproverOptions { public string WorkspaceRoot { get; set; } // Required public string StateFilePath { get; set; } // Default: "git-improver-state.json" public CommitMessageRules Rules { get; set; } public AiOptions Ai { get; set; } public int MaxCommitsPerRepo { get; set; } // Default: 100 public DateTimeOffset? AnalyzeSince { get; set; } public string[] ExcludedAuthors { get; set; } // Default: [] public void ValidateAndThrow(); } ``` --- ### CommitMessageRules Quality rules configuration. ```csharp public sealed class CommitMessageRules { public int MinSubjectLength { get; set; } // Default: 10 public int MaxSubjectLength { get; set; } // Default: 72 public int MinBodyLength { get; set; } // Default: 0 public bool RequireConventionalCommit { get; set; } // Default: false public bool RequireIssueReference { get; set; } // Default: false public string[] BannedPhrases { get; set; } // Default: common vague words public string[] ConventionalTypes { get; set; } // Default: feat, fix, docs, etc. } ``` --- ### AiOptions AI provider configuration. ```csharp public sealed class AiOptions { [JsonIgnore] public string ApiKey { get; set; } // Not persisted public string Provider { get; set; } // Default: "Claude" public string Model { get; set; } // Default: "claude-sonnet-4-20250514" public bool IncludeDiffContext { get; set; } // Default: true public int MaxDiffLines { get; set; } // Default: 200 public int MaxTokens { get; set; } // Default: 500 public int RateLimitDelayMs { get; set; } // Default: 500 public static AIProvider ParseProvider(string? provider); } ``` --- ### HistoryAnalysisOptions ```csharp public sealed class HistoryAnalysisOptions { public AnalysisDepth Depth { get; set; } // Quick, Standard, Deep, Full public DateTimeOffset? Since { get; set; } public string[]? IncludeBranches { get; set; } public string[]? ExcludeAuthors { get; set; } public bool AnalyzeMerges { get; set; } // Default: true public bool DetectDuplicates { get; set; } // Default: true } ``` --- ### CleanupExecutionOptions ```csharp public sealed record CleanupExecutionOptions { public bool CreateBackup { get; init; } // Default: true public string? BackupBranchName { get; init; } public bool AllowPushedCommits { get; init; } // Default: false public bool AutoForcePush { get; init; } // Default: false public bool UseAiForMessages { get; init; } // Default: true } ``` --- ## Enumerations ### Analysis & Quality ```csharp public enum AnalysisStatus { Pending, Analyzed, Applied, Failed, Skipped } public enum IssueSeverity { Info, Warning, Error } public enum OperationStatus { Pending, Applied, Failed, Undone } ``` ### Health Grades ```csharp public enum HealthGrade { Excellent, // 90-100: Best practices followed Good, // 70-89: Minor issues, generally healthy Fair, // 50-69: Noticeable issues, needs attention Poor, // 30-49: Significant problems, cleanup recommended Critical // 0-29: Severe issues, immediate action required } public enum HealthIssueSeverity { Info, Warning, Error, Critical } ``` ### Cleanup ```csharp public enum CleanupType { SquashDuplicates, RewordMessages, SquashMerges, RebaseLinearize, ArchiveBranches, FixAuthorship, ConsolidateMerges } public enum CleanupAutomationLevel { FullyAutomated, // Can run with one click SemiAutomated, // Requires user review/approval Manual // Requires manual git commands } public enum CleanupOperationStatus { Suggested, Approved, InProgress, Completed, Failed, Skipped } public enum RiskLevel { None, Low, Medium, High, VeryHigh } public enum EstimatedEffort { Minimal, Low, Medium, High, VeryHigh } ``` ### Analysis Depth & Format ```csharp public enum AnalysisDepth { Quick, // Sample 200 commits, basic metrics Standard, // 1000 commits, all metrics Deep, // 5000 commits, comprehensive Full // All commits (slow for large repos) } public enum ReportFormat { Json, Markdown, Html, Console } ``` --- ## Extensions ### ServiceCollectionExtensions ```csharp public static class ServiceCollectionExtensions { /// /// Registers all GitMessageImprover services with the DI container. /// public static IServiceCollection AddGitMessageImprover( this IServiceCollection services, Action configureOptions); } ``` **Registered Services:** - `GitImproverOptions` (Singleton) - `CommitMessageRules` (Singleton) - `AiOptions` (Singleton) - `IStateRepository` (Singleton) - `ICommitMessageAnalyzer` (Singleton) - `IGitOperationsService` (Singleton) - `ICommitMessageRewriter` (Singleton) - `IGitMessageImproverService` (Singleton) --- ## Usage Patterns ### Pattern 1: CLI Tool ```csharp var options = new GitImproverOptions { WorkspaceRoot = args[0] }; await using var service = await GitMessageImproverService.CreateAsync(options); var repos = await service.ScanAndRegisterReposAsync(); var analyses = await service.AnalyzeAllReposAsync(onlyNeedsImprovement: true); foreach (var analysis in analyses) { Console.WriteLine($"[{analysis.Quality.OverallScore}] {analysis.ShortHash}: {analysis.OriginalMessage}"); } ``` ### Pattern 2: MAUI/WPF App with DI ```csharp // In MauiProgram.cs services.AddGitMessageImprover(opt => { opt.WorkspaceRoot = Preferences.Get("workspace", ""); opt.Ai.ApiKey = SecureStorage.GetAsync("api_key").Result ?? ""; }); // In ViewModel public class CommitViewModel(IGitMessageImproverService service) { public async Task LoadAsync() { await service.LoadStateAsync(); Repos = new ObservableCollection(service.Repos); } } ``` ### Pattern 3: Focused Interface Usage ```csharp // Only need push operations - inject the focused interface public class PushHandler(IGitPushService pushService) { public bool SafePush(string repoPath, string commitHash) { if (pushService.IsCommitPushed(repoPath, commitHash)) return true; return pushService.Push(repoPath).Success; } } ``` ### Pattern 4: Health Analysis Pipeline ```csharp // Analyze -> Review -> Cleanup var report = await service.AnalyzeHistoryHealthAsync(repoPath); if (report.Score.Grade <= HealthGrade.Fair) { // Export for review var markdown = await service.ExportHealthReportAsync(report, ReportFormat.Markdown); await File.WriteAllTextAsync("health-report.md", markdown); // Execute safe automated cleanups if (report.CleanupSuggestions?.AutomatedOperations.Any() == true) { var result = await service.ExecuteAllCleanupsAsync( repo, report.CleanupSuggestions, new CleanupExecutionOptions { CreateBackup = true, AllowPushedCommits = false }); } } ``` --- ## Error Handling | Exception | Cause | Resolution | |-----------|-------|------------| | `ApiKeyNotConfiguredException` | AI API key not configured | Set `AiOptions.ApiKey` | | `ValidationException` | Invalid `GitImproverOptions` | Check required fields | | `InvalidOperationException` | No suggested message for commit | Generate suggestion first | | `ArgumentException` | Commit or repository not found | Verify paths and hashes | --- ## Thread Safety Notes - Repository cache uses `ConcurrentDictionary` with LRU eviction - All async methods support `CancellationToken` - State operations are serialized through `IStateRepository` - Dispose the service when done to release git handles ```csharp // Always dispose await using var service = await GitMessageImproverService.CreateAsync(options); // or using var service = ...; // or explicitly service.Dispose(); ```