Kailash for Ruby

Ruby License Tests

High-performance workflow automation SDK for Ruby, powered by a compiled Rust engine. Build, validate, and execute workflow DAGs with 139 built-in node types, custom Ruby callback nodes, enterprise RBAC/ABAC authorization, an AI agent framework, database modeling, and multi-channel deployment -- all from idiomatic Ruby.

Key Features

  • 139 built-in workflow nodes -- HTTP, SQL, file I/O, AI/LLM, authentication, security, monitoring, edge computing, RAG pipelines, and more
  • Custom Ruby callback nodes -- register any lambda, Proc, or callable object as a first-class workflow node
  • GVL release during execution -- the Rust runtime releases Ruby's Global VM Lock, enabling true concurrent workflow execution across threads
  • Kaizen AI agent framework -- 42+ classes covering agents, LLM clients, orchestration, cost tracking, vision/audio processing, structured output, and agent-to-agent communication
  • Enterprise features -- RBAC with hierarchical roles, ABAC with 16 operators, audit trails, multi-tenancy isolation, compliance reporting
  • Nexus multi-channel deployment -- server configuration, JWT authentication, middleware presets, MCP protocol, workflow registries
  • DataFlow database framework -- model definitions, field types, query dialects, tenant-scoped query interception, migrations, schema caching
  • Thread-safe design -- all core objects are safe to share across threads, with block-based resource management (Registry.open, Runtime.open) that guarantees cleanup

Installation

The gem is not yet published to RubyGems. Install from source.

Prerequisites

  • Ruby >= 3.2
  • Rust toolchain (stable, 1.70+)
  • Bundler

Building from Source

git clone https://github.com/kailash/kailash.git
cd kailash/bindings/kailash-ruby
bundle install
rake compile

On macOS, the build script handles code signing automatically. The compiled native extension (.bundle) is placed in lib/kailash/.

Quick Start

Basic Workflow

require "kailash"

# Block-based API auto-closes resources on exit
Kailash::Registry.open do |registry|
  # Build a workflow DAG
  builder = Kailash::WorkflowBuilder.new
  builder.add_node("NoOpNode", "step1", {})
  builder.add_node("NoOpNode", "step2", {})
  builder.connect("step1", "output", "step2", "input")
  workflow = builder.build(registry)

  # Execute the workflow
  Kailash::Runtime.open(registry) do |runtime|
    result = runtime.execute(workflow, { "data" => "hello" })
    puts result.run_id                    # => "a3f1b2c4-..."
    puts result.results["step1"]["data"]  # => "hello"
  end

  workflow.close
end

Custom Callback Node

Register Ruby lambdas, Procs, or any object responding to #call as workflow nodes:

Kailash::Registry.open do |registry|
  # Register a lambda as a custom node type
  uppercase = ->(inputs) { { "result" => inputs["text"].upcase } }
  registry.register_callback("UppercaseNode", uppercase, ["text"], ["result"])

  # Use it in a workflow alongside built-in nodes
  builder = Kailash::WorkflowBuilder.new
  builder.add_node("UppercaseNode", "transform", {})
  workflow = builder.build(registry)

  Kailash::Runtime.open(registry) do |runtime|
    result = runtime.execute(workflow, { "text" => "hello world" })
    puts result.results["transform"]["result"]  # => "HELLO WORLD"
  end

  workflow.close
end

Callback nodes support any callable -- lambdas, Procs, and objects with a #call method. They can return complex nested data structures (hashes, arrays, numbers, booleans, nil) and are fully thread-safe.

AI Agent with LlmClient

# Configure an agent
config = Kailash::Kaizen::AgentConfig.new
config.set_model("gpt-4")
config.set_system_prompt("You are a helpful assistant.")
config.set_temperature(0.7)
config.set_max_iterations(10)

# Create an LLM client and agent
client = Kailash::Kaizen::LlmClient.new("openai")
agent = Kailash::Kaizen::Agent.new(config, client)

# Run the agent
result = agent.run("What is the capital of France?")
puts result["response"]
puts result["iterations"]
puts result["total_tokens"]

Multi-Agent Orchestration

Orchestration topology (agents, strategy, routes, dependencies) can be configured today, but execution is not yet available in the Ruby binding. #run / #orchestrate raise Kailash::ExecutionError because real agent execution requires a Rust-side BaseAgent adapter that a Ruby callable cannot implement (tracked by #1685). For real single-agent LLM egress today, use Kailash::Kaizen::Agent (shown above).

ort = Kailash::Kaizen::OrchestrationRuntime.new("sequential")
ort.add_agent("researcher")
ort.add_agent("writer")
ort.set_max_iterations(50)

# Configuration is available now:
puts ort.strategy      # => "sequential"
puts ort.agent_count   # => 2

