Cursor rule
.cursor/rules/configuration-management.mdcConfiguration and settings management patterns
Cursor rules
Quality
65/100
Scores the file, not the repository.Length
724 words
32 headings · 17 code blocksRepository
103
— · pushed 17 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# Configuration Management89## ConfigManager Pattern1011### Singleton Access12Always access ConfigManager through the singleton instance:1314```csharp15var apiKey = ConfigManager.Instance.GetGeminiApiKey();16ConfigManager.Instance.SetGeminiApiKey("new-key");17```1819### Configuration Keys20- Define keys as `public const string` constants21- Use descriptive UPPER_SNAKE_CASE names22- Group related keys together2324```csharp25public const string GEMINI_API_KEY = "gemini_api_key";26public const string GEMINI_MODEL = "gemini_model";27public const string TRANSLATION_SERVICE = "translation_service";28```2930## Getter/Setter Pattern3132### Standard Pattern33For each configuration value, provide Get/Set methods:3435```csharp36// Get method37public string GetGeminiApiKey()38{39 return GetValue(GEMINI_API_KEY);40}4142// Set method (auto-saves)43public void SetGeminiApiKey(string apiKey)44{45 _configValues[GEMINI_API_KEY] = apiKey;46 SaveConfig();47}48```4950### Typed Getters51Provide typed getters for common types:5253```csharp54// Boolean55public bool GetBoolValue(string key, bool defaultValue = false)56{57 if (_configValues.TryGetValue(key, out var value))58 {59 return value.ToLower() == "true" || value == "1";60 }61 return defaultValue;62}6364// Integer65public int GetIntValue(string key, int defaultValue = 0)66{67 if (_configValues.TryGetValue(key, out var value))68 {69 if (int.TryParse(value, out int result))70 {71 return result;72 }73 }74 return defaultValue;75}7677// Double/Float78public double GetDoubleValue(string key, double defaultValue = 0.0)79{80 if (_configValues.TryGetValue(key, out var value))81 {82 if (double.TryParse(value, out double result))83 {84 return result;85 }86 }87 return defaultValue;88}89```9091## Configuration Files9293### File Structure94- Main config: `config.txt` (in app directory)95- Service-specific configs: `gemini_config.txt`, `ollama_config.txt`, etc.96- Format: `key=value` pairs, one per line97- Multiline values use tags: `<tag>content</tag>`9899### Loading Configuration100```csharp101private void LoadConfig()102{103 if (!File.Exists(_configFilePath))104 {105 CreateDefaultConfig();106 return;107 }108109 string content = File.ReadAllText(_configFilePath);110 ProcessMultilineValues(content);111 ProcessSingleLineValues(content);112}113```114115### Saving Configuration116```csharp117public void SaveConfig()118{119 try120 {121 var lines = new List<string>();122 foreach (var kvp in _configValues)123 {124 if (kvp.Value.Contains('\n'))125 {126 // Multiline value127 lines.Add($"<{kvp.Key}>");128 lines.Add(kvp.Value);129 lines.Add($"</{kvp.Key}>");130 }131 else132 {133 lines.Add($"{kvp.Key}={kvp.Value}");134 }135 }136 File.WriteAllLines(_configFilePath, lines);137 }138 catch (Exception ex)139 {140 Console.WriteLine($"Error saving config: {ex.Message}");141 }142}143```144145## Service-Specific Configuration146147### Separate Config Files148Some services use separate config files for complex settings:149150- `gemini_config.txt` - Gemini prompt templates151- `ollama_config.txt` - Ollama prompt templates152- `chatgpt_config.txt` - ChatGPT prompt templates153154### Loading Service Configs155```csharp156public string GetGeminiPrompt()157{158 if (File.Exists(_geminiConfigFilePath))159 {160 return File.ReadAllText(_geminiConfigFilePath);161 }162 return GetDefaultGeminiPrompt();163}164```165166## Default Values167168### Providing Defaults169Always provide sensible defaults:170171```csharp172public string GetOllamaModel()173{174 return GetValue(OLLAMA_MODEL, "llama3"); // Default model175}176177public int GetCaptureFPS()178{179 return GetIntValue(CAPTURE_FPS, 10); // Default 10 FPS180}181```182183## Settings Window Integration184185### Binding Pattern186Settings window binds directly to ConfigManager:187188```csharp189// In SettingsWindow.xaml.cs190private void LoadSettings()191{192 ApiKeyTextBox.Text = ConfigManager.Instance.GetGeminiApiKey();193 ModelComboBox.SelectedItem = ConfigManager.Instance.GetGeminiModel();194}195196private void SaveSettings()197{198 ConfigManager.Instance.SetGeminiApiKey(ApiKeyTextBox.Text);199 ConfigManager.Instance.SetGeminiModel(ModelComboBox.SelectedItem?.ToString() ?? "");200}201```202203### Two-Way Binding204For real-time updates, use two-way binding:205206```xml207<TextBox Text="{Binding ApiKey, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>208```209210## Window Position Persistence211212### Saving Window State213```csharp214public void SetWindowPosition(string windowName, double left, double top, double width, double height)215{216 SetValue($"{windowName}_left", left.ToString());217 SetValue($"{windowName}_top", top.ToString());218 SetValue($"{windowName}_width", width.ToString());219 SetValue($"{windowName}_height", height.ToString());220 SaveConfig();221}222```223224### Loading Window State225```csharp226public WindowPosition? GetWindowPosition(string windowName)227{228 var left = GetDoubleValue($"{windowName}_left", -1);229 var top = GetDoubleValue($"{windowName}_top", -1);230231 if (left < 0 || top < 0)232 {233 return null; // No saved position234 }235236 return new WindowPosition237 {238 X = left,239 Y = top,240 Width = GetDoubleValue($"{windowName}_width", 800),241 Height = GetDoubleValue($"{windowName}_height", 600)242 };243}244```245246## API Key Security247248### Storage249- API keys stored in plain text config files (local only)250- Never log API keys (mask in console output)251- Never commit API keys to version control252253### Masking in Logs254```csharp255Console.WriteLine($"API Key: {(key.Length > 0 ? "***" : "not set")}");256```257258## Configuration Validation259260### Validation Pattern261Validate settings before saving:262263```csharp264public bool ValidateSettings()265{266 if (string.IsNullOrWhiteSpace(GetGeminiApiKey()))267 {268 MessageBox.Show("Gemini API key is required", "Validation Error");269 return false;270 }271272 if (!IsValidModel(GetGeminiModel()))273 {274 MessageBox.Show("Invalid model selected", "Validation Error");275 return false;276 }277278 return true;279}280```281282## Migration and Backwards Compatibility283284### Handling Config Changes285When adding new settings, provide defaults:286287```csharp288// New setting with default289public string GetNewSetting()290{291 return GetValue(NEW_SETTING_KEY, "default-value");292}293```294295### Removing Old Settings296Clean up deprecated settings:297298```csharp299// Remove old key if it exists300if (_configValues.ContainsKey("old_key"))301{302 _configValues.Remove("old_key");303 SaveConfig();304}305```306307## Configuration Constants308309### Supported Values310Define supported values as constants:311312```csharp313public static readonly IReadOnlyList<string> SupportedOcrMethods = new List<string>314{315 "EasyOCR",316 "Manga OCR",317 "docTR",318 "Windows OCR"319};320321public static bool IsSupportedOcrMethod(string method)322{323 return SupportedOcrMethods.Contains(method, StringComparer.OrdinalIgnoreCase);324}325```326
Also in SethRobinson/UGTLive
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| SethRobinson/UGTLive.cursor/rules/ui-ux-patterns.mdc · 103 | Cursor rules | stylearchtypesui+1 | 62/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/architecture-patterns.mdc · 103 | Cursor rules | buildtestlint-formatstyle+6 | 77/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/async-threading-patterns.mdc · 103 | Cursor rules | styleuido-not | 65/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/code-style-conventions.mdc · 103 | Cursor rules | stylearchtypesdocs | 62/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/debugging-testing.mdc · 103 | Cursor rules | buildteststylearch+3 | 69/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/locale-invariant-formatting.mdc · 103 | Cursor rules | lint-formatuido-not | 61/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/service-integration-patterns.mdc · 103 | Cursor rules | buildteststylearch | 69/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/translation-workflow.mdc · 103 | Cursor rules | testlint-formatarchapi+3 | 66/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/ugtlive-project-guide.mdc · 103 | Cursor rules | stylearchuideployment+1 | 69/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/versioning-workflow.mdc · 103 | Cursor rules | stylegitdeploymentagent-behaviour+1 | 62/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/wpf-ui-patterns.mdc · 103 | Cursor rules | setuplint-formatstylearch+1 | 66/100 | 3 days ago | |
| SethRobinson/UGTLiveAGENTS.md · 103 | AGENTS.md | testgitsecurityperformance+1 | 74/100 | 3 days ago |
Diff against .cursor/rules/ui-ux-patterns.mdc Diff against .cursor/rules/architecture-patterns.mdc Diff against .cursor/rules/async-threading-patterns.mdc Diff against .cursor/rules/code-style-conventions.mdc Diff against .cursor/rules/debugging-testing.mdc Diff against .cursor/rules/locale-invariant-formatting.mdc Diff against .cursor/rules/service-integration-patterns.mdc Diff against .cursor/rules/translation-workflow.mdc Diff against .cursor/rules/ugtlive-project-guide.mdc Diff against .cursor/rules/versioning-workflow.mdc Diff against .cursor/rules/wpf-ui-patterns.mdc Diff against AGENTS.md
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| ThanhTrunggDEV/DontBeLazy.cursor/rules/rust-testing.mdc · 6 | Cursor rules | teststyletesting-strategy | 90/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/dart-testing.mdc · 6 | Cursor rules | teststyletypestesting-strategy | 85/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/dart-coding-style.mdc · 6 | Cursor rules | lint-formatstyletypesdo-not | 84/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/rust-security.mdc · 6 | Cursor rules | stylesecuritydatabasedo-not | 80/100 | 3 days ago | |
| imazen/imageflow.cursor/rules/ci.mdc · 4.4k | Cursor rules | setupbuildtestarch+3 | 79/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/rust-coding-style.mdc · 6 | Cursor rules | lint-formatstyle | 78/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/dart-hooks.mdc · 6 | Cursor rules | lint-formatarchtesting-strategygit+1 | 78/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/architecture-patterns.mdc · 103 | Cursor rules | buildtestlint-formatstyle+6 | 77/100 | 3 days ago |
