Buble SDK for Ruby
Official Ruby SDK for Buble, built for the Buble public API.
Use this SDK from server-side Ruby applications to discover media models, upload source media, create asynchronous image and video generation tasks, run preconfigured Buble app workflows, and call chat models through OpenAI, Anthropic Messages, and Gemini-compatible API formats.
Keep API keys on the server. Do not expose BUBLE_API_KEY in browser, mobile, or other client-side code.
Installation
After publication to RubyGems:
gem install buble
Bundler:
gem "buble"
The gem requires Ruby 3.3+ and has no runtime dependencies outside the Ruby standard library.
Quick Start
Set your API key:
export BUBLE_API_KEY="sk_..."
The generation examples below create real Buble generation tasks and may consume credits.
require "buble"
client = Buble::Client.new
task = client.generations.create(
model: "google/nano-banana",
mode: "text_to_image",
prompt: "A cinematic product photo of a matte black espresso cup",
aspect_ratio: "1:1",
output_format: "png"
)
result = client.generations.wait(task.dig("data", "id"))
puts result.dig("data", "result", "images", 0, "url")
The client reads BUBLE_API_KEY and BUBLE_BASE_URL from the environment when omitted.
Configuration
client = Buble::Client.new(
api_key: "sk_...",
base_url: "https://buble.ai",
timeout: 60,
headers: {
"X-Request-Id" => "request-id"
}
)
Discover Media Models
models = client.media_models.list(media_type: "video")
models.fetch("data", []).each do |model|
puts model["model"]
end
Use media model discovery as the source of truth for model keys, modes, required inputs, and public parameters. New Buble models can become available without an SDK release.
Upload Files
upload = Buble::FileUpload.from_path("reference.png", content_type: "image/png")
uploaded = client.files.upload(
upload,
file_type: "image",
model: "google/nano-banana",
mode: "image_to_image"
)
task = client.generations.create(
model: "google/nano-banana",
mode: "image_to_image",
prompt: "Turn this reference into a polished ecommerce hero image.",
image_urls: [uploaded.dig("data", "url")]
)
Uploads support local paths, IO objects, and Buble::FileUpload. Path uploads are streamed from disk.
Video Generation
task = client.generations.create(
model: "gork/grok-imagine-video",
mode: "text_to_video",
prompt: "A slow cinematic shot of a futuristic train station at sunrise.",
duration: "5s",
resolution: "480p",
aspect_ratio: "16:9"
)
result = client.generations.wait(
task.dig("data", "id"),
interval: 2,
timeout: 900
)
puts result.dig("data", "result", "videos", 0, "url")
Generation request bodies use Buble's flat public API shape. Put model-specific controls in keyword arguments; the SDK serializes those controls at the JSON request root.
Do not send internal Buble fields such as input, options, scene, sub_mode_id, provider, mediaType, or media_type.
Apps
app = client.apps.retrieve("video-background-remover")
puts app.dig("data", "input_parameters")
task = client.apps.generations.create("video-background-remover", {
"source_video" => ["https://example.com/source.mp4"],
"refine_foreground_edges" => true,
"subject_is_person" => true
})
result = client.apps.generations.wait("video-background-remover", task.dig("data", "id"))
Apps are preconfigured workflows. Only send parameter names returned by client.apps.list or client.apps.retrieve(...).
Chat
OpenAI-Compatible
completion = client.chat.completions.create(
model: "openai/gpt-5.4",
messages: [
{ role: "user", content: "Write a short launch summary." }
],
max_completion_tokens: 800
)
puts completion.dig("choices", 0, "message", "content")
Streaming
client.chat.completions.stream_text(
model: "openai/gpt-5.4",
messages: [
{ role: "user", content: "Write one sentence at a time." }
]
).each do |text|
print text
end
Anthropic-Compatible
= client.chat..create(
model: "openai/gpt-5.4",
system: "You are concise.",
messages: [
{ role: "user", content: "Summarize this release." }
],
max_tokens: 800
)
Gemini-Compatible
response = client.chat.gemini.generate_content("openai/gpt-5.4", {
contents: [
{
role: "user",
parts: [
{ text: "Write a short launch summary." }
]
}
]
})
Gemini streaming uses stream_generate_content, not stream: true on generate_content.
Chat methods preserve protocol-native response shapes as Ruby Hashes with string keys.
Error Handling
begin
client.generations.retrieve("task_id")
rescue Buble::APIError => error
warn error.status
warn error.code
warn error.
warn error.details
end
begin
client.generations.wait("task_id")
rescue Buble::GenerationFailedError => error
warn error.task["error"]
end
Development
cd ruby
bundle install
bundle exec rake test
bundle exec rubocop
gem build buble.gemspec
Live smoke test:
BUBLE_API_KEY=sk_... ruby -Ilib tools/live_smoke.rb
The live smoke test calls discovery and chat endpoints only and does not create billable generation tasks.
Publishing Checklist
RubyGems package identity:
- Gem name:
buble - Namespace:
Buble - License: MIT
- Homepage:
https://buble.ai/
Build and publish:
cd ruby
bundle exec rake test
bundle exec rubocop
gem build buble.gemspec
Publication is handled by the monorepo Release Ruby SDK GitHub Actions workflow. Configure RubyGems Trusted Publishing for:
- Repository owner:
bublehq - Repository name:
sdks - Workflow filename:
release-ruby-sdk.yml - Environment:
release
Then publish from the monorepo with:
git tag ruby-v0.1.0
git push origin ruby-v0.1.0
RubyGems versions are immutable. After 0.1.0 is published, fixes must use a new version such as 0.1.1.