# Execution raises until real orchestration is wired (#1685):
begin
  ort.run("Research and write about AI safety")
rescue Kailash::ExecutionError => e
  warn e.message       # "OrchestrationRuntime#run is not supported in the Ruby binding: ..."
end
ort.close

RBAC Authorization

# Define roles and permissions
read_perm  = Kailash::Enterprise::Permission.new("documents", "read")
write_perm = Kailash::Enterprise::Permission.new("documents", "write")

editor = Kailash::Enterprise::Role.new("editor")
editor.add_permission(read_perm)
editor.add_permission(write_perm)

# Evaluate access
evaluator = Kailash::Enterprise::RbacEvaluator.new
evaluator.add_role(editor)

user = Kailash::Enterprise::User.new("alice")
user.add_role("editor")

result = evaluator.check(user, "documents", "read")
puts result[:allowed]  # => true

# Explain access decisions
explanation = evaluator.explain(user, "documents", "write")
puts explanation[:reason]

DataFlow: Database Model Definition

model = Kailash::DataFlow::ModelDefinition.new("User", "users")
model.field("id", "integer", primary_key: true)
model.field("email", "text", required: true, unique: true)
model.field("name", "text", required: true)
model.field("active", "boolean")
model.auto_timestamps

puts model.primary_key    # => "id"
puts model.fields.length  # => 6 (including created_at, updated_at)
model.close

Block-Based Resource Management

All resource-owning objects support explicit close and idempotent cleanup. Core objects also provide block-based constructors:

# Registry.open and Runtime.open guarantee cleanup
Kailash::Registry.open do |registry|
  Kailash::Runtime.open(registry) do |runtime|
    # resources are automatically closed when the block exits,
    # even if an exception is raised
  end
end

# Manual lifecycle management
registry = Kailash::Registry.new
runtime  = Kailash::Runtime.new(registry)
# ... use registry and runtime ...
runtime.close
registry.close

API Overview

Core (Kailash::)

Class Description
Registry Node type registry (139+ built-in types), .open
WorkflowBuilder DAG builder with add_node and connect
Workflow Immutable validated workflow (from builder.build)
Runtime Workflow execution engine, .open
RuntimeConfig Execution settings (concurrency, timeouts, debug)
ExecutionResult Execution output with results hash and run_id

Error hierarchy (all inherit from Kailash::Error < StandardError):

Class Raised when
BuildError Workflow validation fails (empty, bad connection)
ExecutionError Node execution fails at runtime
NodeError Node-level error
ConfigError Invalid configuration value
ValueError Unsupported Ruby type in value conversion

Kaizen -- AI Agent Framework (Kailash::Kaizen::)

Class Description
Agent Core AI agent with TAOD loop and #run
AgentConfig Agent configuration (model, temperature, tokens)
LlmClient LLM provider client (openai, anthropic, mock)
CostTracker Token usage and cost tracking
ToolDef / ToolParam Tool definitions with typed parameters
ToolRegistry Tool registration and lookup
SessionMemory Key-value session memory with store/recall
AgentCard / AgentRegistry Agent-to-agent discovery
OrchestrationRuntime Multi-agent orchestration (sequential/parallel)
MultiAgentOrchestrator Advanced orchestration with routes and dependencies
SupervisorAgent Supervisor-worker delegation pattern
WorkerAgent Worker with capabilities and progress tracking
StreamingAgent Streaming-capable agent
AgentExecutor Agent execution with timeout and retries
StructuredOutput JSON parsing with retry
OutputSchema JSON schema validation
VisionProcessor Image analysis (single, batch, file)
AudioProcessor Audio transcription with timestamps
MultimodalOrchestrator Multi-modal processing (text + vision + audio)
EatpPosture EATP v0.8.0 trust posture levels
HumanCompetency CARE framework human competency categories
RetryConfig / RetryPolicy Retry configuration with backoff strategies
A2AProtocol Agent-to-agent communication protocol
InMemoryMessageBus In-memory pub/sub message bus
AgentCheckpoint Agent state checkpoint/resume

