- Add comprehensive zero-config preset system (production, development, minimal) - Implement intelligent auto-configuration for models and storage - Add Node.js version enforcement for ONNX Runtime stability - Force single-threaded ONNX operations to prevent V8 HandleScope crashes - Create extensible configuration architecture - Add 14 distributed system presets for enterprise deployments - Include detailed documentation and migration guides BREAKING CHANGE: Now requires Node.js 22.x LTS for optimal stability
13 KiB
13 KiB
Brainy Zero-Config Initiative
Strategic Plan for Configuration Simplification
Created: 2025-08-29
Version: 2.9.0 Released with precision parameter fix
🚨 Current State: Configuration Overload
Problem Scale
- 60+ configuration options across 10+ categories
- 500+ lines of TypeScript interfaces just for config
- Nested configs up to 5 levels deep
- Users overwhelmed with choices that should be automatic
Major Issues Discovered
-
embeddingOptionsdoesn't exist!- Used in explorer but not in actual API
- Should be via
embeddingFunctionwithcreateEmbeddingFunction()
-
Storage Confusion
- 7+ different storage configurations
- Complex nested options for S3/GCS/R2
- No auto-detection from environment
-
Redundant Mode Flags
readOnly,frozen,writeOnly,lazyLoadInReadOnlyMode,allowDirectReads- Too many overlapping concepts
-
Manual Performance Tuning
- Users set
batchSize,hotCacheMaxSize,efConstruction - Should be automatic based on data size and resources
- Users set
✅ What Brainy Already Auto-Detects
Environment & Resources
- Environment Type: Browser vs Node vs Serverless (✅ Working)
- Memory Available: Via
AutoConfigurationclass (✅ Exists) - CPU Cores: Detected for thread management (✅ Working)
- Threading: Auto-detects worker thread availability (✅ Working)
- Storage Type: Auto-picks OPFS (browser) or filesystem (Node) (✅ Working)
Model & Embedding Management
- Default Embedding:
defaultEmbeddingFunctionworks automatically (✅) - Model Downloads: Auto-downloads on first use (✅ Fixed in 2.7.x)
- Model Manager: Falls back through multiple sources (✅)
- Universal Memory Manager: Auto-selects embedding strategy (✅)
Performance Optimization
- HNSW Defaults: M=16, efConstruction=200 (✅ Set)
- Distance Function: Defaults to cosine (✅)
- Dimensions: Fixed at 384 for all-MiniLM-L6-v2 (✅)
- Cache Auto-tuning:
CacheAutoConfiguratoradapts to usage (✅) - Batch Processing: Auto-batches operations (✅)
- Cleanup: Periodic cleanup runs automatically (✅)
Augmentations
- Default Set: Core augmentations load automatically (✅)
- WAL: Write-ahead logging for durability (✅)
- Connection Pool: Manages connections automatically (✅)
- Entity Registry: Fast ID lookups (✅)
- Request Deduplication: Prevents duplicate work (✅)
🎯 Zero-Config Vision
True Zero Config (Works Today!)
const brain = new BrainyData()
await brain.init()
// ✅ Everything works!
Current Limitations:
- Uses memory storage (not persistent)
- Uses FP32 models (not Q8)
- Loads all augmentations (might be heavy)
Ideal Minimal Config (Proposed)
// Option 1: Preset-based
const brain = new BrainyData('production') // or 'development', 'minimal'
// Option 2: Three key decisions
const brain = new BrainyData({
storage: 'disk', // or 'memory', 'cloud', auto-detected
model: 'small', // or 'fast' (q8 vs fp32)
features: 'default' // or 'minimal', 'full'
})
// Option 3: Even simpler
const brain = new BrainyData({ mode: 'production' })
📋 Implementation Plan
Phase 1: Add Missing Auto-Detection (v2.10)
1.1 Storage Auto-Detection
function autoDetectStorage(): StorageConfig {
// Check environment variables
if (process.env.AWS_BUCKET) return { type: 's3', bucket: process.env.AWS_BUCKET }
if (process.env.GCS_BUCKET) return { type: 'gcs', bucket: process.env.GCS_BUCKET }
// Check environment type
if (isBrowser()) return { type: 'opfs' }
if (process.env.VERCEL) return { type: 'memory' } // Serverless
// Default to filesystem with smart path
return {
type: 'filesystem',
path: process.env.BRAINY_DATA_PATH || './brainy-data'
}
}
1.2 Model Precision Auto-Selection
function autoSelectModelPrecision(): 'fp32' | 'q8' {
const memoryMB = getAvailableMemory() / 1024 / 1024
// Use Q8 for constrained environments
if (isBrowser()) return 'q8'
if (memoryMB < 512) return 'q8'
if (process.env.BRAINY_MODEL === 'small') return 'q8'
return 'fp32' // Default to full precision
}
1.3 Feature Level Auto-Configuration
function autoConfigureFeatures(): FeatureLevel {
// Minimal for browsers and serverless
if (isBrowser() || isServerless()) return 'minimal'
// Full for development
if (process.env.NODE_ENV === 'development') return 'full'
// Default for production
return 'default'
}
Phase 2: Simplify Config Interface (v3.0)
2.1 New Simple Config
export interface BrainyConfig {
// Just 3-5 top-level options
mode?: 'development' | 'production' | 'minimal'
storage?: 'auto' | 'memory' | 'disk' | 'cloud' | StorageConfig
model?: 'fast' | 'small' | 'auto' | ModelConfig
features?: 'minimal' | 'default' | 'full' | string[]
// Everything else hidden
advanced?: LegacyConfig
}
2.2 Mode Presets
const PRESETS = {
development: {
storage: 'memory',
model: 'fast',
features: 'full',
logging: { verbose: true }
},
production: {
storage: 'disk',
model: 'auto',
features: 'default',
logging: { verbose: false }
},
minimal: {
storage: 'memory',
model: 'small',
features: 'minimal',
logging: { verbose: false }
}
}
2.3 Smart Defaults by Environment
constructor(config?: string | BrainyConfig) {
// String shorthand
if (typeof config === 'string') {
this.config = PRESETS[config]
return
}
// Auto-detect everything if no config
if (!config) {
config = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development'
}
}
// Expand simple config to full config
this.config = expandConfig(config)
}
Phase 3: Intelligent Resource Adaptation (v3.1)
3.1 Dynamic Performance Tuning
class ResourceAdaptiveConfig {
async adapt() {
const resources = await detectResources()
// Auto-configure based on available resources
if (resources.memoryGB > 8) {
this.enableFeature('aggressive-caching')
this.setHNSW({ M: 32, efConstruction: 400 })
} else if (resources.memoryGB < 1) {
this.enableFeature('minimal-memory')
this.setHNSW({ M: 8, efConstruction: 100 })
}
// Adapt to data size
const dataSize = await this.estimateDataSize()
if (dataSize > 1_000_000) {
this.enableFeature('partitioned-index')
}
}
}
3.2 Usage-Based Optimization
class UsageOptimizer {
async optimizeFromUsage() {
const patterns = await this.analyzeUsagePatterns()
if (patterns.readWriteRatio > 10) {
// Read-heavy: optimize for search
this.config.cache.size = 'large'
this.config.index.eager = true
} else if (patterns.readWriteRatio < 0.1) {
// Write-heavy: optimize for ingestion
this.config.batch.size = 'large'
this.config.index.lazy = true
}
}
}
🔧 Required Changes
Immediate (v2.10)
- Add
embeddingOptionssupport or document correct usage - Fix storage auto-detection from environment variables
- Add model precision auto-selection
- Create preset system for common configurations
Short-term (v3.0)
- New simplified config interface with backward compatibility
- Mode-based presets (development/production/minimal)
- Deprecation warnings for complex configs
- Migration guide from old to new config
Long-term (v3.1+)
- Full resource adaptation based on runtime environment
- Usage-based optimization that learns from patterns
- Cloud config service for centralized configuration
- Zero-config by default with optional overrides
📊 Success Metrics
Developer Experience
- Time to first query: < 30 seconds (from npm install)
- Lines of config: 0-5 (vs current 50+)
- Documentation needed: 1 page (vs current 10+)
Performance
- Auto-config performance: Within 10% of manual tuning
- Resource usage: Automatically optimized for environment
- Startup time: < 2 seconds with auto-config
Adoption
- Zero-config usage: > 80% of new projects
- Migration rate: > 50% of existing projects in 6 months
- Support tickets: 50% reduction in config-related issues
🚀 Next Steps
- Release v2.9.0 ✅ DONE - Fixed precision parameter
- Create feature flag for new config system
- Implement auto-detection functions
- Test in different environments (browser, serverless, Node)
- Document migration path from complex to simple config
- Release v2.10 with auto-detection
- Gather feedback and iterate
- Release v3.0 with new config interface
📝 Notes
What Makes Config Complex
- Too many choices that could be automatic
- Nested structures that hide important options
- Unclear relationships between options
- Manual tuning of performance parameters
- Environment-specific configurations
What Users Actually Need
- Where to store data (99% just want persistence)
- How fast vs how small (model tradeoff)
- Feature level (minimal/default/full)
Everything else should be automatic!
Key Insight
"The best configuration is no configuration. The second best is one that fits in a tweet."
Most users just want:
const brain = new BrainyData({ mode: 'production' })
And everything else should just work perfectly.
🔍 Deep Codebase Analysis Results
Environment Detection Already Available
// src/utils/environment.ts
- isBrowser() ✅
- isNode() ✅
- isWebWorker() ✅
- isProductionEnvironment() ✅ (checks NODE_ENV, K_SERVICE, GOOGLE_CLOUD_PROJECT)
- areWorkerThreadsAvailable() ✅
- checkWebGPUSupport() ✅
// Serverless detection (src/embeddings/universal-memory-manager.ts)
- VERCEL ✅
- NETLIFY ✅
- AWS_LAMBDA_FUNCTION_NAME ✅
- FUNCTIONS_WORKER_RUNTIME ✅
Resource Detection Capabilities
// src/utils/autoConfiguration.ts - EXISTS but NOT USED!
class AutoConfiguration {
detectEnvironment() ✅
detectResources() ✅ // CPU cores, memory
detectStorageCapabilities() ✅
generateRecommendedConfig() ✅
adaptToDataset() ✅
}
// src/utils/cacheAutoConfig.ts - ACTIVELY USED
class CacheAutoConfigurator {
autoDetectOptimalConfig() ✅
adaptConfiguration() ✅ // Runtime adaptation
detectEnvironment() ✅
}
Environment Variables Already Checked
// Model paths
BRAINY_MODELS_PATH ✅
BRAINY_ALLOW_REMOTE_MODELS ✅
BRAINY_Q8_CONFIRMED ✅
// Distributed mode
BRAINY_ROLE ✅ (writer/reader/hybrid)
SERVICE_ENDPOINT ✅
// Cloud storage
AWS_ACCESS_KEY_ID ✅ (but only in scaledHNSWSystem)
AWS_SECRET_ACCESS_KEY ✅
AWS_LAMBDA_FUNCTION_NAME ✅
// Environment
NODE_ENV ✅
K_SERVICE ✅ (Google Cloud Run)
GOOGLE_CLOUD_PROJECT ✅
VERCEL ✅
NETLIFY ✅
// Memory optimization
ORT_DISABLE_MEMORY_ARENA ✅
Storage Auto-Detection MISSING
// createStorage() in storageFactory.ts
// Currently requires explicit type specification
// NO auto-detection from environment!
// What we need to add:
function autoDetectStorageType(): StorageType {
// Check cloud providers
if (process.env.AWS_BUCKET || process.env.AWS_ACCESS_KEY_ID) return 's3'
if (process.env.GCS_BUCKET || process.env.GOOGLE_APPLICATION_CREDENTIALS) return 'gcs'
if (process.env.AZURE_STORAGE_ACCOUNT) return 'azure'
// Check environment
if (isBrowser()) return 'opfs'
if (process.env.VERCEL || process.env.NETLIFY) return 'memory'
// Default to filesystem
return 'filesystem'
}
The BIG Discovery: AutoConfiguration EXISTS but UNUSED!
// src/utils/autoConfiguration.ts
// COMPLETE auto-configuration system already built!
// But NEVER called from BrainyData constructor!
// It can detect:
- Environment (browser/nodejs/serverless)
- Available memory
- CPU cores
- Threading availability
- Storage capabilities
- S3 availability
- Recommended HNSW params
- Optimization flags
// But it's just sitting there unused! 😱
What Needs to be Connected
- Wire up AutoConfiguration in constructor
constructor(config?: BrainyConfig) {
if (!config) {
// Use the existing AutoConfiguration!
const autoConfig = await AutoConfiguration.getInstance().detectAndConfigure()
config = this.convertAutoConfigToBrainyConfig(autoConfig)
}
}
- Add embedding options to config
// Currently embeddingOptions doesn't exist in BrainyDataConfig
// But explorer uses it!
interface BrainyDataConfig {
embeddingOptions?: {
precision?: 'fp32' | 'q8'
modelCachePath?: string
}
}
- Create preset system
const PRESETS = {
'zero': {}, // True zero config
'production': { storage: 'disk', model: 'q8', features: 'default' },
'development': { storage: 'memory', model: 'fp32', features: 'full' },
'serverless': { storage: 'memory', model: 'q8', features: 'minimal' }
}
The Path Forward is Clear!
90% of the auto-detection code already exists! We just need to:
- Connect AutoConfiguration to BrainyData constructor
- Add embeddingOptions to config interface
- Create preset system
- Add storage auto-detection from env vars
- Wire model precision to embedding function creation
This could literally be done in < 200 lines of code!