RODEO

Scene Builder

Fluent API for composing scenes

const builder = rodeo.scenes.build();

All methods return this for chaining except create().

intention(id)

builder.intention("intention-uuid")

audience(id)

builder.audience("audience-uuid")

arc(type)

builder.arc("approach")
// "approach" | "surround" | "crescendo" | "slow_burn" | "single_strike" | "siege" | "gift"

constraints(c)

builder.constraints({
  maxDuration: "4h",
  maxBeats: 6,
  budget: 100,
})

pacing(p)

builder.pacing({ interval: "30m" })

beat(b)

Call multiple times for multiple beats.

builder
  .beat({
    sequence: 1,
    channel_id: "uuid",
    content: { body: "First message" },
    tone: { warmth: "warm", urgency: "none", ask: "implicit" },
    timing: { mode: "absolute", at: "2025-01-15T08:00:00Z" },
  })
  .beat({
    sequence: 2,
    channel_id: "uuid",
    content: { body: "Follow up" },
    tone: { warmth: "warm", urgency: "gentle", ask: "soft" },
    timing: { mode: "relative", after: "30m", anchor: "beat:1" },
  })

rule(r)

Call multiple times for multiple rules.

builder
  .rule({
    condition: { type: "response", metric: "replied", sentiment: "positive" },
    action: "accelerate",
    params: { factor: 2 },
  })
  .rule({
    condition: { type: "sentiment", metric: "hostile" },
    action: "terminate",
  })

Signal handlers

builder
  .onDecline("terminate")
  .onPositive("continue")
  .onNeutral("continue")
  .onNegative("decelerate")

create()

Submits the scene. Returns a promise.

const result = await builder.create();
// result.scene (status: "draft"), result.beats

Full example

const result = await rodeo.scenes
  .build()
  .intention(intention.id)
  .audience(audience.id)
  .arc("surround")
  .constraints({ maxBeats: 4, maxDuration: "2h", budget: 50 })
  .onDecline("terminate")
  .onPositive("accelerate")
  .onNegative("decelerate")
  .rule({
    condition: { type: "response", metric: "replied", sentiment: "positive" },
    action: "accelerate",
    params: { factor: 2 },
  })
  .beat({
    sequence: 1,
    channel_id: sms.id,
    content: { body: "Hey — heard you're the best." },
    tone: { warmth: "warm", urgency: "none", ask: "implicit" },
    timing: { mode: "absolute", at: "2025-01-15T08:00:00Z" },
  })
  .beat({
    sequence: 2,
    channel_id: email.id,
    content: { subject: "Opportunity", body: "Full details..." },
    tone: { warmth: "warm", urgency: "gentle", ask: "soft" },
    timing: { mode: "relative", after: "40m", anchor: "beat:1" },
  })
  .beat({
    sequence: 3,
    channel_id: referral.id,
    content: { brief: "Mention us naturally" },
    tone: { warmth: "familiar", urgency: "none", ask: "none" },
    timing: { mode: "relative", after: "4m", anchor: "beat:2" },
  })
  .beat({
    sequence: 4,
    channel_id: phone.id,
    content: { script: "Closing call" },
    tone: { warmth: "familiar", urgency: "present", ask: "direct" },
    timing: { mode: "relative", after: "6m", anchor: "beat:3" },
  })
  .create();

await rodeo.scenes.declare(result.scene.id);