brainy/docs/vfs/COMMON_PATTERNS.md
David Snelling adda1570f3 docs(8.0): Phase F — deep clean across 21 docs
Aligned every public doc to the 8.0 contract: filesystem + memory adapters
only, vector index provider terminology (config.vector with recall +
quantization + persistMode knobs), no cloud storage adapters, no closed-
source product names.

Tier 1 — heavier rewrites:
- docs/architecture/storage-architecture.md
- docs/architecture/data-storage-architecture.md
- docs/architecture/distributed-storage.md DELETED — content was 100%
  cloud-coordination examples with no 8.0 substance.
- docs/guides/distributed-system.md DELETED — same reason; no inbound refs.
- docs/SCALING.md rewritten for single-node guidance.
- docs/PLUGINS.md, docs/augmentations/{COMPLETE-REFERENCE,README}.md:
  HnswProvider→VectorIndexProvider, hnsw→vector key.
- docs/PERFORMANCE.md, docs/BATCHING.md cloud-detection + sharding
  sections replaced with single-node vector tuning + filesystem framing.

Tier 2 — surgical renames + cloud-section deletions:
- architecture/{index,initialization-and-rebuild,overview}.md
- transactions.md, DEVELOPER_LEARNING_PATH.md
- vfs/{VFS_API_GUIDE,COMMON_PATTERNS}.md
- api/README.md, guides/{inspection,import-flow}.md

Tier 3 — light edits:
- docs/README.md, architecture/augmentation-system-audit.md

MIGRATION-V3-TO-V4.md untouched (internal migration doc, no stale terms).
2026-06-09 16:13:35 -07:00

14 KiB

🎯 VFS Common Patterns: Do This, Not That

Learn the correct patterns for using Brainy VFS. Avoid the mistakes that cause crashes, poor performance, and API confusion.

🚨 Critical Pattern: Safe Tree Operations

WRONG - Causes Infinite Recursion

// DON'T DO THIS - Directory appears as its own child!
function buildFileTree(allItems, parentPath) {
  return allItems.filter(item => {
    // This includes the parent directory itself!
    return item.path.startsWith(parentPath)
  })
}

// Result: /dir -> /dir -> /dir -> ∞ (crashes browser/server)

CORRECT - Tree-Aware Methods

// ✅ Pattern 1: Direct children for UI trees
async function loadDirectoryUI(path: string) {
  const children = await vfs.getDirectChildren(path)

  // Guaranteed: No self-inclusion, no recursion
  return children.map(child => ({
    name: child.metadata.name,
    path: child.metadata.path,
    type: child.metadata.vfsType,
    hasChildren: child.metadata.vfsType === 'directory'
  }))
}

// ✅ Pattern 2: Complete tree structure
async function buildCompleteTree(path: string) {
  return await vfs.getTreeStructure(path, {
    maxDepth: 5,           // Prevent deep recursion
    includeHidden: false,  // Skip .hidden files
    sort: 'name'          // Organized output
  })
}

// ✅ Pattern 3: Detailed inspection
async function inspectPath(path: string) {
  const info = await vfs.inspect(path)
  return {
    current: info.node,
    children: info.children,    // Direct children only
    parent: info.parent,        // Parent directory
    stats: info.stats          // Size, permissions, etc.
  }
}

🗃️ Storage Configuration Patterns

WRONG - Memory Storage for Files

// DON'T DO THIS - Data disappears when process exits!
const brain = new Brainy({
  storage: { type: 'memory' }  // ❌ Temporary only
})

// Files written here are lost forever on restart
await vfs.writeFile('/important.doc', content)

CORRECT - Persistent Storage

// ✅ Pattern 1: Filesystem storage (development)
const brain = new Brainy({
  storage: {
    type: 'filesystem',
    path: './brainy-data'    // Persisted to disk
  }
})

// ✅ Pattern 2: Filesystem (production default)
const brain = new Brainy({
  storage: {
    type: 'filesystem',
    rootDirectory: '/var/lib/brainy'
  }
})

// ✅ Pattern 3: Auto-detection (recommended)
const brain = new Brainy()  // Picks filesystem on Node, memory in browser

🔍 Search Patterns

WRONG - Manual String Matching

// DON'T DO THIS - Missing semantic understanding
async function findFilesOldWay(query: string) {
  const allFiles = await vfs.readdir('/', { recursive: true })
  return allFiles.filter(file =>
    file.includes(query.toLowerCase())  // ❌ Basic string match
  )
}
// ✅ Pattern 1: Content-aware search
async function findFilesByContent(query: string) {
  return await vfs.search(query, {
    type: 'file',           // Only search files
    limit: 50,             // Reasonable limit
    threshold: 0.7         // Minimum relevance
  })
}

// ✅ Pattern 2: Filtered search
async function findInDirectory(query: string, basePath: string) {
  return await vfs.search(query, {
    path: basePath,        // Limit to specific directory
    includeContent: true,  // Include file content in results
    sort: 'relevance'      // Best matches first
  })
}

// ✅ Pattern 3: Metadata-based search
async function findByAttributes(criteria: any) {
  return await vfs.find({
    where: criteria,       // MongoDB-style queries
    orderBy: 'modified',   // Sort by last modified
    limit: 100
  })
}

