Class: SwarmSDK::Swarm::Builder

Inherits:
Builders::BaseBuilder show all
Defined in:
lib/swarm_sdk/swarm/builder.rb

Overview

Builder provides a beautiful Ruby DSL for building swarms

The DSL combines YAML simplicity with Ruby power, enabling:

  • Fluent, chainable configuration
  • Hooks as Ruby blocks OR shell commands
  • Full Ruby language features (variables, conditionals, loops)
  • Type-safe, IDE-friendly API

Examples:

Basic usage

swarm = SwarmSDK.build do
  name "Dev Team"
  lead :backend

  agent :backend do
    model "gpt-5"
    prompt "You build APIs"
    tools :Read, :Write, :Bash

    # Hook as Ruby block - inline logic!
    hook :pre_tool_use, matcher: "Bash" do |ctx|
      SwarmSDK::Hooks::Result.halt("Blocked!") if ctx.tool_call.parameters[:command].include?("rm -rf")
    end
  end
end

swarm.execute("Build auth API")

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Builders::BaseBuilder

#agent, #all_agents, #id, #name, #scratchpad, #swarms

Constructor Details

#initialize(allow_filesystem_tools: nil) ⇒ Builder



47
48
49
50
51
52
53
# File 'lib/swarm_sdk/swarm/builder.rb', line 47

def initialize(allow_filesystem_tools: nil)
  super
  @lead_agent = nil
  @swarm_hooks = []
  @observer_configs = []
  @execution_timeout = nil
end

Class Method Details

.build(allow_filesystem_tools: nil, &block) ⇒ Object



40
41
42
43
44
# File 'lib/swarm_sdk/swarm/builder.rb', line 40

def build(allow_filesystem_tools: nil, &block)
  builder = new(allow_filesystem_tools: allow_filesystem_tools)
  builder.instance_eval(&block)
  builder.build_swarm
end

Instance Method Details

#build_swarmObject

Build the actual Swarm instance

Raises:



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/swarm_sdk/swarm/builder.rb', line 122

def build_swarm
  raise ConfigurationError, "Swarm name not set. Use: name 'My Swarm'" unless @swarm_name
  raise ConfigurationError, "No agents defined. Use: agent :name { ... }" if @agents.empty?
  raise ConfigurationError, "Lead agent not set. Use: lead :agent_name" unless @lead_agent

  # Validate filesystem tools BEFORE building
  validate_all_agents_filesystem_tools if @all_agents_config
  validate_agent_filesystem_tools

  build_single_swarm
end

#execution_timeout(seconds) ⇒ Object

Set execution timeout (seconds)



56
57
58
# File 'lib/swarm_sdk/swarm/builder.rb', line 56

def execution_timeout(seconds)
  @execution_timeout = seconds
end

#hook(event, command: nil, timeout: nil, &block) ⇒ Object

Add swarm-level hook (swarm_start, swarm_stop only)

Examples:

Shell command

hook :swarm_start, command: "echo 'Starting' >> log.txt"

Ruby block

hook :swarm_start do |ctx|
  puts "Swarm starting: #{ctx.metadata[:prompt]}"
end


112
113
114
115
116
117
118
119
# File 'lib/swarm_sdk/swarm/builder.rb', line 112

def hook(event, command: nil, timeout: nil, &block)
  # Validate swarm-level events
  unless [:swarm_start, :swarm_stop].include?(event)
    raise ArgumentError, "Invalid swarm-level hook: #{event}. Only :swarm_start and :swarm_stop allowed at swarm level. Use all_agents { hook ... } or agent { hook ... } for other events."
  end

  @swarm_hooks << { event: event, command: command, timeout: timeout, block: block }
end

#lead(agent_name) ⇒ Object

Set lead agent



61
62
63
# File 'lib/swarm_sdk/swarm/builder.rb', line 61

def lead(agent_name)
  @lead_agent = agent_name
end

#observer(agent_name, **options) { ... } ⇒ Object

Define observer agent behavior

Configures an agent to run in parallel with main execution, triggered by specific events. The block defines event handlers.

Examples:

Basic observer

observer :profiler do
  on :swarm_start do |event|
    "Analyze this prompt: #{event[:prompt]}"
  end
end

Observer with options

observer :monitor, timeout: 120 do
  on :tool_call do |event|
    next unless event[:tool_name] == "Bash"
    "Check command: #{event[:arguments][:command]}"
  end
end

Yields:

  • Observer configuration block



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/swarm_sdk/swarm/builder.rb', line 88

def observer(agent_name, **options, &block)
  unless @agents.key?(agent_name)
    raise ConfigurationError,
      "Observer agent '#{agent_name}' not defined. " \
        "Define the agent first with `agent :#{agent_name} do ... end`"
  end

  config = Observer::Config.new(agent_name)
  config.options.merge!(options) if options.any?
  builder = Observer::Builder.new(agent_name, config)
  builder.instance_eval(&block)

  @observer_configs << config
end