Recipe: live channels (resolve by name, read status, start/stop safely)
Recipe: live channels (resolve by name, read status, start/stop safely)
Recipe: live channels (resolve by name, read status, start/stop safely)
Prompt exampleFind the live channel named "Studio A", show its status, start it and wait until it's running, then stop it.
Vibe prompts name a channel by name ("Studio A") but every lifecycle verb takes a
<live-channel-id>. These helpers resolve the id, read status via the status name the
platform returns, and drive the start/stop lifecycle. Reads are Class A (safe anywhere);
start/stop are Class C — they allocate real, billable streaming infrastructure and have
no folder anchor, so they run non-prod only and must always be paired.
Key facts
get_live_channelsreturns a plain array of channel objects (not{items}). Resolve bychannel["name"].- A channel's status is nested:
channel["status"]["description"]is the status name ("Idle","Running","Starting","Stopping","Error", …) andchannel["status"]["id"]is aLiveChannelStatusLookupUUID. Seereference/enums.mdfor the full status/type tables (ints, names, and lookup UUIDs). - Status verb: Python keeps
get_live_channel_statusinternal, so derive status from the channel object (as below). JS exposesgetLiveChannelStatus(id)publicly. start_live_channel(id, wait_for_start=True)blocks until Running (≤1200s @20s);stop_live_channel(id, wait_for_stop=True)blocks until Idle (≤720s @2s). Passwait=Falseto fire-and-poll yourself.
Python
# components: get_live_channels, get_live_channel, start_live_channel, stop_live_channel
RUNNING, IDLE = "Running", "Idle" # LiveChannelStatus names; see reference/enums.md
def resolve_channel_id(sdk, name):
"""Resolve a live channel by exact name to its id; None if absent.
Raises on ambiguity (two channels sharing a name) — fail-closed, never guess.
"""
matches = [c["id"] for c in (get_live_channels(sdk) or []) if c.get("name") == name]
unique = list(dict.fromkeys(matches))
if len(unique) > 1:
raise ValueError(f"Ambiguous live channel name {name!r}: {len(unique)} matches")
return unique[0] if unique else None
def channel_status(sdk, channel_id):
"""Current status NAME ('Idle'/'Running'/...) for channel_id, or None.
Python has no public status verb, so read it off the channel object exactly as
the SDK's internal helper does: channel['status']['description'].
"""
channel = get_live_channel(sdk, channel_id)
return ((channel or {}).get("status") or {}).get("description")
def start_and_confirm(sdk, channel_id):
"""Start the channel, blocking until Running. CLASS C — non-prod only."""
start_live_channel(sdk, channel_id, True) # waits for Running
assert channel_status(sdk, channel_id) == RUNNING
return RUNNING
def stop_and_confirm(sdk, channel_id):
"""Stop the channel, blocking until Idle. Always run this after start_and_confirm."""
stop_live_channel(sdk, channel_id, True) # waits for Idle
assert channel_status(sdk, channel_id) == IDLE
return IDLEJavaScript
// components: getLiveChannels, getLiveChannel, startLiveChannel, stopLiveChannel
const RUNNING = "Running", IDLE = "Idle"; // LiveChannelStatus names; see reference/enums.md
export async function resolveChannelId(sdk, name) {
const matches = ((await getLiveChannels(sdk)) || [])
.filter((c) => c.name === name).map((c) => c.id);
const unique = [...new Set(matches)];
if (unique.length > 1) throw new Error(`Ambiguous live channel name '${name}': ${unique.length} matches`);
return unique.length ? unique[0] : null;
}
export async function channelStatus(sdk, channelId) {
// JS also exposes sdk.getLiveChannelStatus(channelId) directly; this mirrors Python.
const channel = await getLiveChannel(sdk, channelId);
return channel?.status?.description ?? null;
}
export async function startAndConfirm(sdk, channelId) {
// CLASS C — non-prod only.
await startLiveChannel(sdk, channelId, true); // waits for Running
if ((await channelStatus(sdk, channelId)) !== RUNNING) throw new Error("channel not Running");
return RUNNING;
}
export async function stopAndConfirm(sdk, channelId) {
await stopLiveChannel(sdk, channelId, true); // waits for Idle
if ((await channelStatus(sdk, channelId)) !== IDLE) throw new Error("channel not Idle");
return IDLE;
}Notes
- Always pair start with stop. There is no run-root cascade for live channels, so the
only cleanup is an explicit
stop_*. Wrap start/stop in try/finally so a started channel is stopped even if an assertion fails. - Prerequisites to start. A channel generally needs an attached input (and, for some
types, ≥2 schedule events) or it bounces back to
Idle/Error. Inspectchannel["associatedInputs"]/get_live_inputsfirst; readchannel["statusMessage"]on failure. - Stale status? Call
live_channel_refresh(Class B) to resync from infrastructure, then re-readget_live_channels. - Channel type lives at
channel["type"](a lookup); map ints/UUIDs via theLiveChannelType/LiveChannelTypeLookuptables inreference/enums.md.
