Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
config.go36.4 kB
// Package config handles Neo4j-compatible configuration via environment variables. // // NornicDB uses environment variables for configuration to maintain compatibility with // Neo4j tooling and deployment workflows. All Neo4j environment variables are supported, // plus NornicDB-specific extensions prefixed with NORNICDB_. // // Configuration is loaded from environment variables using LoadFromEnv() and can be // validated with Validate() before use. // // Example Usage: // // config := config.LoadFromEnv() // if err := config.Validate(); err != nil { // log.Fatalf("Invalid config: %v", err) // } // // fmt.Printf("Bolt server: %s:%d\n", // config.Server.BoltAddress, config.Server.BoltPort) // // Environment Variables: // // Neo4j-Compatible: // - NEO4J_AUTH="username/password" or "none" // - NEO4J_dbms_connector_bolt_listen__address_port=7687 // - NEO4J_dbms_connector_http_listen__address_port=7474 // - NEO4J_dbms_directories_data="./data" // // NornicDB-Specific: // - NORNICDB_MEMORY_DECAY_ENABLED=true // - NORNICDB_MEMORY_DECAY_INTERVAL=1h // - NORNICDB_EMBEDDING_PROVIDER="ollama" or "openai" // - NORNICDB_EMBEDDING_MODEL=bge-m3 // - NORNICDB_AUDIT_ENABLED=true // // For a complete list, see the Config struct field documentation. package config import ( "fmt" "os" "runtime/debug" "strconv" "strings" "time" ) // Config holds all NornicDB configuration loaded from environment variables. // // Configuration is organized into logical sections: // - Auth: Authentication and authorization // - Database: Storage and transaction settings // - Server: Bolt and HTTP server settings // - Memory: NornicDB-specific memory decay and embeddings // - Compliance: GDPR/HIPAA/FISMA/SOC2 compliance controls // - Logging: Logging configuration // - Features: Experimental and optional features (feature flags) // // Use LoadFromEnv() to create a Config from environment variables. // // Example: // // config := config.LoadFromEnv() // if err := config.Validate(); err != nil { // log.Fatal(err) // } // // fmt.Printf("Config: %s\n", config) type Config struct { // Authentication (NEO4J_AUTH format: "username/password" or "none") Auth AuthConfig // Database settings Database DatabaseConfig // Server settings Server ServerConfig // Memory/Decay settings (NornicDB-specific) Memory MemoryConfig // Embedding worker settings (NornicDB-specific) EmbeddingWorker EmbeddingWorkerConfig // Compliance settings for GDPR/HIPAA/FISMA/SOC2 (NornicDB-specific) Compliance ComplianceConfig // Logging Logging LoggingConfig // Feature flags for experimental/optional features Features FeatureFlagsConfig } // AuthConfig holds authentication settings. type AuthConfig struct { // Enabled controls whether authentication is required Enabled bool // InitialUsername is the default admin username InitialUsername string // InitialPassword is the default admin password InitialPassword string // MinPasswordLength for password policy MinPasswordLength int // TokenExpiry for JWT tokens TokenExpiry time.Duration // JWTSecret for signing tokens JWTSecret string } // DatabaseConfig holds database settings. type DatabaseConfig struct { // DataDir is the directory for data storage DataDir string // DefaultDatabase name DefaultDatabase string // ReadOnly mode ReadOnly bool // TransactionTimeout for long-running queries TransactionTimeout time.Duration // MaxConcurrentTransactions limit MaxConcurrentTransactions int // === Durability Settings === // These control the trade-off between performance and data safety. // Default settings provide good balance; opt-in to stricter settings // for financial or critical data. // WALSyncMode controls when WAL writes are synced to disk. // - "batch" (default): fsync every WALSyncInterval - good balance // - "immediate": fsync after each write - safest but 2-5x slower // - "none": no fsync - fastest but data loss on crash // Environment: NORNICDB_WAL_SYNC_MODE WALSyncMode string // WALSyncInterval for batch sync mode (default: 100ms). // Smaller = safer but slower, larger = faster but more data at risk. // Environment: NORNICDB_WAL_SYNC_INTERVAL WALSyncInterval time.Duration // StrictDurability enables maximum safety settings (opt-in): // - WAL: immediate sync (fsync every write) // - Badger: SyncWrites=true // - AsyncEngine: smaller flush interval (10ms) // WARNING: 2-5x slower writes. Use for financial/critical data only. // Environment: NORNICDB_STRICT_DURABILITY StrictDurability bool } // ServerConfig holds server settings. type ServerConfig struct { // BoltEnabled controls Bolt protocol server BoltEnabled bool // BoltPort for Bolt connections (default 7687) BoltPort int // BoltAddress to bind to BoltAddress string // BoltTLSEnabled for encrypted connections BoltTLSEnabled bool // BoltTLSCert path to certificate BoltTLSCert string // BoltTLSKey path to private key BoltTLSKey string // HTTPEnabled controls HTTP API server HTTPEnabled bool // HTTPPort for HTTP connections (default 7474) HTTPPort int // HTTPAddress to bind to HTTPAddress string // HTTPSEnabled for encrypted connections HTTPSEnabled bool // HTTPSPort for HTTPS connections (default 7473) HTTPSPort int // HTTPTLSCert path to certificate HTTPTLSCert string // HTTPTLSKey path to private key HTTPTLSKey string } // EmbeddingWorkerConfig holds settings for the background embedding worker. // Environment variables: // - NORNICDB_EMBED_SCAN_INTERVAL: How often to scan for unembedded nodes (default: 15m) // - NORNICDB_EMBED_BATCH_DELAY: Delay between processing nodes (default: 500ms) // - NORNICDB_EMBED_MAX_RETRIES: Max retry attempts per node (default: 3) // - NORNICDB_EMBED_CHUNK_SIZE: Max characters per chunk (default: 512) // - NORNICDB_EMBED_CHUNK_OVERLAP: Characters to overlap between chunks (default: 50) type EmbeddingWorkerConfig struct { // ScanInterval is how often to scan for nodes without embeddings ScanInterval time.Duration // BatchDelay is the delay between processing individual nodes BatchDelay time.Duration // MaxRetries is the max retry attempts per node MaxRetries int // ChunkSize is max characters per chunk (matches MIMIR_EMBEDDINGS_CHUNK_SIZE) ChunkSize int // ChunkOverlap is characters to overlap between chunks (matches MIMIR_EMBEDDINGS_CHUNK_OVERLAP) ChunkOverlap int } // MemoryConfig holds NornicDB memory decay settings and runtime memory management. type MemoryConfig struct { // DecayEnabled controls memory decay DecayEnabled bool // DecayInterval for recalculation DecayInterval time.Duration // ArchiveThreshold below which memories are archived ArchiveThreshold float64 // EmbeddingProvider (ollama, openai) EmbeddingProvider string // EmbeddingModel name EmbeddingModel string // EmbeddingAPIURL endpoint EmbeddingAPIURL string // EmbeddingDimensions size EmbeddingDimensions int // EmbeddingCacheSize is max embeddings to cache (0 = disabled, default: 10000) // Each cached embedding uses ~4KB (1024 dims × 4 bytes) // 10000 cache = ~40MB memory, provides significant speedup for repeated queries EmbeddingCacheSize int // AutoLinksEnabled for automatic relationship detection AutoLinksEnabled bool // AutoLinksSimilarityThreshold for similarity-based links AutoLinksSimilarityThreshold float64 // === Runtime Memory Management (Go runtime tuning) === // RuntimeLimit is the soft memory limit (GOMEMLIMIT) in bytes // 0 = unlimited (Go manages automatically) // Set to 80% of container memory for optimal performance RuntimeLimit int64 // RuntimeLimitStr is the human-readable form (e.g., "2GB", "512MB") RuntimeLimitStr string // GCPercent controls GC aggressiveness (GOGC) // 100 = default, lower = more aggressive (less memory, more CPU) GCPercent int // PoolEnabled controls object pooling for query results PoolEnabled bool // PoolMaxSize limits pool memory usage per pool PoolMaxSize int // QueryCacheEnabled controls query plan caching QueryCacheEnabled bool // QueryCacheSize is the maximum number of cached query plans QueryCacheSize int // QueryCacheTTL is how long cached plans remain valid QueryCacheTTL time.Duration } // ComplianceConfig holds settings for GDPR/HIPAA/FISMA/SOC2 compliance. // These are framework-agnostic controls that satisfy multiple regulations. type ComplianceConfig struct { // AuditLogging - Required by: GDPR Art.30, HIPAA §164.312(b), FISMA, SOC2 AuditEnabled bool AuditLogPath string AuditRetentionDays int // How long to keep audit logs (HIPAA: 6 years, SOC2: 7 years) // Data Retention - Required by: GDPR Art.5(1)(e), HIPAA §164.530(j) RetentionEnabled bool RetentionPolicyDays int // Default retention period (0 = indefinite) RetentionAutoDelete bool // Auto-delete vs archive after retention RetentionExemptRoles []string // Roles exempt from retention (e.g., "admin") // Access Control - Required by: GDPR Art.32, HIPAA §164.312(a), FISMA AccessControlEnabled bool SessionTimeout time.Duration MaxFailedLogins int LockoutDuration time.Duration // Encryption - Required by: GDPR Art.32, HIPAA §164.312(a)(2)(iv) EncryptionAtRest bool EncryptionInTransit bool EncryptionKeyPath string // Data Subject Rights - Required by: GDPR Art.15-20 DataExportEnabled bool // Right to data portability DataErasureEnabled bool // Right to erasure/be forgotten DataAccessEnabled bool // Right of access // Anonymization - Required by: GDPR Recital 26 AnonymizationEnabled bool AnonymizationMethod string // "pseudonymization", "generalization", "suppression" // Consent - Required by: GDPR Art.7 ConsentRequired bool ConsentVersioning bool ConsentAuditTrail bool // Breach Notification - Required by: GDPR Art.33-34, HIPAA §164.408 BreachDetectionEnabled bool BreachNotifyEmail string BreachNotifyWebhook string } // LoggingConfig holds logging settings. type LoggingConfig struct { // Level (DEBUG, INFO, WARN, ERROR) Level string // Format (json, text) Format string // Output path (stdout, stderr, or file path) Output string // QueryLogEnabled for query logging QueryLogEnabled bool // SlowQueryThreshold for logging slow queries SlowQueryThreshold time.Duration } // FeatureFlagsConfig holds all feature flags for experimental/optional features. // Centralized location for all feature toggles in NornicDB. type FeatureFlagsConfig struct { // Kalman filtering for predictive smoothing KalmanEnabled bool // Topological link prediction AUTOMATIC integration // NOTE: Neo4j GDS procedures (CALL gds.linkPrediction.*) are ALWAYS available // This flag only controls automatic integration with inference.Engine.OnStore() TopologyAutoIntegrationEnabled bool // Enable automatic topology in OnStore() TopologyAlgorithm string // adamic_adar, jaccard, etc. TopologyWeight float64 // 0.0-1.0, weight vs semantic TopologyTopK int TopologyMinScore float64 TopologyGraphRefreshInterval int // A/B testing for automatic topology integration TopologyABTestEnabled bool TopologyABTestPercentage int // 0-100 // Heimdall - the cognitive guardian of NornicDB // When enabled, NornicDB loads a local SLM for anomaly detection, // runtime diagnosis, and memory curation. // Environment: NORNICDB_HEIMDALL_ENABLED (default: false) HeimdallEnabled bool // Heimdall model name (without .gguf extension) // Environment: NORNICDB_HEIMDALL_MODEL (default: qwen2.5-1.5b-instruct-q4_k_m) HeimdallModel string // GPU layers for Heimdall SLM (-1=auto, 0=CPU only) // Falls back to CPU if GPU memory insufficient // Environment: NORNICDB_HEIMDALL_GPU_LAYERS (default: -1) HeimdallGPULayers int // Context size for Heimdall model (max tokens in context window) // Default: 32768 (32K - maxed out, no performance impact) // Environment: NORNICDB_HEIMDALL_CONTEXT_SIZE (default: 32768) HeimdallContextSize int // Batch size for Heimdall model (tokens processed at once) // Default: 8192 (8K - maxed out, no performance impact) // Environment: NORNICDB_HEIMDALL_BATCH_SIZE (default: 8192) HeimdallBatchSize int // Max tokens for Heimdall generation // Environment: NORNICDB_HEIMDALL_MAX_TOKENS (default: 512) HeimdallMaxTokens int // Temperature for Heimdall (lower = more deterministic) // Environment: NORNICDB_HEIMDALL_TEMPERATURE (default: 0.1) HeimdallTemperature float32 // Enable Heimdall anomaly detection on graph // Environment: NORNICDB_HEIMDALL_ANOMALY_DETECTION (default: true when Heimdall enabled) HeimdallAnomalyDetection bool // Enable Heimdall runtime diagnosis // Environment: NORNICDB_HEIMDALL_RUNTIME_DIAGNOSIS (default: true when Heimdall enabled) HeimdallRuntimeDiagnosis bool // Enable Heimdall memory curation (experimental) // Environment: NORNICDB_HEIMDALL_MEMORY_CURATION (default: false) HeimdallMemoryCuration bool } // Heimdall config getter methods for heimdall.FeatureFlagsSource interface func (f *FeatureFlagsConfig) GetHeimdallEnabled() bool { return f.HeimdallEnabled } func (f *FeatureFlagsConfig) GetHeimdallModel() string { return f.HeimdallModel } func (f *FeatureFlagsConfig) GetHeimdallGPULayers() int { return f.HeimdallGPULayers } func (f *FeatureFlagsConfig) GetHeimdallContextSize() int { return f.HeimdallContextSize } func (f *FeatureFlagsConfig) GetHeimdallBatchSize() int { return f.HeimdallBatchSize } func (f *FeatureFlagsConfig) GetHeimdallMaxTokens() int { return f.HeimdallMaxTokens } func (f *FeatureFlagsConfig) GetHeimdallTemperature() float32 { return f.HeimdallTemperature } func (f *FeatureFlagsConfig) GetHeimdallAnomalyDetection() bool { return f.HeimdallAnomalyDetection } func (f *FeatureFlagsConfig) GetHeimdallRuntimeDiagnosis() bool { return f.HeimdallRuntimeDiagnosis } func (f *FeatureFlagsConfig) GetHeimdallMemoryCuration() bool { return f.HeimdallMemoryCuration } // LoadFromEnv loads configuration from environment variables. // // This function reads all configuration from the environment, using Neo4j-compatible // variable names where applicable (e.g., NEO4J_AUTH, NEO4J_dbms_*) and NornicDB-specific // variables prefixed with NORNICDB_. // // All values have sensible defaults, so LoadFromEnv() can be called without any // environment variables set. // // Example: // // // Minimal setup - uses all defaults // config := config.LoadFromEnv() // // // With custom environment // os.Setenv("NEO4J_AUTH", "myuser/mypass") // os.Setenv("NEO4J_dbms_connector_bolt_listen__address_port", "7688") // os.Setenv("NORNICDB_EMBEDDING_PROVIDER", "openai") // os.Setenv("NORNICDB_EMBEDDING_API_KEY", "sk-...") // config = config.LoadFromEnv() // // if err := config.Validate(); err != nil { // log.Fatal(err) // } // // Returns a fully populated Config with defaults applied where environment // variables are not set. // // Example 1 - Basic Development Setup: // // // No environment variables set - use defaults // config := config.LoadFromEnv() // // // Auth disabled by default (NEO4J_AUTH=none) // fmt.Printf("Auth enabled: %v\n", config.Auth.Enabled) // false // // // Bolt server on default port // fmt.Printf("Bolt: %s:%d\n", // config.Server.BoltAddress, config.Server.BoltPort) // 0.0.0.0:7687 // // // Memory decay enabled by default // fmt.Printf("Decay enabled: %v\n", config.Memory.DecayEnabled) // true // // Example 2 - Production with Authentication: // // // Set environment variables // os.Setenv("NEO4J_AUTH", "admin/SecurePassword123!") // os.Setenv("NEO4J_dbms_connector_bolt_listen__address_port", "7687") // os.Setenv("NORNICDB_AUTH_JWT_SECRET", "your-32-char-secret-key-here!!") // os.Setenv("NORNICDB_AUDIT_ENABLED", "true") // // config := config.LoadFromEnv() // // // Validate before use // if err := config.Validate(); err != nil { // log.Fatal("Invalid config:", err) // } // // // Auth now enabled // fmt.Printf("Admin: %s\n", config.Auth.InitialUsername) // admin // fmt.Printf("Audit: %s\n", config.Compliance.AuditLogPath) // // Example 3 - Docker Compose Setup: // // # docker-compose.yml // services: // nornicdb: // image: nornicdb:latest // environment: // - NEO4J_AUTH=neo4j/password // - NEO4J_dbms_directories_data=/data // - NORNICDB_MEMORY_DECAY_ENABLED=true // - NORNICDB_EMBEDDING_PROVIDER=ollama // - NORNICDB_EMBEDDING_API_URL=http://ollama:11434 // - NORNICDB_AUDIT_ENABLED=true // - NORNICDB_AUDIT_LOG_PATH=/logs/audit.log // volumes: // - nornicdb-data:/data // - nornicdb-logs:/logs // ports: // - "7687:7687" // - "7474:7474" // // // In application code // config := config.LoadFromEnv() // // All environment variables automatically loaded // // Example 4 - HIPAA Compliance Configuration: // // // Set HIPAA-required environment variables // os.Setenv("NEO4J_AUTH", "admin/ComplexPassword123!") // os.Setenv("NORNICDB_AUTH_TOKEN_EXPIRY", "4h") // os.Setenv("NORNICDB_AUDIT_ENABLED", "true") // os.Setenv("NORNICDB_AUDIT_RETENTION_DAYS", "2555") // 7 years // os.Setenv("NORNICDB_ENCRYPTION_AT_REST", "true") // os.Setenv("NORNICDB_ENCRYPTION_IN_TRANSIT", "true") // os.Setenv("NORNICDB_MAX_FAILED_LOGINS", "3") // os.Setenv("NORNICDB_LOCKOUT_DURATION", "30m") // os.Setenv("NORNICDB_SESSION_TIMEOUT", "15m") // // config := config.LoadFromEnv() // // // Verify HIPAA requirements met // if !config.Compliance.AuditEnabled { // log.Fatal("HIPAA requires audit logging") // } // if config.Compliance.AuditRetentionDays < 2555 { // log.Fatal("HIPAA requires 7-year audit retention") // } // // Example 5 - Multi-Environment Setup: // // // Load from .env file first // err := godotenv.Load(".env." + os.Getenv("ENV")) // if err != nil { // log.Printf("No .env file: %v", err) // } // // // Then load from environment // config := config.LoadFromEnv() // // // Override for specific environment // switch os.Getenv("ENV") { // case "production": // if !config.Auth.Enabled { // log.Fatal("Production requires authentication!") // } // case "development": // config.Logging.Level = "DEBUG" // case "test": // config.Database.DataDir = os.TempDir() // } // // ELI12: // // Think of LoadFromEnv like reading a recipe from sticky notes on your fridge: // // - Each sticky note is an environment variable (e.g., "PORT=7687") // - If there's no sticky note, use the default ("PORT not found? Use 7687") // - The function reads ALL the sticky notes and builds a complete recipe // // Why use environment variables? // 1. Security: Keep secrets out of code (passwords, API keys) // 2. Flexibility: Change settings without recompiling // 3. Docker-friendly: Easy to configure containers // 4. 12-Factor App: Industry best practice // // Neo4j Compatibility: // - NEO4J_AUTH format: "username/password" or "none" // - NEO4J_dbms_* settings match Neo4j exactly // - Tools like Neo4j Desktop work out of the box // // Common Environment Variables: // // Authentication: // - NEO4J_AUTH="neo4j/password" (enable auth) // - NEO4J_AUTH="none" (disable auth, dev only) // - NORNICDB_AUTH_JWT_SECRET="..." (32+ chars) // // Network: // - NEO4J_dbms_connector_bolt_listen__address_port=7687 // - NEO4J_dbms_connector_http_listen__address_port=7474 // // Storage: // - NEO4J_dbms_directories_data="./data" // - NEO4J_dbms_default__database="nornicdb" // // Memory (NornicDB-specific): // - NORNICDB_MEMORY_DECAY_ENABLED=true // - NORNICDB_EMBEDDING_PROVIDER=ollama // - NORNICDB_EMBEDDING_MODEL=bge-m3 // // Compliance: // - NORNICDB_AUDIT_ENABLED=true // - NORNICDB_AUDIT_RETENTION_DAYS=2555 // - NORNICDB_ENCRYPTION_AT_REST=true // // Configuration Priority: // 1. Environment variables (highest) // 2. Default values (if env var not set) // 3. No config files (environment-only by design) // // Validation: // // Always call config.Validate() after LoadFromEnv() to catch errors: // - Missing required fields // - Invalid values (negative numbers, bad formats) // - Conflicting settings // // Performance: // - O(n) where n = number of environment variables // - Typically <1ms to load full configuration // - Config is loaded once at startup // // Thread Safety: // // LoadFromEnv reads environment variables which are process-global and // should not be modified after startup. The returned Config is immutable. func LoadFromEnv() *Config { config := &Config{} // Authentication - NEO4J_AUTH format: "username/password" or "none" // Default: disabled for easy development authStr := getEnv("NEO4J_AUTH", "none") if authStr == "none" { config.Auth.Enabled = false config.Auth.InitialUsername = "admin" config.Auth.InitialPassword = "admin" } else { config.Auth.Enabled = true parts := strings.SplitN(authStr, "/", 2) if len(parts) == 2 { config.Auth.InitialUsername = parts[0] config.Auth.InitialPassword = parts[1] } else { config.Auth.InitialUsername = "admin" config.Auth.InitialPassword = authStr } } config.Auth.MinPasswordLength = getEnvInt("NEO4J_dbms_security_auth_minimum__password__length", 8) config.Auth.TokenExpiry = getEnvDuration("NORNICDB_AUTH_TOKEN_EXPIRY", 24*time.Hour) config.Auth.JWTSecret = getEnv("NORNICDB_AUTH_JWT_SECRET", generateDefaultSecret()) // Database settings config.Database.DataDir = getEnv("NEO4J_dbms_directories_data", "./data") config.Database.DefaultDatabase = getEnv("NEO4J_dbms_default__database", "nornicdb") config.Database.ReadOnly = getEnvBool("NEO4J_dbms_read__only", false) config.Database.TransactionTimeout = getEnvDuration("NEO4J_dbms_transaction_timeout", 30*time.Second) config.Database.MaxConcurrentTransactions = getEnvInt("NEO4J_dbms_transaction_concurrent_maximum", 1000) // Durability settings - defaults optimized for performance // Set NORNICDB_STRICT_DURABILITY=true for maximum safety (financial/critical data) config.Database.StrictDurability = getEnvBool("NORNICDB_STRICT_DURABILITY", false) if config.Database.StrictDurability { // Strict mode: override to maximum safety config.Database.WALSyncMode = "immediate" config.Database.WALSyncInterval = 0 // Not used in immediate mode } else { // Default mode: good balance of performance and safety config.Database.WALSyncMode = getEnv("NORNICDB_WAL_SYNC_MODE", "batch") config.Database.WALSyncInterval = getEnvDuration("NORNICDB_WAL_SYNC_INTERVAL", 100*time.Millisecond) } // Server settings - Bolt config.Server.BoltEnabled = getEnvBool("NEO4J_dbms_connector_bolt_enabled", true) config.Server.BoltPort = getEnvInt("NEO4J_dbms_connector_bolt_listen__address_port", 7687) config.Server.BoltAddress = getEnv("NEO4J_dbms_connector_bolt_listen__address", "0.0.0.0") config.Server.BoltTLSEnabled = getEnvBool("NEO4J_dbms_connector_bolt_tls__level", false) config.Server.BoltTLSCert = getEnv("NEO4J_dbms_ssl_policy_bolt_base__directory", "") + "/public.crt" config.Server.BoltTLSKey = getEnv("NEO4J_dbms_ssl_policy_bolt_base__directory", "") + "/private.key" // Server settings - HTTP config.Server.HTTPEnabled = getEnvBool("NEO4J_dbms_connector_http_enabled", true) config.Server.HTTPPort = getEnvInt("NEO4J_dbms_connector_http_listen__address_port", 7474) config.Server.HTTPAddress = getEnv("NEO4J_dbms_connector_http_listen__address", "0.0.0.0") config.Server.HTTPSEnabled = getEnvBool("NEO4J_dbms_connector_https_enabled", false) config.Server.HTTPSPort = getEnvInt("NEO4J_dbms_connector_https_listen__address_port", 7473) config.Server.HTTPTLSCert = getEnv("NEO4J_dbms_ssl_policy_https_base__directory", "") + "/public.crt" config.Server.HTTPTLSKey = getEnv("NEO4J_dbms_ssl_policy_https_base__directory", "") + "/private.key" // Memory settings (NornicDB-specific, prefixed with NORNICDB_) config.Memory.DecayEnabled = getEnvBool("NORNICDB_MEMORY_DECAY_ENABLED", true) config.Memory.DecayInterval = getEnvDuration("NORNICDB_MEMORY_DECAY_INTERVAL", time.Hour) config.Memory.ArchiveThreshold = getEnvFloat("NORNICDB_MEMORY_ARCHIVE_THRESHOLD", 0.05) config.Memory.EmbeddingProvider = getEnv("NORNICDB_EMBEDDING_PROVIDER", "ollama") config.Memory.EmbeddingModel = getEnv("NORNICDB_EMBEDDING_MODEL", "bge-m3") config.Memory.EmbeddingAPIURL = getEnv("NORNICDB_EMBEDDING_API_URL", "http://localhost:11434") config.Memory.EmbeddingDimensions = getEnvInt("NORNICDB_EMBEDDING_DIMENSIONS", 1024) config.Memory.EmbeddingCacheSize = getEnvInt("NORNICDB_EMBEDDING_CACHE_SIZE", 10000) // Default: 10K (~40MB) config.Memory.AutoLinksEnabled = getEnvBool("NORNICDB_AUTO_LINKS_ENABLED", true) config.Memory.AutoLinksSimilarityThreshold = getEnvFloat("NORNICDB_AUTO_LINKS_THRESHOLD", 0.82) // Runtime memory management settings config.Memory.RuntimeLimitStr = getEnv("NORNICDB_MEMORY_LIMIT", "0") config.Memory.RuntimeLimit = parseMemorySize(config.Memory.RuntimeLimitStr) config.Memory.GCPercent = getEnvInt("NORNICDB_GC_PERCENT", 100) config.Memory.PoolEnabled = getEnvBool("NORNICDB_POOL_ENABLED", true) config.Memory.PoolMaxSize = getEnvInt("NORNICDB_POOL_MAX_SIZE", 1000) config.Memory.QueryCacheEnabled = getEnvBool("NORNICDB_QUERY_CACHE_ENABLED", true) config.Memory.QueryCacheSize = getEnvInt("NORNICDB_QUERY_CACHE_SIZE", 1000) config.Memory.QueryCacheTTL = getEnvDuration("NORNICDB_QUERY_CACHE_TTL", 5*time.Minute) // Embedding worker settings (NornicDB-specific) config.EmbeddingWorker.ScanInterval = getEnvDuration("NORNICDB_EMBED_SCAN_INTERVAL", 15*time.Minute) config.EmbeddingWorker.BatchDelay = getEnvDuration("NORNICDB_EMBED_BATCH_DELAY", 500*time.Millisecond) config.EmbeddingWorker.MaxRetries = getEnvInt("NORNICDB_EMBED_MAX_RETRIES", 3) config.EmbeddingWorker.ChunkSize = getEnvInt("NORNICDB_EMBED_CHUNK_SIZE", 512) config.EmbeddingWorker.ChunkOverlap = getEnvInt("NORNICDB_EMBED_CHUNK_OVERLAP", 50) // Compliance settings (NornicDB-specific, framework-agnostic) // Audit Logging config.Compliance.AuditEnabled = getEnvBool("NORNICDB_AUDIT_ENABLED", true) config.Compliance.AuditLogPath = getEnv("NORNICDB_AUDIT_LOG_PATH", "./logs/audit.log") config.Compliance.AuditRetentionDays = getEnvInt("NORNICDB_AUDIT_RETENTION_DAYS", 2555) // ~7 years for SOC2 // Data Retention config.Compliance.RetentionEnabled = getEnvBool("NORNICDB_RETENTION_ENABLED", false) config.Compliance.RetentionPolicyDays = getEnvInt("NORNICDB_RETENTION_POLICY_DAYS", 0) config.Compliance.RetentionAutoDelete = getEnvBool("NORNICDB_RETENTION_AUTO_DELETE", false) config.Compliance.RetentionExemptRoles = getEnvStringSlice("NORNICDB_RETENTION_EXEMPT_ROLES", []string{"admin"}) // Access Control config.Compliance.AccessControlEnabled = getEnvBool("NORNICDB_ACCESS_CONTROL_ENABLED", true) config.Compliance.SessionTimeout = getEnvDuration("NORNICDB_SESSION_TIMEOUT", 30*time.Minute) config.Compliance.MaxFailedLogins = getEnvInt("NORNICDB_MAX_FAILED_LOGINS", 5) config.Compliance.LockoutDuration = getEnvDuration("NORNICDB_LOCKOUT_DURATION", 15*time.Minute) // Encryption config.Compliance.EncryptionAtRest = getEnvBool("NORNICDB_ENCRYPTION_AT_REST", false) config.Compliance.EncryptionInTransit = getEnvBool("NORNICDB_ENCRYPTION_IN_TRANSIT", true) config.Compliance.EncryptionKeyPath = getEnv("NORNICDB_ENCRYPTION_KEY_PATH", "") // Data Subject Rights config.Compliance.DataExportEnabled = getEnvBool("NORNICDB_DATA_EXPORT_ENABLED", true) config.Compliance.DataErasureEnabled = getEnvBool("NORNICDB_DATA_ERASURE_ENABLED", true) config.Compliance.DataAccessEnabled = getEnvBool("NORNICDB_DATA_ACCESS_ENABLED", true) // Anonymization config.Compliance.AnonymizationEnabled = getEnvBool("NORNICDB_ANONYMIZATION_ENABLED", true) config.Compliance.AnonymizationMethod = getEnv("NORNICDB_ANONYMIZATION_METHOD", "pseudonymization") // Consent config.Compliance.ConsentRequired = getEnvBool("NORNICDB_CONSENT_REQUIRED", false) config.Compliance.ConsentVersioning = getEnvBool("NORNICDB_CONSENT_VERSIONING", true) config.Compliance.ConsentAuditTrail = getEnvBool("NORNICDB_CONSENT_AUDIT_TRAIL", true) // Breach Notification config.Compliance.BreachDetectionEnabled = getEnvBool("NORNICDB_BREACH_DETECTION_ENABLED", false) config.Compliance.BreachNotifyEmail = getEnv("NORNICDB_BREACH_NOTIFY_EMAIL", "") config.Compliance.BreachNotifyWebhook = getEnv("NORNICDB_BREACH_NOTIFY_WEBHOOK", "") // Logging settings config.Logging.Level = getEnv("NEO4J_dbms_logs_debug_level", "INFO") config.Logging.Format = getEnv("NORNICDB_LOG_FORMAT", "json") config.Logging.Output = getEnv("NORNICDB_LOG_OUTPUT", "stdout") config.Logging.QueryLogEnabled = getEnvBool("NEO4J_dbms_logs_query_enabled", false) config.Logging.SlowQueryThreshold = getEnvDuration("NEO4J_dbms_logs_query_threshold", 5*time.Second) // Feature flags config.Features.KalmanEnabled = getEnvBool("NORNICDB_KALMAN_ENABLED", false) // Topology procedures are always available; this controls automatic integration only config.Features.TopologyAutoIntegrationEnabled = getEnvBool("NORNICDB_TOPOLOGY_AUTO_INTEGRATION_ENABLED", false) config.Features.TopologyAlgorithm = getEnv("NORNICDB_TOPOLOGY_ALGORITHM", "adamic_adar") config.Features.TopologyWeight = getEnvFloat("NORNICDB_TOPOLOGY_WEIGHT", 0.4) config.Features.TopologyTopK = getEnvInt("NORNICDB_TOPOLOGY_TOPK", 10) config.Features.TopologyMinScore = getEnvFloat("NORNICDB_TOPOLOGY_MIN_SCORE", 0.3) config.Features.TopologyGraphRefreshInterval = getEnvInt("NORNICDB_TOPOLOGY_GRAPH_REFRESH_INTERVAL", 100) config.Features.TopologyABTestEnabled = getEnvBool("NORNICDB_TOPOLOGY_AB_TEST_ENABLED", false) config.Features.TopologyABTestPercentage = getEnvInt("NORNICDB_TOPOLOGY_AB_TEST_PERCENTAGE", 50) // Heimdall - the cognitive guardian feature flags // Opt-in cognitive database features - disabled by default config.Features.HeimdallEnabled = getEnvBool("NORNICDB_HEIMDALL_ENABLED", false) config.Features.HeimdallModel = getEnv("NORNICDB_HEIMDALL_MODEL", "qwen2.5-0.5b-instruct") config.Features.HeimdallGPULayers = getEnvInt("NORNICDB_HEIMDALL_GPU_LAYERS", -1) // -1 = auto config.Features.HeimdallContextSize = getEnvInt("NORNICDB_HEIMDALL_CONTEXT_SIZE", 32768) // 32K max (no perf impact) config.Features.HeimdallBatchSize = getEnvInt("NORNICDB_HEIMDALL_BATCH_SIZE", 8192) // 8K max (no perf impact) config.Features.HeimdallMaxTokens = getEnvInt("NORNICDB_HEIMDALL_MAX_TOKENS", 1024) // 1K output (faster) config.Features.HeimdallTemperature = float32(getEnvFloat("NORNICDB_HEIMDALL_TEMPERATURE", 0.1)) // Sub-features default to true when Heimdall is enabled config.Features.HeimdallAnomalyDetection = getEnvBool("NORNICDB_HEIMDALL_ANOMALY_DETECTION", config.Features.HeimdallEnabled) config.Features.HeimdallRuntimeDiagnosis = getEnvBool("NORNICDB_HEIMDALL_RUNTIME_DIAGNOSIS", config.Features.HeimdallEnabled) config.Features.HeimdallMemoryCuration = getEnvBool("NORNICDB_HEIMDALL_MEMORY_CURATION", false) // Experimental return config } // Validate checks the configuration for logical errors and invalid values. // // This method checks: // - Authentication is properly configured if enabled // - Password meets minimum length requirements // - Port numbers are valid (> 0) // - Embedding dimensions are positive // // Call Validate() after LoadFromEnv() and before using the Config. // // Example: // // config := config.LoadFromEnv() // if err := config.Validate(); err != nil { // log.Fatalf("Configuration error: %v", err) // } // // Config is valid, proceed with startup // // Returns nil if configuration is valid, or an error describing the problem. func (c *Config) Validate() error { if c.Auth.Enabled { if c.Auth.InitialUsername == "" { return fmt.Errorf("authentication enabled but no username provided") } if len(c.Auth.InitialPassword) < c.Auth.MinPasswordLength { return fmt.Errorf("password must be at least %d characters", c.Auth.MinPasswordLength) } } if c.Server.BoltEnabled && c.Server.BoltPort <= 0 { return fmt.Errorf("invalid bolt port: %d", c.Server.BoltPort) } if c.Server.HTTPEnabled && c.Server.HTTPPort <= 0 { return fmt.Errorf("invalid http port: %d", c.Server.HTTPPort) } if c.Memory.EmbeddingDimensions <= 0 { return fmt.Errorf("invalid embedding dimensions: %d", c.Memory.EmbeddingDimensions) } return nil } // String returns a safe string representation of the Config. // // Sensitive values like passwords and API keys are NOT included in the output, // making this safe for logging. // // Example: // // config := config.LoadFromEnv() // log.Printf("Starting with config: %s", config) // // Output: Config{Auth: true, Bolt: 0.0.0.0:7687, HTTP: 0.0.0.0:7474, DataDir: ./data} // // Returns a string suitable for logging and debugging. func (c *Config) String() string { return fmt.Sprintf( "Config{Auth: %v, Bolt: %s:%d, HTTP: %s:%d, DataDir: %s}", c.Auth.Enabled, c.Server.BoltAddress, c.Server.BoltPort, c.Server.HTTPAddress, c.Server.HTTPPort, c.Database.DataDir, ) } // Helper functions for environment variable parsing func getEnv(key, defaultVal string) string { if val := os.Getenv(key); val != "" { return val } return defaultVal } func getEnvInt(key string, defaultVal int) int { if val := os.Getenv(key); val != "" { if i, err := strconv.Atoi(val); err == nil { return i } } return defaultVal } func getEnvFloat(key string, defaultVal float64) float64 { if val := os.Getenv(key); val != "" { if f, err := strconv.ParseFloat(val, 64); err == nil { return f } } return defaultVal } func getEnvBool(key string, defaultVal bool) bool { if val := os.Getenv(key); val != "" { val = strings.ToLower(val) return val == "true" || val == "1" || val == "yes" || val == "on" } return defaultVal } func getEnvDuration(key string, defaultVal time.Duration) time.Duration { if val := os.Getenv(key); val != "" { if d, err := time.ParseDuration(val); err == nil { return d } // Try parsing as seconds if secs, err := strconv.Atoi(val); err == nil { return time.Duration(secs) * time.Second } } return defaultVal } func getEnvStringSlice(key string, defaultVal []string) []string { if val := os.Getenv(key); val != "" { // Split by comma, trim whitespace parts := strings.Split(val, ",") result := make([]string, 0, len(parts)) for _, p := range parts { if trimmed := strings.TrimSpace(p); trimmed != "" { result = append(result, trimmed) } } if len(result) > 0 { return result } } return defaultVal } func generateDefaultSecret() string { // In production, this should be explicitly set return "CHANGE_ME_IN_PRODUCTION_" + strconv.FormatInt(time.Now().UnixNano(), 36) } // parseMemorySize parses a human-readable memory size string. // Supports: "1024", "1KB", "1MB", "1GB", "1TB", "0", "unlimited" func parseMemorySize(s string) int64 { s = strings.TrimSpace(strings.ToUpper(s)) if s == "" || s == "0" || s == "UNLIMITED" { return 0 } s = strings.TrimSuffix(s, "B") var multiplier int64 = 1 switch { case strings.HasSuffix(s, "K"): multiplier = 1024 s = strings.TrimSuffix(s, "K") case strings.HasSuffix(s, "M"): multiplier = 1024 * 1024 s = strings.TrimSuffix(s, "M") case strings.HasSuffix(s, "G"): multiplier = 1024 * 1024 * 1024 s = strings.TrimSuffix(s, "G") case strings.HasSuffix(s, "T"): multiplier = 1024 * 1024 * 1024 * 1024 s = strings.TrimSuffix(s, "T") } val, err := strconv.ParseInt(s, 10, 64) if err != nil { return 0 } return val * multiplier } // FormatMemorySize formats bytes as human-readable string. func FormatMemorySize(bytes int64) string { const ( KB = 1024 MB = KB * 1024 GB = MB * 1024 TB = GB * 1024 ) switch { case bytes >= TB: return fmt.Sprintf("%.2f TB", float64(bytes)/float64(TB)) case bytes >= GB: return fmt.Sprintf("%.2f GB", float64(bytes)/float64(GB)) case bytes >= MB: return fmt.Sprintf("%.2f MB", float64(bytes)/float64(MB)) case bytes >= KB: return fmt.Sprintf("%.2f KB", float64(bytes)/float64(KB)) default: return fmt.Sprintf("%d B", bytes) } } // ApplyRuntimeMemory applies the runtime memory settings to the Go runtime. // Should be called early in main() before heavy allocations. func (c *MemoryConfig) ApplyRuntimeMemory() { if c.RuntimeLimit > 0 { debug.SetMemoryLimit(c.RuntimeLimit) } if c.GCPercent != 100 { debug.SetGCPercent(c.GCPercent) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server