Oz Ruby SDK
The Oz Ruby SDK provides convenient access to the Oz API — Warp's cloud agent platform — from any Ruby 3.1+ application. Run and manage cloud agents, schedules, agent identities, environments, and artifacts with an idiomatic, resource-oriented client.
This is the Ruby counterpart to the official Python and TypeScript SDKs.
Installation
Add it to your Gemfile:
gem 'oz-agent-sdk'
Then run bundle install. Or install it directly:
gem install oz-agent-sdk
Quick start
require 'oz'
client = Oz::Client.new(
api_key: ENV['WARP_API_KEY'] # the default; can be omitted if the env var is set
)
response = client.agent.run(prompt: 'Fix the bug in auth.rb')
puts response.run_id
puts response.state # => "QUEUED"
The API key is read from the WARP_API_KEY environment variable by default, so in most
cases you can simply write Oz::Client.new.
Configuration
Configure a single client instance, or set global defaults once at boot.
# Per-client
client = Oz::Client.new(
api_key: 'sk-...',
base_url: 'https://app.warp.dev/api/v1', # default; override with OZ_API_BASE_URL
timeout: 60, # seconds
max_retries: 2, # retries for transient failures
default_headers: { 'X-My-Header' => 'value' },
logger: Logger.new($stdout) # optional Faraday request logging
)
# Global defaults + shared client
Oz.configure do |config|
config.api_key = ENV.fetch('WARP_API_KEY')
config.max_retries = 3
end
Oz.client.agent.runs.list(limit: 20).each { |run| puts run.title }
Environment variables
| Variable | Description |
|---|---|
WARP_API_KEY |
Bearer token used to authenticate requests. |
OZ_API_BASE_URL |
Override the API base URL. |
OZ_API_CUSTOM_HEADERS |
Extra headers, one Key: Value per line, added to every request. |
Usage with a custom configuration
Pass a config hash to customise the run's environment, model, MCP servers, and more:
response = client.agent.run(
prompt: 'Fix the bug in auth.rb',
config: {
environment_id: 'your-environment-id', # UID of a cloud environment
model_id: 'claude-sonnet-4', # optional: specify the LLM model
name: 'bug-fix-config', # optional: label for traceability
base_prompt: 'You are a helpful coding assistant.'
}
)
puts response.run_id
MCP servers
client.agent.run(
prompt: 'Check my GitHub issues',
config: {
environment_id: 'your-environment-id',
mcp_servers: {
github: { warp_id: 'your-shared-mcp-server-id' },
'custom-server' => {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem'],
env: { 'PATH' => '/usr/local/bin' }
},
'remote-server' => {
url: 'https://mcp.example.com/sse',
headers: { 'Authorization' => 'Bearer token' }
}
}
}
)
Resources
The client mirrors the API's resource hierarchy under client.agent.
Runs
client.agent.run(prompt: 'Refactor the parser') # start a run
run = client.agent.runs.retrieve('run-id') # fetch one run
client.agent.runs.cancel('run-id') # cancel a run
client.agent.runs.submit_followup('run-id', message: 'continue', mode: 'plan')
client.agent.runs.('run-id')
Pagination
runs.list returns an Oz::CursorPage. Iterate one page, or transparently walk all pages
with auto_paging_each:
page = client.agent.runs.list(limit: 50, state: %w[INPROGRESS QUEUED])
page.each { |run| puts run.run_id } # this page only
client.agent.runs.list(limit: 50).auto_paging_each do |run|
puts run.title # every run across all pages
end
Schedules
schedule = client.agent.schedules.create(
cron_schedule: '0 9 * * *',
name: 'nightly-dependency-check',
prompt: 'Check for outdated dependencies and open a PR'
)
client.agent.schedules.list
client.agent.schedules.retrieve(schedule.schedule_id)
client.agent.schedules.update(schedule.schedule_id, enabled: false)
client.agent.schedules.pause(schedule.schedule_id)
client.agent.schedules.resume(schedule.schedule_id)
client.agent.schedules.delete(schedule.schedule_id)
Agent identities
identity = client.agent.identities.create(name: 'ci-bot', description: 'CI agent')
client.agent.identities.list
client.agent.identities.retrieve(identity.uid)
client.agent.identities.update(identity.uid, description: 'Updated')
client.agent.identities.delete(identity.uid)
Agents, environments, and artifacts
client.agent.list(sort_by: 'last_run') # available agents (skills)
client.agent.list_environments # cloud environments
client.agent.get_artifact('artifact-uid') # a plan / screenshot / file artifact
Sessions and conversations
client.agent.sessions.check_redirect('session-uuid')
client.agent.conversations.check_redirect('conversation-id')
Responses
Responses are wrapped in Oz::Model, which exposes fields as methods and via [], and
wraps nested objects/arrays recursively. Unknown/optional fields return nil.
run = client.agent.runs.retrieve('run-id')
run.state # => "SUCCEEDED"
run['run_id'] # => "run-id"
run.is_sandbox_running? # predicate form for booleans
run.agent_config.model_id # nested access
run.to_h # plain Hash with string keys
Error handling
Every API failure raises a subclass of Oz::APIError, carrying the HTTP status, the parsed
response body, a machine-readable code, and the request_id.
begin
client.agent.run(prompt: 'do the thing')
rescue Oz::RateLimitError => e
retry_after(e)
rescue Oz::AuthenticationError
warn 'Check your WARP_API_KEY'
rescue Oz::APIStatusError => e
warn "API error #{e.status_code} (#{e.code}): #{e.}"
rescue Oz::APIConnectionError => e
warn "Network problem: #{e.}"
end
| Exception | When |
|---|---|
Oz::BadRequestError |
HTTP 400 |
Oz::AuthenticationError |
HTTP 401 / missing API key |
Oz::PermissionDeniedError |
HTTP 403 |
Oz::NotFoundError |
HTTP 404 |
Oz::ConflictError |
HTTP 409 |
Oz::UnprocessableEntityError |
HTTP 422 |
Oz::RateLimitError |
HTTP 429 |
Oz::InternalServerError |
HTTP 5xx |
Oz::APIConnectionError |
Connection failure |
Oz::APITimeoutError |
Request timeout |
All inherit from Oz::APIError < Oz::Error < StandardError.
Retries
Connection errors, timeouts, and HTTP 408, 409, 429, and 5xx responses are retried
automatically (default: 2 retries) with exponential backoff and jitter. A numeric
Retry-After header is honoured. Tune it with max_retries: (set to 0 to disable).
Development
This project uses mise to manage the Ruby toolchain. The default
version is Ruby 4.0 (pinned in mise.toml); the gem itself supports Ruby
3.1+.
make setup # mise install + current Bundler + bundle install (run once)
make spec # run tests
make lint # run RuboCop
make ci # lint + tests (what CI runs)
make build # build the gem
make help # list all tasks
On Ruby 4, use Bundler ≥ 2.7 (or 4.x). Bundler < 2.7 calls the removed
CGI.parseand will fail —make setupinstalls a compatible one for you.
See CONTRIBUTING.md for more, and docs/ for deeper guides.
License
Released under the Apache-2.0 license.