use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use super::documents::{DocumentsConfig, LlmConfig};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1 {
#[serde(rename = "$schema")]
pub schema: String,
#[serde(default)]
pub scan: ScanConfig,
#[serde(default)]
pub watch: WatchConfig,
#[serde(default)]
pub cache: CacheConfig,
#[serde(default)]
pub mcp: McpConfig,
#[serde(default)]
pub languages: std::collections::BTreeMap<String, LanguageConfig>,
#[serde(default)]
pub documents: DocumentsConfig,
#[serde(default)]
pub memory: MemoryConfig,
#[serde(default)]
pub crawl: CrawlConfig,
#[serde(default)]
pub llm: LlmConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ScanConfig {
#[serde(default = "ScanConfig::default_include")]
#[schemars(inner(length(min = 1)))]
pub include: Vec<String>,
#[serde(default = "ScanConfig::default_exclude")]
#[schemars(inner(length(min = 1)))]
pub exclude: Vec<String>,
#[serde(default = "ScanConfig::default_respect_gitignore")]
pub respect_gitignore: bool,
#[serde(default = "ScanConfig::default_max_file_bytes")]
#[schemars(range(min = 1024))]
pub max_file_bytes: u64,
#[serde(default = "ScanConfig::default_skip_submodules")]
pub skip_submodules: bool,
#[serde(default = "ScanConfig::default_eager_l2")]
pub eager_l2: bool,
}
impl ScanConfig {
fn default_include() -> Vec<String> {
vec!["**/*".to_string()]
}
fn default_exclude() -> Vec<String> {
[
"**/target/**",
"**/node_modules/**",
"**/dist/**",
"**/.venv/**",
"**/.basemind/**",
"**/.git/**",
]
.iter()
.map(|s| (*s).to_string())
.collect()
}
fn default_respect_gitignore() -> bool {
true
}
fn default_max_file_bytes() -> u64 {
2_097_152
}
fn default_skip_submodules() -> bool {
true
}
fn default_eager_l2() -> bool {
true
}
}
impl Default for ScanConfig {
fn default() -> Self {
Self {
include: Self::default_include(),
exclude: Self::default_exclude(),
respect_gitignore: Self::default_respect_gitignore(),
max_file_bytes: Self::default_max_file_bytes(),
skip_submodules: Self::default_skip_submodules(),
eager_l2: Self::default_eager_l2(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WatchConfig {
#[serde(default = "WatchConfig::default_debounce_ms")]
#[schemars(range(min = 0, max = 60000))]
pub debounce_ms: u64,
#[serde(default)]
pub live_l2: bool,
}
impl WatchConfig {
fn default_debounce_ms() -> u64 {
250
}
}
impl Default for WatchConfig {
fn default() -> Self {
Self {
debounce_ms: Self::default_debounce_ms(),
live_l2: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CacheConfig {
#[serde(default = "CacheConfig::default_file_map_lru")]
#[schemars(range(min = 0))]
pub file_map_lru: usize,
}
impl CacheConfig {
fn default_file_map_lru() -> usize {
256
}
}
impl Default for CacheConfig {
fn default() -> Self {
Self {
file_map_lru: Self::default_file_map_lru(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct McpConfig {
#[serde(default = "McpConfig::default_transport")]
pub transport: McpTransport,
}
impl McpConfig {
fn default_transport() -> McpTransport {
McpTransport::Stdio
}
}
impl Default for McpConfig {
fn default() -> Self {
Self {
transport: Self::default_transport(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum McpTransport {
Stdio,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct LanguageConfig {
#[serde(default = "LanguageConfig::default_enabled")]
pub enabled: bool,
}
impl LanguageConfig {
fn default_enabled() -> bool {
true
}
}
impl Default for LanguageConfig {
fn default() -> Self {
Self {
enabled: Self::default_enabled(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct MemoryConfig {
#[serde(default = "MemoryConfig::default_enabled")]
pub enabled: bool,
#[serde(default)]
pub scope_strategy: MemoryScopeStrategy,
}
impl MemoryConfig {
fn default_enabled() -> bool {
true
}
}
impl Default for MemoryConfig {
fn default() -> Self {
Self {
enabled: Self::default_enabled(),
scope_strategy: MemoryScopeStrategy::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case")]
pub enum MemoryScopeStrategy {
#[default]
GitRemoteWithFallback,
WorkdirOnly,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CrawlConfig {
#[serde(default = "CrawlConfig::default_respect_robots_txt")]
pub respect_robots_txt: bool,
#[serde(default = "CrawlConfig::default_max_pages")]
#[schemars(range(min = 1))]
pub max_pages: u32,
#[serde(default = "CrawlConfig::default_max_depth")]
#[schemars(range(min = 0))]
pub max_depth: u32,
#[serde(default = "CrawlConfig::default_max_body_size")]
#[schemars(range(min = 1024))]
pub max_body_size: u64,
#[serde(default = "CrawlConfig::default_user_agent")]
#[schemars(length(min = 1))]
pub user_agent: String,
}
impl CrawlConfig {
fn default_respect_robots_txt() -> bool {
true
}
fn default_max_pages() -> u32 {
32
}
fn default_max_depth() -> u32 {
2
}
fn default_max_body_size() -> u64 {
4 * 1024 * 1024
}
fn default_user_agent() -> String {
format!(
"basemind/{} (+https://github.com/Goldziher/basemind)",
env!("CARGO_PKG_VERSION")
)
}
}
impl Default for CrawlConfig {
fn default() -> Self {
Self {
respect_robots_txt: Self::default_respect_robots_txt(),
max_pages: Self::default_max_pages(),
max_depth: Self::default_max_depth(),
max_body_size: Self::default_max_body_size(),
user_agent: Self::default_user_agent(),
}
}
}
impl ConfigV1 {
pub fn with_defaults() -> Self {
Self {
schema: "v1".to_string(),
scan: ScanConfig::default(),
watch: WatchConfig::default(),
cache: CacheConfig::default(),
mcp: McpConfig::default(),
languages: Default::default(),
documents: DocumentsConfig::default(),
memory: MemoryConfig::default(),
crawl: CrawlConfig::default(),
llm: LlmConfig::default(),
}
}
}