🏗️ Initialization Patterns

WRONG - Race Conditions

// DON'T DO THIS - Not waiting for initialization
const brain = new Brainy()
const vfs = brain.vfs()

// ❌ Using VFS before it's ready
await vfs.writeFile('/file.txt', 'content')  // May fail!

CORRECT - Proper Initialization

// ✅ Pattern 1: Sequential initialization
async function initializeVFS() {
  const brain = new Brainy({
    storage: { type: 'filesystem', path: './data' }
  })

  // Wait for brain to be ready
  await brain.init()

  // Then initialize VFS
  const vfs = brain.vfs()
  await vfs.init()

  // Now safe to use
  return vfs
}

// ✅ Pattern 2: With error handling
async function robustVFSInit() {
  try {
    const brain = new Brainy()
    await brain.init()

    const vfs = brain.vfs()
    await vfs.init()

    // Verify it's working
    await vfs.stat('/')  // Should not throw

    return vfs
  } catch (error) {
    console.error('VFS initialization failed:', error)
    throw new Error(`Cannot initialize VFS: ${error.message}`)
  }
}

// ✅ Pattern 3: Singleton pattern for apps
class VFSManager {
  private static instance: any = null

  static async getInstance() {
    if (!this.instance) {
      const brain = new Brainy()
      await brain.init()
      this.instance = brain.vfs()
      await this.instance.init()
    }
    return this.instance
  }
}

📝 File Operation Patterns

WRONG - Blocking Operations

// DON'T DO THIS - Blocking the main thread
async function badFileProcessing(files: string[]) {
  for (const file of files) {
    const content = await vfs.readFile(file)  // ❌ Sequential
    await processContent(content)              // ❌ Blocking
    await vfs.writeFile(file + '.processed', result)
  }
}

CORRECT - Efficient Operations

// ✅ Pattern 1: Parallel processing
async function efficientProcessing(files: string[]) {
  const operations = files.map(async (file) => {
    try {
      const content = await vfs.readFile(file)
      const result = await processContent(content)
      await vfs.writeFile(file + '.processed', result)
      return { file, success: true }
    } catch (error) {
      return { file, success: false, error: error.message }
    }
  })

  return await Promise.allSettled(operations)
}

// ✅ Pattern 2: Batch operations with limits
async function batchProcessFiles(files: string[], batchSize = 10) {
  const results = []

  for (let i = 0; i < files.length; i += batchSize) {
    const batch = files.slice(i, i + batchSize)
    const batchResults = await Promise.all(
      batch.map(file => processFile(file))
    )
    results.push(...batchResults)

    // Optional: Add delay between batches
    if (i + batchSize < files.length) {
      await new Promise(resolve => setTimeout(resolve, 100))
    }
  }

  return results
}

// ✅ Pattern 3: Streaming for large files
async function streamLargeFile(filePath: string) {
  const stream = await vfs.createReadStream(filePath, {
    highWaterMark: 64 * 1024  // 64KB chunks
  })

  return new Promise((resolve, reject) => {
    let content = ''

    stream.on('data', (chunk) => {
      content += chunk.toString()
    })

    stream.on('end', () => resolve(content))
    stream.on('error', reject)
  })
}

🔗 Relationship Patterns

WRONG - Manual Relationship Tracking

// DON'T DO THIS - Reinventing the graph
const fileRelationships = new Map()  // ❌ Manual tracking

function linkFiles(sourceFile: string, targetFile: string, relationship: string) {
  if (!fileRelationships.has(sourceFile)) {
    fileRelationships.set(sourceFile, [])
  }
  fileRelationships.get(sourceFile).push({ target: targetFile, type: relationship })
}

CORRECT - Use Built-in Relationships

// ✅ Pattern 1: Semantic relationships
async function createFileRelationships() {
  // Link test to source file
  await vfs.addRelationship(
    '/src/auth.ts',
    '/tests/auth.test.ts',
    'tested-by'
  )

  // Link documentation to implementation
  await vfs.addRelationship(
    '/docs/api.md',
    '/src/api.ts',
    'documents'
  )

  // Link dependency relationships
  await vfs.addRelationship(
    '/src/index.ts',
    '/src/utils.ts',
    'imports'
  )
}

// ✅ Pattern 2: Query relationships
async function findRelatedFiles(filePath: string) {
  // Find all files related to this one
  const related = await vfs.getRelated(filePath, {
    depth: 2,                    // Include relationships of relationships
    types: ['tests', 'documents', 'imports'],  // Filter relationship types
    direction: 'both'            // Both incoming and outgoing
  })

  return related
}

// ✅ Pattern 3: Relationship-based search
async function findTestFiles(sourceFile: string) {
  return await vfs.search('', {
    connected: {
      to: sourceFile,
      via: 'tested-by',
      direction: 'incoming'
    }
  })
}

🚀 Performance Patterns

WRONG - Loading Everything

// DON'T DO THIS - Loading massive directories
async function loadEntireProject() {
  const allFiles = await vfs.getTreeStructure('/', {
    // ❌ No limits, could be millions of files
  })

  return allFiles  // ❌ Crashes on large projects
}

