Skip to main content

zeph_config/
root.rs

1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use std::collections::HashMap;
5use std::num::NonZeroUsize;
6
7use crate::tools::ToolsConfig;
8use serde::{Deserialize, Serialize};
9use zeph_common::secret::Secret;
10
11use crate::agent::{AgentConfig, FocusConfig, SubAgentConfig};
12use crate::channels::{A2aServerConfig, DiscordConfig, McpConfig, SlackConfig, TelegramConfig};
13use crate::classifiers::ClassifiersConfig;
14use crate::cli::CliConfig;
15use crate::defaults::{default_skill_paths, default_sqlite_path_field};
16use crate::experiment::{ExperimentConfig, OrchestrationConfig};
17use crate::features::{
18    CostConfig, DaemonConfig, DebugConfig, GatewayConfig, IndexConfig, SchedulerConfig,
19    SkillPromptMode, SkillsConfig, VaultConfig,
20};
21use crate::hooks::HooksConfig;
22use crate::learning::LearningConfig;
23use crate::logging::LoggingConfig;
24use crate::memory::{
25    CompressionConfig, DocumentConfig, GraphConfig, MagicDocsConfig, MemoryConfig, SemanticConfig,
26    SessionsConfig, SidequestConfig, TierConfig, VectorBackend,
27};
28use crate::metrics::MetricsConfig;
29use crate::notifications::NotificationsConfig;
30use crate::providers::{
31    LlmConfig, get_default_embedding_model, get_default_response_cache_ttl_secs,
32    get_default_router_ema_alpha, get_default_router_reorder_interval,
33};
34use crate::security::TrustConfig;
35use crate::security::{SecurityConfig, TimeoutConfig};
36use crate::telemetry::TelemetryConfig;
37use crate::ui::LspConfig;
38use crate::ui::{AcpConfig, TuiConfig};
39
40/// Top-level agent configuration.
41///
42/// Loaded from a TOML file via [`Config::load`]. Env-var overrides can be applied
43/// via `apply_env_overrides`. Secret resolution via `VaultProvider`
44/// is handled in `zeph-core` through the `SecretResolver` trait.
45#[derive(Debug, Deserialize, Serialize)]
46pub struct Config {
47    pub agent: AgentConfig,
48    pub llm: LlmConfig,
49    pub skills: SkillsConfig,
50    pub memory: MemoryConfig,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub telegram: Option<TelegramConfig>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub discord: Option<DiscordConfig>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub slack: Option<SlackConfig>,
57    #[serde(default)]
58    pub tools: ToolsConfig,
59    #[serde(default)]
60    pub a2a: A2aServerConfig,
61    #[serde(default)]
62    pub mcp: McpConfig,
63    #[serde(default)]
64    pub index: IndexConfig,
65    #[serde(default)]
66    pub vault: VaultConfig,
67    #[serde(default)]
68    pub security: SecurityConfig,
69    #[serde(default)]
70    pub timeouts: TimeoutConfig,
71    #[serde(default)]
72    pub cost: CostConfig,
73    #[serde(default)]
74    pub gateway: GatewayConfig,
75    #[serde(default)]
76    pub daemon: DaemonConfig,
77    #[serde(default)]
78    pub scheduler: SchedulerConfig,
79    #[serde(default)]
80    pub tui: TuiConfig,
81    #[serde(default)]
82    pub acp: AcpConfig,
83    #[serde(default)]
84    pub agents: SubAgentConfig,
85    #[serde(default)]
86    pub orchestration: OrchestrationConfig,
87    #[serde(default)]
88    pub classifiers: ClassifiersConfig,
89    #[serde(default)]
90    pub experiments: ExperimentConfig,
91    #[serde(default)]
92    pub debug: DebugConfig,
93    #[serde(default)]
94    pub logging: LoggingConfig,
95    #[serde(default)]
96    pub hooks: HooksConfig,
97    #[serde(default)]
98    pub lsp: LspConfig,
99    /// `MagicDocs` auto-maintained markdown (#2702).
100    #[serde(default)]
101    pub magic_docs: MagicDocsConfig,
102    /// Profiling and distributed tracing configuration.
103    #[serde(default)]
104    pub telemetry: TelemetryConfig,
105    /// Prometheus metrics export configuration.
106    #[serde(default)]
107    pub metrics: MetricsConfig,
108    /// Session UX settings (recap-on-resume, etc.).
109    #[serde(default)]
110    pub session: crate::session::SessionConfig,
111    /// Session-scoped CLI overrides (bare mode, JSON output, auto-approve).
112    #[serde(default)]
113    pub cli: CliConfig,
114    /// MARCH self-check quality pipeline configuration.
115    #[serde(default)]
116    pub quality: crate::quality::QualityConfig,
117    /// Per-turn completion notification settings (macOS banners, ntfy webhook).
118    #[serde(default)]
119    pub notifications: NotificationsConfig,
120    /// Resolved secrets from vault. Never serialized — populated at runtime.
121    #[serde(skip)]
122    pub secrets: ResolvedSecrets,
123}
124
125/// Secrets resolved from the vault at runtime.
126///
127/// Populated by `SecretResolver::resolve_secrets()` in `zeph-core`.
128/// Never serialized to TOML.
129#[derive(Debug, Default)]
130pub struct ResolvedSecrets {
131    pub claude_api_key: Option<Secret>,
132    pub openai_api_key: Option<Secret>,
133    pub gemini_api_key: Option<Secret>,
134    pub compatible_api_keys: HashMap<String, Secret>,
135    pub discord_token: Option<Secret>,
136    pub slack_bot_token: Option<Secret>,
137    pub slack_signing_secret: Option<Secret>,
138    /// Arbitrary skill secrets resolved from `ZEPH_SECRET_*` vault keys.
139    /// Key is the lowercased name after stripping the prefix (e.g. `github_token`).
140    pub custom: HashMap<String, Secret>,
141}
142
143impl Default for Config {
144    #[allow(clippy::too_many_lines)] // flat struct literal with one field per config section — no meaningful split exists
145    fn default() -> Self {
146        Self {
147            agent: AgentConfig {
148                name: "Zeph".into(),
149                max_tool_iterations: 10,
150                auto_update_check: true,
151                instruction_files: Vec::new(),
152                instruction_auto_detect: true,
153                max_tool_retries: 2,
154                tool_repeat_threshold: 2,
155                max_retry_duration_secs: 30,
156                focus: FocusConfig::default(),
157                tool_filter: crate::agent::ToolFilterConfig::default(),
158                budget_hint_enabled: true,
159                supervisor: crate::agent::TaskSupervisorConfig::default(),
160            },
161            llm: LlmConfig {
162                providers: Vec::new(),
163                routing: crate::providers::LlmRoutingStrategy::None,
164                embedding_model: get_default_embedding_model(),
165                candle: None,
166                stt: None,
167                response_cache_enabled: false,
168                response_cache_ttl_secs: get_default_response_cache_ttl_secs(),
169                semantic_cache_enabled: false,
170                semantic_cache_threshold: 0.95,
171                semantic_cache_max_candidates: 10,
172                router_ema_enabled: false,
173                router_ema_alpha: get_default_router_ema_alpha(),
174                router_reorder_interval: get_default_router_reorder_interval(),
175                router: None,
176                instruction_file: None,
177                summary_model: None,
178                summary_provider: None,
179                complexity_routing: None,
180                coe: None,
181            },
182            skills: SkillsConfig {
183                paths: default_skill_paths(),
184                max_active_skills: NonZeroUsize::new(5).expect("5 is non-zero"),
185                disambiguation_threshold: 0.20,
186                min_injection_score: 0.20,
187                cosine_weight: 0.7,
188                hybrid_search: true,
189                learning: LearningConfig::default(),
190                trust: TrustConfig::default(),
191                prompt_mode: SkillPromptMode::Auto,
192                two_stage_matching: false,
193                confusability_threshold: 0.0,
194                rl_routing_enabled: false,
195                rl_learning_rate: 0.01,
196                rl_weight: 0.3,
197                rl_persist_interval: 10,
198                rl_warmup_updates: 50,
199                rl_embed_dim: None,
200                generation_provider: crate::providers::ProviderName::default(),
201                generation_output_dir: None,
202                mining: crate::features::SkillMiningConfig::default(),
203                evaluation: crate::features::SkillEvaluationConfig::default(),
204                proactive_exploration: crate::features::ProactiveExplorationConfig::default(),
205            },
206            memory: MemoryConfig {
207                sqlite_path: default_sqlite_path_field(),
208                history_limit: 50,
209                qdrant_url: "http://localhost:6334".into(),
210                qdrant_api_key: None,
211                semantic: SemanticConfig::default(),
212                summarization_threshold: 50,
213                context_budget_tokens: 0,
214                soft_compaction_threshold: 0.60,
215                hard_compaction_threshold: 0.90,
216                compaction_preserve_tail: 6,
217                compaction_cooldown_turns: 2,
218                auto_budget: true,
219                prune_protect_tokens: 40_000,
220                cross_session_score_threshold: 0.35,
221                vector_backend: VectorBackend::default(),
222                token_safety_margin: 1.0,
223                redact_credentials: true,
224                autosave_assistant: true,
225                autosave_min_length: 20,
226                tool_call_cutoff: 6,
227                sqlite_pool_size: 5,
228                sessions: SessionsConfig::default(),
229                documents: DocumentConfig::default(),
230                eviction: crate::memory::EvictionConfig::default(),
231                compression: CompressionConfig::default(),
232                sidequest: SidequestConfig::default(),
233                graph: GraphConfig::default(),
234                compression_guidelines: crate::memory::CompressionGuidelinesConfig::default(),
235                shutdown_summary: true,
236                shutdown_summary_min_messages: 4,
237                shutdown_summary_max_messages: 20,
238                shutdown_summary_timeout_secs: 30,
239                structured_summaries: false,
240                tiers: TierConfig::default(),
241                admission: crate::memory::AdmissionConfig::default(),
242                digest: crate::memory::DigestConfig::default(),
243                context_strategy: crate::memory::ContextStrategy::default(),
244                crossover_turn_threshold: 20,
245                consolidation: crate::memory::ConsolidationConfig::default(),
246                forgetting: crate::memory::ForgettingConfig::default(),
247                database_url: None,
248                store_routing: crate::memory::StoreRoutingConfig::default(),
249                persona: crate::memory::PersonaConfig::default(),
250                trajectory: crate::memory::TrajectoryConfig::default(),
251                category: crate::memory::CategoryConfig::default(),
252                tree: crate::memory::TreeConfig::default(),
253                microcompact: crate::memory::MicrocompactConfig::default(),
254                autodream: crate::memory::AutoDreamConfig::default(),
255                key_facts_dedup_threshold: 0.95,
256                compression_spectrum: crate::features::CompressionSpectrumConfig::default(),
257                retrieval: crate::memory::RetrievalConfig::default(),
258                reasoning: crate::memory::ReasoningConfig::default(),
259                hebbian: crate::memory::HebbianConfig::default(),
260            },
261            telegram: None,
262            discord: None,
263            slack: None,
264            tools: ToolsConfig::default(),
265            a2a: A2aServerConfig::default(),
266            mcp: McpConfig::default(),
267            index: IndexConfig::default(),
268            vault: VaultConfig::default(),
269            security: SecurityConfig::default(),
270            timeouts: TimeoutConfig::default(),
271            cost: CostConfig::default(),
272            gateway: GatewayConfig::default(),
273            daemon: DaemonConfig::default(),
274            scheduler: SchedulerConfig::default(),
275            tui: TuiConfig::default(),
276            acp: AcpConfig::default(),
277            agents: SubAgentConfig::default(),
278            orchestration: OrchestrationConfig::default(),
279            classifiers: ClassifiersConfig::default(),
280            experiments: ExperimentConfig::default(),
281            debug: DebugConfig::default(),
282            logging: LoggingConfig::default(),
283            lsp: LspConfig::default(),
284            hooks: HooksConfig::default(),
285            magic_docs: MagicDocsConfig::default(),
286            telemetry: TelemetryConfig::default(),
287            metrics: MetricsConfig::default(),
288            session: crate::session::SessionConfig::default(),
289            cli: CliConfig::default(),
290            quality: crate::quality::QualityConfig::default(),
291            notifications: NotificationsConfig::default(),
292            secrets: ResolvedSecrets::default(),
293        }
294    }
295}