brainy/docs/guides/model-loading.md
David Snelling ca9129a924 chore(8.0): modernize toolchain + position Bun as a runtime
Consumer-invisible modernization pass — no public API or runtime-behavior
change; dist for the override-only files is byte-identical.

Toolchain:
- CI: GitHub Actions matrix — Node 22/24 (test:unit) + Bun latest (test:bun).
- engines: node ">=22" (was "22.x"), bun ">=1.1.0".
- tsconfig: isolatedModules + noImplicitOverride; add the 33 `override`
  modifiers the flag requires across storage/integrations/vfs/transaction.
- deps: @types/node ^22; add prettier; drop dead standard-version,
  @rollup/plugin-* and the redundant embedded eslintConfig (flat
  eslint.config.js is the active config — verified identical lint output).

paramValidation: replace the top-level `await import('node:os'/'node:fs')`
with static ESM imports. The top-level-await form poisoned the module graph;
static imports also drop the browser/edge fallback branches no supported
runtime reaches (8.0 is Node/Bun/Deno-only).

Bun positioning: recommend Bun as a runtime (`bun add` / `bun run`), which is
green (test:bun 8/8). Drop single-binary `bun build --compile` as a target —
native addons cannot embed into it, and Bun 1.3.10 has a `--compile` codegen
regression around top-level await. Rename the Bun test to bun-runtime-test.ts
and correct docs that overclaimed single-binary support.

Gates: typecheck 0, build 0, test:unit 1743/1743, test:bun 8/8.
2026-07-01 09:16:46 -07:00

5.2 KiB

Model Loading Guide

Brainy uses AI embedding models to understand and process your data. With the Candle WASM engine, the model is embedded at compile time - no downloads, no configuration, no external dependencies.

Zero Configuration (Default)

For all developers, no configuration is needed:

const brain = new Brainy()
await brain.init() // Model is already embedded - nothing to download!

What happens automatically:

  1. Candle WASM module loads (~90MB, includes model weights)
  2. Model initializes in ~200ms
  3. Ready to use immediately

No downloads. No CDN. No configuration. Just works.

How It Works

The all-MiniLM-L6-v2 model is embedded in the WASM binary using Rust's include_bytes! macro:

candle_embeddings_bg.wasm (~90MB)
├── Candle ML Runtime (~3MB)
├── Model Weights (safetensors format, ~87MB)
└── Tokenizer (HuggingFace tokenizers, ~450KB)

This single WASM file contains everything needed for sentence embeddings.

Environments

# Bun as a runtime — supported and recommended
bun add @soulcraft/brainy
bun run server.ts

Brainy is pure WebAssembly with no native binaries, so the module graph stays bundler-friendly. Single-binary bun build --compile is not a supported target at present: Bun 1.3.10 has a --compile codegen regression (__promiseAll is not defined) triggered by top-level await in the bundled graph. Run Brainy under the Bun runtime (above) instead.

Node.js

// Standard Node.js
node dist/server.js

// Runs identically to Bun

Browser

// Model loads via WASM (single file, no additional assets)
const brain = new Brainy()
await brain.init()

Docker/Kubernetes

FROM oven/bun:1.1
WORKDIR /app
COPY package*.json ./
RUN bun install
COPY . .
EXPOSE 3000
CMD ["bun", "run", "server.ts"]

# That's it! No model download step needed.
# Model is embedded in the npm package.

Model Information

all-MiniLM-L6-v2 (Embedded)

  • Dimensions: 384 (fixed)
  • Format: Safetensors (FP32)
  • Size: ~87MB (embedded in WASM)
  • Total WASM Size: ~90MB
  • Language: English-optimized, works with all languages
  • Inference: ~2-10ms per embedding
  • Initialization: ~200ms

Memory Usage

  • Loaded WASM: ~90MB
  • Inference peak: ~140MB total
  • Steady state: ~100MB

Comparing to Previous Architecture

Feature Before (ONNX) Now (Candle WASM)
Model downloads Required on first use None - embedded
External dependencies onnxruntime-web None
Model files model.onnx, tokenizer.json Embedded in WASM
Offline support Required setup Works by default
Bun compile Broken Works
Configuration Environment variables None needed

Troubleshooting

"Failed to initialize Candle Embedding Engine"

Cause: WASM loading issue.

Solutions:

# Rebuild the WASM
npm run build:candle

# Verify WASM exists
ls dist/embeddings/wasm/pkg/candle_embeddings_bg.wasm
# Should be ~90MB

Out of Memory

Cause: Container/environment has less than 256MB RAM.

Solutions:

# Increase memory limit (recommended: 512MB+)
docker run -m 512m my-app

Slow Initialization (>500ms)

Cause: Cold start, large WASM parsing.

Solutions:

// Initialize once at startup, not per-request
await brain.init()  // Do this once

// Then reuse for all requests
app.get('/api', async (req, res) => {
  const results = await brain.find(req.query)
  res.json(results)
})

Migration from Previous Versions

From v6.x (ONNX)

No changes needed for most users:

// Same API - just upgrade
const brain = new Brainy()
await brain.init()

What's removed:

  • BRAINY_ALLOW_REMOTE_MODELS - no downloads
  • BRAINY_MODELS_PATH - no external model files
  • npm run download-models - no longer needed

What's new:

  • Faster initialization
  • Bundler-friendly (pure WASM, no native binaries)
  • No network requirements

From Custom Embedding Functions

If you provided a custom embedding function, it still works:

const brain = new Brainy({
  embeddingFunction: myCustomEmbedder  // Still supported
})

Advanced: Building Custom WASM

For contributors who want to modify the embedding engine:

# Navigate to Candle WASM source
cd src/embeddings/candle-wasm

# Build with wasm-pack
wasm-pack build --target web --release

# Copy to pkg folder
cp pkg/* ../wasm/pkg/

# Build TypeScript
npm run build

Best Practices

Development

// Just works - no setup
const brain = new Brainy()
await brain.init()

Production

// Initialize once at startup
const brain = new Brainy()
await brain.init()

// Singleton pattern recommended
export { brain }

Deployment

# Option 1: Bun runtime
bun run server.ts

# Option 2: Docker
docker build -t my-app .
docker run -p 3000:3000 my-app

Additional Resources

Need help? Open an issue