Context
Orpheus currently lives in a single orpheus.yaml file. That works for one station, but it doesn't support per-environment overrides, runtime tuning without restarts, or configuration versioning. Implement a layered configuration system:
- Base:
orpheus.yaml (checked into git)
- Overrides: Database-stored settings (runtime-tunable)
- Final: Environment variables (deployment-specific, highest priority)
This enables a future multi-station deployment where each station has a base config with local overrides.
Architecturally Significant Requirements (ASRs)
Interface (Contract):
ConfigStore class with methods:
get(key: str, default: Any = None) -> Any — layered lookup (env → DB → YAML).
set(key: str, value: Any, author: str = "system") -> ConfigVersion — write to DB layer with version tracking.
history(key: str, limit: int = 10) -> List[ConfigVersion] — audit trail.
subscribe(key_pattern: str, callback: Callable) -> None — hot-reload notification.
ConfigVersion dataclass: {"key": str, "value": Any, "author": str, "changed_at": str, "version": int}.
- Backward compatibility:
OrpheusConfig.get_instance() delegates to ConfigStore internally.
Implementation (Internal Logic):
- Layered resolver: check env vars first, then SQLite
config_overrides table, then YAML file.
- SQLite schema:
config_versions table with key, value_json, author, changed_at, version (auto-increment per key).
- MQTT publication to
orpheus/system/config_changed with key and new value on every set() call.
Architectural Constraints
- Must be backward-compatible with existing
OrpheusConfig.get_instance() usage.
- Database schema must version every configuration change (who changed what, when).
- Must not require a migration for existing deployments — if no DB config exists, fall back to YAML.
- Configuration changes must be publishable to MQTT so agents can hot-reload without restart.
- Must be Python 3.9 compatible.
Acceptance Criteria
Feature: Database-Backed Configuration System
Scenario: Layered config lookup (env > DB > YAML)
Given orpheus.yaml sets "audio.volume" to 0.5
And the DB override sets "audio.volume" to 0.7
When config.get("audio.volume") is called
Then the returned value is 0.7
Scenario: Environment variable takes highest priority
Given orpheus.yaml sets "audio.volume" to 0.5
And the DB override sets "audio.volume" to 0.7
And ORPHEUS_AUDIO_VOLUME env var is set to 0.3
When config.get("audio.volume") is called
Then the returned value is 0.3
Scenario: Config change triggers MQTT notification
Given an agent subscribes to "orpheus/system/config_changed"
When config.set("audio.volume", 0.8, author="admin") is called
Then the agent receives an MQTT message with key "audio.volume" and value 0.8
And a new version record is created in the config_versions table
Scenario: Backward compatibility with existing code
Given existing code calls OrpheusConfig.get_instance()
When the ConfigStore is initialized
Then OrpheusConfig.get_instance() still works identically
And no code changes are required in existing agents
Definition of Done
Context
Orpheus currently lives in a single
orpheus.yamlfile. That works for one station, but it doesn't support per-environment overrides, runtime tuning without restarts, or configuration versioning. Implement a layered configuration system:orpheus.yaml(checked into git)This enables a future multi-station deployment where each station has a base config with local overrides.
Architecturally Significant Requirements (ASRs)
Interface (Contract):
ConfigStoreclass with methods:get(key: str, default: Any = None) -> Any— layered lookup (env → DB → YAML).set(key: str, value: Any, author: str = "system") -> ConfigVersion— write to DB layer with version tracking.history(key: str, limit: int = 10) -> List[ConfigVersion]— audit trail.subscribe(key_pattern: str, callback: Callable) -> None— hot-reload notification.ConfigVersiondataclass:{"key": str, "value": Any, "author": str, "changed_at": str, "version": int}.OrpheusConfig.get_instance()delegates toConfigStoreinternally.Implementation (Internal Logic):
config_overridestable, then YAML file.config_versionstable withkey,value_json,author,changed_at,version(auto-increment per key).orpheus/system/config_changedwith key and new value on everyset()call.Architectural Constraints
OrpheusConfig.get_instance()usage.Acceptance Criteria
Definition of Done
ConfigStoreclass inorpheus-commonimplementing the layered lookup (YAML → DB → env).