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, GoalConfig, SubAgentConfig};
12use crate::channels::{A2aServerConfig, DiscordConfig, McpConfig, SlackConfig, TelegramConfig};
13use crate::classifiers::ClassifiersConfig;
14use crate::cli::CliConfig;
15use crate::cocoon::CocoonConfig;
16use crate::defaults::{default_skill_paths, default_sqlite_path_field};
17use crate::execution::ExecutionConfig;
18use crate::experiment::{ExperimentConfig, OrchestrationConfig};
19use crate::features::{
20    CostConfig, DaemonConfig, DebugConfig, GatewayConfig, IndexConfig, SchedulerConfig,
21    SkillPromptMode, SkillsConfig, VaultConfig,
22};
23use crate::hooks::HooksConfig;
24use crate::learning::LearningConfig;
25use crate::logging::LoggingConfig;
26use crate::memory::{
27    CompressionConfig, DocumentConfig, GraphConfig, MagicDocsConfig, MemoryConfig, SemanticConfig,
28    SessionsConfig, SidequestConfig, TierConfig, VectorBackend,
29};
30use crate::metrics::MetricsConfig;
31use crate::notifications::NotificationsConfig;
32use crate::providers::{
33    LlmConfig, get_default_embedding_model, get_default_response_cache_ttl_secs,
34    get_default_router_ema_alpha, get_default_router_reorder_interval,
35};
36use crate::security::TrustConfig;
37use crate::security::{SecurityConfig, TimeoutConfig};
38use crate::telemetry::TelemetryConfig;
39use crate::ui::LspConfig;
40use crate::ui::{AcpConfig, TuiConfig};
41
42/// Top-level agent configuration.
43///
44/// Loaded from a TOML file via [`Config::load`]. Env-var overrides can be applied
45/// via `apply_env_overrides`. Secret resolution via `VaultProvider`
46/// is handled in `zeph-core` through the `SecretResolver` trait.
47#[derive(Debug, Deserialize, Serialize)]
48pub struct Config {
49    pub agent: AgentConfig,
50    pub llm: LlmConfig,
51    pub skills: SkillsConfig,
52    pub memory: MemoryConfig,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub telegram: Option<TelegramConfig>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub discord: Option<DiscordConfig>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub slack: Option<SlackConfig>,
59    #[serde(default)]
60    pub tools: ToolsConfig,
61    /// Named execution environments for per-turn CWD and env-var selection.
62    ///
63    /// Opt-in โ€” existing configs without `[execution]` deserialise with all defaults.
64    #[serde(default)]
65    pub execution: ExecutionConfig,
66    #[serde(default)]
67    pub a2a: A2aServerConfig,
68    #[serde(default)]
69    pub mcp: McpConfig,
70    #[serde(default)]
71    pub index: IndexConfig,
72    #[serde(default)]
73    pub vault: VaultConfig,
74    #[serde(default)]
75    pub security: SecurityConfig,
76    #[serde(default)]
77    pub timeouts: TimeoutConfig,
78    #[serde(default)]
79    pub cost: CostConfig,
80    #[serde(default)]
81    pub gateway: GatewayConfig,
82    #[serde(default)]
83    pub daemon: DaemonConfig,
84    #[serde(default)]
85    pub scheduler: SchedulerConfig,
86    #[serde(default)]
87    pub tui: TuiConfig,
88    #[serde(default)]
89    pub acp: AcpConfig,
90    #[serde(default)]
91    pub agents: SubAgentConfig,
92    #[serde(default)]
93    pub orchestration: OrchestrationConfig,
94    #[serde(default)]
95    pub classifiers: ClassifiersConfig,
96    #[serde(default)]
97    pub experiments: ExperimentConfig,
98    #[serde(default)]
99    pub debug: DebugConfig,
100    #[serde(default)]
101    pub logging: LoggingConfig,
102    #[serde(default)]
103    pub hooks: HooksConfig,
104    #[serde(default)]
105    pub lsp: LspConfig,
106    /// `MagicDocs` auto-maintained markdown (#2702).
107    #[serde(default)]
108    pub magic_docs: MagicDocsConfig,
109    /// Profiling and distributed tracing configuration.
110    #[serde(default)]
111    pub telemetry: TelemetryConfig,
112    /// Prometheus metrics export configuration.
113    #[serde(default)]
114    pub metrics: MetricsConfig,
115    /// Session UX settings (recap-on-resume, etc.).
116    #[serde(default)]
117    pub session: crate::session::SessionConfig,
118    /// `zeph serve` persistent agent service settings (spec-068 ยง9).
119    #[serde(default)]
120    pub serve: crate::serve::ServeConfig,
121    /// Session-scoped CLI overrides (bare mode, JSON output, auto-approve).
122    #[serde(default)]
123    pub cli: CliConfig,
124    /// MARCH self-check quality pipeline configuration.
125    #[serde(default)]
126    pub quality: crate::quality::QualityConfig,
127    /// Per-turn completion notification settings (macOS banners, ntfy webhook).
128    #[serde(default)]
129    pub notifications: NotificationsConfig,
130    /// Long-horizon goal lifecycle configuration.
131    #[serde(default)]
132    pub goals: GoalConfig,
133    /// Cocoon display and behaviour settings (independent of `[[llm.providers]]` Cocoon entry).
134    #[serde(default)]
135    pub cocoon: CocoonConfig,
136    /// Resolved secrets from vault. Never serialized โ€” populated at runtime.
137    #[serde(skip)]
138    pub secrets: ResolvedSecrets,
139    /// Git worktree isolation configuration.
140    #[serde(default)]
141    pub worktree: crate::worktree::WorktreeConfig,
142    /// Durable execution layer configuration (`[durable]`).
143    #[serde(default)]
144    pub durable: crate::durable::DurableConfig,
145    /// Ultra-compressed telegraphic output mode configuration (`[caveman]`).
146    ///
147    /// Toggle at runtime with `/caveman [on|off]` or via the bundled `caveman` skill.
148    #[serde(default)]
149    pub caveman: crate::features::CavemanConfig,
150    /// Knowledge-ingest subsystem configuration (`[knowledge]`).
151    ///
152    /// Controls `zeph knowledge ingest` behaviour: provider selection, concurrency cap,
153    /// document limit, and recall inclusion of imported rows (spec-067).
154    #[serde(default)]
155    pub knowledge: crate::knowledge::KnowledgeConfig,
156    /// Deep-link scheme configuration (`[deep_link]`). Gated by the `deep-link` feature.
157    #[cfg(feature = "deep-link")]
158    #[serde(default)]
159    pub deep_link: crate::deep_link::DeepLinkConfig,
160}
161
162/// Secrets resolved from the vault at runtime.
163///
164/// Populated by `SecretResolver::resolve_secrets()` in `zeph-core`.
165/// Never serialized to TOML.
166#[derive(Debug, Default)]
167pub struct ResolvedSecrets {
168    pub claude_api_key: Option<Secret>,
169    pub openai_api_key: Option<Secret>,
170    pub gemini_api_key: Option<Secret>,
171    pub compatible_api_keys: HashMap<String, Secret>,
172    pub discord_token: Option<Secret>,
173    pub slack_bot_token: Option<Secret>,
174    pub slack_signing_secret: Option<Secret>,
175    /// Gonka wallet private key for signing blockchain transactions.
176    pub gonka_private_key: Option<Secret>,
177    /// Gonka wallet address for node identity verification.
178    pub gonka_address: Option<Secret>,
179    /// Cocoon sidecar access hash resolved from the vault key `ZEPH_COCOON_ACCESS_HASH`.
180    pub cocoon_access_hash: Option<Secret>,
181    /// Arbitrary skill secrets resolved from `ZEPH_SECRET_*` vault keys.
182    /// Key is the lowercased name after stripping the prefix (e.g. `github_token`).
183    pub custom: HashMap<String, Secret>,
184}
185
186impl Default for Config {
187    #[allow(clippy::too_many_lines)] // flat struct literal with one field per config section โ€” no meaningful split exists
188    fn default() -> Self {
189        Self {
190            agent: AgentConfig {
191                name: "Zeph".into(),
192                max_tool_iterations: 10,
193                auto_update_check: true,
194                instruction_files: Vec::new(),
195                instruction_auto_detect: true,
196                max_tool_retries: 2,
197                tool_repeat_threshold: 2,
198                max_retry_duration_secs: 30,
199                focus: FocusConfig::default(),
200                tool_filter: crate::agent::ToolFilterConfig::default(),
201                budget_hint_enabled: true,
202                supervisor: crate::agent::TaskSupervisorConfig::default(),
203            },
204            llm: LlmConfig {
205                providers: Vec::new(),
206                routing: crate::providers::LlmRoutingStrategy::None,
207                embedding_model: get_default_embedding_model(),
208                candle: None,
209                stt: None,
210                response_cache_enabled: false,
211                response_cache_ttl_secs: get_default_response_cache_ttl_secs(),
212                semantic_cache_enabled: false,
213                semantic_cache_threshold: 0.95,
214                semantic_cache_max_candidates: 10,
215                router_ema_enabled: false,
216                router_ema_alpha: get_default_router_ema_alpha(),
217                router_reorder_interval: get_default_router_reorder_interval(),
218                router: None,
219                instruction_file: None,
220                summary_model: None,
221                summary_provider: None,
222                complexity_routing: None,
223                coe: None,
224                stream_limits: crate::StreamLimits::default(),
225            },
226            skills: SkillsConfig {
227                paths: default_skill_paths(),
228                max_active_skills: NonZeroUsize::new(5).expect("5 is non-zero"),
229                disambiguation_threshold: 0.20,
230                min_injection_score: 0.20,
231                cosine_weight: 0.7,
232                hybrid_search: true,
233                bm25_alpha: 0.7,
234                learning: LearningConfig::default(),
235                trust: TrustConfig::default(),
236                prompt_mode: SkillPromptMode::Auto,
237                two_stage_matching: false,
238                confusability_threshold: 0.0,
239                rl_routing_enabled: false,
240                rl_learning_rate: 0.01,
241                rl_weight: 0.3,
242                rl_persist_interval: 10,
243                rl_warmup_updates: 50,
244                rl_embed_dim: None,
245                query_rewrite_provider: crate::providers::ProviderName::default(),
246                generation_provider: crate::providers::ProviderName::default(),
247                generation_timeout_ms: 60_000,
248                generation_output_dir: None,
249                mining: crate::features::SkillMiningConfig::default(),
250                evaluation: crate::features::SkillEvaluationConfig::default(),
251                proactive_exploration: crate::features::ProactiveExplorationConfig::default(),
252                disambiguate_provider: crate::providers::ProviderName::default(),
253                semantic_scan: false,
254                semantic_scan_provider: crate::providers::ProviderName::default(),
255                group_structured: false,
256                support_similarity_threshold: 0.50,
257            },
258            memory: MemoryConfig {
259                sqlite_path: default_sqlite_path_field(),
260                history_limit: 50,
261                qdrant_url: "http://localhost:6334".into(),
262                qdrant_api_key: None,
263                qdrant_timeout_secs: 10,
264                semantic: SemanticConfig::default(),
265                summarization_threshold: 50,
266                summarization_llm_timeout_secs: 60,
267                context_budget_tokens: 0,
268                soft_compaction_threshold: 0.60,
269                hard_compaction_threshold: 0.90,
270                compaction_preserve_tail: 6,
271                compaction_cooldown_turns: 2,
272                auto_budget: true,
273                prune_protect_tokens: 40_000,
274                cross_session_score_threshold: 0.35,
275                vector_backend: VectorBackend::default(),
276                token_safety_margin: 1.0,
277                redact_credentials: true,
278                autosave_assistant: true,
279                autosave_min_length: 20,
280                tool_call_cutoff: 6,
281                sqlite_pool_size: 5,
282                sessions: SessionsConfig::default(),
283                documents: DocumentConfig::default(),
284                eviction: crate::memory::EvictionConfig::default(),
285                compression: CompressionConfig::default(),
286                sidequest: SidequestConfig::default(),
287                graph: GraphConfig::default(),
288                compression_guidelines: crate::memory::CompressionGuidelinesConfig::default(),
289                shutdown_summary: true,
290                shutdown_summary_min_messages: 4,
291                shutdown_summary_max_messages: 20,
292                shutdown_summary_timeout_secs: 30,
293                shutdown_summary_provider: crate::providers::ProviderName::default(),
294                compaction_provider: crate::providers::ProviderName::default(),
295                structured_summaries: false,
296                tiers: TierConfig::default(),
297                admission: crate::memory::AdmissionConfig::default(),
298                digest: crate::memory::DigestConfig::default(),
299                context_strategy: crate::memory::ContextStrategy::default(),
300                crossover_turn_threshold: 20,
301                consolidation: crate::memory::ConsolidationConfig::default(),
302                forgetting: crate::memory::ForgettingConfig::default(),
303                database_url: None,
304                store_routing: crate::memory::StoreRoutingConfig::default(),
305                persona: crate::memory::PersonaConfig::default(),
306                trajectory: crate::memory::TrajectoryConfig::default(),
307                category: crate::memory::CategoryConfig::default(),
308                tree: crate::memory::TreeConfig::default(),
309                microcompact: crate::memory::MicrocompactConfig::default(),
310                autodream: crate::memory::AutoDreamConfig::default(),
311                key_facts_dedup_threshold: 0.95,
312                compression_spectrum: crate::features::CompressionSpectrumConfig::default(),
313                retrieval: crate::memory::RetrievalConfig::default(),
314                reasoning: crate::memory::ReasoningConfig::default(),
315                hebbian: crate::memory::HebbianConfig::default(),
316                memcot: crate::memory::MemCotConfig::default(),
317                retrieval_failures: crate::memory::RetrievalFailuresConfig::default(),
318                quality_gate: crate::memory::WriteQualityGateConfig::default(),
319                tiered_retrieval: crate::memory::TieredRetrievalConfig::default(),
320                optical_forgetting: crate::memory::OpticalForgettingConfig::default(),
321                em_graph: crate::memory::EmGraphConfig::default(),
322                episodic_consolidation: crate::memory::EpisodicConsolidationConfig::default(),
323                shadow_memory: crate::memory::TrajectoryRiskAccumulatorConfig::default(),
324                five_signal: crate::memory::FiveSignalConfig::default(),
325                fidelity: None,
326            },
327            telegram: None,
328            discord: None,
329            slack: None,
330            tools: ToolsConfig::default(),
331            execution: ExecutionConfig::default(),
332            a2a: A2aServerConfig::default(),
333            mcp: McpConfig::default(),
334            index: IndexConfig::default(),
335            vault: VaultConfig::default(),
336            security: SecurityConfig::default(),
337            timeouts: TimeoutConfig::default(),
338            cost: CostConfig::default(),
339            gateway: GatewayConfig::default(),
340            daemon: DaemonConfig::default(),
341            scheduler: SchedulerConfig::default(),
342            tui: TuiConfig::default(),
343            acp: AcpConfig::default(),
344            agents: SubAgentConfig::default(),
345            orchestration: OrchestrationConfig::default(),
346            classifiers: ClassifiersConfig::default(),
347            experiments: ExperimentConfig::default(),
348            debug: DebugConfig::default(),
349            logging: LoggingConfig::default(),
350            lsp: LspConfig::default(),
351            hooks: HooksConfig::default(),
352            magic_docs: MagicDocsConfig::default(),
353            telemetry: TelemetryConfig::default(),
354            metrics: MetricsConfig::default(),
355            session: crate::session::SessionConfig::default(),
356            serve: crate::serve::ServeConfig::default(),
357            cli: CliConfig::default(),
358            quality: crate::quality::QualityConfig::default(),
359            notifications: NotificationsConfig::default(),
360            goals: GoalConfig::default(),
361            cocoon: CocoonConfig::default(),
362            secrets: ResolvedSecrets::default(),
363            worktree: crate::worktree::WorktreeConfig::default(),
364            durable: crate::durable::DurableConfig::default(),
365            caveman: crate::features::CavemanConfig::default(),
366            knowledge: crate::knowledge::KnowledgeConfig::default(),
367            #[cfg(feature = "deep-link")]
368            deep_link: crate::deep_link::DeepLinkConfig::default(),
369        }
370    }
371}