Follow the Journey
3 min read

The SDK Design

Building brainzlab-ruby

I spent way too long debating gem names.

recall-ruby? brainzlab-recall? bl-recall?

Then it hit me: why have separate gems at all?

One gem to rule them all

The Brainz Lab SDK is one gem: brainzlab. That's it.

gem 'brainzlab'

Inside, everything is namespaced:

BrainzLab::Recall.info("User signed up", user_id: 123)
BrainzLab::Reflex.capture(exception)
BrainzLab::Vault.get("stripe/api_key")
BrainzLab::Pulse.increment("orders.created")

Clean. Obvious. One require, everything available.

Why not separate gems?

I tried it the other way. recall-ruby for logging. reflex-ruby for errors. Separate repos, separate versions, separate changelogs.

It sucked.

Version conflicts: "Recall 1.2 requires shared-client 2.0, but Reflex 1.1 requires shared-client 1.5."

Dependency hell: "You need to add five gems to use three products."

Upgrade fatigue: "New version of Recall! Also new version of Reflex! Also new version of the shared client! Also..."

One gem solves all of this. One version. One changelog. Everything stays in sync.

The configuration

Here's the full setup:

# config/initializers/brainzlab.rb
BrainzLab.configure do |config|
  # Core settings
  config.environment = Rails.env

  # Enable products you use
  config.recall_url = ENV['RECALL_URL']
  config.reflex_url = ENV['REFLEX_URL']
  config.vault_url = ENV['VAULT_URL']

  # Optional: customize behavior
  config.async = true  # Fire-and-forget (default)
  config.timeout = 5   # Seconds
end

Only configure what you use. Don't use Vault? Don't set vault_url. The SDK won't load Vault code.

Lazy loading magic

This was tricky to get right.

If someone only uses Recall, I don't want to load Reflex, Pulse, Vault, or anything else. Waste of memory, slower boot times.

The solution: lazy loading with helpful errors.

# Only Recall configured
BrainzLab::Recall.info("Works!")  # ✓

BrainzLab::Vault.get("stripe/key")
# => BrainzLab::NotConfiguredError:
#    Vault is not configured.
#    Add to your initializer:
#      config.vault_url = ENV['VAULT_URL']

Clear error. Tells you exactly what to do. No cryptic stack traces.

Rails integration

For Rails apps, the SDK does extra magic automatically:

Error capturing: Just install the gem. Exceptions get sent to Reflex. No code changes.

Request logging: Middleware captures requests and responses. Every HTTP call logged to Recall.

Job tracking: ActiveJob instrumentation built-in. Background jobs are traced automatically.

# This is the entire integration
gem 'brainzlab'

# In config/initializers/brainzlab.rb
BrainzLab.configure do |config|
  config.recall_url = ENV['RECALL_URL']
  config.reflex_url = ENV['REFLEX_URL']
end

# That's it. Errors and logs just work.

Zero-config observability. The dream.

Async by default

Telemetry should never slow down your app.

# This returns immediately
BrainzLab::Recall.info("Fast operation")
# Data is queued and sent in background

# Need confirmation? Use sync mode
BrainzLab::Recall.info("Critical audit log", sync: true)
# Waits for acknowledgment

99% of the time, you want async. Fire-and-forget. If a log fails to send, it's not the end of the world.

For audit logs, financial transactions, compliance stuff—use sync mode. It's slower but guaranteed.

Environment awareness

Every log, error, and metric knows where it came from:

BrainzLab::Recall.info("Something happened")
# Automatically tagged with:
#   environment: "production"
#   service: "myapp"
#   version: "1.2.3"

No manual tagging. The SDK reads from Rails and Git automatically.

When Claude asks "what errors happened in production vs staging?", the data is already separated.

Open source

The SDK uses the O'Saasy License: github.com/brainz-lab/brainzlab-ruby

Use it, fork it, run it however you want. Just don't resell it as a service.

If you want to build your own MCP tools on top of Recall or Reflex, the SDK is how you'd do it. That's intentional.

The more people building on Brainz Lab, the more valuable the ecosystem becomes.

— Andres

All posts Follow along

Want to follow the journey?

Get Updates