{"id":49574733,"url":"https://github.com/conductor-oss/ruby-sdk","last_synced_at":"2026-05-03T16:07:07.296Z","repository":{"id":349833684,"uuid":"1154127027","full_name":"conductor-oss/ruby-sdk","owner":"conductor-oss","description":"Ruby SDK for Conductor","archived":false,"fork":false,"pushed_at":"2026-04-30T19:07:37.000Z","size":451,"stargazers_count":0,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T21:08:09.911Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/conductor-oss.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-10T03:24:43.000Z","updated_at":"2026-04-28T15:42:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/conductor-oss/ruby-sdk","commit_stats":null,"previous_names":["conductor-oss/ruby-sdk"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/conductor-oss/ruby-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conductor-oss%2Fruby-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conductor-oss%2Fruby-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conductor-oss%2Fruby-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conductor-oss%2Fruby-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/conductor-oss","download_url":"https://codeload.github.com/conductor-oss/ruby-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conductor-oss%2Fruby-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32575200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-03T16:07:06.427Z","updated_at":"2026-05-03T16:07:07.280Z","avatar_url":"https://github.com/conductor-oss.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Conductor Ruby SDK\n\nOfficial Ruby SDK for [Conductor OSS](https://github.com/conductor-oss/conductor) - a durable workflow orchestration engine.\n\n[![Gem Version](https://badge.fury.io/rb/conductor_ruby.svg)](https://badge.fury.io/rb/conductor_ruby)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n\n## Features\n\n- **Full Feature Parity** with Python SDK\n- **Ruby-Idiomatic Workflow DSL** - Clean block-based syntax with 25+ task types\n- **Worker Framework** - Multi-threaded task execution with class-based and block-based workers\n- **LLM/AI Tasks** - Chat completion, embeddings, RAG, image/audio generation\n- **Orkes Cloud Support** - Authentication, secrets, integrations, prompts\n- **Comprehensive Testing** - 400+ unit tests, 110 integration tests\n\n## Installation\n\nAdd to your Gemfile:\n\n```ruby\ngem 'conductor_ruby'\n```\n\nOr install directly:\n\n```bash\ngem install conductor_ruby\n```\n\n## Quick Start\n\n### Hello World\n\n```ruby\nrequire 'conductor'\n\n# Configuration (reads CONDUCTOR_SERVER_URL from environment)\nconfig = Conductor::Configuration.new\n\n# Create clients\nclients = Conductor::Orkes::OrkesClients.new(config)\nexecutor = clients.get_workflow_executor\n\n# Define a worker\nclass GreetWorker\n  include Conductor::Worker::WorkerModule\n  worker_task 'greet'\n\n  def execute(task)\n    name = get_input(task, 'name', 'World')\n    { 'result' =\u003e \"Hello, #{name}!\" }\n  end\nend\n\n# Build workflow using new DSL\nworkflow = Conductor.workflow :greetings, version: 1, executor: executor do\n  greet = simple :greet, name: wf[:name]\n  output result: greet[:result]\nend\n\n# Register and execute\nworkflow.register(overwrite: true)\n\n# Start workers\nrunner = Conductor::Worker::TaskRunner.new(config)\nrunner.register_worker(GreetWorker.new)\nrunner.start\n\n# Execute workflow\nresult = workflow.execute(input: { 'name' =\u003e 'Ruby' }, wait_for_seconds: 30)\nputs \"Result: #{result.output['result']}\"  # =\u003e \"Hello, Ruby!\"\n\nrunner.stop\n```\n\n## Workflow DSL\n\nThe SDK provides a clean, Ruby-idiomatic DSL for building workflows:\n\n```ruby\nworkflow = Conductor.workflow :order_processing, version: 1, executor: executor do\n  # Access workflow inputs with wf[:param]\n  user = simple :get_user, user_id: wf[:user_id]\n  \n  # Reference task outputs with task[:field]\n  order = simple :validate_order, email: user[:email]\n  \n  # HTTP calls\n  http :call_api, url: 'https://api.example.com', method: :post, body: { id: order[:id] }\n  \n  # Parallel execution\n  parallel do\n    simple :ship_order, order_id: order[:id]\n    simple :send_confirmation, email: user[:email]\n  end\n  \n  # Conditional branching\n  decide order[:region] do\n    on 'US' do\n      simple :us_shipping\n    end\n    on 'EU' do\n      simple :eu_shipping\n    end\n    otherwise do\n      terminate :failed, 'Unsupported region'\n    end\n  end\n  \n  # Set workflow output\n  output tracking: order[:tracking_number], status: 'completed'\nend\n\n# Register and execute\nworkflow.register(overwrite: true)\nresult = workflow.execute(input: { user_id: 123 }, wait_for_seconds: 60)\n```\n\n### Task Methods Reference\n\n#### Basic Tasks\n\n```ruby\n# Simple task (worker execution)\nresult = simple :task_name, input1: 'value', input2: wf[:param]\n\n# Inline code execution\njq :transform, query: '.items | map(.name)', input: previous[:data]\njavascript :compute, script: 'return inputs.a + inputs.b', a: 1, b: 2\n\n# Set workflow variables\nset_variable :save_state, user_id: user[:id], status: 'active'\n\n# Human/manual task\nhuman :approval, display_name: 'Manager Approval', form_template: 'approval_form'\n```\n\n#### HTTP Tasks\n\n```ruby\n# HTTP request\nhttp :call_api,\n  url: 'https://api.example.com/users',\n  method: :post,\n  headers: { 'Authorization' =\u003e 'Bearer ${workflow.secrets.api_token}' },\n  body: { name: wf[:name], email: wf[:email] }\n\n# HTTP polling (wait for condition)\nhttp_poll :wait_for_ready,\n  url: 'https://api.example.com/status/${workflow.input.job_id}',\n  method: :get,\n  termination_condition: '$.status == \"ready\"',\n  polling_interval: 5,\n  polling_strategy: :fixed\n```\n\n#### Control Flow\n\n```ruby\n# Parallel execution (fork/join)\nparallel do\n  simple :branch_a\n  simple :branch_b\n  simple :branch_c\nend\n\n# Conditional branching\ndecide order[:status] do\n  on 'pending' do\n    simple :process_pending\n  end\n  on 'approved' do\n    simple :process_approved\n  end\n  otherwise do\n    simple :handle_unknown\n  end\nend\n\n# Conditional shortcuts\nwhen_true user[:is_premium] do\n  simple :apply_discount\nend\n\nwhen_false order[:validated] do\n  terminate :failed, 'Order validation failed'\nend\n\n# Loop over items\nloop_over users[:list], as: :user do\n  simple :process_user, user_id: iteration[:user][:id]\nend\n\n# Do-while loop\ndo_while :retry_loop, condition: '${retry_ref.output.success} == false' do\n  simple :retry_operation\nend\n```\n\n#### Sub-workflows\n\n```ruby\n# Call another workflow\nsub_workflow :process_order,\n  workflow_name: 'order_processor',\n  version: 2,\n  input: { order_id: wf[:order_id] }\n\n# Start workflow (fire-and-forget)\nstart_workflow :trigger_notification,\n  workflow_name: 'send_notifications',\n  input: { user_id: user[:id] }\n\n# Inline sub-workflow definition\ninline_workflow :nested_process do\n  simple :step1\n  simple :step2\nend\n```\n\n#### Wait and Events\n\n```ruby\n# Wait for duration\nwait :pause, duration: '30s'   # or '5m', '1h', '2d'\n\n# Wait until specific time\nwait :scheduled, until: '2024-12-25T00:00:00Z'\n\n# Wait for external webhook\nwait_for_webhook :external_callback,\n  matches: { 'type' =\u003e 'payment', 'order_id' =\u003e '${workflow.input.order_id}' }\n\n# Publish event\nevent :notify, sink: 'conductor:workflow_events', payload: { status: 'completed' }\n```\n\n#### Termination\n\n```ruby\n# Complete workflow\nterminate :success, 'Processing completed successfully'\n\n# Fail workflow\nterminate :failed, 'Validation error: missing required field'\n```\n\n#### Dynamic Tasks\n\n```ruby\n# Dynamic task name (resolved at runtime)\ndynamic :run_handler, task_to_execute: wf[:handler_name]\n\n# Dynamic fork (parallel tasks determined at runtime)\ndynamic_fork :process_all,\n  tasks_input: wf[:items],\n  task_name: 'process_item'\n```\n\n### LLM/AI Tasks\n\n```ruby\nworkflow = Conductor.workflow :ai_assistant, executor: executor do\n  # Chat completion (messages auto-converted from simple format)\n  response = llm_chat :chat,\n    provider: 'openai',\n    model: 'gpt-4',\n    messages: [\n      { role: :system, message: 'You are a helpful assistant.' },\n      { role: :user, message: wf[:question] }\n    ],\n    temperature: 0.7\n\n  # Text completion\n  llm_text :complete,\n    provider: 'anthropic',\n    model: 'claude-3-sonnet',\n    prompt: 'Summarize: ${workflow.input.text}'\n\n  # Generate embeddings\n  embeddings = llm_embeddings :embed,\n    provider: 'openai',\n    model: 'text-embedding-3-small',\n    text: wf[:document]\n\n  # Store embeddings in vector DB\n  llm_store_embeddings :store,\n    provider: 'pinecone',\n    index: 'documents',\n    embeddings: embeddings[:embeddings],\n    metadata: { doc_id: wf[:doc_id] }\n\n  # Search embeddings\n  llm_search_embeddings :search,\n    provider: 'pinecone',\n    index: 'documents',\n    query: wf[:search_query],\n    max_results: 10\n\n  # Generate image\n  generate_image :create_image,\n    provider: 'openai',\n    model: 'dall-e-3',\n    prompt: 'A sunset over mountains',\n    size: '1024x1024'\n\n  # Generate audio (text-to-speech)\n  generate_audio :speak,\n    provider: 'openai',\n    model: 'tts-1',\n    text: response[:content],\n    voice: 'nova'\n\n  # MCP (Model Context Protocol) integration\n  tools = list_mcp_tools :get_tools, server_name: 'my_mcp_server'\n  \n  call_mcp_tool :use_tool,\n    server_name: 'my_mcp_server',\n    tool_name: 'search_documents',\n    arguments: { query: wf[:query] }\n\n  output answer: response[:content]\nend\n```\n\n### Output References\n\nThe DSL uses a clean syntax for referencing outputs:\n\n```ruby\n# Workflow input reference\nwf[:user_id]              # =\u003e '${workflow.input.user_id}'\n\n# Task output reference\ntask[:field]              # =\u003e '${task_ref.output.field}'\ntask[:nested][:path]      # =\u003e '${task_ref.output.nested.path}'\n\n# Loop iteration references (inside loop_over)\niteration[:current_item]  # Current item being processed\niteration[:index]         # Current index (0-based)\niteration[:user][:name]   # If `as: :user` specified\n```\n\n## Examples\n\nThe `examples/` directory contains comprehensive examples:\n\n| Example | Description |\n|---------|-------------|\n| [`helloworld/`](examples/helloworld/) | Simplest complete example - worker + workflow + execution |\n| [`workflow_dsl.rb`](examples/workflow_dsl.rb) | Comprehensive new DSL showcase |\n| [`simple_worker.rb`](examples/simple_worker.rb) | Worker patterns: class-based, block-based, error handling |\n| [`kitchensink.rb`](examples/kitchensink.rb) | All major task types using new DSL |\n| [`dynamic_workflow.rb`](examples/dynamic_workflow.rb) | Create and execute workflows at runtime |\n| [`workflow_ops.rb`](examples/workflow_ops.rb) | Lifecycle operations: pause, resume, restart, retry |\n| [`agentic_workflows/`](examples/agentic_workflows/) | LLM chat and AI workflow examples |\n\nRun examples:\n\n```bash\n# Set environment variables\nexport CONDUCTOR_SERVER_URL=http://localhost:8080/api\n# For Orkes Cloud:\n# export CONDUCTOR_AUTH_KEY=your_key\n# export CONDUCTOR_AUTH_SECRET=your_secret\n\n# Run hello world\ncd examples/helloworld \u0026\u0026 bundle exec ruby helloworld.rb\n\n# Run DSL showcase\nbundle exec ruby examples/workflow_dsl.rb\n\n# Run kitchen sink\nbundle exec ruby examples/kitchensink.rb\n```\n\n## Worker Framework\n\n### Class-Based Workers\n\n```ruby\nclass ImageProcessor\n  include Conductor::Worker::WorkerModule\n\n  worker_task 'process_image', poll_interval: 1, thread_count: 4\n\n  def execute(task)\n    url = get_input(task, 'image_url')\n    # Process image...\n    \n    result = Conductor::Http::Models::TaskResult.complete\n    result.add_output_data('processed_url', processed_url)\n    result.log('Image processed successfully')\n    result\n  end\nend\n```\n\n### Block-Based Workers\n\n```ruby\nworker = Conductor::Worker.define('simple_task') do |task|\n  input = task.input_data['value']\n  { result: input * 2 }  # Return hash for automatic TaskResult\nend\n```\n\n### Running Workers\n\n```ruby\nrunner = Conductor::Worker::TaskRunner.new(config)\nrunner.register_worker(ImageProcessor.new)\nrunner.register_worker(worker)\nrunner.start(threads: 4)\n\n# Graceful shutdown\ntrap('INT') { runner.stop }\nsleep while runner.running?\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\nexport CONDUCTOR_SERVER_URL=http://localhost:8080/api\nexport CONDUCTOR_AUTH_KEY=your_key        # For Orkes Cloud\nexport CONDUCTOR_AUTH_SECRET=your_secret  # For Orkes Cloud\n```\n\n### Programmatic\n\n```ruby\nconfig = Conductor::Configuration.new(\n  server_api_url: 'https://play.orkes.io/api',\n  auth_key: 'your_key',\n  auth_secret: 'your_secret',\n  auth_token_ttl_min: 45,\n  verify_ssl: true\n)\n```\n\n## API Coverage\n\n### Resource APIs (17 classes)\n\n| API | Description |\n|-----|-------------|\n| WorkflowResourceApi | Workflow execution and management |\n| TaskResourceApi | Task polling and updates |\n| MetadataResourceApi | Workflow/task definitions |\n| SchedulerResourceApi | Scheduled workflows |\n| EventResourceApi | Event handlers |\n| WorkflowBulkResourceApi | Bulk operations |\n| PromptResourceApi | AI prompt templates |\n| SecretResourceApi | Secret management |\n| IntegrationResourceApi | External integrations |\n| + 8 more | Authorization, Users, Groups, Roles, etc. |\n\n### High-Level Clients (9 classes)\n\n```ruby\nclients = Conductor::Orkes::OrkesClients.new(config)\n\nworkflow_client = clients.get_workflow_client\ntask_client = clients.get_task_client\nmetadata_client = clients.get_metadata_client\nscheduler_client = clients.get_scheduler_client\nprompt_client = clients.get_prompt_client\nsecret_client = clients.get_secret_client\nauthorization_client = clients.get_authorization_client\nworkflow_executor = clients.get_workflow_executor\n```\n\n## Testing\n\n```bash\n# Unit tests\nbundle exec rspec spec/conductor/\n\n# Integration tests (requires Conductor server)\nCONDUCTOR_SERVER_URL=http://localhost:8080/api bundle exec rspec spec/integration/\n```\n\n## Requirements\n\n- Ruby 2.6+ (Ruby 3+ recommended)\n- Conductor OSS 3.x or Orkes Cloud\n\n## Dependencies\n\n- `faraday ~\u003e 2.0` - HTTP client\n- `faraday-net_http_persistent ~\u003e 2.0` - Connection pooling\n- `faraday-retry ~\u003e 2.0` - Automatic retries\n- `concurrent-ruby ~\u003e 1.2` - Thread-safe concurrency\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Run tests (`bundle exec rspec`)\n4. Commit your changes (`git commit -m 'Add amazing feature'`)\n5. Push to the branch (`git push origin feature/amazing-feature`)\n6. Open a Pull Request\n\n## License\n\nApache 2.0 - see [LICENSE](LICENSE) for details.\n\n## Links\n\n- [Conductor OSS](https://github.com/conductor-oss/conductor)\n- [Orkes Cloud](https://orkes.io)\n- [Documentation](https://conductor-oss.org)\n- [Python SDK](https://github.com/conductor-sdk/conductor-python)\n- [Community Slack](https://join.slack.com/t/orkes-conductor/shared_invite/zt-2vdbx239s-Eacdyqya9giNLHfrCavfaA)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconductor-oss%2Fruby-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconductor-oss%2Fruby-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconductor-oss%2Fruby-sdk/lists"}