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