CORRECT - Smart Loading

// ✅ Pattern 1: Paginated loading
async function loadDirectoryPage(path: string, page = 0, size = 50) {
  const children = await vfs.getDirectChildren(path, {
    limit: size,
    offset: page * size,
    sort: 'name'
  })

  const total = await vfs.getChildrenCount(path)

  return {
    items: children,
    page,
    size,
    total,
    hasMore: (page + 1) * size < total
  }
}

// ✅ Pattern 2: Lazy loading with caching
class FileTreeCache {
  private cache = new Map()

  async getDirectory(path: string) {
    if (this.cache.has(path)) {
      return this.cache.get(path)
    }

    const children = await vfs.getDirectChildren(path)
    this.cache.set(path, children)

    // Auto-expire cache after 5 minutes
    setTimeout(() => this.cache.delete(path), 5 * 60 * 1000)

    return children
  }
}

// ✅ Pattern 3: Progressive disclosure
async function buildLazyTree(rootPath: string) {
  const tree = await vfs.getTreeStructure(rootPath, {
    maxDepth: 1,  // Only immediate children
    lazy: true    // Enable lazy loading for subdirectories
  })

  // Expand directories on demand
  tree.expandDirectory = async (path: string) => {
    const subtree = await vfs.getTreeStructure(path, {
      maxDepth: 1
    })
    return subtree.children
  }

  return tree
}

🔧 Error Handling Patterns

WRONG - Silent Failures

// DON'T DO THIS - Ignoring errors
async function badErrorHandling(path: string) {
  try {
    return await vfs.readFile(path)
  } catch (error) {
    return null  // ❌ Silent failure
  }
}

CORRECT - Robust Error Handling

// ✅ Pattern 1: Specific error handling
async function robustFileRead(path: string) {
  try {
    return await vfs.readFile(path)
  } catch (error) {
    if (error.code === 'ENOENT') {
      throw new Error(`File not found: ${path}`)
    } else if (error.code === 'EACCES') {
      throw new Error(`Permission denied: ${path}`)
    } else if (error.code === 'EISDIR') {
      throw new Error(`Path is a directory, not a file: ${path}`)
    } else {
      throw new Error(`Failed to read ${path}: ${error.message}`)
    }
  }
}

// ✅ Pattern 2: Retry with backoff
async function resilientOperation(operation: () => Promise<any>, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation()
    } catch (error) {
      if (attempt === maxRetries) {
        throw error
      }

      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000
      await new Promise(resolve => setTimeout(resolve, delay))

      console.warn(`Attempt ${attempt} failed, retrying in ${delay}ms...`)
    }
  }
}

// ✅ Pattern 3: Graceful degradation
async function gracefulFileExplorer(path: string) {
  try {
    // Try the optimal method first
    return await vfs.getDirectChildren(path)
  } catch (error) {
    console.warn('Direct children failed, trying basic readdir:', error.message)

    try {
      // Fallback to basic directory listing
      const entries = await vfs.readdir(path)
      return entries.map(name => ({
        metadata: { name, path: `${path}/${name}` },
        // Missing detailed metadata, but functional
      }))
    } catch (fallbackError) {
      console.error('All methods failed:', fallbackError.message)
      return []  // Empty result rather than crash
    }
  }
}

📚 Integration Patterns

React Hook Pattern

function useVFS() {
  const [vfs, setVFS] = useState<any>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    async function initVFS() {
      try {
        const brain = new Brainy({
          storage: { type: 'filesystem', path: './brainy-data' }
        })
        await brain.init()

        const vfsInstance = brain.vfs()
        await vfsInstance.init()

        setVFS(vfsInstance)
      } catch (err) {
        setError(err.message)
      } finally {
        setLoading(false)
      }
    }

    initVFS()
  }, [])

  return { vfs, loading, error }
}

Express.js Middleware Pattern

function vfsMiddleware() {
  let vfsInstance: any = null

  return async (req: any, res: any, next: any) => {
    if (!vfsInstance) {
      try {
        const brain = new Brainy()
        await brain.init()
        vfsInstance = brain.vfs()
        await vfsInstance.init()
      } catch (error) {
        return res.status(500).json({ error: 'VFS initialization failed' })
      }
    }

    req.vfs = vfsInstance
    next()
  }
}

🎯 Summary: Do This, Not That

Avoid These Patterns Use These Instead
Manual tree filtering vfs.getDirectChildren()
Memory storage for files Filesystem (snapshot off-site for backup)
Sequential file operations Parallel processing with limits
Manual relationship tracking Built-in vfs.addRelationship()
Loading entire directories Paginated/lazy loading
Silent error handling Specific error types and fallbacks
Blocking synchronous calls Async/await with proper error handling

🎉 Following these patterns will give you:

  • 🚫 Zero infinite recursion in file explorers
  • Fast performance even with large directories
  • 🔄 Reliable error recovery and graceful degradation
  • 🧠 Semantic intelligence for powerful file search
  • 📈 Scalable architecture that grows with your needs

Next Steps: Check out the VFS API Guide for complete method documentation.