brainy/docs/vfs/VFS_INITIALIZATION.md
David Snelling 606445cd61 feat(8.0): API simplification — remove neural()/Db.search, one storage path key, integration→0
8.0 RC cleanup toward "one place per thing, zero-config, no deprecation":

- Remove the `brain.neural()` clustering namespace (ImprovedNeuralAPI + the dead
  legacy NeuralAPI + the neural CLI + neural-only types). Similarity is `find({vector})`
  / `similar({to})`; attribute grouping is the aggregation `GROUP BY` engine. The separate
  entity-extraction / smart-import feature (NeuralImport, NeuralEntityExtractor, SmartExtractor,
  NaturalLanguageProcessor, `brain.extract()`/`brain.nlp()`) is kept.
- Remove `Db.search()`; `find()` is the one query verb (accepts a bare string or FindParams).
  Fix the bundled MCP client, which called a non-existent `brain.search(query, limit)` →
  now `find({ query, limit })`.
- Storage config: collapse to one canonical top-level `path` key. The pre-8.0 aliases
  (`rootDirectory`, `options.*`, `fileSystemStorage.*`) are removed and now THROW with the
  exact rename instead of silently defaulting to `./brainy-data` on upgrade. A single resolver
  feeds createStorage, the 7.x→8.0 migration probe, and the plugin-factory handoff, so a native
  storage provider resolves the identical root (no split-brain).
- Fix `similar({ threshold })`: the min-similarity filter was silently dropped; it is now
  applied as a post-filter on `result.score` (the documented way to bound semantic results).
- Fix `vfs.rename()` on a directory: child path updates spread the entity vector into `update()`
  and failed dimension validation; they are metadata-only updates now.
- Fix `vfs.move()`: copy+delete orphaned the content-addressed content blob (the destination
  shared the source hash, then unlink removed it). `move()` now delegates to `rename()` — an
  in-place path change that preserves the blob and the entity id, for files and directories.
- Fix streaming import: the bulk fast path never flushed mid-import nor signalled queryability.
  Entity writes are now chunked by a progressive flush interval (100 → 1000 → 5000); each chunk
  flushes and emits `progress.queryable`, so imported data is queryable during the import.
- Sweep all docs, comments, and JSDoc for the removed/changed APIs.

Integration suite: 49 files / 588 passed / 0 failed. Unit: 80 files / 1456 passed, no type errors.
2026-06-20 13:31:11 -07:00

5.6 KiB

VFS Initialization Guide

Quick Start

The Brainy VFS is automatically initialized during brain.init(). No separate initialization needed!

import { Brainy } from '@soulcraft/brainy'

// Create and initialize Brainy
const brain = new Brainy({
  storage: { type: 'filesystem', path: './data' }
})
await brain.init()  // VFS is auto-initialized here!

// Use VFS immediately - it's a property, not a method!
await brain.vfs.writeFile('/test.txt', 'Hello World')
const files = await brain.vfs.readdir('/')

What Changed in v5.1.0?

Before (v4.x and early v5.0.0):

const brain = new Brainy(...)
await brain.init()

const vfs = brain.vfs()     // ❌ Method call
await vfs.init()             // ❌ Separate initialization
await vfs.writeFile(...)

After:

const brain = new Brainy(...)
await brain.init()           // VFS auto-initialized!

await brain.vfs.writeFile(...)  // ✅ Property access, just works!

Key Changes:

  1. vfs()vfs: Method call becomes property access
  2. Auto-initialization: VFS initialized during brain.init()
  3. Zero complexity: No separate vfs.init() call needed
  4. Consistent pattern: VFS treated like any other brain API

Migration from v4.x/v5.0.0

Old Pattern (DEPRECATED):

const vfs = brain.vfs()
await vfs.init()
await vfs.writeFile('/test.txt', 'data')

New Pattern:

// Just remove the () and init() call
await brain.vfs.writeFile('/test.txt', 'data')

Why Auto-Initialization?

VFS stores files as entities and relationships in the same graph as everything else. There's no reason to treat it differently! Auto-initialization:

  • Simpler API: One less step to remember
  • Fewer errors: Can't forget to initialize
  • More intuitive: Property access feels natural
  • Consistent: Matches how other brain APIs work

Complete Example

import { Brainy } from '@soulcraft/brainy'

async function useVFS() {
  // Initialize Brainy
  const brain = new Brainy({
    storage: {
      type: 'filesystem',  // or 'memory', 's3', 'r2'
      path: './brainy-data'
    }
  })
  await brain.init()  // VFS ready after this!

  // Use VFS immediately
  await brain.vfs.writeFile('/readme.txt', 'Welcome to VFS!')
  await brain.vfs.mkdir('/documents')

  const files = await brain.vfs.readdir('/')
  console.log('Files in root:', files.map(f => f.name))

  const content = await brain.vfs.readFile('/readme.txt')
  console.log('File content:', content.toString())
}

useVFS().catch(console.error)

TypeScript Usage

import { Brainy, VirtualFileSystem } from '@soulcraft/brainy'

class FileManager {
  private brain: Brainy

  async initialize(): Promise<void> {
    this.brain = new Brainy({
      storage: { type: 'filesystem' }
    })
    await this.brain.init()
    // VFS is ready! No separate initialization needed
  }

  async writeFile(path: string, content: string): Promise<void> {
    if (!this.brain) {
      throw new Error('FileManager not initialized. Call initialize() first.')
    }
    // Use VFS as property
    await this.brain.vfs.writeFile(path, content)
  }

  async listFiles(path: string): Promise<string[]> {
    const entries = await this.brain.vfs.readdir(path)
    return entries.map(e => e.name)
  }
}

Error Messages

If you see this error:

Brainy not initialized. Call init() first.

It means you tried to use VFS before calling brain.init(). Always initialize Brainy first:

await brain.init()  // Required!
await brain.vfs.writeFile(...)  // Now this works

Snapshot Support

VFS files are ordinary entities, so they participate fully in the 8.0 Db API: a persisted snapshot contains every VFS file, and a snapshot opened with Brainy.load() serves VFS reads at the snapshot's state:

const brain = new Brainy({ storage: { type: 'filesystem', path: './data' } })
await brain.init()

// Create files
await brain.vfs.writeFile('/config.json', '{"version": 1}')

// Snapshot the whole store (VFS files included)
const pin = brain.now()
await pin.persist('/backups/with-vfs')
await pin.release()

// Later changes never touch the snapshot
await brain.vfs.writeFile('/config.json', '{"version": 2}')

See Snapshots & Time Travel.

FAQ

Q: Do I need to call vfs.init() anymore?

A: No! VFS is automatically initialized during brain.init() in v5.1.0+.

Q: Why did the API change from vfs() to vfs?

A: VFS uses the same entity/relationship graph as everything else. There's no reason to treat it differently from other brain APIs.

Q: Will my old code break?

A: If you're using brain.vfs() or await vfs.init(), you'll need to update to the new pattern. The migration is simple - just remove the () and init() calls.

Q: Can I still configure VFS?

A: Yes, VFS configuration is passed through brain.init() config. The VFS-specific options are applied during auto-initialization.

Q: Does this work with all storage adapters?

A: Yes! VFS auto-initialization works with both shipped adapters (FileSystem and Memory) and any plugin-provided storage adapter.

Q: What if I need multiple VFS instances?

A: Each Brainy instance has its own VFS. Create multiple Brainy instances if you need multiple VFS instances.