Audiences
Target profiles with context, rhythm, and contact bounds
An audience is who a scene targets — an individual, a role type, or a cohort.
Types
| Type | Description | Example |
|---|---|---|
individual | Specific person | "Jordan, mobile butcher in TX Hill Country" |
role | Type of person | "Mobile butchers in central Texas" |
cohort | Shared characteristics | "Lapsed subscribers from Q3" |
Context
Freeform JSON describing the target:
context: {
name: "Jordan",
role: "mobile butcher",
region: "TX-Hill-Country",
timezone: "America/Chicago",
notes: "Prefers early morning. Works weekends.",
}Informs beat composition and timing; not system-enforced.
Rhythm
rhythm: {
preferredTimes: ["08:00-10:00", "17:00-19:00"],
preferredDays: ["mon", "tue", "wed", "thu", "fri"],
timezone: "America/Chicago",
}Bounds
Hard limits enforced by the membrane. Violations produce bounds_blocked status.
bounds: {
maxBeatsPerDay: 3,
maxBeatsPerWeek: 8,
cooldownMinutes: 60,
}State
| Field | Description |
|---|---|
lastContacted | Last beat fired |
beatsToday | Beats fired today |
beatsThisWeek | Beats fired this week |
cooldownUntil | Earliest next beat |
declined | Explicit decline flag |
signals | Accumulated sensor signals |
Auto-initialized on creation, updated as beats fire.
Enforcement
The membrane checks before every beat:
declinedtrue? Block beat, terminate scenecooldownUntilin future? Block beatbeatsToday >= maxBeatsPerDay? Block beatbeatsThisWeek >= maxBeatsPerWeek? Block beat
Blocked beats trigger the scene's onBoundsExceeded handler.
Usage
const audience = await rodeo.audiences.create({
type: "individual",
identity: { externalId: "butcher-042" },
context: { name: "Jordan", role: "mobile butcher", region: "TX-Hill-Country" },
bounds: { maxBeatsPerDay: 3, maxBeatsPerWeek: 8, cooldownMinutes: 60 },
rhythm: { preferredTimes: ["08:00-10:00"], timezone: "America/Chicago" },
});