From 310f788f5f675fecbea5b2de427efc02a8d5a4d0 Mon Sep 17 00:00:00 2001 From: Cytown Date: Mon, 23 Mar 2026 11:20:42 +0800 Subject: [PATCH] rename security.yml to .security.yml --- pkg/config/REFACTORING_SUMMARY.md | 225 ------------------------ pkg/config/SECURITY_CONFIG.md | 52 +++--- pkg/config/config.go | 8 +- pkg/config/example_security_usage.go | 46 ++--- pkg/config/security.go | 2 +- pkg/config/security_integration_test.go | 14 +- pkg/config/security_test.go | 8 +- security.example.yml | 184 ------------------- 8 files changed, 65 insertions(+), 474 deletions(-) delete mode 100644 pkg/config/REFACTORING_SUMMARY.md delete mode 100644 security.example.yml diff --git a/pkg/config/REFACTORING_SUMMARY.md b/pkg/config/REFACTORING_SUMMARY.md deleted file mode 100644 index 2c4b30c9a..000000000 --- a/pkg/config/REFACTORING_SUMMARY.md +++ /dev/null @@ -1,225 +0,0 @@ -# Security Configuration Refactoring Summary - -## Overview - -Successfully refactored `pkg/config/config.go` to support a separate `security.yml` file for storing all sensitive data (API keys, tokens, secrets, passwords). - -## Changes Made - -### New Files Created - -1. **`pkg/config/security.go`** (New file) - - Defines `SecurityConfig` structure for all sensitive data - - Implements `LoadSecurityConfig()` to load from YAML - - Implements `SaveSecurityConfig()` to save with secure permissions (0o600) - - Implements `ResolveReference()` to resolve `ref:` prefixed strings - - Supports all model, channel, web tool, and skills security entries - -2. **`pkg/config/security_test.go`** (New file) - - Comprehensive unit tests for security config loading - - Tests for reference resolution (models, channels, web tools, skills) - - Tests for file I/O operations - -3. **`pkg/config/security_integration_test.go`** (New file) - - Integration tests for full workflow - - Tests backward compatibility with direct values - - Tests mixed usage of references and direct values - - Tests error handling for invalid references - -4. **`security.example.yml`** (New file) - - Template for users to copy and fill in - - Includes all possible security entries with placeholder values - - Located at project root - -5. **`pkg/config/SECURITY_CONFIG.md`** (New file) - - Complete documentation for the security config feature - - Usage examples and reference format guide - - Migration guide from old config - - Security best practices - -6. **`pkg/config/example_security_usage.go`** (New file) - - Practical examples in Go comment format - - Shows complete workflow from creation to usage - - Lists all available reference paths - -### Modified Files - -1. **`pkg/config/config.go`** - - Added `applySecurityConfig()` function to resolve all `ref:` references - - Modified `LoadConfig()` to: - - Load security config from `security.yml` - - Apply security references to all config fields - - Maintain backward compatibility with direct values - - Updated warning message to suggest using `security.yml` - -## Key Features - -### Reference Format - -Uses dot notation for referencing values: -- Models: `ref:model_list..api_key` -- Channels: `ref:channels..` -- Web Tools: `ref:web..` -- Skills: `ref:skills..` - -### Supported Security Entries - -**Models:** -- API keys for all model configurations - -**Channels:** -- Telegram: token -- Feishu: app_secret, encrypt_key, verification_token -- Discord: token -- QQ: app_secret -- DingTalk: client_secret -- Slack: bot_token, app_token -- Matrix: access_token -- LINE: channel_secret, channel_access_token -- OneBot: access_token -- WeCom: token, encoding_aes_key -- WeComApp: corp_secret, token, encoding_aes_key -- WeComAIBot: token, encoding_aes_key -- Pico: token -- IRC: password, nickserv_password, sasl_password - -**Web Tools:** -- Brave: api_key -- Tavily: api_key -- Perplexity: api_key -- GLMSearch: api_key - -**Skills:** -- GitHub: token -- ClawHub: auth_token - -### Backward Compatibility - -- Direct values in `config.json` still work -- Mixed usage of references and direct values is supported -- Optional security file (if missing, only references fail) -- No breaking changes to existing configurations - -## Testing - -All tests pass successfully: - -```bash -go test ./pkg/config -v -``` - -Test coverage includes: -- ✅ Unit tests for reference resolution -- ✅ Integration tests for full workflow -- ✅ Backward compatibility tests -- ✅ Error handling tests -- ✅ File I/O and permission tests -- ✅ All existing config tests still pass - -## Usage Example - -### config.json -```json -{ - "version": 1, - "model_list": [ - { - "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_base": "https://api.openai.com/v1", - "api_key": "ref:model_list.gpt-5.4.api_key" - } - ], - "channels": { - "telegram": { - "enabled": true, - "token": "ref:channels.telegram.token" - } - } -} -``` - -### security.yml -```yaml -model_list: - gpt-5.4: - api_key: "sk-proj-actual-key-here" - -channels: - telegram: - token: "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz" -``` - -## Migration Path - -1. Copy `security.example.yml` to `~/.picoclaw/security.yml` -2. Fill in actual API keys and tokens -3. Update `config.json` to use `ref:` references -4. Set proper permissions: `chmod 600 ~/.picoclaw/security.yml` -5. Test with `picoclaw --version` - -## Security Benefits - -1. **Separation of concerns**: Configuration and secrets are in separate files -2. **Easier sharing**: Config can be shared without exposing secrets -3. **Better version control**: `security.yml` can be added to `.gitignore` -4. **Flexible deployment**: Different environments can use different security files -5. **Secure file permissions**: Saved with `0o600` by default - -## Implementation Details - -### File Loading Flow - -``` -LoadConfig() - ├─ Load config.json - ├─ Detect version - ├─ Parse config based on version - ├─ Load security.yml (optional) - ├─ Apply security references - │ └─ Resolve all "ref:" prefixes - ├─ Parse environment variables - ├─ Resolve API keys (file://, enc://) - ├─ Expand multi-key models - └─ Validate and return -``` - -### Reference Resolution - -The `ResolveReference()` function: -1. Checks if string starts with `ref:` -2. Parses the dot-notation path -3. Navigates the security config structure -4. Returns the actual value -5. Returns error if path doesn't exist - -### Error Handling - -- Clear error messages with full context -- Includes the reference path and field name -- Fails early on invalid references -- Maintains backward compatibility - -## Dependencies - -Added dependency: `gopkg.in/yaml.v3` for YAML parsing - -## Files Modified Summary - -- **Created**: 6 new files (security.go, tests, docs, examples) -- **Modified**: 1 file (config.go - added security integration) -- **Lines added**: ~1000+ lines (including tests and documentation) -- **Backward compatible**: ✅ Yes -- **Breaking changes**: ❌ None - -## Next Steps - -1. Update main README to mention security.yml -2. Add security.yml to .gitignore -3. Update documentation with security config examples -4. Consider adding migration tool for existing users -5. Add validation for security.yml schema - -## Conclusion - -The refactoring successfully implements a secure, flexible, and backward-compatible way to manage sensitive configuration data. All tests pass and the feature is ready for use. diff --git a/pkg/config/SECURITY_CONFIG.md b/pkg/config/SECURITY_CONFIG.md index c1aa38acc..c5aed54ae 100644 --- a/pkg/config/SECURITY_CONFIG.md +++ b/pkg/config/SECURITY_CONFIG.md @@ -2,11 +2,11 @@ ## Overview -This refactoring introduces a `security.yml` file to store all sensitive data (API keys, tokens, secrets, passwords) separately from the main configuration. This improves security by: +This refactoring introduces a `.security.yml` file to store all sensitive data (API keys, tokens, secrets, passwords) separately from the main configuration. This improves security by: 1. **Separation of concerns**: Configuration settings and secrets are in separate files 2. **Easier sharing**: The main config can be shared without exposing sensitive data -3. **Better version control**: `security.yml` can be added to `.gitignore` +3. **Better version control**: `.security.yml` can be added to `.gitignore` 4. **Flexible deployment**: Different environments can use different security files ## File Structure @@ -14,14 +14,14 @@ This refactoring introduces a `security.yml` file to store all sensitive data (A ``` ~/.picoclaw/ ├── config.json # Main configuration (safe to share) -└── security.yml # Security data (never share) +└── .security.yml # Security data (never share) ``` ## Usage ### Basic Configuration -In your `config.json`, use `ref:` references to point to values in `security.yml`: +In your `config.json`, use `ref:` references to point to values in `.security.yml`: ```json { @@ -45,7 +45,7 @@ In your `config.json`, use `ref:` references to point to values in `security.yml ### Security Configuration -In your `security.yml`, store the actual values: +In your `.security.yml`, store the actual values: ```yaml model_list: @@ -135,9 +135,9 @@ The refactoring maintains full backward compatibility: 1. **Direct values**: You can still use direct values in `config.json` (not recommended for production) 2. **Mixed usage**: You can mix `ref:` references and direct values -3. **Optional security file**: If `security.yml` doesn't exist, all references will fail (but direct values still work) +3. **Optional security file**: If `.security.yml` doesn't exist, all references will fail (but direct values still work) -### API Key Formats in security.yml +### API Key Formats in .security.yml **Models (gpt-5.4, claude-sonnet-4.6, etc.):** - Must use `api_keys` (array) format @@ -190,16 +190,16 @@ In `config.json`: ## Migration Guide -### Step 1: Create security.yml +### Step 1: Create .security.yml Copy the example template: ```bash -cp security.example.yml ~/.picoclaw/security.yml +cp security.example.yml ~/.picoclaw/.security.yml ``` ### Step 2: Fill in your actual values -Edit `~/.picoclaw/security.yml` and replace placeholder values with your actual API keys and tokens. +Edit `~/.picoclaw/.security.yml` and replace placeholder values with your actual API keys and tokens. ### Step 3: Update config.json @@ -240,11 +240,11 @@ picoclaw --version ## Security Best Practices -1. **Never commit `security.yml`** to version control -2. **Set file permissions**: `chmod 600 ~/.picoclaw/security.yml` +1. **Never commit `.security.yml`** to version control +2. **Set file permissions**: `chmod 600 ~/.picoclaw/.security.yml` 3. **Use different keys** for different environments (dev, staging, production) -4. **Rotate keys regularly** and update `security.yml` -5. **Backup securely**: Encrypt backups containing `security.yml` +4. **Rotate keys regularly** and update `.security.yml` +5. **Backup securely**: Encrypt backups containing `.security.yml` ## API @@ -254,7 +254,7 @@ picoclaw --version func LoadSecurityConfig(securityPath string) (*SecurityConfig, error) ``` -Loads the security configuration from `security.yml`. Returns an empty `SecurityConfig` if the file doesn't exist. +Loads the security configuration from `.security.yml`. Returns an empty `SecurityConfig` if the file doesn't exist. ### SaveSecurityConfig @@ -262,7 +262,7 @@ Loads the security configuration from `security.yml`. Returns an empty `Security func SaveSecurityConfig(securityPath string, sec *SecurityConfig) error ``` -Saves the security configuration to `security.yml` with `0o600` permissions. +Saves the security configuration to `.security.yml` with `0o600` permissions. ### ResolveReference @@ -278,7 +278,7 @@ Resolves a reference string (e.g., `"ref:model_list.test.api_key"`) and returns func SecurityPath(configPath string) string ``` -Returns the path to `security.yml` relative to the config file. +Returns the path to `.security.yml` relative to the config file. ## Example: Complete Configuration @@ -323,7 +323,7 @@ Returns the path to `security.yml` relative to the config file. } ``` -### security.yml +### .security.yml ```yaml model_list: gpt-5.4: @@ -362,13 +362,13 @@ go test ./pkg/config -run TestSecurityConfig ### Error: "model security entry not found" -- Ensure the model name in your reference matches exactly in `security.yml` -- Check that the `model_list` section exists in `security.yml` +- Ensure the model name in your reference matches exactly in `.security.yml` +- Check that the `model_list` section exists in `.security.yml` - For models with indexed names (e.g., "gpt-5.4:0"), ensure the exact name is used or check the base name without index ### Error: "failed to load security config" -- Verify `security.yml` exists in the same directory as `config.json` +- Verify `.security.yml` exists in the same directory as `config.json` - Check the YAML syntax is valid (use a YAML validator) - Ensure file permissions allow reading @@ -376,7 +376,7 @@ go test ./pkg/config -run TestSecurityConfig - Verify the reference format is correct - Check the path structure matches the examples above -- Ensure all required sections exist in `security.yml` +- Ensure all required sections exist in `.security.yml` ## Advanced Features @@ -392,7 +392,7 @@ Both models and web tools support multiple API keys for improved reliability: #### Example: Model with Multiple Keys -**security.yml:** +**.security.yml:** ```yaml model_list: gpt-5.4: @@ -417,7 +417,7 @@ model_list: #### Example: Web Tool with Multiple Keys -**security.yml:** +**.security.yml:** ```yaml web: brave: @@ -504,7 +504,7 @@ All formats work identically in `config.json` - you always use the same referenc When you have multiple models with the same base name but different API keys, you can use indexed names: -**security.yml:** +**.security.yml:** ```yaml model_list: gpt-5.4: @@ -538,7 +538,7 @@ Environment variables follow this pattern: `PICOCLAW_
___ "abc") - // This allows security.yml to use simpler keys like "test-model" instead of "test-model:0" + // This allows .security.yml to use simpler keys like "test-model" instead of "test-model:0" baseName := model.ModelName if entry, exists := sec.ModelList[baseName]; exists { copyArray(&model.apiKeys, &entry.APIKeys) @@ -1838,7 +1838,7 @@ func SaveConfig(path string, cfg *Config) error { } } if err := saveSecurityConfig(securityPath(path), cfg.security); err != nil { - logger.ErrorCF("config", "cannot save security.yml", map[string]any{"error": err}) + logger.ErrorCF("config", "cannot save .security.yml", map[string]any{"error": err}) return err } diff --git a/pkg/config/example_security_usage.go b/pkg/config/example_security_usage.go index d4df93473..cba76c6bc 100644 --- a/pkg/config/example_security_usage.go +++ b/pkg/config/example_security_usage.go @@ -118,7 +118,7 @@ chmod 600 ~/.picoclaw/security.yml ```gitignore # Security configuration -security.yml +.security.yml ``` ## 5. Verify it works @@ -136,7 +136,7 @@ Examples: - ref:model_list.gpt-5.4.api_key - ref:model_list.claude-sonnet-4.6.api_key -**Note:** In security.yml, use `api_keys` (array) format for models. +**Note:** In .security.yml, use `api_keys` (array) format for models. Both single and multiple keys should use the array format. ## Channel Tokens/Secrets @@ -172,8 +172,8 @@ Both single and multiple keys should use the array format. - ref:web.glm_search.api_key **Note:** -- Brave, Tavily, Perplexity: Use `api_keys` (array) format in security.yml -- GLMSearch: Use `api_key` (single string) format in security.yml +- Brave, Tavily, Perplexity: Use `api_keys` (array) format in .security.yml +- GLMSearch: Use `api_key` (single string) format in .security.yml ## Skills Registry Tokens - ref:skills.github.token @@ -206,7 +206,7 @@ You can also mix references and direct values: "model_list": [ { "model_name": "cloud-model", - "api_key": "ref:model_list.cloud-model.api_key" // From security.yml + "api_key": "ref:model_list.cloud-model.api_key" // From .security.yml }, { "model_name": "local-model", @@ -226,11 +226,11 @@ cp ~/.picoclaw/config.json ~/.picoclaw/config.json.backup ## Step 2: Copy the example security file ```bash -cp security.example.yml ~/.picoclaw/security.yml +cp security.example.yml ~/.picoclaw/.security.yml ``` ## Step 3: Fill in your API keys -Edit ~/.picoclaw/security.yml and replace placeholders with your actual keys. +Edit ~/.picoclaw/.security.yml and replace placeholders with your actual keys. ## Step 4: Update config.json references Replace sensitive values in ~/.picoclaw/config.json with ref: references. @@ -255,7 +255,7 @@ You can configure multiple API keys for both models and web tools to enable: ### Example: Model with Multiple Keys -**security.yml:** +**.security.yml:** ```yaml model_list: @@ -284,7 +284,7 @@ model_list: ### Example: Web Tool with Multiple Keys -**security.yml:** +**.security.yml:** ```yaml web: @@ -342,12 +342,12 @@ model_list: ``` -**Important:** All model keys in security.yml must use the `api_keys` (plural) array format. +**Important:** All model keys in .security.yml must use the `api_keys` (plural) array format. The single `api_key` (singular) format is NOT supported for models. ### Model Index Matching -The system supports intelligent model name matching in security.yml: +The system supports intelligent model name matching in .security.yml: **Example 1: Exact Match** ```yaml @@ -357,7 +357,7 @@ The system supports intelligent model name matching in security.yml: "model_name": "gpt-5.4:0" } -# security.yml (exact match with index) +# .security.yml (exact match with index) model_list: gpt-5.4:0: @@ -373,7 +373,7 @@ model_list: "model_name": "gpt-5.4:0" } -# security.yml (base name without index) +# .security.yml (base name without index) model_list: gpt-5.4: @@ -381,7 +381,7 @@ model_list: ``` -Both methods work. The base name match allows you to use simpler keys in security.yml +Both methods work. The base name match allows you to use simpler keys in .security.yml even when your config uses indexed model names for load balancing. ### Security File Permissions @@ -389,34 +389,34 @@ even when your config uses indexed model names for load balancing. The security file should have restricted permissions: ```bash -chmod 600 ~/.picoclaw/security.yml +chmod 600 ~/.picoclaw/.security.yml ``` This ensures only the owner can read and write the file. # Security Best Practices -1. Never commit security.yml to version control -2. Set file permissions: chmod 600 ~/.picoclaw/security.yml +1. Never commit .security.yml to version control +2. Set file permissions: chmod 600 ~/.picoclaw/.security.yml 3. Use different keys for different environments -4. Rotate keys regularly and update security.yml -5. Encrypt backups containing security.yml +4. Rotate keys regularly and update .security.yml +5. Encrypt backups containing .security.yml # Troubleshooting ## Error: "model security entry not found" -- Check that the model name in config.json matches exactly in security.yml -- Verify the model_list section exists in security.yml +- Check that the model name in config.json matches exactly in .security.yml +- Verify the model_list section exists in .security.yml ## Error: "failed to load security config" -- Ensure security.yml exists in the same directory as config.json +- Ensure .security.yml exists in the same directory as config.json - Check YAML syntax is valid - Verify file permissions allow reading ## Error: "unknown reference path" - Verify the reference format is correct - Check the path structure matches the examples above -- Ensure all required sections exist in security.yml +- Ensure all required sections exist in .security.yml */ package config diff --git a/pkg/config/security.go b/pkg/config/security.go index 66d1eef38..b6db7c0e3 100644 --- a/pkg/config/security.go +++ b/pkg/config/security.go @@ -19,7 +19,7 @@ import ( ) const ( - SecurityConfigFile = "security.yml" + SecurityConfigFile = ".security.yml" ) // SecurityConfig stores all sensitive data (API keys, tokens, secrets, passwords) diff --git a/pkg/config/security_integration_test.go b/pkg/config/security_integration_test.go index 99d4f01df..c1e1a2340 100644 --- a/pkg/config/security_integration_test.go +++ b/pkg/config/security_integration_test.go @@ -80,8 +80,8 @@ func TestSecurityConfigIntegration(t *testing.T) { err := os.WriteFile(configPath, []byte(configContent), 0o644) require.NoError(t, err) - // Create security.yml with actual values - securityPath := filepath.Join(tmpDir, "security.yml") + // Create .security.yml with actual values + securityPath := filepath.Join(tmpDir, SecurityConfigFile) securityContent := `model_list: test-model: api_keys: @@ -141,8 +141,8 @@ func TestSecurityConfigWithAPIKeysArray(t *testing.T) { err := os.WriteFile(configPath, []byte(configContent), 0o644) require.NoError(t, err) - // Create security.yml - securityPath := filepath.Join(tmpDir, "security.yml") + // Create .security.yml + securityPath := filepath.Join(tmpDir, SecurityConfigFile) securityContent := `model_list: multi-key-model:0: api_key: "sk-key-1" @@ -197,7 +197,7 @@ func TestAllSecurityKeysAccessible(t *testing.T) { err = os.WriteFile(clawhubAuthTokenFile, []byte("clawhub-auth-token-from-file"), 0o600) require.NoError(t, err) - // Create config.json without sensitive values (they'll be in security.yml) + // Create config.json without sensitive values (they'll be in .security.yml) configPath := filepath.Join(tmpDir, "config.json") configContent := `{ "version": 1, @@ -288,8 +288,8 @@ func TestAllSecurityKeysAccessible(t *testing.T) { err = os.WriteFile(configPath, []byte(configContent), 0o644) require.NoError(t, err) - // Create security.yml with file:// references and plaintext values - securityPath := filepath.Join(tmpDir, "security.yml") + // Create .security.yml with file:// references and plaintext values + securityPath := filepath.Join(tmpDir, SecurityConfigFile) securityContent := `model_list: test-model-1: api_keys: diff --git a/pkg/config/security_test.go b/pkg/config/security_test.go index 482b3578e..74e765f6b 100644 --- a/pkg/config/security_test.go +++ b/pkg/config/security_test.go @@ -16,7 +16,7 @@ import ( func TestSecurityConfig(t *testing.T) { t.Run("LoadNonExistent", func(t *testing.T) { - sec, err := loadSecurityConfig("/nonexistent/security.yml") + sec, err := loadSecurityConfig("/nonexistent/.security.yml") require.NoError(t, err) assert.NotNil(t, sec) assert.Empty(t, sec.ModelList) @@ -32,12 +32,12 @@ func TestSecurityPath(t *testing.T) { { name: "standard path", configDir: "/home/user/.picoclaw/config.json", - want: "/home/user/.picoclaw/security.yml", + want: "/home/user/.picoclaw/.security.yml", }, { name: "nested path", configDir: "/path/to/config/myconfig.json", - want: "/path/to/config/security.yml", + want: "/path/to/config/.security.yml", }, } @@ -51,7 +51,7 @@ func TestSecurityPath(t *testing.T) { func TestSaveAndLoadSecurityConfig(t *testing.T) { tmpDir := t.TempDir() - secPath := filepath.Join(tmpDir, "security.yml") + secPath := filepath.Join(tmpDir, SecurityConfigFile) original := &SecurityConfig{ ModelList: map[string]ModelSecurityEntry{ diff --git a/security.example.yml b/security.example.yml deleted file mode 100644 index 1d7f8bd0c..000000000 --- a/security.example.yml +++ /dev/null @@ -1,184 +0,0 @@ -# PicoClaw Security Configuration -# This file stores all sensitive data (API keys, tokens, secrets, passwords) -# Keep this file secure and never commit it to version control -# Copy this file to security.yml and fill in your actual values - -# Model API Keys -# Use dot notation references in config.json like: "ref:model_list.gpt-5.4.api_key" -# IMPORTANT: Use 'api_keys' (array) format - both single and multiple keys -model_list: - # Example: OpenAI GPT-5.4 (multiple keys for load balancing/failover) - gpt-5.4: - api_keys: - - "your-openai-api-key-1" - - "your-openai-api-key-2" # Optional: failover key - - # Example: Claude Sonnet (single key in array format) - claude-sonnet-4.6: - api_keys: - - "your-anthropic-api-key-here" # Single key MUST be in array format - - # Example: Zhipu GLM - glm-4.7: - api_key: "your-zhipu-api-key-here" - - # Example: DeepSeek - deepseek-chat: - api_key: "your-deepseek-api-key-here" - - # Example: Google Gemini - gemini-2.0-flash: - api_key: "your-gemini-api-key-here" - - # Example: Qwen - qwen-plus: - api_key: "your-qwen-api-key-here" - - # Example: Moonshot - moonshot-v1-8k: - api_key: "your-moonshot-api-key-here" - - # Example: Groq - llama-3.3-70b: - api_key: "your-groq-api-key-here" - - # Example: OpenRouter - openrouter-auto: - api_key: "your-openrouter-api-key-here" - openrouter-gpt-5.4: - api_key: "your-openrouter-api-key-here" - - # Example: NVIDIA - nemotron-4-340b: - api_key: "your-nvidia-api-key-here" - - # Example: Cerebras - cerebras-llama-3.3-70b: - api_key: "your-cerebras-api-key-here" - - # Example: Vivgrid - vivgrid-auto: - api_key: "your-vivgrid-api-key-here" - - # Example: Volcengine - ark-code-latest: - api_key: "your-volcengine-api-key-here" - doubao-pro: - api_key: "your-volcengine-api-key-here" - - # Example: ShengsuanYun - deepseek-v3: - api_key: "your-shengsuanyun-api-key-here" - - # Example: Mistral - mistral-small: - api_key: "your-mistral-api-key-here" - - # Example: Avian - deepseek-v3.2: - api_key: "your-avian-api-key-here" - kimi-k2.5: - api_key: "your-avian-api-key-here" - - # Example: Minimax - MiniMax-M2.5: - api_key: "your-minimax-api-key-here" - - # Example: LongCat - LongCat-Flash-Thinking: - api_key: "your-longcat-api-key-here" - - # Example: ModelScope - modelscope-qwen: - api_key: "your-modelscope-api-key-here" - - # Example: VLLM (local, usually no real key needed) - local-model: - api_key: "" - - # Example: Azure OpenAI - azure-gpt5: - api_key: "your-azure-api-key-here" - -# Channel Tokens and Secrets -channels: - telegram: - token: "your-telegram-bot-token" - - feishu: - app_secret: "your-feishu-app-secret" - encrypt_key: "your-feishu-encrypt-key" - verification_token: "your-feishu-verification-token" - - discord: - token: "your-discord-bot-token" - - qq: - app_secret: "your-qq-app-secret" - - dingtalk: - client_secret: "your-dingtalk-client-secret" - - slack: - bot_token: "your-slack-bot-token" - app_token: "your-slack-app-token" - - matrix: - access_token: "your-matrix-access-token" - - line: - channel_secret: "your-line-channel-secret" - channel_access_token: "your-line-channel-access-token" - - onebot: - access_token: "your-onebot-access-token" - - wecom: - token: "your-wecom-token" - encoding_aes_key: "your-wecom-encoding-aes-key" - - wecom_app: - corp_secret: "your-wecom-app-corp-secret" - token: "your-wecom-app-token" - encoding_aes_key: "your-wecom-app-encoding-aes-key" - - wecom_aibot: - token: "your-wecom-aibot-token" - encoding_aes_key: "your-wecom-aibot-encoding-aes-key" - - pico: - token: "your-pico-token" - - irc: - password: "your-irc-password" - nickserv_password: "your-irc-nickserv-password" - sasl_password: "your-irc-sasl-password" - -# Web Tool API Keys -# IMPORTANT: Use 'api_keys' (array) for Brave, Tavily, Perplexity -# Use 'api_key' (single string) for GLMSearch only -web: - brave: - api_keys: - - "your-brave-api-key-1" - - "your-brave-api-key-2" # Optional: failover key - - tavily: - api_keys: - - "your-tavily-api-key" # Single key MUST be in array format - - perplexity: - api_keys: - - "your-perplexity-api-key-1" - - "your-perplexity-api-key-2" - - glm_search: - api_key: "your-glm-search-api-key" # GLMSearch uses single string format (NOT array) - -# Skills Registry Tokens -skills: - github: - token: "your-github-token" - - clawhub: - auth_token: "your-clawhub-auth-token"