Run Remote Stage from your own code
Both metered lanes are available over HTTP and each returns one JSON object. The division of labour: the page reads concurrency and gaps from the grid, gives each speaker's local start, picks the platform, each session's readiness rung, staffing by name and the drill with their deleted rungs, and runs the delivery gates - all free, in stagekit.js. The run writes the plan or the briefs; the page then holds the reply to its own picks, names and times (stagereply.js).
Base URL and the response shape
Every endpoint lives under https://api.skillsafe.ai/v1/app-api, and every response has one shape:
{ "ok": true, "data": { ... } }
{ "ok": false, "error": { "code": "...", "message": "..." } }
The token is minted for this app (the guest call takes {"slug":"remote-stage"}), so no slug header is needed afterwards. Send it as Authorization: Bearer …. The run body is the input object, sent bare.
| Status | Code | Meaning |
|---|---|---|
| 400 | validation_error | The body is not a JSON object, or a required key (task, event, sessions, facts) is missing. |
| 401 | unauthorized | No token, or a stale one. Mint a guest token or sign in again. |
| 402 | insufficient_credits | The balance is under min_credits. Price with /estimate first. |
| 403 | forbidden | A guest token tried to run: both lanes are metered and need a personal sign-in. |
| 404 | not_found | Unknown job id. |
| 429 | rate_limited | Back off and retry. |
| 5xx | server_error | Transient. Retry with the same Idempotency-Key so a retry never double-bills. |
The task field comes first
Two lanes - plan (the production plan for the organizers) and brief (one tech brief per session for its speaker). A missing or unknown task is answered as plan. Both lanes send the same four fields.
The input
| Field | Required | What |
|---|---|---|
task | yes | plan or brief. If it is missing or neither, do plan and set "task": "plan". |
event | yes | the posture, concurrency and gaps, what was promised, the people free for production, last edition, the practices in place, consent and captions. |
sessions | yes | every session in order with its UTC slot, speaker, offset, the speaker's local start, demo, connection, platform history, moderator, watcher, tech check and the page's readiness rung with its reason. |
facts | yes | the posture, the four menus with their picks, rungs and deleted rungs, the people on duty at peak, the checks, the signals and every finding tagged [fix], [check] or [info], most urgent first. |
retry_note | no | optional; if present, your previous reply was unusable - follow it. |
The rules the model applies
- Fix the interaction posture first: a feed people watch, or an event people are inside. Every menu follows from it, and a recommendation says which it assumes.
- Platform: a one-way feed plus the community's existing chat space by default; the single one-way feed when nobody can watch chat or the audience barely used interaction (it is a real answer, not a fallback); a broadcast tool with a question queue only when procurement already chose it; an assembled stack costs organizer hours and seams; a managed virtual-venue platform when sessions run at once, a sponsor deliverable names a booth or the stream, a directory was sold, or procurement forces it - its directory triggers a data-handling review before signature. The same sessions on a second live platform is out. Put the vendor questions in writing before committing.
- Speakers: a written home-setup note with the join link by default (wired connection, wired headphones, quiet room, camera at eye level and light in front, one window shared, notifications off, no background music); a group check on the real platform when anyone has never presented on it; an individual check plus an instructed local backup recording for a session that cannot be re-run, an unknown or bad connection, or a live demo; a pre-recorded talk with the speaker live in chat for a slot in the speaker's night, a speaker who cannot hold a live slot, or a demo that failed live before. A check on a different tool is out. A local recording does not upload while the talk runs, and the speaker is told where to send it and by when.
- Moderation: one named moderator per concurrent session by default (one across the event for a single track); a technical watcher beside each for anything that cannot be re-run or after a dead feed went unnoticed; a host on the feed for a paid ticket, a sponsor deliverable naming the stream, a continuous programme, or a feed with no other way to tell the audience what is happening. A single feed still gets a watcher. The speaker moderating their own chat is out. Names, not functions.
- Failure drill: a written fallback line published before the day by default; a rehearsed handoff for the likeliest failure (the speaker's connection dropping, the opening words agreed) once a moderator or a host on the feed exists to say them; a warm fallback destination; a full drill on a second platform for a paid ticket, a sponsor contract naming the stream, an unrepeatable session, or a recurring event whose feed died - only where sessions cannot simply be re-posted. A contingency document nobody has read aloud is out.
- Rehearse once on the platform the event runs on. A recording that exists is one somebody will ask to publish: get it into the speaker consent record first. Report what the platform can do on captions; never set the accessibility bar. In the budget, the feed survives every tier; the interaction surface and its staffing go first. Every metric here is self-set.
House rules
- Use only the input and the rules above. The page's sessions, speakers, times, rungs, names and picks are exact - copy them. Every number in a sentence must appear in the input or in the rules above.
- Label anything that is not one of the rules above, and is not in the input, as your own design.
- Never invent a person, a link, a platform name, a date or a figure; where one must be named and is not, write "to be named". Refer to people by name or as they - never infer anyone's gender from a name, and that includes possessives: "their night", "their slot", "the speaker's connection", never his or her.
- Never use backticks, never refer to this input's fields by their key names in a sentence, and never copy this prompt's narrative wording into a reply.
- Reply with ONLY one JSON object - no prose before or after, no code fences.
The replies
plan
summary- one sentence, at most 35 words: the most urgent finding and the first change.posture- one line: a feed people watch, or an event people are inside, as the page says.platform-pick(feed,feedchat,broadcast,assembledormanaged, the page's),note(one sentence),questions(2 to 4 short vendor questions to put in writing, from the rules and the input).speakers- one object per session in the page's order:session(exactly),speaker(exactly),local(the page's local start, exactly, or "unknown"),rung(the page's:link,note,group,individualorprerecord),action(one short sentence: what to send or schedule).staffing- one object per session in the page's order:session(exactly),moderator(the page's name, or "to be named" where the page has none, only a function, or the session's own speaker; "none" when the page's pick has no moderator),watcher(the page's name, or "to be named" where the pick needs one and the page has none; "" where the pick has no watcher),note(one short sentence).drill-pick(none,line,handoff,warmorfull, the page's),line(draft the fallback sentence itself - your design - as the audience would read it: that the feed has dropped, that it is not their connection, and where to go; write "to be named" only for the place when the page does not name it, never for the whole sentence),note(one sentence).rehearsal- one sentence: the rehearsal on the platform the event runs on - confirm it where the page says one is held, otherwise when and who ("to be named" where the page has neither).budget- one sentence: what a lean tier drops first and what survives every tier.checks- one object per delivery gate in the page's order:check(the page's short name, exactly),pass(true or false, as the page says).signals- 2 or 3 short strings, the page's signals, each with what it would change next time.caveats- at most 4 short strings:[fix]findings first in the page's order (the first four when there are more), then[check]findings in the page's order.[]when there are none of either.
{
"task": "plan",
"summary": "one sentence",
"posture": "one line",
"platform": { "pick": "feedchat", "note": "one sentence", "questions": [ "a vendor question" ] },
"speakers": [ { "session": "a session", "speaker": "a name", "local": "09:00", "rung": "note", "action": "one short sentence" } ],
"staffing": [ { "session": "a session", "moderator": "a name", "watcher": "", "note": "one short sentence" } ],
"drill": { "pick": "handoff", "line": "the fallback sentence", "note": "one sentence" },
"rehearsal": "one sentence",
"budget": "one sentence",
"checks": [ { "check": "Named moderators", "pass": true } ],
"signals": [ "what to record and what it changes" ],
"caveats": [ "a caveat" ]
}
The page holds it to its own picks and names: the platform, every session's readiness rung and local start, moderators and watchers by name (never the speaker), the drill with a fallback sentence, and the gates; no figure may appear that the input does not hold.
brief
briefs- one object per session in the page's order:session(exactly),speaker(exactly),local(the page's local start, exactly, or "unknown"),rung(the page's),message(at most 150 words, addressed to the speaker):note- one sentence, at most 30 words, for the organizers: what to settle before these go out.
{
"task": "brief",
"briefs": [ { "session": "a session", "speaker": "a name", "local": "09:00", "rung": "individual", "message": "at most 150 words" } ],
"note": "one sentence"
}
The page requires one brief per session in order, each opening with the UTC and local start, the same-link rule, the wired setup, the rung's check, backup or pre-recording, the demo fallback and music warning, and the drop plan - never a different tool.
Worked examples - every lane, every sample
These are the page's three free samples (fictional events and people; every figure is illustrative). Each input is exactly what the page sends; each reply is the saved reply the sample replays, shipped as the validating model wrote it; the last line is the page's own check. Every sample has both lanes.
Bayline Python Online (two tracks, a paid ticket) - plan
6 sessions, at most 2 at once; managed virtual-venue platform; moderator, technical watcher and a host on the feed; a full outage drill on a second platform; 0 of 6 gates.
Input:
{
"task": "plan",
"event": "Event: Bayline Python Online; an event people are inside - an interaction surface is open; 6 sessions, at most 2 at once, shortest gap 10 minutes, programme span 180 minutes\nPromised: paid virtual ticket yes; a sponsor deliverable naming the stream or a virtual booth no; an attendee directory sold no; a platform forced by procurement or a sponsor no\nPeople: 5 people free to do only production during a session; existing community chat space yes; someone has streamed before no; a recurring event yes; platform choice reversible for 30 more days\nLast edition: a feed died yes; a dead feed went unnoticed no; the audience barely used live interaction no\nPractice: rehearsal on the real platform no; fallback line published no; the person who says it knows the sentence no; the same sessions on a second live platform no; a contingency document nobody has read aloud yes; every session recorded and re-postable no\nConsent and access: recordings in the speaker consent record no; attendees on camera anywhere no; captions required no (platform support unknown); demo speakers warned about background music no",
"sessions": "Sessions, in order (session | UTC | speaker | speaker offset | speaker local start | cannot be re-run | live demo | connection | presented on this platform before | demo failed before | moderator | watcher | tech check | readiness rung | why):\n1. Opening keynote | 15:00-15:45 | Maya Orrenby | +1 | 16:00 | yes | no | good | yes | no | Jun | Ravi | on the real platform | individual | cannot be re-run\n2. Typing at scale | 16:00-16:40 | Leo Quarrender | +2 | 18:00 | no | yes | unknown | no | no | Ines | NONE | on the real platform | individual | never presented on this platform; connection unknown; live demo\n3. Async in practice | 16:00-16:40 | Hana Ostrevin | +10 | 02:00 | no | no | unknown | no | no | Kofi | NONE | not yet | prerecord | never presented on this platform; connection unknown; middle of the speaker's night | SPEAKER'S NIGHT\n4. Packaging clinic | 16:50-17:30 | Sam Pellucan | -7 | 09:50 | no | yes | good | yes | yes | Sam Pellucan | NONE | ON ANOTHER TOOL | prerecord | live demo; the demo failed live before\n5. Data pipelines | 16:50-17:30 | Priya Ventrakil | +5:30 | 22:20 | no | no | good | yes | no | Jun | NONE | on the real platform | note | the default\n6. Closing | 17:40-18:00 | Maya Orrenby | +1 | 18:40 | no | no | good | yes | no | Kofi | Ravi | on the real platform | note | the default",
"facts": "Interaction posture: an event people are inside; concurrency 2; continuous programme yes\nPlatform: the page's pick is managed; rungs Single one-way feed available; One-way feed plus the existing chat space default; Broadcast tool with a built-in question queue dominated; Assembled stack available; Managed virtual-venue platform promoted; a second live platform carrying the same sessions deleted\nSpeaker readiness: the event's deepest rung is prerecord; rungs Slides and a join link available; A written home-setup note default; One shared group tech-check window promoted; Individual tech check plus an instructed local backup recording promoted; A pre-recorded talk played to schedule, speaker live in chat promoted; a tech check on a different tool deleted\nModeration staffing: the page's pick is host; rungs No moderation staffing available; One moderator across the whole event fails at two sessions; One moderator per concurrent session default; Moderator plus a technical watcher promoted; Moderator, technical watcher and a host on the feed promoted; A technical watcher per feed, no moderator not applicable; the speaker moderating their own chat deleted; people on duty at peak 6\nFailure drill: the page's pick is full; rungs No drill available; A written fallback line published before the day default; A rehearsed handoff for the single likeliest failure promoted; A standing fallback destination kept warm available; A full outage drill on a second platform promoted; a contingency document nobody has read aloud deleted\nChecks (0 of 6): Named moderators (Every concurrent session has a named moderator, or its interaction surface is closed) MISSING; Real-platform check (Every speaker has joined the platform the event actually runs on before the day) MISSING; Fallback line (The fallback line is published and the person who will say it knows the sentence) MISSING; Rehearsal (One rehearsal runs on the platform the event actually runs on) MISSING; Staffing (The people on duty per session fit the people free to do only production) MISSING; No deleted rung (No deleted rung is in use) MISSING\nSignals to record: Speakers who joined a check on the real platform before the day, over speakers scheduled (self-set) - the one leading indicator; Time from a feed dropping to the audience being told something (self-set); Questions relayed to a speaker against questions asked (self-set)\nFindings (14):\n[fix] self_moderated (staffing): Sam Pellucan would moderate their own chat while presenting - deleted; name a separate moderator.\n[fix] other_tool (speakers): Tech check on a different tool for: Sam Pellucan - deleted; it tests nothing about the real platform's screen share or audio. Re-run it on the event's platform.\n[fix] understaffed (staffing): 6 people on duty at peak (Moderator, technical watcher and a host on the feed x 2 concurrent sessions) against 5 people free to do only production - cut concurrency or close the surface.\n[fix] doc_only (drill): A contingency document nobody has read aloud is deleted - publish one fallback sentence where the audience looks, and rehearse who says it.\n[check] night (time zones): Middle of the speaker's night: Hana Ostrevin at 02:00 local (Async in practice) - move the slot, or pre-record with the speaker live in chat.\n[check] no_line (drill): No fallback line published - one sentence, before the day, naming exactly where to go when the feed dies; a virtual event fails as silence.\n[check] no_watcher (staffing): No named technical watcher for: Typing at scale, Async in practice, Packaging clinic, Data pipelines - one person watching the output as an attendee sees it.\n[check] no_rehearsal (rehearsal): No rehearsal on the platform the event runs on - the step that gets cut, and a rehearsal on another tool tests nothing.\n[check] consent (consent): 4 sessions will create a local or pre-recorded file - get it into the speaker consent record before the file exists; a backup is not a recording anyone agreed to publish.\n[check] music (speakers): Warn demo speakers: no background music in anything shared - incidental music can get the stream taken down mid-session.\n[check] checks (measurement): Delivery gates: 0 of 6 (all self-set).\n[info] managed (platform): A managed virtual-venue platform is promoted (2 sessions at once) - its directory and lead capture trigger a data-handling review before signature.\n[info] recurring (speakers): A recurring event: the home-setup note, the rehearsed crew and a warm fallback all pay off again next edition.\n[info] first_stream (rehearsal): Nobody has streamed before - the rehearsal on the real platform is the cheapest insurance on this page."
}
Reply:
{
"task": "plan",
"summary": "Sam Pellucan is set to moderate their own chat while presenting; name a separate moderator for Packaging clinic before anything else.",
"posture": "An event people are inside - an interaction surface is open.",
"platform": {
"pick": "managed",
"note": "A managed virtual-venue platform is used because two sessions run at once, and its directory and lead capture will need a data-handling review before signing.",
"questions": [
"Can the platform reliably run two sessions at once across the full 180-minute programme?",
"What does the platform's attendee directory collect, and what triggers its required data-handling review?",
"Since the platform choice is only reversible for 30 more days, what is the cutoff to decide by?"
]
},
"speakers": [
{
"session": "Opening keynote",
"speaker": "Maya Orrenby",
"local": "16:00",
"rung": "individual",
"action": "Schedule an individual tech check on the platform and instruct a local backup recording that does not upload during the talk."
},
{
"session": "Typing at scale",
"speaker": "Leo Quarrender",
"local": "18:00",
"rung": "individual",
"action": "Schedule an individual tech check on the platform and instruct a local backup recording that does not upload during the talk."
},
{
"session": "Async in practice",
"speaker": "Hana Ostrevin",
"local": "02:00",
"rung": "prerecord",
"action": "Have the speaker pre-record the talk to play to schedule, with them live in chat during the slot."
},
{
"session": "Packaging clinic",
"speaker": "Sam Pellucan",
"local": "09:50",
"rung": "prerecord",
"action": "Have the speaker pre-record the talk to play to schedule, with them live in chat during the slot."
},
{
"session": "Data pipelines",
"speaker": "Priya Ventrakil",
"local": "22:20",
"rung": "note",
"action": "Send the written home-setup note with the join link before the day."
},
{
"session": "Closing",
"speaker": "Maya Orrenby",
"local": "18:40",
"rung": "note",
"action": "Send the written home-setup note with the join link before the day."
}
],
"staffing": [
{
"session": "Opening keynote",
"moderator": "Jun",
"watcher": "Ravi",
"note": "Cannot be re-run, so Jun and Ravi both stay with it from open to close."
},
{
"session": "Typing at scale",
"moderator": "Ines",
"watcher": "to be named",
"note": "A live demo with an unknown connection needs a named technical watcher before the day."
},
{
"session": "Async in practice",
"moderator": "Kofi",
"watcher": "to be named",
"note": "Even pre-recorded, a technical watcher should still confirm the feed during this speaker's night slot."
},
{
"session": "Packaging clinic",
"moderator": "to be named",
"watcher": "to be named",
"note": "Sam Pellucan cannot moderate their own chat while presenting; name a separate moderator and a technical watcher."
},
{
"session": "Data pipelines",
"moderator": "Jun",
"watcher": "to be named",
"note": "Default staffing; a named technical watcher is still missing."
},
{
"session": "Closing",
"moderator": "Kofi",
"watcher": "Ravi",
"note": "Default staffing, with both roles already named."
}
],
"drill": {
"pick": "full",
"line": "The feed has dropped - this is not a problem with your connection; the backup destination is to be named, and we will share the link there as soon as it is ready.",
"note": "A full drill on a second platform is picked because last edition's feed died, tickets are paid, and sessions are not recorded for reposting."
},
"rehearsal": "No rehearsal has run yet on the platform the event runs on; schedule one for to be named, led by to be named.",
"budget": "If budget gets cut, trim the interaction surface and its staffing before anything else; the feed itself keeps running regardless of tier.",
"checks": [
{
"check": "Named moderators",
"pass": false
},
{
"check": "Real-platform check",
"pass": false
},
{
"check": "Fallback line",
"pass": false
},
{
"check": "Rehearsal",
"pass": false
},
{
"check": "Staffing",
"pass": false
},
{
"check": "No deleted rung",
"pass": false
}
],
"signals": [
"Speakers who joined a real-platform check before the day, over speakers scheduled - the leading indicator; a low share next time would mean pulling that check in earlier.",
"Time from a feed dropping to telling the audience - a slow time next time would mean naming the fallback speaker and rehearsing the line sooner.",
"Questions relayed to a speaker against questions asked - a wide gap next time would mean adding chat moderation capacity."
],
"caveats": [
"Sam Pellucan would moderate their own chat while presenting; name a separate moderator.",
"Sam Pellucan's tech check was on a different tool and tests nothing about the real platform; rerun it there.",
"Peak staffing needs 6 people against 5 free for production; cut concurrency or close the surface.",
"The only failure-drill document has never been read aloud; publish one fallback sentence and rehearse who says it."
]
}
The page's check: kept - nothing to flag
Bayline Python Online (two tracks, a paid ticket) - brief
6 sessions, at most 2 at once; managed virtual-venue platform; moderator, technical watcher and a host on the feed; a full outage drill on a second platform; 0 of 6 gates.
Input:
{
"task": "brief",
"event": "Event: Bayline Python Online; an event people are inside - an interaction surface is open; 6 sessions, at most 2 at once, shortest gap 10 minutes, programme span 180 minutes\nPromised: paid virtual ticket yes; a sponsor deliverable naming the stream or a virtual booth no; an attendee directory sold no; a platform forced by procurement or a sponsor no\nPeople: 5 people free to do only production during a session; existing community chat space yes; someone has streamed before no; a recurring event yes; platform choice reversible for 30 more days\nLast edition: a feed died yes; a dead feed went unnoticed no; the audience barely used live interaction no\nPractice: rehearsal on the real platform no; fallback line published no; the person who says it knows the sentence no; the same sessions on a second live platform no; a contingency document nobody has read aloud yes; every session recorded and re-postable no\nConsent and access: recordings in the speaker consent record no; attendees on camera anywhere no; captions required no (platform support unknown); demo speakers warned about background music no",
"sessions": "Sessions, in order (session | UTC | speaker | speaker offset | speaker local start | cannot be re-run | live demo | connection | presented on this platform before | demo failed before | moderator | watcher | tech check | readiness rung | why):\n1. Opening keynote | 15:00-15:45 | Maya Orrenby | +1 | 16:00 | yes | no | good | yes | no | Jun | Ravi | on the real platform | individual | cannot be re-run\n2. Typing at scale | 16:00-16:40 | Leo Quarrender | +2 | 18:00 | no | yes | unknown | no | no | Ines | NONE | on the real platform | individual | never presented on this platform; connection unknown; live demo\n3. Async in practice | 16:00-16:40 | Hana Ostrevin | +10 | 02:00 | no | no | unknown | no | no | Kofi | NONE | not yet | prerecord | never presented on this platform; connection unknown; middle of the speaker's night | SPEAKER'S NIGHT\n4. Packaging clinic | 16:50-17:30 | Sam Pellucan | -7 | 09:50 | no | yes | good | yes | yes | Sam Pellucan | NONE | ON ANOTHER TOOL | prerecord | live demo; the demo failed live before\n5. Data pipelines | 16:50-17:30 | Priya Ventrakil | +5:30 | 22:20 | no | no | good | yes | no | Jun | NONE | on the real platform | note | the default\n6. Closing | 17:40-18:00 | Maya Orrenby | +1 | 18:40 | no | no | good | yes | no | Kofi | Ravi | on the real platform | note | the default",
"facts": "Interaction posture: an event people are inside; concurrency 2; continuous programme yes\nPlatform: the page's pick is managed; rungs Single one-way feed available; One-way feed plus the existing chat space default; Broadcast tool with a built-in question queue dominated; Assembled stack available; Managed virtual-venue platform promoted; a second live platform carrying the same sessions deleted\nSpeaker readiness: the event's deepest rung is prerecord; rungs Slides and a join link available; A written home-setup note default; One shared group tech-check window promoted; Individual tech check plus an instructed local backup recording promoted; A pre-recorded talk played to schedule, speaker live in chat promoted; a tech check on a different tool deleted\nModeration staffing: the page's pick is host; rungs No moderation staffing available; One moderator across the whole event fails at two sessions; One moderator per concurrent session default; Moderator plus a technical watcher promoted; Moderator, technical watcher and a host on the feed promoted; A technical watcher per feed, no moderator not applicable; the speaker moderating their own chat deleted; people on duty at peak 6\nFailure drill: the page's pick is full; rungs No drill available; A written fallback line published before the day default; A rehearsed handoff for the single likeliest failure promoted; A standing fallback destination kept warm available; A full outage drill on a second platform promoted; a contingency document nobody has read aloud deleted\nChecks (0 of 6): Named moderators (Every concurrent session has a named moderator, or its interaction surface is closed) MISSING; Real-platform check (Every speaker has joined the platform the event actually runs on before the day) MISSING; Fallback line (The fallback line is published and the person who will say it knows the sentence) MISSING; Rehearsal (One rehearsal runs on the platform the event actually runs on) MISSING; Staffing (The people on duty per session fit the people free to do only production) MISSING; No deleted rung (No deleted rung is in use) MISSING\nSignals to record: Speakers who joined a check on the real platform before the day, over speakers scheduled (self-set) - the one leading indicator; Time from a feed dropping to the audience being told something (self-set); Questions relayed to a speaker against questions asked (self-set)\nFindings (14):\n[fix] self_moderated (staffing): Sam Pellucan would moderate their own chat while presenting - deleted; name a separate moderator.\n[fix] other_tool (speakers): Tech check on a different tool for: Sam Pellucan - deleted; it tests nothing about the real platform's screen share or audio. Re-run it on the event's platform.\n[fix] understaffed (staffing): 6 people on duty at peak (Moderator, technical watcher and a host on the feed x 2 concurrent sessions) against 5 people free to do only production - cut concurrency or close the surface.\n[fix] doc_only (drill): A contingency document nobody has read aloud is deleted - publish one fallback sentence where the audience looks, and rehearse who says it.\n[check] night (time zones): Middle of the speaker's night: Hana Ostrevin at 02:00 local (Async in practice) - move the slot, or pre-record with the speaker live in chat.\n[check] no_line (drill): No fallback line published - one sentence, before the day, naming exactly where to go when the feed dies; a virtual event fails as silence.\n[check] no_watcher (staffing): No named technical watcher for: Typing at scale, Async in practice, Packaging clinic, Data pipelines - one person watching the output as an attendee sees it.\n[check] no_rehearsal (rehearsal): No rehearsal on the platform the event runs on - the step that gets cut, and a rehearsal on another tool tests nothing.\n[check] consent (consent): 4 sessions will create a local or pre-recorded file - get it into the speaker consent record before the file exists; a backup is not a recording anyone agreed to publish.\n[check] music (speakers): Warn demo speakers: no background music in anything shared - incidental music can get the stream taken down mid-session.\n[check] checks (measurement): Delivery gates: 0 of 6 (all self-set).\n[info] managed (platform): A managed virtual-venue platform is promoted (2 sessions at once) - its directory and lead capture trigger a data-handling review before signature.\n[info] recurring (speakers): A recurring event: the home-setup note, the rehearsed crew and a warm fallback all pay off again next edition.\n[info] first_stream (rehearsal): Nobody has streamed before - the rehearsal on the real platform is the cheapest insurance on this page."
}
Reply:
{
"task": "brief",
"briefs": [
{
"session": "Opening keynote",
"speaker": "Maya Orrenby",
"local": "16:00",
"rung": "individual",
"message": "Your session is scheduled for 15:00-15:45 UTC, which should be 16:00 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Join an individual check on the event's platform and keep a local backup recording running that does not upload while you talk; send it to to be named by to be named. Your local recording will be covered by the consent record before it is made. If your connection drops, rejoin with the same link while the moderator covers."
},
{
"session": "Typing at scale",
"speaker": "Leo Quarrender",
"local": "18:00",
"rung": "individual",
"message": "Your session is scheduled for 16:00-16:40 UTC, which should be 18:00 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Join an individual check on the event's platform and keep a local backup recording running that does not upload while you talk; send it to to be named by to be named. Since this session includes a live demo, prepare a recorded fallback of it, and avoid background music in anything you share. Your local recording will be covered by the consent record before it is made. If your connection drops, rejoin with the same link while the moderator covers."
},
{
"session": "Async in practice",
"speaker": "Hana Ostrevin",
"local": "02:00",
"rung": "prerecord",
"message": "Your session is scheduled for 16:00-16:40 UTC, which should be 02:00 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Your talk will be pre-recorded and played to schedule, with you live in chat during the slot; the recording is due to be named. The recording will be covered by the consent record before it is made. If your connection drops while you're live in chat, rejoin with the same link while the moderator covers."
},
{
"session": "Packaging clinic",
"speaker": "Sam Pellucan",
"local": "09:50",
"rung": "prerecord",
"message": "Your session is scheduled for 16:50-17:30 UTC, which should be 09:50 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Your talk will be pre-recorded and played to schedule, with you live in chat during the slot; the recording is due to be named. Since your demo is part of the pre-recorded talk, prepare a recorded fallback of it as well, and avoid background music in anything you share. The recording will be covered by the consent record before it is made. If your connection drops while you're live in chat, rejoin with the same link while the moderator covers."
},
{
"session": "Data pipelines",
"speaker": "Priya Ventrakil",
"local": "22:20",
"rung": "note",
"message": "Your session is scheduled for 16:50-17:30 UTC, which should be 22:20 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Please read the setup note we send before the day. If your connection drops, rejoin with the same link while the moderator covers."
},
{
"session": "Closing",
"speaker": "Maya Orrenby",
"local": "18:40",
"rung": "note",
"message": "Your session is scheduled for 17:40-18:00 UTC, which should be 18:40 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Please read the setup note we send before the day. If your connection drops, rejoin with the same link while the moderator covers."
}
],
"note": "Before sending, name a moderator for Packaging clinic other than Sam Pellucan, who cannot moderate their own chat while presenting."
}
The page's check: kept - nothing to flag
Quillon Rust Live (a single feed people watch) - plan
1 sessions, at most 1 at once; single one-way feed; a technical watcher per feed, no moderator; a rehearsed handoff for the single likeliest failure; 6 of 6 gates.
Input:
{
"task": "plan",
"event": "Event: Quillon Rust Live; a feed people watch - no interaction surface; 1 session, at most 1 at once, shortest gap none, programme span 45 minutes\nPromised: paid virtual ticket no; a sponsor deliverable naming the stream or a virtual booth no; an attendee directory sold no; a platform forced by procurement or a sponsor no\nPeople: 2 people free to do only production during a session; existing community chat space no; someone has streamed before yes; a recurring event yes; platform choice reversible for an unknown time\nLast edition: a feed died no; a dead feed went unnoticed no; the audience barely used live interaction no\nPractice: rehearsal on the real platform yes; fallback line published yes; the person who says it knows the sentence yes; the same sessions on a second live platform no; a contingency document nobody has read aloud no; every session recorded and re-postable yes\nConsent and access: recordings in the speaker consent record yes; attendees on camera anywhere no; captions required no (platform support unknown); demo speakers warned about background music yes",
"sessions": "Sessions, in order (session | UTC | speaker | speaker offset | speaker local start | cannot be re-run | live demo | connection | presented on this platform before | demo failed before | moderator | watcher | tech check | readiness rung | why):\n1. Lifetimes without tears | 18:00-18:45 | Ola Brzanek | +1 | 19:00 | no | no | good | yes | no | NONE | Piotr | on the real platform | note | the default",
"facts": "Interaction posture: a feed people watch; concurrency 1; continuous programme no\nPlatform: the page's pick is feed; rungs Single one-way feed default; One-way feed plus the existing chat space available; Broadcast tool with a built-in question queue dominated; Assembled stack available; Managed virtual-venue platform not yet; a second live platform carrying the same sessions deleted\nSpeaker readiness: the event's deepest rung is note; rungs Slides and a join link available; A written home-setup note default; One shared group tech-check window available; Individual tech check plus an instructed local backup recording not yet; A pre-recorded talk played to schedule, speaker live in chat not yet; a tech check on a different tool deleted\nModeration staffing: the page's pick is watchonly plus a host on the feed; rungs No moderation staffing deleted; One moderator across the whole event skipped; One moderator per concurrent session skipped; Moderator plus a technical watcher skipped; Moderator, technical watcher and a host on the feed promoted; A technical watcher per feed, no moderator default; the speaker moderating their own chat deleted; people on duty at peak 2\nFailure drill: the page's pick is handoff; rungs No drill available; A written fallback line published before the day default; A rehearsed handoff for the single likeliest failure promoted; A standing fallback destination kept warm dominated - sessions re-postable; A full outage drill on a second platform dominated - sessions re-postable; a contingency document nobody has read aloud deleted\nChecks (6 of 6): Named moderators (Every concurrent session has a named moderator, or its interaction surface is closed) passed; Real-platform check (Every speaker has joined the platform the event actually runs on before the day) passed; Fallback line (The fallback line is published and the person who will say it knows the sentence) passed; Rehearsal (One rehearsal runs on the platform the event actually runs on) passed; Staffing (The people on duty per session fit the people free to do only production) passed; No deleted rung (No deleted rung is in use) passed\nSignals to record: Speakers who joined a check on the real platform before the day, over speakers scheduled (self-set) - the one leading indicator; Time from a feed dropping to the audience being told something (self-set); Sessions delivered without an audience-visible failure, over sessions scheduled (self-set)\nFindings (3):\n[info] reposting (drill): Every session is recorded and can be re-posted - the content-survives axis stops mattering, and the rehearsed handoff beats a warm fallback or a full drill.\n[info] recurring (speakers): A recurring event: the home-setup note, the rehearsed crew and a warm fallback all pay off again next edition.\n[info] checks (measurement): Delivery gates: 6 of 6 (all self-set)."
}
Reply:
{
"task": "plan",
"summary": "Every session here is recorded and can be re-posted, so the rehearsed handoff already picked beats a warm fallback or a full drill.",
"posture": "A feed people watch - no interaction surface.",
"platform": {
"pick": "feed",
"note": "A single one-way feed is used because there is no existing community chat space to pair it with.",
"questions": [
"Can the platform reliably deliver a single feed for the full session with no backup chat layer?",
"What captions support does the platform offer, since that is currently unconfirmed?",
"Is the platform choice still reversible, and if so, until when?"
]
},
"speakers": [
{
"session": "Lifetimes without tears",
"speaker": "Ola Brzanek",
"local": "19:00",
"rung": "note",
"action": "Send the written home-setup note with the join link before the day."
}
],
"staffing": [
{
"session": "Lifetimes without tears",
"moderator": "none",
"watcher": "Piotr",
"note": "No moderator is needed since there is no chat to run, and the host on the feed covers audience updates."
}
],
"drill": {
"pick": "handoff",
"line": "The feed has dropped - this is not a problem with your connection; please stay here, and if we need to move the stream, the backup destination is to be named, with the link to follow shortly.",
"note": "A rehearsed handoff is enough because every session is recorded and can be re-posted, so a warm fallback or full drill is not needed."
},
"rehearsal": "A rehearsal has already run on the platform the event runs on.",
"budget": "With no interaction surface already built into this event, a leaner budget has nothing to trim beyond keeping the single feed running at every tier.",
"checks": [
{
"check": "Named moderators",
"pass": true
},
{
"check": "Real-platform check",
"pass": true
},
{
"check": "Fallback line",
"pass": true
},
{
"check": "Rehearsal",
"pass": true
},
{
"check": "Staffing",
"pass": true
},
{
"check": "No deleted rung",
"pass": true
}
],
"signals": [
"Speakers who joined a real-platform check before the day, over speakers scheduled - the leading indicator; a drop next time would mean pulling that check in earlier.",
"Time from a feed dropping to telling the audience - a slow time next time would mean briefing the host more tightly on the handoff line.",
"Sessions delivered without an audience-visible failure, over sessions scheduled - a drop next time would mean re-running the platform rehearsal."
],
"caveats": []
}
The page's check: kept - nothing to flag
Quillon Rust Live (a single feed people watch) - brief
1 sessions, at most 1 at once; single one-way feed; a technical watcher per feed, no moderator; a rehearsed handoff for the single likeliest failure; 6 of 6 gates.
Input:
{
"task": "brief",
"event": "Event: Quillon Rust Live; a feed people watch - no interaction surface; 1 session, at most 1 at once, shortest gap none, programme span 45 minutes\nPromised: paid virtual ticket no; a sponsor deliverable naming the stream or a virtual booth no; an attendee directory sold no; a platform forced by procurement or a sponsor no\nPeople: 2 people free to do only production during a session; existing community chat space no; someone has streamed before yes; a recurring event yes; platform choice reversible for an unknown time\nLast edition: a feed died no; a dead feed went unnoticed no; the audience barely used live interaction no\nPractice: rehearsal on the real platform yes; fallback line published yes; the person who says it knows the sentence yes; the same sessions on a second live platform no; a contingency document nobody has read aloud no; every session recorded and re-postable yes\nConsent and access: recordings in the speaker consent record yes; attendees on camera anywhere no; captions required no (platform support unknown); demo speakers warned about background music yes",
"sessions": "Sessions, in order (session | UTC | speaker | speaker offset | speaker local start | cannot be re-run | live demo | connection | presented on this platform before | demo failed before | moderator | watcher | tech check | readiness rung | why):\n1. Lifetimes without tears | 18:00-18:45 | Ola Brzanek | +1 | 19:00 | no | no | good | yes | no | NONE | Piotr | on the real platform | note | the default",
"facts": "Interaction posture: a feed people watch; concurrency 1; continuous programme no\nPlatform: the page's pick is feed; rungs Single one-way feed default; One-way feed plus the existing chat space available; Broadcast tool with a built-in question queue dominated; Assembled stack available; Managed virtual-venue platform not yet; a second live platform carrying the same sessions deleted\nSpeaker readiness: the event's deepest rung is note; rungs Slides and a join link available; A written home-setup note default; One shared group tech-check window available; Individual tech check plus an instructed local backup recording not yet; A pre-recorded talk played to schedule, speaker live in chat not yet; a tech check on a different tool deleted\nModeration staffing: the page's pick is watchonly plus a host on the feed; rungs No moderation staffing deleted; One moderator across the whole event skipped; One moderator per concurrent session skipped; Moderator plus a technical watcher skipped; Moderator, technical watcher and a host on the feed promoted; A technical watcher per feed, no moderator default; the speaker moderating their own chat deleted; people on duty at peak 2\nFailure drill: the page's pick is handoff; rungs No drill available; A written fallback line published before the day default; A rehearsed handoff for the single likeliest failure promoted; A standing fallback destination kept warm dominated - sessions re-postable; A full outage drill on a second platform dominated - sessions re-postable; a contingency document nobody has read aloud deleted\nChecks (6 of 6): Named moderators (Every concurrent session has a named moderator, or its interaction surface is closed) passed; Real-platform check (Every speaker has joined the platform the event actually runs on before the day) passed; Fallback line (The fallback line is published and the person who will say it knows the sentence) passed; Rehearsal (One rehearsal runs on the platform the event actually runs on) passed; Staffing (The people on duty per session fit the people free to do only production) passed; No deleted rung (No deleted rung is in use) passed\nSignals to record: Speakers who joined a check on the real platform before the day, over speakers scheduled (self-set) - the one leading indicator; Time from a feed dropping to the audience being told something (self-set); Sessions delivered without an audience-visible failure, over sessions scheduled (self-set)\nFindings (3):\n[info] reposting (drill): Every session is recorded and can be re-posted - the content-survives axis stops mattering, and the rehearsed handoff beats a warm fallback or a full drill.\n[info] recurring (speakers): A recurring event: the home-setup note, the rehearsed crew and a warm fallback all pay off again next edition.\n[info] checks (measurement): Delivery gates: 6 of 6 (all self-set)."
}
Reply:
{
"task": "brief",
"briefs": [
{
"session": "Lifetimes without tears",
"speaker": "Ola Brzanek",
"local": "19:00",
"rung": "note",
"message": "Your session is scheduled for 18:00-18:45 UTC, which should be 19:00 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Please read the setup note we send before the day. If your connection drops, rejoin with the same link while the host covers, since this feed has no moderator."
}
],
"note": "Confirm the actual join link before sending so it doesn't go out marked to be named."
}
The page's check: kept - nothing to flag
Varnholt Platform Summit (company-run, a forced platform) - plan
5 sessions, at most 1 at once; managed virtual-venue platform; moderator, technical watcher and a host on the feed; a rehearsed handoff for the single likeliest failure; 4 of 6 gates.
Input:
{
"task": "plan",
"event": "Event: Varnholt Platform Summit; an event people are inside - an interaction surface is open; 5 sessions, at most 1 at once, shortest gap 5 minutes, programme span 195 minutes\nPromised: paid virtual ticket no; a sponsor deliverable naming the stream or a virtual booth yes; an attendee directory sold yes; a platform forced by procurement or a sponsor Managed virtual-venue platform\nPeople: 3 people free to do only production during a session; existing community chat space no; someone has streamed before yes; a recurring event no; platform choice reversible for 10 more days\nLast edition: a feed died no; a dead feed went unnoticed yes; the audience barely used live interaction no\nPractice: rehearsal on the real platform yes; fallback line published yes; the person who says it knows the sentence no; the same sessions on a second live platform no; a contingency document nobody has read aloud no; every session recorded and re-postable yes\nConsent and access: recordings in the speaker consent record no; attendees on camera anywhere yes; captions required yes (platform support unknown); demo speakers warned about background music no",
"sessions": "Sessions, in order (session | UTC | speaker | speaker offset | speaker local start | cannot be re-run | live demo | connection | presented on this platform before | demo failed before | moderator | watcher | tech check | readiness rung | why):\n1. CEO keynote | 14:00-14:30 | Dana Harrowmere | -5 | 09:00 | yes | no | good | yes | no | Grace | Tomas | on the real platform | individual | cannot be re-run\n2. Product roadmap | 14:35-15:15 | Arjun Kesavane | -8 | 06:35 | no | yes | good | yes | no | Grace | Tomas | on the real platform | individual | live demo\n3. Customer panel | 15:20-16:00 | Lucia Tarravel | -3 | 12:20 | no | no | unknown | no | no | Grace | Tomas | not yet | individual | never presented on this platform; connection unknown\n4. Live build | 16:05-16:50 | Kenji Amaroku | +9 | 01:05 | no | yes | good | yes | no | Grace | Tomas | on the real platform | prerecord | live demo; middle of the speaker's night | SPEAKER'S NIGHT\n5. Wrap-up | 16:55-17:15 | Dana Harrowmere | -5 | 11:55 | no | no | good | yes | no | Grace | Tomas | on the real platform | note | the default",
"facts": "Interaction posture: an event people are inside; concurrency 1; continuous programme yes\nPlatform: the page's pick is managed; rungs Single one-way feed available; One-way feed plus the existing chat space available; Broadcast tool with a built-in question queue dominated; Assembled stack available; Managed virtual-venue platform promoted; a second live platform carrying the same sessions deleted\nSpeaker readiness: the event's deepest rung is prerecord; rungs Slides and a join link available; A written home-setup note default; One shared group tech-check window promoted; Individual tech check plus an instructed local backup recording promoted; A pre-recorded talk played to schedule, speaker live in chat promoted; a tech check on a different tool deleted\nModeration staffing: the page's pick is host; rungs No moderation staffing available; One moderator across the whole event default; One moderator per concurrent session same as event-wide; Moderator plus a technical watcher promoted; Moderator, technical watcher and a host on the feed promoted; A technical watcher per feed, no moderator not applicable; the speaker moderating their own chat deleted; people on duty at peak 3\nFailure drill: the page's pick is handoff; rungs No drill available; A written fallback line published before the day default; A rehearsed handoff for the single likeliest failure promoted; A standing fallback destination kept warm dominated - sessions re-postable; A full outage drill on a second platform dominated - sessions re-postable; a contingency document nobody has read aloud deleted\nChecks (4 of 6): Named moderators (Every concurrent session has a named moderator, or its interaction surface is closed) passed; Real-platform check (Every speaker has joined the platform the event actually runs on before the day) MISSING; Fallback line (The fallback line is published and the person who will say it knows the sentence) MISSING; Rehearsal (One rehearsal runs on the platform the event actually runs on) passed; Staffing (The people on duty per session fit the people free to do only production) passed; No deleted rung (No deleted rung is in use) passed\nSignals to record: Speakers who joined a check on the real platform before the day, over speakers scheduled (self-set) - the one leading indicator; Time from a feed dropping to the audience being told something (self-set); Questions relayed to a speaker against questions asked (self-set)\nFindings (8):\n[check] night (time zones): Middle of the speaker's night: Kenji Amaroku at 01:05 local (Live build) - move the slot, or pre-record with the speaker live in chat.\n[check] line_unrehearsed (drill): The fallback line is published but nobody has been told to say it live - name the person and give them the sentence.\n[check] captions (accessibility): Captions are required and the platform's support is unconfirmed - ask the vendor in writing and report what it can and cannot do.\n[check] consent (consent): 4 sessions will create a local or pre-recorded file - get it into the speaker consent record before the file exists; a backup is not a recording anyone agreed to publish.\n[check] music (speakers): Warn demo speakers: no background music in anything shared - incidental music can get the stream taken down mid-session.\n[check] checks (measurement): Delivery gates: 4 of 6 (all self-set).\n[info] reverse (platform): The platform choice stops being reversible in 10 days - put the vendor questions in writing now.\n[info] reposting (drill): Every session is recorded and can be re-posted - the content-survives axis stops mattering, and the rehearsed handoff beats a warm fallback or a full drill."
}
Reply:
{
"task": "plan",
"summary": "Most urgent: Live build falls in their night at 01:05 local for Kenji Amaroku; it already runs pre-recorded with Kenji Amaroku live in chat as the first change.",
"posture": "An event people are inside - an interaction surface is open.",
"platform": {
"pick": "managed",
"note": "The page's choice fits: procurement already forced a managed virtual-venue platform, the sponsor deliverable names the stream, and the directory that was sold still needs a data-handling review completed before signature.",
"questions": [
"What does the platform support for captions, and in which languages?",
"What does the directory's data-handling review require before signature?",
"Is the 10-day window to reverse this platform choice firm?"
]
},
"speakers": [
{
"session": "CEO keynote",
"speaker": "Dana Harrowmere",
"local": "09:00",
"rung": "individual",
"action": "Schedule the individual check on the real platform and set up the instructed local backup recording, since this session cannot be re-run."
},
{
"session": "Product roadmap",
"speaker": "Arjun Kesavane",
"local": "06:35",
"rung": "individual",
"action": "Schedule the individual check on the real platform and set up the instructed local backup recording for the live demo."
},
{
"session": "Customer panel",
"speaker": "Lucia Tarravel",
"local": "12:20",
"rung": "individual",
"action": "Schedule the still-outstanding individual check on the real platform now, given the unknown connection and no history on this platform."
},
{
"session": "Live build",
"speaker": "Kenji Amaroku",
"local": "01:05",
"rung": "prerecord",
"action": "Record the talk ahead of time for scheduled playback, with Kenji Amaroku live in chat during the slot."
},
{
"session": "Wrap-up",
"speaker": "Dana Harrowmere",
"local": "11:55",
"rung": "note",
"action": "Send the written home-setup note with the join link."
}
],
"staffing": [
{
"session": "CEO keynote",
"moderator": "Grace",
"watcher": "Tomas",
"note": "A host on the feed is also needed for this continuous, sponsored programme - to be named."
},
{
"session": "Product roadmap",
"moderator": "Grace",
"watcher": "Tomas",
"note": "The same host on the feed carries through the live demo - still to be named."
},
{
"session": "Customer panel",
"moderator": "Grace",
"watcher": "Tomas",
"note": "The host on the feed continues here too - still to be named."
},
{
"session": "Live build",
"moderator": "Grace",
"watcher": "Tomas",
"note": "The host on the feed covers the pre-recorded playback - still to be named."
},
{
"session": "Wrap-up",
"moderator": "Grace",
"watcher": "Tomas",
"note": "The host on the feed closes out the event - still to be named."
}
],
"drill": {
"pick": "handoff",
"line": "The feed has dropped - this is not a problem with your connection. Please stay here; we are reconnecting, and if we need to move you, we will send you to the backup location, to be named.",
"note": "The fallback line is published but needs to be rehearsed aloud with whoever will say it on duty - Grace or the host, to be named - before the day."
},
"rehearsal": "A rehearsal has already been held on the platform the event runs on, so that check already passes.",
"budget": "A lean budget would cut the interaction surface and its staffing first; the feed itself holds at every tier.",
"checks": [
{
"check": "Named moderators",
"pass": true
},
{
"check": "Real-platform check",
"pass": false
},
{
"check": "Fallback line",
"pass": false
},
{
"check": "Rehearsal",
"pass": true
},
{
"check": "Staffing",
"pass": true
},
{
"check": "No deleted rung",
"pass": true
}
],
"signals": [
"Speakers who join a real-platform check before the day, over speakers scheduled - a low share would add another group check before the next event.",
"Time from a feed dropping to telling the audience something - a slow time would move the drill up to a full outage drill on a second platform.",
"Questions relayed to a speaker against questions asked - a wide gap would add a dedicated relay role to moderation."
],
"caveats": [
"Live build sits in their night for Kenji Amaroku at 01:05 local.",
"The fallback line is published, but the person who will say it has not been told the sentence.",
"Captions are required but the platform's caption support is unconfirmed - ask the vendor in writing.",
"4 sessions will create a local or pre-recorded file not yet in the speaker consent record."
]
}
The page's check: kept - nothing to flag
Varnholt Platform Summit (company-run, a forced platform) - brief
5 sessions, at most 1 at once; managed virtual-venue platform; moderator, technical watcher and a host on the feed; a rehearsed handoff for the single likeliest failure; 4 of 6 gates.
Input:
{
"task": "brief",
"event": "Event: Varnholt Platform Summit; an event people are inside - an interaction surface is open; 5 sessions, at most 1 at once, shortest gap 5 minutes, programme span 195 minutes\nPromised: paid virtual ticket no; a sponsor deliverable naming the stream or a virtual booth yes; an attendee directory sold yes; a platform forced by procurement or a sponsor Managed virtual-venue platform\nPeople: 3 people free to do only production during a session; existing community chat space no; someone has streamed before yes; a recurring event no; platform choice reversible for 10 more days\nLast edition: a feed died no; a dead feed went unnoticed yes; the audience barely used live interaction no\nPractice: rehearsal on the real platform yes; fallback line published yes; the person who says it knows the sentence no; the same sessions on a second live platform no; a contingency document nobody has read aloud no; every session recorded and re-postable yes\nConsent and access: recordings in the speaker consent record no; attendees on camera anywhere yes; captions required yes (platform support unknown); demo speakers warned about background music no",
"sessions": "Sessions, in order (session | UTC | speaker | speaker offset | speaker local start | cannot be re-run | live demo | connection | presented on this platform before | demo failed before | moderator | watcher | tech check | readiness rung | why):\n1. CEO keynote | 14:00-14:30 | Dana Harrowmere | -5 | 09:00 | yes | no | good | yes | no | Grace | Tomas | on the real platform | individual | cannot be re-run\n2. Product roadmap | 14:35-15:15 | Arjun Kesavane | -8 | 06:35 | no | yes | good | yes | no | Grace | Tomas | on the real platform | individual | live demo\n3. Customer panel | 15:20-16:00 | Lucia Tarravel | -3 | 12:20 | no | no | unknown | no | no | Grace | Tomas | not yet | individual | never presented on this platform; connection unknown\n4. Live build | 16:05-16:50 | Kenji Amaroku | +9 | 01:05 | no | yes | good | yes | no | Grace | Tomas | on the real platform | prerecord | live demo; middle of the speaker's night | SPEAKER'S NIGHT\n5. Wrap-up | 16:55-17:15 | Dana Harrowmere | -5 | 11:55 | no | no | good | yes | no | Grace | Tomas | on the real platform | note | the default",
"facts": "Interaction posture: an event people are inside; concurrency 1; continuous programme yes\nPlatform: the page's pick is managed; rungs Single one-way feed available; One-way feed plus the existing chat space available; Broadcast tool with a built-in question queue dominated; Assembled stack available; Managed virtual-venue platform promoted; a second live platform carrying the same sessions deleted\nSpeaker readiness: the event's deepest rung is prerecord; rungs Slides and a join link available; A written home-setup note default; One shared group tech-check window promoted; Individual tech check plus an instructed local backup recording promoted; A pre-recorded talk played to schedule, speaker live in chat promoted; a tech check on a different tool deleted\nModeration staffing: the page's pick is host; rungs No moderation staffing available; One moderator across the whole event default; One moderator per concurrent session same as event-wide; Moderator plus a technical watcher promoted; Moderator, technical watcher and a host on the feed promoted; A technical watcher per feed, no moderator not applicable; the speaker moderating their own chat deleted; people on duty at peak 3\nFailure drill: the page's pick is handoff; rungs No drill available; A written fallback line published before the day default; A rehearsed handoff for the single likeliest failure promoted; A standing fallback destination kept warm dominated - sessions re-postable; A full outage drill on a second platform dominated - sessions re-postable; a contingency document nobody has read aloud deleted\nChecks (4 of 6): Named moderators (Every concurrent session has a named moderator, or its interaction surface is closed) passed; Real-platform check (Every speaker has joined the platform the event actually runs on before the day) MISSING; Fallback line (The fallback line is published and the person who will say it knows the sentence) MISSING; Rehearsal (One rehearsal runs on the platform the event actually runs on) passed; Staffing (The people on duty per session fit the people free to do only production) passed; No deleted rung (No deleted rung is in use) passed\nSignals to record: Speakers who joined a check on the real platform before the day, over speakers scheduled (self-set) - the one leading indicator; Time from a feed dropping to the audience being told something (self-set); Questions relayed to a speaker against questions asked (self-set)\nFindings (8):\n[check] night (time zones): Middle of the speaker's night: Kenji Amaroku at 01:05 local (Live build) - move the slot, or pre-record with the speaker live in chat.\n[check] line_unrehearsed (drill): The fallback line is published but nobody has been told to say it live - name the person and give them the sentence.\n[check] captions (accessibility): Captions are required and the platform's support is unconfirmed - ask the vendor in writing and report what it can and cannot do.\n[check] consent (consent): 4 sessions will create a local or pre-recorded file - get it into the speaker consent record before the file exists; a backup is not a recording anyone agreed to publish.\n[check] music (speakers): Warn demo speakers: no background music in anything shared - incidental music can get the stream taken down mid-session.\n[check] checks (measurement): Delivery gates: 4 of 6 (all self-set).\n[info] reverse (platform): The platform choice stops being reversible in 10 days - put the vendor questions in writing now.\n[info] reposting (drill): Every session is recorded and can be re-posted - the content-survives axis stops mattering, and the rehearsed handoff beats a warm fallback or a full drill."
}
Reply:
{
"task": "brief",
"briefs": [
{
"session": "CEO keynote",
"speaker": "Dana Harrowmere",
"local": "09:00",
"rung": "individual",
"message": "Your session is scheduled for 14:00-14:30 UTC, which should be 09:00 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Join an individual check on the event's platform and keep a local backup recording running that does not upload while you talk; send it to to be named by to be named. Your local recording will be covered by the consent record before it is made. If your connection drops, rejoin with the same link while the moderator covers."
},
{
"session": "Product roadmap",
"speaker": "Arjun Kesavane",
"local": "06:35",
"rung": "individual",
"message": "Your session is scheduled for 14:35-15:15 UTC, which should be 06:35 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Join an individual check on the event's platform and keep a local backup recording running that does not upload while you talk; send it to to be named by to be named. Since this session includes a live demo, prepare a recorded fallback of it, and avoid background music in anything you share. Your local recording will be covered by the consent record before it is made. If your connection drops, rejoin with the same link while the moderator covers."
},
{
"session": "Customer panel",
"speaker": "Lucia Tarravel",
"local": "12:20",
"rung": "individual",
"message": "Your session is scheduled for 15:20-16:00 UTC, which should be 12:20 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Join an individual check on the event's platform and keep a local backup recording running that does not upload while you talk; send it to to be named by to be named. Your local recording will be covered by the consent record before it is made. If your connection drops, rejoin with the same link while the moderator covers."
},
{
"session": "Live build",
"speaker": "Kenji Amaroku",
"local": "01:05",
"rung": "prerecord",
"message": "Your session is scheduled for 16:05-16:50 UTC, which should be 01:05 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Your talk will be pre-recorded and played to schedule, with you live in chat during the slot; the recording is due to be named. Since your demo is part of the pre-recorded talk, prepare a recorded fallback of it as well, and avoid background music in anything you share. The recording will be covered by the consent record before it is made. If your connection drops while you're live in chat, rejoin with the same link while the moderator covers."
},
{
"session": "Wrap-up",
"speaker": "Dana Harrowmere",
"local": "11:55",
"rung": "note",
"message": "Your session is scheduled for 16:55-17:15 UTC, which should be 11:55 your local time — please tell us now if that's wrong. The join link will be the same one on the day, on the single platform the whole event runs on; the link itself is to be named. Please plan for a wired connection, wired headphones rather than laptop audio, and nothing syncing in the background. Please read the setup note we send before the day. If your connection drops, rejoin with the same link while the moderator covers."
}
],
"note": "Before sending, get all four recorded sessions into the speaker consent record, since none are currently covered."
}
The page's check: kept - nothing to flag
The run-sheet CSV for the first sample
session,start_utc,end_utc,speaker,speaker_local_start,readiness,moderator,watcher,tech_check
Opening keynote,15:00,15:45,Maya Orrenby,16:00,individual,Jun,Ravi,real
Typing at scale,16:00,16:40,Leo Quarrender,18:00,individual,Ines,,real
Async in practice,16:00,16:40,Hana Ostrevin,02:00,prerecord,Kofi,,none
Packaging clinic,16:50,17:30,Sam Pellucan,09:50,prerecord,Sam Pellucan,,other
Data pipelines,16:50,17:30,Priya Ventrakil,22:20,note,Jun,,real
Closing,17:40,18:00,Maya Orrenby,18:40,note,Kofi,Ravi,real
Build the input yourself
Load the engine in node (global.window = global; require("./stagekit.js"); require("./stagereply.js")), then:
const K = StageKit, R = StageReply;
const f = K.form({ name: "My Conf Online", surface: "surface", chatSpace: "yes", people: "5", paidTicket: "yes",
sessions: fs.readFileSync("sessions.csv", "utf8") });
// f.concurrency, f.minGap, f.sessions (localStart, night, rung, why), f.needed
// f.recPlat, f.readyRung, f.recStaff, f.recDrill and their rungs, f.checks, f.findings
K.runCSV(f) // session, start_utc, end_utc, speaker, speaker_local_start, ...
const b = K.buildInput(f, "plan"); // or "brief"
const wire = K.toWire(b.input); // POST this to /estimate and /run
// then: const reply = R.normalize(R.parseReply(job.output.output), "plan");
// R.check(reply, b) // {status: kept or flagged, notes}
Get a token for the steps below from /tokens.html.
Step 1 — a tiny client helper
One function that sends JSON and unwraps the response. Paste a personal token from /tokens.html, or leave it empty and mint a guest token in step 2.
BASE="https://api.skillsafe.ai/v1/app-api"
TOKEN="paste-your-token-here" # from https://remote-stage.skillsafe.ai/tokens.html
api() { # api METHOD PATH [JSON-BODY]
curl -s -X "$1" "$BASE$2" -H "Content-Type: application/json" \
${TOKEN:+-H "Authorization: Bearer $TOKEN"} ${3:+--data "$3"}
}
import json, urllib.request
BASE = "https://api.skillsafe.ai/v1/app-api"
TOKEN = "paste-your-token-here" # from https://remote-stage.skillsafe.ai/tokens.html
def api(method, path, body=None, headers=None):
req = urllib.request.Request(BASE + path, method=method,
data=None if body is None else json.dumps(body).encode(),
headers={"Content-Type": "application/json", **({"Authorization": "Bearer " + TOKEN} if TOKEN else {}), **(headers or {})})
with urllib.request.urlopen(req) as r:
env = json.load(r)
if env.get("error"):
raise RuntimeError(env["error"])
return env["data"]
// remote-stage.mjs -- Node 18+ (global fetch)
const BASE = "https://api.skillsafe.ai/v1/app-api";
let TOKEN = "paste-your-token-here"; // from https://remote-stage.skillsafe.ai/tokens.html
async function api(method, path, body, headers = {}) {
const r = await fetch(BASE + path, { method, headers: { "Content-Type": "application/json",
...(TOKEN ? { Authorization: "Bearer " + TOKEN } : {}), ...headers },
body: body === undefined ? undefined : JSON.stringify(body) });
const env = await r.json();
if (env.error) throw new Error(env.error.code + ": " + env.error.message);
return env.data;
}
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
var token = "paste-your-token-here" // from https://remote-stage.skillsafe.ai/tokens.html
func api(method, path string, body any, headers map[string]string) (map[string]any, error) {
var buf bytes.Buffer
if body != nil { json.NewEncoder(&buf).Encode(body) }
req, _ := http.NewRequest(method, base+path, &buf)
req.Header.Set("Content-Type", "application/json")
if token != "" { req.Header.Set("Authorization", "Bearer "+token) }
for k, v := range headers { req.Header.Set(k, v) }
res, err := http.DefaultClient.Do(req)
if err != nil { return nil, err }
defer res.Body.Close()
var env struct { Data map[string]any; Error map[string]any }
json.NewDecoder(res.Body).Decode(&env)
if env.Error != nil { return nil, fmt.Errorf("%v", env.Error) }
return env.Data, nil
}
// RemoteStage.java -- Java 17+, with com.fasterxml.jackson.core:jackson-databind
import com.fasterxml.jackson.databind.*;
import java.net.URI; import java.net.http.*; import java.util.*;
public class RemoteStage {
static final String BASE = "https://api.skillsafe.ai/v1/app-api";
static String token = "paste-your-token-here"; // from https://remote-stage.skillsafe.ai/tokens.html
static final ObjectMapper M = new ObjectMapper();
static final HttpClient C = HttpClient.newHttpClient();
static JsonNode api(String method, String path, Object body, Map<String, String> headers) throws Exception {
var b = HttpRequest.newBuilder(URI.create(BASE + path)).header("Content-Type", "application/json");
if (!token.isEmpty()) b.header("Authorization", "Bearer " + token);
if (headers != null) headers.forEach(b::header);
b.method(method, body == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofString(M.writeValueAsString(body)));
JsonNode env = M.readTree(C.send(b.build(), HttpResponse.BodyHandlers.ofString()).body());
if (env.hasNonNull("error")) throw new RuntimeException(env.get("error").toString());
return env.get("data");
}
}
require "json"
require "net/http"
BASE = "https://api.skillsafe.ai/v1/app-api"
TOKEN = "paste-your-token-here" # from https://remote-stage.skillsafe.ai/tokens.html
def api(method, path, body = nil, headers = {})
uri = URI(BASE + path)
req = Net::HTTPGenericRequest.new(method, !body.nil?, true, uri.request_uri,
{ "Content-Type" => "application/json" }.merge(TOKEN.empty? ? {} : { "Authorization" => "Bearer #{TOKEN}" }).merge(headers))
req.body = JSON.generate(body) unless body.nil?
env = JSON.parse(Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }.body)
raise env["error"].to_s if env["error"]
env["data"]
end
<?php
const BASE = "https://api.skillsafe.ai/v1/app-api";
$TOKEN = "paste-your-token-here"; // from https://remote-stage.skillsafe.ai/tokens.html
function api(string $method, string $path, $body = null, array $headers = []) {
global $TOKEN;
$h = ["Content-Type: application/json"];
if ($TOKEN) $h[] = "Authorization: Bearer $TOKEN";
foreach ($headers as $k => $v) $h[] = "$k: $v";
$ch = curl_init(BASE . $path);
curl_setopt_array($ch, [CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $h, CURLOPT_RETURNTRANSFER => true]);
if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
$env = json_decode(curl_exec($ch), true);
if (!empty($env["error"])) throw new Exception(json_encode($env["error"]));
return $env["data"];
}
// Program.cs -- .NET 6+ console app
using System.Net.Http.Json; using System.Text.Json; using System.Text.Json.Nodes;
static class Api {
public const string Base = "https://api.skillsafe.ai/v1/app-api";
public static string Token = "paste-your-token-here"; // from https://remote-stage.skillsafe.ai/tokens.html
static readonly HttpClient C = new();
public static async Task<JsonNode?> Call(string method, string path, object? body = null, Dictionary<string, string>? headers = null) {
var req = new HttpRequestMessage(new HttpMethod(method), Base + path);
if (Token != "") req.Headers.Add("Authorization", "Bearer " + Token);
if (headers != null) foreach (var h in headers) req.Headers.Add(h.Key, h.Value);
if (body != null) req.Content = JsonContent.Create(body);
var env = JsonNode.Parse(await (await C.SendAsync(req)).Content.ReadAsStringAsync())!;
if (env["error"] is JsonNode e && e.GetValueKind() != JsonValueKind.Null) throw new Exception(e.ToJsonString());
return env["data"];
}
}
Step 2 — a token
A guest token is enough for /me and /estimate. A run is metered, so it needs a personal token: sign in on /tokens.html and copy it from there.
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN=$(curl -s -X POST "$BASE/guest" -H "Content-Type: application/json" -d '{"slug":"remote-stage"}' | jq -r '.data.token')
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN = ""
TOKEN = api("POST", "/guest", {"slug": "remote-stage"})["token"]
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN = "";
TOKEN = (await api("POST", "/guest", { slug: "remote-stage" })).token;
// inside main: a guest token (enough for /me and /estimate); a run needs your personal token
token = ""
g, err := api("POST", "/guest", map[string]string{"slug": "remote-stage"}, nil)
if err != nil { panic(err) }
token = g["token"].(string)
// inside main: a guest token (enough for /me and /estimate); a run needs your personal token
token = "";
token = api("POST", "/guest", Map.of("slug", "remote-stage"), null).get("token").asText();
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN.replace("")
TOKEN.replace(api("POST", "/guest", { slug: "remote-stage" })["token"])
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
$TOKEN = "";
$TOKEN = api("POST", "/guest", ["slug" => "remote-stage"])["token"];
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
Api.Token = "";
Api.Token = (await Api.Call("POST", "/guest", new { slug = "remote-stage" }))!["token"]!.GetValue<string>();
Step 3 — GET /me
Who the token is (subject_type: user or guest) and the credit balance.
api GET /me | jq '.data | {subject_type, credits}'
me = api("GET", "/me")
print(me["subject_type"], me.get("credits"))
const me = await api("GET", "/me");
console.log(me.subject_type, me.credits);
me, _ := api("GET", "/me", nil, nil)
fmt.Println(me["subject_type"], me["credits"])
JsonNode me = api("GET", "/me", null, null);
System.out.println(me.get("subject_type") + " " + me.get("credits"));
me = api("GET", "/me")
puts [me["subject_type"], me["credits"]].inspect
$me = api("GET", "/me");
echo $me["subject_type"], " ", $me["credits"] ?? "", "\n";
var me = await Api.Call("GET", "/me");
Console.WriteLine($"{me!["subject_type"]} {me["credits"]}");
Step 4 — POST /estimate
Free. The body is the run input itself, the bare object (never wrapped in {"input": ...}). hold_credits is a reservation, not the price; min_credits is what the balance must cover; model_alias reads gpt-terra.
# input.json: the run input object - {"task": "plan", "event": "Event: ...; an event people are inside; 6 sessions, at most 2 at once ...", "sessions": "Sessions, in order ...", "facts": "Interaction posture: ..."}
# - see the input table
api POST /estimate "$(cat input.json)" | jq '.data | {hold_credits, min_credits, model, model_alias, markup_bps, warnings}'
inp = json.load(open("input.json")) # {"task": "plan", "event": "Event: ...; an event people are inside; 6 sessions, at most 2 at once ...", "sessions": "Sessions, in order ...", "facts": "Interaction posture: ..."}
# - see the input table
est = api("POST", "/estimate", inp)
print(est["hold_credits"], est["min_credits"], est["model"], est.get("warnings"))
import { readFileSync } from "node:fs";
const input = JSON.parse(readFileSync("input.json", "utf8")); // {task: "plan" or "brief", event, sessions, facts} (see the input table)
const est = await api("POST", "/estimate", input);
console.log(est.hold_credits, est.min_credits, est.model, est.warnings);
raw, _ := os.ReadFile("input.json") // add "os" to the imports
var input map[string]any
json.Unmarshal(raw, &input)
est, _ := api("POST", "/estimate", input, nil)
fmt.Println(est["hold_credits"], est["min_credits"], est["model"])
Map<String, Object> input = M.readValue(new java.io.File("input.json"), Map.class);
JsonNode est = api("POST", "/estimate", input, null);
System.out.println(est.get("hold_credits") + " " + est.get("min_credits") + " " + est.get("model"));
input = JSON.parse(File.read("input.json"))
est = api("POST", "/estimate", input)
puts [est["hold_credits"], est["min_credits"], est["model"]].inspect
$input = json_decode(file_get_contents("input.json"), true);
$est = api("POST", "/estimate", $input);
echo $est["hold_credits"], " ", $est["min_credits"], " ", $est["model"], "\n";
var input = JsonNode.Parse(File.ReadAllText("input.json"))!;
var est = await Api.Call("POST", "/estimate", input);
Console.WriteLine($"{est!["hold_credits"]} {est["min_credits"]} {est["model"]}");
Step 5 — POST /run, then poll the job
Send an Idempotency-Key built from the lane and the input: a retry with the same key never bills twice. The page uses remote-stage:<task>:<inputHash>:a<attempt> - the lane is part of the key - and its one automatic reformat retry is a new attempt number, named in the page as one extra run. A plan carries summary, posture, platform, speakers, staffing, drill, rehearsal, budget, checks, signals and caveats; a brief reply carries briefs (session, speaker, local, rung, message) and note. The code below prints the headline parts of either (list items are plain strings).
KEY="remote-stage:plan:$(shasum -a 256 input.json | cut -c1-16):a1"
JOB=$(curl -s -X POST "$BASE/run" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $KEY" --data @input.json | jq -r '.data.job_id')
while :; do
J=$(api GET "/jobs/$JOB"); S=$(echo "$J" | jq -r '.data.status')
case "$S" in succeeded|failed|cancelled) break;; esac; sleep 2
done
echo "$J" | jq -r '.data.output.output' > reply.json # one JSON object, the reply contract
echo "$J" | jq '.data | {charged_credits, truncated}'
jq -r '.summary // .format, .note // .posture, ((.signals // .caveats)[] | "\(.signal // .caveat): \(.text // .text)")' reply.json
jq -r '.budget // .note // empty' reply.json # the budget split (plan)
import hashlib, time
key = "remote-stage:" + inp["task"] + ":" + hashlib.sha256(json.dumps(inp).encode()).hexdigest()[:16] + ":a1"
job = api("POST", "/run", inp, {"Idempotency-Key": key})
while True:
j = api("GET", "/jobs/" + job["job_id"])
if j["status"] in ("succeeded", "failed", "cancelled"):
break
time.sleep(2)
reply = json.loads(j["output"]["output"]) # the reply as one JSON object
print(j["charged_credits"], j.get("truncated"), reply.get("summary"))
print(reply.get("note") or reply.get("posture", ""))
for s in reply.get("signals") or reply.get("caveats") or []:
print(s.get("signal", s.get("caveat")), "-", s.get("text", s.get("text")))
if reply.get("budget"):
print("budget:", reply["budget"])
import { createHash } from "node:crypto";
const key = `remote-stage:${input.task}:${createHash("sha256").update(JSON.stringify(input)).digest("hex").slice(0, 16)}:a1`;
const job = await api("POST", "/run", input, { "Idempotency-Key": key });
let j;
do { await new Promise((r) => setTimeout(r, 2000)); j = await api("GET", "/jobs/" + job.job_id); }
while (!["succeeded", "failed", "cancelled"].includes(j.status));
const reply = JSON.parse(j.output.output);
console.log(j.charged_credits, j.truncated, reply.summary);
console.log(reply.note ?? reply.posture);
for (const s of reply.signals || reply.caveats || []) console.log(s.signal ?? s.caveat, "-", s.text ?? s.text);
if (reply.budget) console.log("budget:", reply.budget);
sum := sha256.Sum256(raw) // add "crypto/sha256", "encoding/hex", "time" to the imports
key := "remote-stage:" + input["task"].(string) + ":" + hex.EncodeToString(sum[:8]) + ":a1"
job, _ := api("POST", "/run", input, map[string]string{"Idempotency-Key": key})
var j map[string]any
for {
time.Sleep(2 * time.Second)
j, _ = api("GET", "/jobs/"+job["job_id"].(string), nil, nil)
if s := j["status"]; s == "succeeded" || s == "failed" || s == "cancelled" { break }
}
var reply map[string]any
json.Unmarshal([]byte(j["output"].(map[string]any)["output"].(string)), &reply)
items, _ := reply["signals"].([]any) // signals and caveats are plain strings
fmt.Println(j["charged_credits"], j["truncated"], reply["summary"])
fmt.Println(reply["note"], reply["posture"])
for _, x := range items {
c := x.(map[string]any)
fmt.Println(c["signal"], "-", c["status"])
}
if fix, ok := reply["budget"].(string); ok && fix != "" {
fmt.Println("budget:", fix)
}
var digest = java.security.MessageDigest.getInstance("SHA-256").digest(M.writeValueAsBytes(input));
String key = "remote-stage:" + input.get("task") + ":" + HexFormat.of().formatHex(digest, 0, 8) + ":a1";
JsonNode job = api("POST", "/run", input, Map.of("Idempotency-Key", key)), j;
do { Thread.sleep(2000); j = api("GET", "/jobs/" + job.get("job_id").asText(), null, null); }
while (!Set.of("succeeded", "failed", "cancelled").contains(j.get("status").asText()));
JsonNode reply = M.readTree(j.get("output").get("output").asText());
System.out.println(j.get("charged_credits") + " " + reply.get("summary"));
System.out.println(reply.path("note").asText(reply.path("posture").asText()));
for (JsonNode s : reply.has("signals") ? reply.path("signals") : reply.path("caveats")) System.out.println(s.path("signal").asText(s.path("caveat").asText()) + " - " + s.path("status").asText(s.path("text").asText()));
if (!reply.path("budget").asText().isEmpty()) System.out.println("budget: " + reply.get("budget").asText());
require "digest"
key = "remote-stage:#{input["task"]}:#{Digest::SHA256.hexdigest(JSON.generate(input))[0, 16]}:a1"
job = api("POST", "/run", input, { "Idempotency-Key" => key })
j = nil
loop do
sleep 2
j = api("GET", "/jobs/#{job["job_id"]}")
break if %w[succeeded failed cancelled].include?(j["status"])
end
reply = JSON.parse(j["output"]["output"])
puts [j["charged_credits"], j["truncated"], reply["summary"]].inspect
puts reply["note"] || reply["posture"]
(reply["signals"] || reply["caveats"] || []).each { |s| puts "#{s["signal"] || s["caveat"]} - #{s["text"] || s["text"]}" }
puts "budget: #{reply["budget"]}" unless reply["budget"].to_s.empty?
$key = "remote-stage:" . $input["task"] . ":" . substr(hash("sha256", json_encode($input)), 0, 16) . ":a1";
$job = api("POST", "/run", $input, ["Idempotency-Key" => $key]);
do { sleep(2); $j = api("GET", "/jobs/" . $job["job_id"]); }
while (!in_array($j["status"], ["succeeded", "failed", "cancelled"]));
$reply = json_decode($j["output"]["output"], true);
echo $j["charged_credits"], " ", ($reply["summary"] ?? ""), "\n";
echo $reply["note"] ?? $reply["posture"] ?? "", "\n";
foreach ($reply["signals"] ?? $reply["caveats"] ?? [] as $s) echo $s["signal"] ?? $s["caveat"], " - ", $s["text"] ?? $s["text"], "\n";
if (!empty($reply["budget"])) echo "budget: ", $reply["budget"], "\n";
var digest = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(input.ToJsonString()));
var key = $"remote-stage:{input["task"]}:{Convert.ToHexString(digest, 0, 8).ToLowerInvariant()}:a1";
var job = await Api.Call("POST", "/run", input, new() { ["Idempotency-Key"] = key });
JsonNode j;
do { await Task.Delay(2000); j = (await Api.Call("GET", "/jobs/" + job!["job_id"]))!; }
while (!new[] { "succeeded", "failed", "cancelled" }.Contains(j["status"]!.GetValue<string>()));
var reply = JsonNode.Parse(j["output"]!["output"]!.GetValue<string>());
Console.WriteLine($"{j["charged_credits"]} {reply!["summary"]}");
Console.WriteLine($"{reply["note"] ?? reply["posture"]}");
foreach (var s in (reply["signals"] ?? reply["caveats"]) as JsonArray ?? new JsonArray()) Console.WriteLine($"{s!["signal"] ?? s["caveat"]} - {s["text"] ?? s["text"]}");
if (reply["budget"] is JsonNode fix && fix.GetValue<string>() != "") Console.WriteLine("budget: " + fix);
Step 6 — POST /run-stream
The same run as Server-Sent Events, with the same input.json. Browsers receive progress ticks rather than text deltas; the final done event carries the reply.
# Server-Sent Events: tick/delta events while the job runs, then a final event with the job
curl -N -s -X POST "$BASE/run-stream" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: remote-stage:plan:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json
rev = json.load(open("input.json")) # the same run input as input.json: {"task": "plan", "event": "Event: ...; an event people are inside; 6 sessions, at most 2 at once ...", "sessions": "Sessions, in order ...", "facts": "Interaction posture: ..."}
# - see the input table
req = urllib.request.Request(BASE + "/run-stream", method="POST", data=json.dumps(rev).encode(),
headers={"Content-Type": "application/json", "Authorization": "Bearer " + TOKEN,
"Idempotency-Key": "remote-stage:plan:" + hashlib.sha256(json.dumps(rev).encode()).hexdigest()[:16] + ":a1"})
with urllib.request.urlopen(req) as r:
for line in r:
line = line.decode().strip()
if line.startswith("data:"):
print(line[5:].strip()[:200])
const rev = JSON.parse(readFileSync("input.json", "utf8"));
const r = await fetch(BASE + "/run-stream", { method: "POST", body: JSON.stringify(rev), headers: {
"Content-Type": "application/json", Authorization: "Bearer " + TOKEN,
"Idempotency-Key": `remote-stage:plan:${createHash("sha256").update(JSON.stringify(rev)).digest("hex").slice(0, 16)}:a1` } });
const dec = new TextDecoder();
for await (const chunk of r.body) for (const line of dec.decode(chunk).split("\n"))
if (line.startsWith("data:")) console.log(line.slice(5).trim().slice(0, 200));
rraw, _ := os.ReadFile("input.json") // add "bufio", "strings" to the imports
rs := sha256.Sum256(rraw)
req, _ := http.NewRequest("POST", base+"/run-stream", bytes.NewReader(rraw))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Idempotency-Key", "remote-stage:plan:"+hex.EncodeToString(rs[:8])+":a1")
res, _ := http.DefaultClient.Do(req)
sc := bufio.NewScanner(res.Body)
for sc.Scan() { if l := sc.Text(); strings.HasPrefix(l, "data:") { fmt.Println(l[5:]) } }
String rev = java.nio.file.Files.readString(java.nio.file.Path.of("input.json"));
var rd = java.security.MessageDigest.getInstance("SHA-256").digest(rev.getBytes());
var sreq = HttpRequest.newBuilder(URI.create(BASE + "/run-stream")).header("Content-Type", "application/json")
.header("Authorization", "Bearer " + token).header("Idempotency-Key", "remote-stage:plan:" + HexFormat.of().formatHex(rd, 0, 8) + ":a1")
.POST(HttpRequest.BodyPublishers.ofString(rev)).build();
C.send(sreq, HttpResponse.BodyHandlers.ofLines()).body().filter(l -> l.startsWith("data:")).forEach(System.out::println);
rev = File.read("input.json")
uri = URI(BASE + "/run-stream")
req = Net::HTTP::Post.new(uri, "Content-Type" => "application/json", "Authorization" => "Bearer #{TOKEN}",
"Idempotency-Key" => "remote-stage:plan:#{Digest::SHA256.hexdigest(rev)[0, 16]}:a1")
req.body = rev
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |h|
h.request(req) { |res| res.read_body { |chunk| chunk.each_line { |l| puts l if l.start_with?("data:") } } }
end
$rev = file_get_contents("input.json");
$ch = curl_init(BASE . "/run-stream");
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $rev, CURLOPT_HTTPHEADER => [
"Content-Type: application/json", "Authorization: Bearer $TOKEN",
"Idempotency-Key: remote-stage:plan:" . substr(hash("sha256", $rev), 0, 16) . ":a1"],
CURLOPT_WRITEFUNCTION => function ($ch, $chunk) { foreach (explode("\n", $chunk) as $l) if (str_starts_with($l, "data:")) echo $l, "\n"; return strlen($chunk); }]);
curl_exec($ch);
var rev = File.ReadAllText("input.json");
var rd = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(rev));
var sreq = new HttpRequestMessage(HttpMethod.Post, Api.Base + "/run-stream") { Content = new StringContent(rev, System.Text.Encoding.UTF8, "application/json") };
sreq.Headers.Add("Authorization", "Bearer " + Api.Token);
sreq.Headers.Add("Idempotency-Key", $"remote-stage:plan:{Convert.ToHexString(rd, 0, 8).ToLowerInvariant()}:a1");
using var http = new HttpClient();
using var res = await http.SendAsync(sreq, HttpCompletionOption.ResponseHeadersRead);
using var rdr = new StreamReader(await res.Content.ReadAsStreamAsync());
for (string? l; (l = await rdr.ReadLineAsync()) != null;) if (l.StartsWith("data:")) Console.WriteLine(l);