Execution not yet available in the Ruby binding (#1685). The orchestration and multimodal execution methods — StreamingAgent#run, OrchestrationRuntime#run, MultiAgentOrchestrator#orchestrate, SupervisorAgent#run, WorkerAgent#run, AgentExecutor#execute_single, VisionProcessor#analyze/#analyze_batch/#analyze_file, AudioProcessor#transcribe/#transcribe_with_timestamps/#transcribe_file, and MultimodalOrchestrator#process — raise Kailash::ExecutionError rather than returning fabricated data. Real execution is not wired in the Ruby binding yet (each method's error message names its specific requirement — e.g. a BaseAgent adapter or an LlmClient-backed processor a Ruby callable cannot provide). Their configuration and getter methods work today. For real single-agent LLM egress, use Agent (and TaodRunner for the TAOD loop).

Enterprise (Kailash::Enterprise::)

Class Description
Permission RBAC permission (resource + action, wildcards)
Role / RoleBuilder Named role with permissions
User User with role assignments
RbacEvaluator RBAC permission evaluator with check and explain
RbacPolicy / RbacPolicyBuilder RBAC policy definitions
AbacPolicy Attribute-based access control policy
AbacEvaluator ABAC evaluator (first_applicable, deny_override)
PolicyEngine Combined policy evaluation engine
AuditEvent Structured audit event with UUID and timestamp
AuditLogger / AuditFilter Audit logging with filtering
TenantContext / TenantInfo Tenant metadata and context propagation
TenantRegistry Tenant registration and lookup
TenantStatus Tenant lifecycle (active, suspended, archived)
EnterpriseTenantContext Tenant isolation enforcement
EnterpriseContext Combined tenant + user context with roles
AccessDecision Access decision with reason
SecurityClassification Data classification (public, internal, confidential, secret)
SSOProvider SSO provider configuration (OIDC, SAML)
TokenManager Token lifecycle management
CompetencyRequirement Human competency requirement levels
ComplianceReport / ComplianceManager Compliance reporting

Nexus -- Multi-Channel Deployment (Kailash::Nexus::)

Class Description
NexusConfig Server configuration (host, port, channels)
NexusApp Application server with health checks
Preset Middleware preset (none, lightweight, standard, saas, enterprise)
HandlerParam Handler parameter definition (name, type, required)
JwtConfig JWT authentication (secret, expiry, issuer)
JwtClaims JWT token claims builder
RbacConfig Route-level RBAC (roles, permissions, routes)
MiddlewareConfig Middleware stack from preset
AuthRateLimitConfig Rate limiting (authenticated, anonymous, burst)
McpServer MCP protocol server (stdio, SSE, HTTP transports)
PluginManager Plugin lifecycle management
EventBus Event pub/sub bus
WorkflowRegistry Named workflow registration and lookup

DataFlow -- Database Framework (Kailash::DataFlow::)

Class Description
DataFlow Main entry point (register models, set tenant)
Config Database connection (URL, pool size, auto-migrate)
ModelDefinition Model builder (fields, primary key, timestamps)
FieldType / FieldDef Field type enums and definitions
FilterCondition Query filter (eq, ne, gt, gte, lt, lte, like, null)
QueryDialect SQL dialect (sqlite, postgres, mysql) with auto-detect
TenantContext Multi-tenancy context for query isolation
QueryInterceptor Automatic tenant-scoped query rewriting
DataFlowTransaction Transaction with commit/rollback
DataFlowExpress Express mode for rapid model registration
DataFlowInspector Schema inspection
Migration / MigrationManager Database migration management
SchemaCache In-memory schema caching
ValidationLayer Field validation: rules, named validators, validate
StrictMode Settings object only — see the note below
LoggingConfig Query logging (level, format, slow query threshold)
ErrorEnhancer Enhanced error context (query, params, stack)
DebugAgent Query debugging

ValidationLayer is backed by kailash_dataflow::validation::ValidationLayer (crates/kailash-dataflow/src/validation.rs:729-918). Register rules per model and field, then get the violations back:

layer = Kailash::DataFlow::ValidationLayer.new
layer.add_rule("User", "name", "min_length", 2)          # min_length, max_length,
layer.add_rule("User", "status", "one_of", %w[active])   # pattern, range, one_of
layer.add_validator("User", "email", "email")            # email, url, uuid, phone
layer.add_custom_rule("User", "code") { |v| v.start_with?("K") }

layer.validate("User", { "name" => "A" })
# => [{ "field" => "name", "rule" => "min_length", "message" => "...", "value" => "A" }]
layer.valid?("User", { "name" => "Alice" })  # => true

Rules fail CLOSED: a rule applied to a value whose type it cannot evaluate, and a custom block that raises or returns a non-boolean, both report a violation rather than a pass (crates/kailash-dataflow/src/validation.rs:257-268). The enable_strict_mode / strict_mode? / one-argument add_validator(name) / zero-argument validator_count accessors are deprecated as of #2497 and removed in 5.0.0; each warns that it reaches no validation. The replacements and the operator checklist are in DEPRECATION.md.

StrictMode holds three boolean settings and nothing reads them: the Ruby binding does not reference kailash_dataflow::strict, and the class registers no method that takes data or returns a verdict (bindings/kailash-ruby/ext/kailash/src/dataflow.rs:2571-2580 for the state, :4544-4571 for the registered methods). Tracked as #2587; the Python binding already wires the same Rust surface.

Value Conversion

Ruby values are automatically converted to the Rust Value type and back:

Ruby type Rust Value Notes
String (UTF-8) String Preserves Unicode
String (ASCII-8BIT) Bytes Binary data round-trips correctly
Integer Integer 64-bit signed
Float Float 64-bit IEEE 754
true / false Bool
nil Null
Array Array Recursive, mixed types supported
Hash Object String keys; symbol keys auto-converted
Symbol (as key) String Converted via to_s

Unsupported types (Object, Regexp, Range, Proc) raise Kailash::ValueError. Nesting depth is limited to 64 levels.

Thread Safety

The Kailash Ruby binding is designed for concurrent use:

  • GVL release -- Runtime#execute releases the Global VM Lock before entering the Rust runtime, allowing other Ruby threads to run concurrently while workflows execute.
  • Shared runtime -- a single Runtime instance can be safely shared across multiple threads, with each thread building and executing its own workflows.
  • Thread-safe close -- close is idempotent and safe to call from multiple threads simultaneously.
  • Framework objects -- Kaizen, Enterprise, Nexus, and DataFlow types are all safe for concurrent access from multiple threads.
Kailash::Registry.open do |registry|
  Kailash::Runtime.open(registry) do |runtime|
    threads = 8.times.map do |i|
      Thread.new do
        builder = Kailash::WorkflowBuilder.new
        builder.add_node("NoOpNode", "worker_#{i}", {})
        wf = builder.build(registry)
        result = runtime.execute(wf, { "index" => i })
        puts "Thread #{i}: #{result.results["worker_#{i}"]["index"]}"
        wf.close
      end
    end
    threads.each(&:join)
  end
end

Known Limitation: No Ruby Thread Interrupts During Execution

When Runtime#execute or Agent#run releases the GVL to run Rust code, the current Ruby thread cannot be interrupted by Thread#kill, Thread#raise, or Timeout.timeout. Ruby's signal delivery and thread interruption require the GVL, and the Rust runtime does not currently register an unblocking function (UBF) with Ruby's threading subsystem.

Impact: Timeout.timeout(5) { runtime.execute(workflow, inputs) } will not interrupt the Rust execution. The timeout fires only after the Rust call completes and the GVL is reacquired.

Workaround: Use RuntimeConfig timeout settings, which are enforced inside the Rust runtime:

config = Kailash::RuntimeConfig.new
config.workflow_timeout = 5   # overall workflow deadline (seconds)
config.node_timeout = 3       # per-node deadline (seconds)
runtime = Kailash::Runtime.new(registry, config)

Building from Source

Full Build Steps

cd bindings/kailash-ruby

# Install Ruby dependencies
bundle install

# Compile the native extension (builds Rust code via cargo)
rake compile

# On macOS, sign the compiled bundle for notarization
codesign --sign - --force lib/kailash/kailash.bundle

Development Workflow

# Rebuild after Rust changes
rake compile

# Run the full test suite
bundle exec rspec

# Run a specific spec file
bundle exec rspec spec/callback_node_spec.rb

# Run with verbose output
bundle exec rspec --format documentation

Testing

The test suite covers core workflow execution, all four frameworks, custom callback nodes, value round-trips, GVL release behavior, thread safety, and memory safety.

bundle exec rspec

1,092 tests, 0 failures across 14 spec files:

Spec file Coverage
registry_spec.rb Node type registry, .open block API
builder_workflow_spec.rb WorkflowBuilder, Workflow introspection
runtime_spec.rb Runtime, RuntimeConfig, ExecutionResult, .open
callback_node_spec.rb Custom lambda/Proc/callable nodes, errors
value_spec.rb Value round-trips (all types, nesting, binary)
gvl_release_spec.rb Concurrent execution, GVL release verification
thread_safety_spec.rb Concurrent registry/runtime/framework access
memory_spec.rb Close semantics, error hierarchy, GC pressure
node_parity_spec.rb 139-node parity with Python binding
kaizen_spec.rb AI agent config, tools, memory, trust postures
kaizen_execution_spec.rb Agent.run, orchestration, vision, audio
enterprise_spec.rb RBAC, ABAC, audit, tenancy, compliance
nexus_spec.rb Server config, JWT, MCP, workflow registry
dataflow_spec.rb Models, filters, dialects, transactions

Platform Support

Platform Architecture Status
macOS arm64 (Apple Silicon) Supported
Linux x86_64 CI validated

Windows support is not yet available.

License

Proprietary. This is a compiled native extension -- no Rust source code is included in the gem. All .rs source files are trade secret and excluded from distribution. See the Kailash SDK license agreement for terms.