README.md
Runbox Ruby Client
Official Ruby client for Runbox - a fast, secure API for running code in isolated containers.
Installation
Add to your Gemfile:
gem "runbox"Or install directly:
gem install runboxQuick Start
require "runbox"
# Configure (or use environment variables)
Runbox.configure do |config|
config.url = "http://localhost:8080"
config.api_key = "your-api-key"
end
# Create a client
client = Runbox::Client.new
# Step 1: Set up a container and get environment info
setup = client.setup(
identifier: "my-session",
language: "python"
)
puts setup.container_id # => "runbox-my-session-python"
puts setup.environment_snapshot.runtime_version # => "3.11.6"
puts setup.environment_snapshot.packages["requests"] # => "2.31.0"
# Step 2: Run code in the container
result = client.run(
container_id: setup.container_id,
files: [{ path: "main.py", content: "print('Hello!')" }],
run_command: "python main.py"
)
puts result.stdout # => "Hello!\n"
puts result.success? # => trueConfiguration
Using Environment Variables
export RUNBOX_URL=http://localhost:8080
export RUNBOX_API_KEY=your-api-keyUsing Configuration Block
Runbox.configure do |config|
config.url = "http://localhost:8080"
config.api_key = "your-api-key"
config.timeout = 60 # HTTP timeout
endPer-Client Configuration
client = Runbox::Client.new(
url: "http://localhost:8080",
api_key: "your-api-key"
)Usage
Setting Up a Container
setup = client.setup(
identifier: "session-123",
language: "python",
env: { "API_KEY" => "secret" }, # Optional: set environment variables
memory: "512m", # Optional: memory limit
network_allow: ["api.stripe.com"] # Optional: allowed network destinations
)
# Access environment information
puts setup.container_id # => "runbox-session-123-python"
puts setup.cached? # => false (true if container was reused)
env = setup.environment_snapshot
puts env.os_name # => "debian"
puts env.os_version # => "12"
puts env.runtime_name # => "python"
puts env.runtime_version # => "3.11.6"
puts env.packages # => {"pip" => "23.0.1", "requests" => "2.31.0", ...}Running Code
result = client.run(
container_id: "runbox-session-123-python",
files: [{ path: "main.py", content: "print('Hello!')" }],
run_command: "python main.py",
env: { "DEBUG" => "true" }, # Optional: runtime environment variables
timeout: 30 # Optional: execution timeout in seconds
)
puts result.success? # => true
puts result.exit_code # => 0
puts result.stdout # => "Hello!\n"
puts result.stderr # => ""
puts result.execution_time_ms # => 42
puts result.timeout? # => falseInstalling Dependencies On-The-Fly
Install new dependencies before running code:
# Python example
result = client.run(
container_id: container_id,
files: [{ path: "main.py", content: "import requests; print(requests.__version__)" }],
run_command: "python main.py",
new_dependencies: ["requests==2.31.0", "pytest"]
)
puts result.packages # => {"pip"=>"23.0.1", "requests"=>"2.31.0", "pytest"=>"7.4.0", ...}
# Ruby example
result = client.run(
container_id: container_id,
files: [{ path: "main.rb", content: "require 'rake'; puts Rake::VERSION" }],
run_command: "ruby main.rb",
new_dependencies: ["rake", "rspec"]
)
# Shell example (uses apk)
result = client.run(
container_id: container_id,
files: [{ path: "script.sh", content: "#!/bin/sh\ncurl --version" }],
run_command: "sh script.sh",
new_dependencies: ["curl", "jq", "git"]
)Note: The packages field is only included in the result when new_dependencies are provided.
Cleanup Containers
deleted = client.delete_containers("session-123")
puts deleted # => ["runbox-session-123-python"]Check Health
health = client.health
puts health[:status] # => "healthy"
puts health[:version] # => "1.0.0"API Reference
client.setup(identifier:, language:, **options)
Set up a container and get environment information.
Parameters:
-
identifier(String, required): Unique identifier for container reuse -
language(String, required): Programming language ("python","ruby","shell") -
env(Hash, optional): Environment variables to set -
timeout(Integer, optional): Default timeout in seconds -
memory(String, optional): Memory limit (e.g.,"256m","1g") -
network_allow(Array, optional): Allowed network destinations
Returns: SetupResult with:
-
container_id: Container ID to use inrun()calls -
cached?: Whether container was reused -
environment_snapshot: Environment information (OS, runtime, packages)
client.run(container_id:, files:, run_command:, **options)
Run code in a container that was set up via setup().
Parameters:
-
container_id(String, required): Container ID fromsetup()response -
files(Array, required): Files to write before running -
run_command(String, required): Command to run -
env(Hash, optional): Runtime environment variables -
timeout(Integer, optional): Execution timeout in seconds
Returns: Result with:
-
success?: Whether run succeeded (exit code 0) -
exit_code: Process exit code -
stdout: Standard output -
stderr: Standard error -
execution_time_ms: Execution time in milliseconds -
timeout?: Whether run timed out
Error Handling
begin
setup = client.setup(identifier: "test", language: "python")
result = client.run(
container_id: setup.container_id,
files: [{ path: "main.py", content: "print('hi')" }],
run_command: "python main.py"
)
rescue Runbox::AuthenticationError => e
puts "Invalid API key"
rescue Runbox::NotFoundError => e
puts "Container not found (did you call setup first?)"
rescue Runbox::ValidationError => e
puts "Invalid request: #{e.message}"
rescue Runbox::RunError => e
puts "Run failed: #{e.message}"
rescue Runbox::ConnectionError => e
puts "Could not connect to Runbox"
endDevelopment
Running Tests
bundle install
bundle exec rake testRunning Integration Tests
Integration tests require a running Runbox server:
# Start Runbox server (in another terminal)
cd ../runbox
docker-compose up
# Run integration tests
export RUNBOX_URL=http://localhost:8080
export RUNBOX_API_KEY=your-api-key
ruby examples/integration_test.rbLinting
bundle exec rubocopCI/CD
-
CI: Runs on every push and PR
- Tests on Ruby 3.1, 3.2, 3.3
- Linting with RuboCop
- Integration tests against live Runbox server
-
CD: Publishes to RubyGems on version tags
- Create a tag:
git tag v1.0.0 && git push --tags - Requires
RUBYGEMS_API_KEYsecret in GitHub
- Create a tag:
License
MIT License - see LICENSE for details.