6.7 KiB
Contributing to Alfred
Settings Management System
Alfred uses a declarative, schema-based configuration system that ensures type safety, validation, and maintainability.
Architecture Overview
settings.toml # Schema definitions (single source of truth)
↓
settings_schema.py # Parser & validation
↓
settings_bootstrap.py # Generation & resolution
↓
.env # Runtime configuration
.env.make # Build variables for Makefile
↓
settings.py # Pydantic Settings (runtime validation)
Key Files
settings.toml— Declarative schema for all settingsalfred/settings_schema.py— Schema parser and validation logicalfred/settings_bootstrap.py— Bootstrap logic (generates.envand.env.make)alfred/settings.py— Pydantic Settings class (runtime).env— Generated configuration file (gitignored).env.make— Build variables for Makefile (gitignored)
Setting Sources
Settings can come from different sources:
| Source | Description | Example |
|---|---|---|
toml |
From pyproject.toml |
Version numbers, build config |
env |
From .env file |
User-provided values, API keys |
generated |
Auto-generated secrets | JWT secrets, passwords |
computed |
Calculated from other settings | Database URIs |
How to Add a New Setting
1. Define in settings.toml
[tool.alfred.settings_schema.MY_NEW_SETTING]
type = "string" # string, integer, float, boolean, secret, computed
source = "env" # env, toml, generated, computed
default = "default_value" # Optional: default value
description = "Description here" # Required: clear description
category = "app" # app, api, database, security, build
required = true # Optional: default is true
validator = "range:1:100" # Optional: validation rule
export_to_env_make = false # Optional: export to .env.make for Makefile
2. Regenerate Configuration
make bootstrap
This will:
- Read the schema from
settings.toml - Generate/update
.envwith the new setting - Generate/update
.env.makeifexport_to_env_make = true - Preserve existing secrets
3. Validate
make validate
This ensures all settings are valid according to the schema.
4. Use in Code
The setting is automatically available in settings.py:
from alfred.settings import settings
print(settings.my_new_setting)
Setting Types
String Setting
[tool.alfred.settings_schema.API_URL]
type = "string"
source = "env"
default = "https://api.example.com"
description = "API base URL"
category = "api"
Integer Setting with Validation
[tool.alfred.settings_schema.MAX_RETRIES]
type = "integer"
source = "env"
default = 3
description = "Maximum retry attempts"
category = "app"
validator = "range:1:10"
Secret (Auto-generated)
[tool.alfred.settings_schema.API_SECRET]
type = "secret"
source = "generated"
secret_rule = "32:b64" # 32 bytes, base64 encoded
description = "API secret key"
category = "security"
Secret rules:
"32:b64"— 32 bytes, URL-safe base64"16:hex"— 16 bytes, hexadecimal
Computed Setting
[tool.alfred.settings_schema.DATABASE_URL]
type = "computed"
source = "computed"
compute_from = ["DB_HOST", "DB_PORT", "DB_NAME"]
compute_template = "postgresql://{DB_HOST}:{DB_PORT}/{DB_NAME}"
description = "Database connection URL"
category = "database"
From TOML (Build Variables)
[tool.alfred.settings_schema.APP_VERSION]
type = "string"
source = "toml"
toml_path = "tool.poetry.version"
description = "Application version"
category = "build"
export_to_env_make = true # Available in Makefile
Validators
Available validators:
range:min:max— Numeric range validationvalidator = "range:0.0:2.0" # For floats validator = "range:1:100" # For integers
Categories
Organize settings by category:
app— Application settingsapi— API keys and external servicesdatabase— Database configurationsecurity— Secrets and security keysbuild— Build-time configuration
Best Practices
- Always add a description — Make it clear what the setting does
- Use appropriate types — Don't use strings for numbers
- Add validation — Use validators for numeric ranges
- Categorize properly — Helps with organization
- Use computed settings — For values derived from others (e.g., URIs)
- Mark secrets as generated — Let the system handle secret generation
- Export build vars — Set
export_to_env_make = truefor Makefile variables
Workflow Example
# 1. Edit settings.toml
vim settings.toml
# 2. Regenerate configuration
make bootstrap
# 3. Validate
make validate
# 4. Test
python -c "from alfred.settings import settings; print(settings.my_new_setting)"
# 5. Commit (settings.toml only, not .env)
git add settings.toml
git commit -m "Add MY_NEW_SETTING"
Commands
make bootstrap # Generate .env and .env.make from schema
make validate # Validate all settings against schema
make help # Show all available commands
Troubleshooting
Setting not found in schema:
KeyError: Missing [tool.alfred.settings_schema] section
→ Check that settings.toml exists and has the correct structure
Validation error:
ValueError: MY_SETTING must be between 1 and 100, got 150
→ Check the validator in settings.toml and adjust the value in .env
Secret not preserved:
→ Secrets are automatically preserved during make bootstrap. If lost, they were never in .env (check .env exists before running bootstrap)
Testing
When adding a new setting, consider adding tests:
# tests/test_settings_schema.py
def test_my_new_setting(self, create_schema_file):
"""Test MY_NEW_SETTING definition."""
schema_toml = """
[tool.alfred.settings_schema.MY_NEW_SETTING]
type = "string"
source = "env"
default = "test"
"""
base_dir = create_schema_file(schema_toml)
schema = load_schema(base_dir)
definition = schema.get("MY_NEW_SETTING")
assert definition.default == "test"
Migration from Old System
If you're migrating from the old system:
- Settings are now in
settings.tomlinstead of scattered across files - No more
.env.example— schema is the source of truth - Secrets are auto-generated and preserved
- Validation happens at bootstrap time, not just runtime
Questions?
Open an issue or check the existing settings in settings.toml for examples.