Run Debrief Table from your own code
Both metered lanes are available over HTTP and each returns one JSON object. The division of labour: the page checks the debrief timing and who is heard, flags orphan entries, blame wording and team-health findings, lists the documents to reconcile, picks the depth, publication and tracking rungs and scales the agenda - all free, in debriefkit.js. The run writes the log or the agenda; the page then holds the reply to its own debrief (debriefreply.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":"debrief-table"}), 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, edition, entries, 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 - log (the dated lessons-learned log, from the draft entries) and agenda (the session agenda with the blameless opening to read out). A missing or unknown task is answered as log. Both lanes send the same four fields.
The input
| Field | Required | What |
|---|---|---|
task | yes | log or agenda. If it is missing or neither, do log and set "task": "log". |
edition | yes | the edition, its dates, the session booked, the team, every named role and whether they have a voice, the documents that exist, the code-of-conduct position and last edition's carry-through. |
entries | yes | every draft entry in order with kind, the three parts, owner, due date and status, and the page's flags. |
facts | yes | the page's depth, publication and tracking picks with their rungs, the passes, the session agenda, the pass threshold, the signals to record and every finding tagged [fix], [check] or [info]. |
retry_note | no | optional; if present, your previous reply was unusable - follow it. |
The rules the model applies
- Debrief every edition, unconditionally - a quiet edition still gets one. Set the date before the team disperses; six weeks out the record is the loudest memories, so say so and downgrade the claim. Internal-facing only: nothing here reaches attendees, speakers or sponsors.
- The blameless frame, said out loud: the question is what conditions allowed something, never who caused it. Findings describe gaps and systems, never people; "they took on too much" is not a finding, "one person held three roles with no backup" is. On a volunteer team, saying "I could not keep up" is a finding about the workload; on a staffed or mixed team, whoever holds the reporting line says the frame.
- Reconstruct the timeline before any judgment; run the what-went-well pass before what-went-poorly. Reconcile only against documents that exist - feedback summary, risk register, planned budget, run of show, the goals set before the event - and hand each back to its owner as a finding, never a redesign. Team-health findings are routed to team structure, not solved here. Trends across editions belong to continuous improvement; this log covers one edition.
- Each entry has three shallow parts - what happened, what was done in the moment, what changes next edition - and a named owner and a due date, or an explicit "no action, because". The one pass threshold: zero orphan entries. Never manufacture an action item to look thorough.
- Depth: a written pre-read plus one session by default; per-track sessions when workstream leads worked independently; the multi-track written review for a leadership handover or several cities under one brand; track rungs are deleted for a team of one or two or an exhausted team. Publication: recap plus retrospective by default; the transparency report only with code-of-conduct sign-off on anonymisation; every public rung deleted for a private event. Tracking: owner and date on every entry plus plan carry-over; a mid-cycle check-in for short-fuse items; a standing tracker where one already exists or structural work was routed; carry-over and tracker deleted for a final or one-off edition. Every threshold here is self-set.
House rules
- Use only the input and the rules above. The page's names, dates, picks, minutes and counts are exact - copy them. Every number in a sentence must appear in the input.
- Label anything that is not one of the rules above, and is not in the input, as your own design.
- Never invent an owner, a date, a finding, a figure or a person; where someone must be named and is not, write "to be named". Never name a person as the cause of anything. Refer to people by name or as they - never infer anyone's gender from a name.
- 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
log
summary- one sentence, at most 35 words: the edition, the pass threshold result, and the first thing to settle.frame- one sentence: the blameless frame as it applies to this team.entries- one object per draft entry in order:n,kind(well,poorlyoroutcome, the page's),happened,done,change(the three parts rewritten in blameless, system terms; keep each decision; "" where the draft has nothing),owner(the draft owner when it is a named person; "to be named" for an open entry without one; "" for a no-action entry without one),due(the draft date exactly, or "" when it has none),status(open,no actionordone, the page's),note(one short sentence: what to settle, or "").routed- the team-health entries the page lists, as numbers;[]when none.reconciliations- one object per document in the page's order:document(exactly),status(existsormissing),handback(one short sentence: what to check and hand back, or that the check is skipped).depth,publication,tracking- eachpickandplanned(the page's keys: depthone,preread,track,written; publicationnothing,recap,retro,full; trackingentry,checkin,carry,tracker),note(one sentence; name any deleted rung).signals- 2 or 3 short strings, the page's signals, each with what it would change next edition (your design).caveats- at most 4 short strings:[fix]findings first (the most urgent four when there are more), then the most important[check]findings.[]when there are none of either.
{
"task": "log",
"summary": "one sentence",
"frame": "one sentence",
"entries": [ { "n": 1, "kind": "well", "happened": "text", "done": "text", "change": "text", "owner": "a name", "due": "YYYY-MM-DD", "status": "open", "note": "" } ],
"routed": [ 4 ],
"reconciliations": [ { "document": "Risk register", "status": "exists", "handback": "one short sentence" } ],
"depth": { "pick": "preread", "planned": "preread", "note": "one sentence" },
"publication": { "pick": "retro", "planned": "retro", "note": "one sentence" },
"tracking": { "pick": "carry", "planned": "carry", "note": "one sentence" },
"signals": [ "what to record and what it changes" ],
"caveats": [ "a caveat" ]
}
The page holds it to its own debrief: every entry in order with its kind, status, draft owner (an orphan gets to be named) and due date, no person named as a cause, the routed team-health entries, every document status and the three menu picks; no figure may appear that the input does not hold.
agenda
title- a short title naming the edition.opening- three or four sentences to read out loud: the blameless frame (conditions, never who caused it), what leaves the room, and the addition for this team type.prereads- the roles the page asks for a written pre-read from, exactly;[]when none.segments- one object per segment in the page's order:segment(exactly),minutes(the page's number),does(one short sentence: what happens in it for this edition - name the documents to reconcile and the entries to settle where relevant).close- one or two sentences: what leaves the room and when the log goes to whoever plans next edition - or, for a final or one-off edition, where the log is filed as the closing record.note- one sentence, at most 30 words, for the facilitator: what to settle before the session.
{
"task": "agenda",
"title": "Debrief - an edition",
"opening": "three or four sentences",
"prereads": [ "a role" ],
"segments": [ { "segment": "Frame", "minutes": 5, "does": "one short sentence" } ],
"close": "one or two sentences",
"note": "one sentence"
}
The page requires its segments in order with their minutes, the pre-read roles exactly, and an opening that states the blameless frame.
Worked examples - every lane, every sample
These are the page's three free samples (fictional events and people; every date 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.
Harbor DevConf (volunteers, three days after) - log
6 entries, 1 orphans; depth pick written pre-read plus one session; publication pick recap plus retrospective; tracking pick standing tracker with a review cadence; a 90-minute session.
Input:
{
"task": "log",
"edition": "Edition: Harbor DevConf 2027; recurring for years; doors closed 2027-05-21; debrief 2027-05-27 (6 days after); next planning starts 2027-07-01; session booked for 90 minutes\nTeam: volunteer-run; effort left normal; workstream leads worked independently no; leadership handover no; several cities under one brand no; a year-round tracker already exists no\nNamed roles: Lead organizer (Mira) - in the room; Program chair (Tomas) - in the room; Volunteer lead (Ana) - NO VOICE; Sponsor lead (Jo) - written input; AV lead (Kai) - in the room\nDocuments to reconcile against: Participant feedback summary exists; Risk register exists; Planned budget exists; Run of show MISSING; Goals the team set before the event exists\nCode of conduct: 1 reports, 1 resolved; visible to the community no; pipeline sign-off on anonymisation no; private or NDA-bound no\nLast edition's items: 7 of 12 done",
"entries": "Draft entries, in order (kind | what happened | done in the moment | what changes | owner | due | status):\n#1 well | The speaker green room ran smoothly with a printed schedule on the door | kept the schedule on the door all day | keep the printed green-room schedule | Tomas | 2027-06-15 | open\n#2 poorly | The registration queue ran 40 minutes at doors - longer than last year | opened a second desk at 09:20 | open two desks from the start with pre-printed badges | Mira | 2027-06-30 | open | cross-edition trend\n#3 poorly | Kai forgot to test the backup projector | borrowed one from the venue | test every backup device the night before | we | NO DATE | open | ORPHAN | BLAME WORDING\n#4 poorly | One person held three roles on day two with no backup | Ana covered until 18:00 | split the volunteer lead role in two | Mira | 2027-07-15 | open | team health\n#5 poorly | Lunch ran out for late arrivals | ordered pizza | no action, because the caterer has already been replaced | NONE | NO DATE | no action\n#6 outcome | Two attendees started an open-source CLI project at the hack table | - | log it in the outcome register | Tomas | 2027-06-01 | open",
"facts": "Depth: planned preread; the page's pick is preread; rungs One session available; Written pre-read plus one session default; Per-track sessions available; Multi-track written review starved\nPublication: planned retro; the page's pick is retro; rungs Nothing published available; Recap only available; Recap plus retrospective default; Recap plus retrospective plus transparency report starved\nTracking: planned carry; the page's pick is tracker; rungs Owner and date on the entry default; Mid-cycle check-in promoted; Plan carry-over default; Standing tracker with a review cadence promoted\nPasses: what went well 1; what went poorly 4; outcomes 1; team-health entries to route #4\nSession agenda for 90 minutes: Frame 5; Timeline 15; What went well 10; What went poorly 15; Reconciliations 15; Team health 10; Owners and dates 10; Publication 10; written pre-read from: Lead organizer, Program chair, Volunteer lead, Sponsor lead, AV lead\nPass threshold: zero orphan entries - fails (1 orphans)\nSignals to record: Days from doors closing to the debrief: 6; Named-role coverage: 4 of 5; Carry-through of last edition's items: 7 of 12; Outcomes captured at the debrief: 1\nFindings (9):\n[check] missing_roles (room): No voice from: Volunteer lead (Ana) - a debrief missing a named role misses the half of the day only they saw. Ask for written input at least.\n[info] volunteer_frame (frame): Say that nobody is here on work time and that \"I could not keep up\" is a finding about the workload, not the person - a criticised volunteer simply stops volunteering.\n[fix] orphans (entries): 1 orphan entry: #3 (we, no date) - a named person and a date, or close it as \"no action, because\".\n[fix] blame (frame): Blame in the wording of #3 - rewrite as the conditions that allowed it, never who caused it.\n[info] route_health (team health): Team-health findings to route to team structure, not solve here: #4.\n[check] trend (entries): #2 compares across editions - that trend belongs to continuous improvement; this log covers one edition.\n[check] no_docs (reconciliation): No reconciliation possible against: run of show - say so and skip the check rather than rebuilding the document from memory.\n[check] tracking_pick (tracking): Planned: plan carry-over; the page's pick is standing tracker with a review cadence.\n[check] pass (measurement): Zero orphan entries: fails - 1 orphan (the one pass threshold; self-set)."
}
Reply:
{
"task": "log",
"summary": "Harbor DevConf 2027's log fails the zero-orphan-entries threshold with one orphan entry, and the first thing to settle is naming an owner and due date for entry 3, or closing it as no action.",
"frame": "Nobody on this team is on the clock, so if a volunteer says they could not keep up, that is read as a finding about their workload, not about them, since criticising a volunteer only makes them stop showing up.",
"entries": [
{
"n": 1,
"kind": "well",
"happened": "The speaker green room ran smoothly with a printed schedule on the door.",
"done": "The schedule stayed posted on the door all day.",
"change": "Keep the printed green-room schedule.",
"owner": "Tomas",
"due": "2027-06-15",
"status": "open",
"note": ""
},
{
"n": 2,
"kind": "poorly",
"happened": "The registration queue ran 40 minutes at the doors.",
"done": "A second desk opened at 09:20.",
"change": "Open two desks from the start, with badges pre-printed.",
"owner": "Mira",
"due": "2027-06-30",
"status": "open",
"note": "This compares to last year; that is a cross-edition trend and belongs to continuous improvement, not this edition's log."
},
{
"n": 3,
"kind": "poorly",
"happened": "The backup projector had not been tested in advance.",
"done": "A replacement was borrowed from the venue.",
"change": "Test every backup device the night before.",
"owner": "to be named",
"due": "",
"status": "open",
"note": "This entry has no named owner or date; settle who owns it and by when, or close it as no action."
},
{
"n": 4,
"kind": "poorly",
"happened": "One person held three roles on day two with no backup.",
"done": "Ana covered until 18:00.",
"change": "Split the volunteer lead role in two.",
"owner": "Mira",
"due": "2027-07-15",
"status": "open",
"note": "This is a team-health finding, routed to team structure rather than solved here."
},
{
"n": 5,
"kind": "poorly",
"happened": "Lunch ran out for late arrivals.",
"done": "Pizza was ordered.",
"change": "No action, because the caterer has already been replaced.",
"owner": "",
"due": "",
"status": "no action",
"note": ""
},
{
"n": 6,
"kind": "outcome",
"happened": "Two attendees started an open-source CLI project at the hack table.",
"done": "",
"change": "Log it in the outcome register.",
"owner": "Tomas",
"due": "2027-06-01",
"status": "open",
"note": ""
}
],
"routed": [
4
],
"reconciliations": [
{
"document": "Participant feedback summary",
"status": "exists",
"handback": "Check the draft entries against the feedback summary and hand any gap back to its owner as a finding."
},
{
"document": "Risk register",
"status": "exists",
"handback": "Check which draft entries were already foreseen in the risk register and hand the gap back as a finding."
},
{
"document": "Planned budget",
"status": "exists",
"handback": "Check the draft entries against the planned budget and hand any variance back as a finding."
},
{
"document": "Run of show",
"status": "missing",
"handback": "No reconciliation is possible against the run of show, since it does not exist; skip the check rather than rebuild it from memory."
},
{
"document": "Goals the team set before the event",
"status": "exists",
"handback": "Check the draft entries against the goals set before the event and hand any gap back as a finding."
}
],
"depth": {
"pick": "preread",
"planned": "preread",
"note": "The written pre-read plus one session is both the plan and the page's pick, the default depth for this team, and no rung is deleted here."
},
"publication": {
"pick": "retro",
"planned": "retro",
"note": "Recap plus retrospective is both the plan and the pick, the default publication, while the transparency report stays out of reach without sign-off on anonymisation."
},
"tracking": {
"pick": "tracker",
"planned": "carry",
"note": "The plan called for plan carry-over, but the page's pick is the standing tracker with a review cadence, promoted because a team-health finding was routed to team structure."
},
"signals": [
"The debrief happened 6 days after doors closed, which keeps the timeline reliable, so next edition should keep booking it within a week of doors closing (own design).",
"Named-role coverage was 4 of 5, since the volunteer lead had no voice, so next edition should require at least written input from every named role before the debrief (own design).",
"Carry-through from last edition was 7 of 12 items, so next edition should open by reviewing which of those 12 are still outstanding (own design)."
],
"caveats": [
"Entry 3 has no named owner or date; give it one or close it as no action.",
"Entry 3's wording named who forgot the task; it has been rewritten around the conditions that allowed it, not the person.",
"The volunteer lead has no voice in this debrief; get at least written input from them.",
"No reconciliation is possible against the run of show, since it does not exist; skip that check rather than rebuild it from memory."
]
}
The page's check: kept - nothing to flag
Harbor DevConf (volunteers, three days after) - agenda
6 entries, 1 orphans; depth pick written pre-read plus one session; publication pick recap plus retrospective; tracking pick standing tracker with a review cadence; a 90-minute session.
Input:
{
"task": "agenda",
"edition": "Edition: Harbor DevConf 2027; recurring for years; doors closed 2027-05-21; debrief 2027-05-27 (6 days after); next planning starts 2027-07-01; session booked for 90 minutes\nTeam: volunteer-run; effort left normal; workstream leads worked independently no; leadership handover no; several cities under one brand no; a year-round tracker already exists no\nNamed roles: Lead organizer (Mira) - in the room; Program chair (Tomas) - in the room; Volunteer lead (Ana) - NO VOICE; Sponsor lead (Jo) - written input; AV lead (Kai) - in the room\nDocuments to reconcile against: Participant feedback summary exists; Risk register exists; Planned budget exists; Run of show MISSING; Goals the team set before the event exists\nCode of conduct: 1 reports, 1 resolved; visible to the community no; pipeline sign-off on anonymisation no; private or NDA-bound no\nLast edition's items: 7 of 12 done",
"entries": "Draft entries, in order (kind | what happened | done in the moment | what changes | owner | due | status):\n#1 well | The speaker green room ran smoothly with a printed schedule on the door | kept the schedule on the door all day | keep the printed green-room schedule | Tomas | 2027-06-15 | open\n#2 poorly | The registration queue ran 40 minutes at doors - longer than last year | opened a second desk at 09:20 | open two desks from the start with pre-printed badges | Mira | 2027-06-30 | open | cross-edition trend\n#3 poorly | Kai forgot to test the backup projector | borrowed one from the venue | test every backup device the night before | we | NO DATE | open | ORPHAN | BLAME WORDING\n#4 poorly | One person held three roles on day two with no backup | Ana covered until 18:00 | split the volunteer lead role in two | Mira | 2027-07-15 | open | team health\n#5 poorly | Lunch ran out for late arrivals | ordered pizza | no action, because the caterer has already been replaced | NONE | NO DATE | no action\n#6 outcome | Two attendees started an open-source CLI project at the hack table | - | log it in the outcome register | Tomas | 2027-06-01 | open",
"facts": "Depth: planned preread; the page's pick is preread; rungs One session available; Written pre-read plus one session default; Per-track sessions available; Multi-track written review starved\nPublication: planned retro; the page's pick is retro; rungs Nothing published available; Recap only available; Recap plus retrospective default; Recap plus retrospective plus transparency report starved\nTracking: planned carry; the page's pick is tracker; rungs Owner and date on the entry default; Mid-cycle check-in promoted; Plan carry-over default; Standing tracker with a review cadence promoted\nPasses: what went well 1; what went poorly 4; outcomes 1; team-health entries to route #4\nSession agenda for 90 minutes: Frame 5; Timeline 15; What went well 10; What went poorly 15; Reconciliations 15; Team health 10; Owners and dates 10; Publication 10; written pre-read from: Lead organizer, Program chair, Volunteer lead, Sponsor lead, AV lead\nPass threshold: zero orphan entries - fails (1 orphans)\nSignals to record: Days from doors closing to the debrief: 6; Named-role coverage: 4 of 5; Carry-through of last edition's items: 7 of 12; Outcomes captured at the debrief: 1\nFindings (9):\n[check] missing_roles (room): No voice from: Volunteer lead (Ana) - a debrief missing a named role misses the half of the day only they saw. Ask for written input at least.\n[info] volunteer_frame (frame): Say that nobody is here on work time and that \"I could not keep up\" is a finding about the workload, not the person - a criticised volunteer simply stops volunteering.\n[fix] orphans (entries): 1 orphan entry: #3 (we, no date) - a named person and a date, or close it as \"no action, because\".\n[fix] blame (frame): Blame in the wording of #3 - rewrite as the conditions that allowed it, never who caused it.\n[info] route_health (team health): Team-health findings to route to team structure, not solve here: #4.\n[check] trend (entries): #2 compares across editions - that trend belongs to continuous improvement; this log covers one edition.\n[check] no_docs (reconciliation): No reconciliation possible against: run of show - say so and skip the check rather than rebuilding the document from memory.\n[check] tracking_pick (tracking): Planned: plan carry-over; the page's pick is standing tracker with a review cadence.\n[check] pass (measurement): Zero orphan entries: fails - 1 orphan (the one pass threshold; self-set)."
}
Reply:
{
"task": "agenda",
"title": "Debrief - Harbor DevConf 2027",
"opening": "This debrief asks only what conditions let something happen, never who is to blame, and no finding in this room will name a person as the cause. Nothing discussed here reaches attendees, speakers or sponsors - it stays inside the organizing team, and only the dated log moves on to whoever plans the next edition. Everyone here gave their own time as a volunteer, so if someone says they could not keep up, that is written down as a gap in the workload, never as something wrong with them.",
"prereads": [
"Lead organizer",
"Program chair",
"Volunteer lead",
"Sponsor lead",
"AV lead"
],
"segments": [
{
"segment": "Frame",
"minutes": 5,
"does": "Open by reading the blameless frame and the volunteer-team line out loud, and confirm the record stays internal to the team."
},
{
"segment": "Timeline",
"minutes": 15,
"does": "Lay the 6 draft entries into the order they happened, before judging any of them as well or poorly done."
},
{
"segment": "What went well",
"minutes": 10,
"does": "Settle entry 1 - keeping the printed green-room schedule on the door - the only what-went-well entry drafted."
},
{
"segment": "What went poorly",
"minutes": 15,
"does": "Work through the 4 what-went-poorly entries - the registration queue, the untested backup projector, the day-two coverage gap and the late lunch shortfall - without naming who caused any of them."
},
{
"segment": "Reconciliations",
"minutes": 15,
"does": "Reconcile against the participant feedback summary, the risk register, the planned budget and the goals the team set before the event, and note that the run of show cannot be checked because it does not exist."
},
{
"segment": "Team health",
"minutes": 10,
"does": "Route entry 4 - one person holding three roles on day two with no backup - to team structure instead of resolving it in this room."
},
{
"segment": "Owners and dates",
"minutes": 10,
"does": "Confirm a named owner and due date for every entry - entry 3 still needs one - and move tracking up from plan carry-over to a standing tracker with a review cadence."
},
{
"segment": "Publication",
"minutes": 10,
"does": "Confirm recap plus retrospective as this edition's publication, matching what was planned, since there is no code-of-conduct sign-off on anonymisation for a transparency report."
}
],
"close": "Nothing beyond the dated log leaves this room, and that log goes to whoever plans the next edition before planning starts on 2027-07-01.",
"note": "Before the session, give entry 3 a named owner and due date or close it as no action, because - it is the only orphan against a zero-orphan threshold."
}
The page's check: kept - Check the opening's wording for blame.
Campus Hack Night (a final edition, seven weeks late) - log
2 entries, 0 orphans; depth pick written pre-read plus one session; publication pick recap plus retrospective; tracking pick owner and date on the entry; a 60-minute session.
Input:
{
"task": "log",
"edition": "Edition: Campus Hack Night - final edition; the final edition; doors closed 2027-03-06; debrief 2027-04-24 (49 days after); next planning starts not set; session booked for 60 minutes\nTeam: mixed-run; effort left exhausted; workstream leads worked independently no; leadership handover no; several cities under one brand no; a year-round tracker already exists no\nNamed roles: Organizer (Lu) - in the room; Sponsor and food lead (Ravi) - in the room\nDocuments to reconcile against: Participant feedback summary exists; Risk register MISSING; Planned budget exists; Run of show MISSING; Goals the team set before the event MISSING\nCode of conduct: 0 reports, 0 resolved; visible to the community no; pipeline sign-off on anonymisation no; private or NDA-bound no\nLast edition's items: not recorded",
"entries": "Draft entries, in order (kind | what happened | done in the moment | what changes | owner | due | status):\n#1 poorly | Wifi dropped for an hour during the final push | moved teams to the second floor | write the venue's wifi capacity into the venue requirements | Lu | 2027-05-15 | open\n#2 poorly | Judging ran past midnight | cut demos to two minutes | publish the demo time limit before the event | Ravi | 2027-05-15 | open",
"facts": "Depth: planned track; the page's pick is preread; rungs One session available; Written pre-read plus one session default; Per-track sessions deleted; Multi-track written review deleted\nPublication: planned full; the page's pick is retro; rungs Nothing published available; Recap only available; Recap plus retrospective default; Recap plus retrospective plus transparency report starved\nTracking: planned carry; the page's pick is entry; rungs Owner and date on the entry default; Mid-cycle check-in available; Plan carry-over deleted; Standing tracker with a review cadence deleted\nPasses: what went well 0; what went poorly 2; outcomes 0; team-health entries to route none\nSession agenda for 60 minutes: Frame 5; Timeline 5; What went well 10; What went poorly 10; Reconciliations 10; Team health 5; Owners and dates 10; Publication 5; written pre-read from: Organizer, Sponsor and food lead\nPass threshold: zero orphan entries - passes\nSignals to record: Days from doors closing to the debrief: 49; Named-role coverage: 2 of 2; Carry-through of last edition's items: not recorded; Outcomes captured at the debrief: 0\nFindings (11):\n[fix] archaeology (timing): The debrief is 49 days after the doors closed - six weeks out the timeline is the loudest three memories. Say so and downgrade the claim the log makes.\n[info] frame_line (frame): Whoever holds the reporting line says the blameless frame out loud - from anyone else it does not bind, and a silent manager reads as an evaluator.\n[info] volunteer_frame (frame): Say that nobody is here on work time and that \"I could not keep up\" is a finding about the workload, not the person - a criticised volunteer simply stops volunteering.\n[check] exhausted (team health): An exhausted team is the first finding, not a scheduling problem to route around - write it as an entry and route it.\n[check] no_well (entries): No what-went-well entries - run that pass first: a practice that worked and goes unnamed is quietly dropped next edition.\n[check] no_docs (reconciliation): No reconciliation possible against: risk register; run of show; goals the team set before the event - say so and skip the check rather than rebuilding the document from memory.\n[check] no_goals (reconciliation): No goals were written before the event - the review is reconstructed, not measured; say so in the log.\n[fix] depth_deleted (depth): Per-track sessions is deleted here - a team this small or this tired gets ceremony, not findings.\n[check] publication_pick (publication): Planned: recap plus retrospective plus transparency report; the page's pick is recap plus retrospective.\n[fix] tracking_deleted (tracking): Plan carry-over is deleted here - a final or one-off edition has no next plan to carry into.\n[info] pass (measurement): Zero orphan entries: passes (the one pass threshold; self-set)."
}
Reply:
{
"task": "log",
"summary": "Campus Hack Night's final-edition log passes the zero-orphan-entries threshold, and the first thing to settle is that the debrief happened 49 days after doors closed, so its claims should be treated as less certain.",
"frame": "Because this team is mixed, whoever holds the reporting line needs to say this out loud for it to count, and for anyone on the team who is not on the clock, saying they could not keep up is a finding about their workload, not about them.",
"entries": [
{
"n": 1,
"kind": "poorly",
"happened": "Wifi dropped for an hour during the final push.",
"done": "Teams were moved to the second floor.",
"change": "Write the venue's wifi capacity into the venue requirements.",
"owner": "Lu",
"due": "2027-05-15",
"status": "open",
"note": ""
},
{
"n": 2,
"kind": "poorly",
"happened": "Judging ran past midnight.",
"done": "Demos were cut to two minutes.",
"change": "Publish the demo time limit before the event.",
"owner": "Ravi",
"due": "2027-05-15",
"status": "open",
"note": ""
}
],
"routed": [],
"reconciliations": [
{
"document": "Participant feedback summary",
"status": "exists",
"handback": "Check the draft entries against the feedback summary and hand any gap back to its owner as a finding."
},
{
"document": "Risk register",
"status": "missing",
"handback": "No reconciliation is possible against the risk register, since it does not exist; skip the check rather than rebuild it from memory."
},
{
"document": "Planned budget",
"status": "exists",
"handback": "Check the draft entries against the planned budget and hand any variance back as a finding."
},
{
"document": "Run of show",
"status": "missing",
"handback": "No reconciliation is possible against the run of show, since it does not exist; skip the check rather than rebuild it from memory."
},
{
"document": "Goals the team set before the event",
"status": "missing",
"handback": "No goals were written before the event, so this review is reconstructed rather than measured against a target; say so rather than rebuilding goals from memory."
}
],
"depth": {
"pick": "preread",
"planned": "track",
"note": "The plan called for per-track sessions, but that rung and the multi-track written review are both deleted for a team this small and this tired, so the page falls back to the default written pre-read plus one session."
},
"publication": {
"pick": "retro",
"planned": "full",
"note": "The plan called for recap plus retrospective plus a transparency report, but that top rung stays starved without code-of-conduct sign-off on anonymisation, so the page's pick is the default recap plus retrospective."
},
"tracking": {
"pick": "entry",
"planned": "carry",
"note": "The plan called for carry-over into next edition's plan, but that rung and the standing tracker are both deleted for this final, one-off edition, leaving owner and date on each entry as the only one in play."
},
"signals": [
"The debrief happened 49 days after doors closed, well past the point where memories hold up, so if a similar event is ever run again, book the debrief within about six weeks (own design).",
"Named-role coverage was 2 of 2, with both named roles in the room, so a future edition could keep relying on just these two roles being present rather than adding process (own design).",
"Outcomes captured at the debrief was 0, so a future edition should ask directly whether anything notable came out of the event, rather than assuming nothing did (own design)."
],
"caveats": [
"The debrief happened 49 days after doors closed, past the point where memories are most reliable; say so and treat this log's claims as less certain.",
"Per-track sessions is deleted for this small, exhausted team; a written pre-read plus one session covers it without the extra ceremony.",
"Plan carry-over is deleted, since this is the final edition with no next plan to carry these items into.",
"The team's exhaustion is itself a finding, not a scheduling problem; it should be written as its own entry and routed to team structure."
]
}
The page's check: kept - nothing to flag
Campus Hack Night (a final edition, seven weeks late) - agenda
2 entries, 0 orphans; depth pick written pre-read plus one session; publication pick recap plus retrospective; tracking pick owner and date on the entry; a 60-minute session.
Input:
{
"task": "agenda",
"edition": "Edition: Campus Hack Night - final edition; the final edition; doors closed 2027-03-06; debrief 2027-04-24 (49 days after); next planning starts not set; session booked for 60 minutes\nTeam: mixed-run; effort left exhausted; workstream leads worked independently no; leadership handover no; several cities under one brand no; a year-round tracker already exists no\nNamed roles: Organizer (Lu) - in the room; Sponsor and food lead (Ravi) - in the room\nDocuments to reconcile against: Participant feedback summary exists; Risk register MISSING; Planned budget exists; Run of show MISSING; Goals the team set before the event MISSING\nCode of conduct: 0 reports, 0 resolved; visible to the community no; pipeline sign-off on anonymisation no; private or NDA-bound no\nLast edition's items: not recorded",
"entries": "Draft entries, in order (kind | what happened | done in the moment | what changes | owner | due | status):\n#1 poorly | Wifi dropped for an hour during the final push | moved teams to the second floor | write the venue's wifi capacity into the venue requirements | Lu | 2027-05-15 | open\n#2 poorly | Judging ran past midnight | cut demos to two minutes | publish the demo time limit before the event | Ravi | 2027-05-15 | open",
"facts": "Depth: planned track; the page's pick is preread; rungs One session available; Written pre-read plus one session default; Per-track sessions deleted; Multi-track written review deleted\nPublication: planned full; the page's pick is retro; rungs Nothing published available; Recap only available; Recap plus retrospective default; Recap plus retrospective plus transparency report starved\nTracking: planned carry; the page's pick is entry; rungs Owner and date on the entry default; Mid-cycle check-in available; Plan carry-over deleted; Standing tracker with a review cadence deleted\nPasses: what went well 0; what went poorly 2; outcomes 0; team-health entries to route none\nSession agenda for 60 minutes: Frame 5; Timeline 5; What went well 10; What went poorly 10; Reconciliations 10; Team health 5; Owners and dates 10; Publication 5; written pre-read from: Organizer, Sponsor and food lead\nPass threshold: zero orphan entries - passes\nSignals to record: Days from doors closing to the debrief: 49; Named-role coverage: 2 of 2; Carry-through of last edition's items: not recorded; Outcomes captured at the debrief: 0\nFindings (11):\n[fix] archaeology (timing): The debrief is 49 days after the doors closed - six weeks out the timeline is the loudest three memories. Say so and downgrade the claim the log makes.\n[info] frame_line (frame): Whoever holds the reporting line says the blameless frame out loud - from anyone else it does not bind, and a silent manager reads as an evaluator.\n[info] volunteer_frame (frame): Say that nobody is here on work time and that \"I could not keep up\" is a finding about the workload, not the person - a criticised volunteer simply stops volunteering.\n[check] exhausted (team health): An exhausted team is the first finding, not a scheduling problem to route around - write it as an entry and route it.\n[check] no_well (entries): No what-went-well entries - run that pass first: a practice that worked and goes unnamed is quietly dropped next edition.\n[check] no_docs (reconciliation): No reconciliation possible against: risk register; run of show; goals the team set before the event - say so and skip the check rather than rebuilding the document from memory.\n[check] no_goals (reconciliation): No goals were written before the event - the review is reconstructed, not measured; say so in the log.\n[fix] depth_deleted (depth): Per-track sessions is deleted here - a team this small or this tired gets ceremony, not findings.\n[check] publication_pick (publication): Planned: recap plus retrospective plus transparency report; the page's pick is recap plus retrospective.\n[fix] tracking_deleted (tracking): Plan carry-over is deleted here - a final or one-off edition has no next plan to carry into.\n[info] pass (measurement): Zero orphan entries: passes (the one pass threshold; self-set)."
}
Reply:
{
"task": "agenda",
"title": "Debrief - Campus Hack Night (final edition)",
"opening": "This debrief looks only at what conditions let something happen, never at who is to blame, and no finding here will name a person as the cause. Nothing discussed stays with participants or sponsors - it stays with this organizing team alone. Because this team is mixed, whoever holds the reporting line needs to say this frame themselves for it to hold, rather than leaving it to someone else in the room. And because people here gave their own time too, anyone who says they could not keep up is pointing at a gap in the workload, never a fault in themselves.",
"prereads": [
"Organizer",
"Sponsor and food lead"
],
"segments": [
{
"segment": "Frame",
"minutes": 5,
"does": "Read the blameless frame out loud, with the reporting-line line and the workload line added for this mixed team, before anything else is discussed."
},
{
"segment": "Timeline",
"minutes": 5,
"does": "Reconstruct the order of the 2 draft entries before judging either of them, and say that a timeline rebuilt 49 days after doors closed holds only the loudest memories, not a precise record."
},
{
"segment": "What went well",
"minutes": 10,
"does": "Run this pass even with zero what-went-well entries drafted, so a practice that worked does not go quietly unnamed."
},
{
"segment": "What went poorly",
"minutes": 10,
"does": "Work through the 2 what-went-poorly entries - the hour of dropped wifi and judging running past midnight - without pointing at anyone for either."
},
{
"segment": "Reconciliations",
"minutes": 10,
"does": "Check against the participant feedback summary and the planned budget, and say outright that the risk register, the run of show and the goals set before the event cannot be checked because none of them exist, so this review is reconstructed, not measured."
},
{
"segment": "Team health",
"minutes": 5,
"does": "Write the team's exhausted state itself as a finding and route it to team structure, since neither of the 2 drafted entries currently covers it."
},
{
"segment": "Owners and dates",
"minutes": 10,
"does": "Confirm the owner and due date already on both entries - Lu's and Ravi's, both due 2027-05-15 - and note that plan carry-over is dropped since this is the final edition."
},
{
"segment": "Publication",
"minutes": 5,
"does": "Confirm recap plus retrospective as the publication, not the fuller transparency report that was planned, since there is no code-of-conduct sign-off on anonymisation."
}
],
"close": "Nothing here reaches participants or sponsors, and because this is the final edition, the dated log is simply filed as the closing record rather than handed to a next edition's planners.",
"note": "Before the session, add a team-health entry for the team's exhausted state so it can be routed to team structure, since none of the drafted entries covers it yet."
}
The page's check: kept - Check the opening's wording for blame.
Quillfern Partner Summit (staffed, private, a handover) - log
4 entries, 0 orphans; depth pick multi-track written review; publication pick nothing published; tracking pick standing tracker with a review cadence; a 120-minute session.
Input:
{
"task": "log",
"edition": "Edition: Quillfern Partner Summit 2027; recurring for years; doors closed 2027-06-10; debrief 2027-06-17 (7 days after); next planning starts 2027-09-01; session booked for 120 minutes\nTeam: staffed-run; effort left normal; workstream leads worked independently yes; leadership handover yes; several cities under one brand no; a year-round tracker already exists yes\nNamed roles: Event director (Noor) - in the room; Content lead (Dev) - in the room; Partner lead (Sam) - in the room; Operations lead (Pia) - in the room\nDocuments to reconcile against: Participant feedback summary exists; Risk register exists; Planned budget exists; Run of show exists; Goals the team set before the event exists\nCode of conduct: 0 reports, 0 resolved; visible to the community no; pipeline sign-off on anonymisation no; private or NDA-bound yes\nLast edition's items: not recorded",
"entries": "Draft entries, in order (kind | what happened | done in the moment | what changes | owner | due | status):\n#1 well | Partner briefings sent a week ahead cut day-one questions | sent them a week ahead | keep the one-week briefing | Sam | 2027-08-15 | open\n#2 poorly | The content lead took on too much in the final week | others picked up the speaker emails | give the content track a deputy | Noor | 2027-07-31 | open | team health\n#3 poorly | The keynote overran by 20 minutes | trimmed the panel | add a visible countdown on stage | Pia | 2027-06-18 | open\n#4 poorly | Badge printer jammed at 08:30 | used handwritten badges | - | NONE | NO DATE | no action",
"facts": "Depth: planned preread; the page's pick is written; rungs One session available; Written pre-read plus one session default; Per-track sessions promoted; Multi-track written review promoted\nPublication: planned retro; the page's pick is nothing; rungs Nothing published default; Recap only deleted; Recap plus retrospective deleted; Recap plus retrospective plus transparency report deleted\nTracking: planned carry; the page's pick is tracker; rungs Owner and date on the entry default; Mid-cycle check-in promoted; Plan carry-over default; Standing tracker with a review cadence promoted\nPasses: what went well 1; what went poorly 3; outcomes 0; team-health entries to route #2\nSession agenda for 120 minutes: Frame 5; Timeline 20; What went well 15; What went poorly 25; Reconciliations 20; Team health 10; Owners and dates 15; Publication 10; written pre-read from: Event director, Content lead, Partner lead, Operations lead\nPass threshold: zero orphan entries - passes\nSignals to record: Days from doors closing to the debrief: 7; Named-role coverage: 4 of 4; Carry-through of last edition's items: not recorded; Outcomes captured at the debrief: 0\nFindings (10):\n[info] frame_line (frame): Whoever holds the reporting line says the blameless frame out loud - from anyone else it does not bind, and a silent manager reads as an evaluator.\n[check] no_reason (entries): #4 is closed as no action with no reason - write \"no action, because\" so the suggestion does not come back next edition as new.\n[check] personal (team health): #2 reads as a personal failing - write the structure that allowed it instead (for example, a role with no backup).\n[info] route_health (team health): Team-health findings to route to team structure, not solve here: #2.\n[check] three_part (entries): Not three-part (what happened, what was done in the moment, what changes): #4.\n[check] overdue (entries): Past due and still open: #3.\n[check] depth_pick (depth): Planned: written pre-read plus one session; the page's pick is multi-track written review.\n[fix] publication_deleted (publication): Recap plus retrospective is deleted here - a private event's findings stay in the team's log.\n[check] tracking_pick (tracking): Planned: plan carry-over; the page's pick is standing tracker with a review cadence.\n[info] pass (measurement): Zero orphan entries: passes (the one pass threshold; self-set)."
}
Reply:
{
"task": "log",
"summary": "The Quillfern Partner Summit 2027 debrief passes its zero orphan entries threshold; settle that publication defaults to nothing published, since recap plus retrospective is deleted for this private event.",
"frame": "This is a staffed team, so whoever holds the reporting line says the frame out loud: the debrief asks what conditions allowed each thing to happen, never who is to blame.",
"entries": [
{
"n": 1,
"kind": "well",
"happened": "Sending partner briefings a week ahead cut down day-one questions.",
"done": "The team sent the partner briefings a week ahead of the summit.",
"change": "Keep the one-week briefing for partners.",
"owner": "Sam",
"due": "2027-08-15",
"status": "open",
"note": ""
},
{
"n": 2,
"kind": "poorly",
"happened": "The content track carried its full final-week workload with no deputy in place to share it.",
"done": "Other people on the team picked up the speaker emails to keep things moving.",
"change": "Give the content track a deputy.",
"owner": "Noor",
"due": "2027-07-31",
"status": "open",
"note": "This is routed to team structure; settle the deputy decision there, not in this log."
},
{
"n": 3,
"kind": "poorly",
"happened": "The keynote ran 20 minutes past its scheduled time.",
"done": "The team trimmed the panel discussion to recover the time.",
"change": "Add a visible countdown on stage.",
"owner": "Pia",
"due": "2027-06-18",
"status": "open",
"note": "This due date has passed while the entry is still open; settle a new date."
},
{
"n": 4,
"kind": "poorly",
"happened": "The badge printer jammed at 08:30.",
"done": "The team switched to handwritten badges.",
"change": "",
"owner": "",
"due": "",
"status": "no action",
"note": "No reason was recorded for taking no action; settle one so this does not return next edition as a new item."
}
],
"routed": [
2
],
"reconciliations": [
{
"document": "Participant feedback summary",
"status": "exists",
"handback": "No draft entry cites the feedback summary directly, so the check is skipped this time."
},
{
"document": "Risk register",
"status": "exists",
"handback": "Check whether an equipment failure like the jammed badge printer was already a listed risk, and hand that gap back as a finding."
},
{
"document": "Planned budget",
"status": "exists",
"handback": "No draft entry cites the planned budget, so the check is skipped this time."
},
{
"document": "Run of show",
"status": "exists",
"handback": "Check the run of show against the 20-minute keynote overrun, and hand the gap back to Pia as a finding."
},
{
"document": "Goals the team set before the event",
"status": "exists",
"handback": "No draft entry cites the goals set before the event, so the check is skipped this time."
}
],
"depth": {
"pick": "written",
"planned": "preread",
"note": "Depth moves up to the multi-track written review because workstream leads worked independently and this edition is a leadership handover, instead of the default written pre-read plus one session."
},
"publication": {
"pick": "nothing",
"planned": "retro",
"note": "Every public rung - recap only, recap plus retrospective, and the transparency report - is deleted for this private event, so the pick falls back to nothing published even though retro was planned."
},
"tracking": {
"pick": "tracker",
"planned": "carry",
"note": "Tracking moves up to a standing tracker with a review cadence because a year-round tracker already exists and the content-track item is routed to team structure, instead of the default plan carry-over."
},
"signals": [
"Seven days passed from doors closing to the debrief, which keeps the record fresh; next edition, keep booking the debrief within two weeks of doors closing (our design).",
"Named-role coverage was 4 of 4, so every named role sat in the room; next edition, keep inviting every named role so none debriefs by proxy (our design).",
"Carry-through of last edition's items was not recorded; next edition, start the debrief by logging it so the standing tracker has something to compare against (our design)."
],
"caveats": [
"Publication falls back to nothing published, since recap plus retrospective is deleted for this private event.",
"Entry 2 reads as a personal failing and needs rewriting as a structural gap, such as a role with no backup.",
"Entry 3 is past due and still open.",
"Entry 4 is closed as no action without a stated reason."
]
}
The page's check: kept - nothing to flag
Quillfern Partner Summit (staffed, private, a handover) - agenda
4 entries, 0 orphans; depth pick multi-track written review; publication pick nothing published; tracking pick standing tracker with a review cadence; a 120-minute session.
Input:
{
"task": "agenda",
"edition": "Edition: Quillfern Partner Summit 2027; recurring for years; doors closed 2027-06-10; debrief 2027-06-17 (7 days after); next planning starts 2027-09-01; session booked for 120 minutes\nTeam: staffed-run; effort left normal; workstream leads worked independently yes; leadership handover yes; several cities under one brand no; a year-round tracker already exists yes\nNamed roles: Event director (Noor) - in the room; Content lead (Dev) - in the room; Partner lead (Sam) - in the room; Operations lead (Pia) - in the room\nDocuments to reconcile against: Participant feedback summary exists; Risk register exists; Planned budget exists; Run of show exists; Goals the team set before the event exists\nCode of conduct: 0 reports, 0 resolved; visible to the community no; pipeline sign-off on anonymisation no; private or NDA-bound yes\nLast edition's items: not recorded",
"entries": "Draft entries, in order (kind | what happened | done in the moment | what changes | owner | due | status):\n#1 well | Partner briefings sent a week ahead cut day-one questions | sent them a week ahead | keep the one-week briefing | Sam | 2027-08-15 | open\n#2 poorly | The content lead took on too much in the final week | others picked up the speaker emails | give the content track a deputy | Noor | 2027-07-31 | open | team health\n#3 poorly | The keynote overran by 20 minutes | trimmed the panel | add a visible countdown on stage | Pia | 2027-06-18 | open\n#4 poorly | Badge printer jammed at 08:30 | used handwritten badges | - | NONE | NO DATE | no action",
"facts": "Depth: planned preread; the page's pick is written; rungs One session available; Written pre-read plus one session default; Per-track sessions promoted; Multi-track written review promoted\nPublication: planned retro; the page's pick is nothing; rungs Nothing published default; Recap only deleted; Recap plus retrospective deleted; Recap plus retrospective plus transparency report deleted\nTracking: planned carry; the page's pick is tracker; rungs Owner and date on the entry default; Mid-cycle check-in promoted; Plan carry-over default; Standing tracker with a review cadence promoted\nPasses: what went well 1; what went poorly 3; outcomes 0; team-health entries to route #2\nSession agenda for 120 minutes: Frame 5; Timeline 20; What went well 15; What went poorly 25; Reconciliations 20; Team health 10; Owners and dates 15; Publication 10; written pre-read from: Event director, Content lead, Partner lead, Operations lead\nPass threshold: zero orphan entries - passes\nSignals to record: Days from doors closing to the debrief: 7; Named-role coverage: 4 of 4; Carry-through of last edition's items: not recorded; Outcomes captured at the debrief: 0\nFindings (10):\n[info] frame_line (frame): Whoever holds the reporting line says the blameless frame out loud - from anyone else it does not bind, and a silent manager reads as an evaluator.\n[check] no_reason (entries): #4 is closed as no action with no reason - write \"no action, because\" so the suggestion does not come back next edition as new.\n[check] personal (team health): #2 reads as a personal failing - write the structure that allowed it instead (for example, a role with no backup).\n[info] route_health (team health): Team-health findings to route to team structure, not solve here: #2.\n[check] three_part (entries): Not three-part (what happened, what was done in the moment, what changes): #4.\n[check] overdue (entries): Past due and still open: #3.\n[check] depth_pick (depth): Planned: written pre-read plus one session; the page's pick is multi-track written review.\n[fix] publication_deleted (publication): Recap plus retrospective is deleted here - a private event's findings stay in the team's log.\n[check] tracking_pick (tracking): Planned: plan carry-over; the page's pick is standing tracker with a review cadence.\n[info] pass (measurement): Zero orphan entries: passes (the one pass threshold; self-set)."
}
Reply:
{
"task": "agenda",
"title": "Debrief - Quillfern Partner Summit 2027",
"opening": "This debrief is blameless: the team is asking what conditions allowed each thing to happen, never who is to blame. Nothing said here reaches attendees, speakers or sponsors - it stays inside the organizing team. Because this is a staffed team, whoever holds the reporting line is the one saying this out loud, so it binds rather than reading as an evaluation.",
"prereads": [
"Event director",
"Content lead",
"Partner lead",
"Operations lead"
],
"segments": [
{
"segment": "Frame",
"minutes": 5,
"does": "Whoever holds the reporting line states the blameless frame out loud before anything else is discussed."
},
{
"segment": "Timeline",
"minutes": 20,
"does": "The team reconstructs the Quillfern Partner Summit 2027 timeline in order, before any judgment is made."
},
{
"segment": "What went well",
"minutes": 15,
"does": "The team reviews entry 1, the one-week partner briefings that cut down day-one questions, before moving to what went poorly."
},
{
"segment": "What went poorly",
"minutes": 25,
"does": "The team works through entries 2, 3 and 4 - the content track's final week, the keynote's 20-minute overrun, and the badge printer jam - in blameless, structural terms."
},
{
"segment": "Reconciliations",
"minutes": 20,
"does": "The team checks the entries against the participant feedback summary, risk register, planned budget, run of show, and the goals set before the event, and hands each gap back to its owner."
},
{
"segment": "Team health",
"minutes": 10,
"does": "The team routes entry 2, the content track's final week, to team structure instead of solving it here."
},
{
"segment": "Owners and dates",
"minutes": 15,
"does": "The team confirms each entry's owner and due date, settles a new date for entry 3's overdue keynote item, and writes the reason entry 4's badge printer item needs no action."
},
{
"segment": "Publication",
"minutes": 10,
"does": "The team confirms that nothing is published externally, since every public rung is deleted for this private event."
}
],
"close": "Nothing from this session reaches attendees, speakers or sponsors; the dated log goes to whoever plans the next edition before planning starts on 2027-09-01.",
"note": "Before the session, settle who holds the reporting line, since that is who must say the blameless frame out loud for it to bind."
}
The page's check: kept - Check the opening's wording for blame.
The log CSV for the first sample
n,kind,what_happened,done_in_the_moment,what_changes,owner,due,status,orphan
1,well,The speaker green room ran smoothly with a printed schedule on the door,kept the schedule on the door all day,keep the printed green-room schedule,Tomas,2027-06-15,open,
2,poorly,The registration queue ran 40 minutes at doors - longer than last year,opened a second desk at 09:20,open two desks from the start with pre-printed badges,Mira,2027-06-30,open,
3,poorly,Kai forgot to test the backup projector,borrowed one from the venue,test every backup device the night before,we,,open,yes
4,poorly,One person held three roles on day two with no backup,Ana covered until 18:00,split the volunteer lead role in two,Mira,2027-07-15,open,
5,poorly,Lunch ran out for late arrivals,ordered pizza,"no action, because the caterer has already been replaced",,,noaction,
6,outcome,Two attendees started an open-source CLI project at the hack table,,log it in the outcome register,Tomas,2027-06-01,open,
Build the input yourself
Load the engine in node (global.window = global; require("./debriefkit.js"); require("./debriefreply.js")), then:
const K = DebriefKit, R = DebriefReply;
const f = K.form({ name: "My Conf 2027", kind: "recurring", eventEnd: "2027-05-21", debriefDate: "2027-05-27", planningStart: "2027-07-01", team: "volunteer",
roles: fs.readFileSync("roles.csv", "utf8"), entries: fs.readFileSync("entries.csv", "utf8"), risk: "yes", budget: "yes" });
// f.entries (kind, owner, t, status, orphan, blame, health), f.orphans, f.pass, f.covered, f.docs
// f.depthRungs, f.recDepth, f.pubRungs, f.recPub, f.trackRungs, f.recTrack, f.agenda, f.preread, f.findings
K.logCSV(f) // n, kind, what_happened, done_in_the_moment, what_changes, owner, due, status, orphan
const b = K.buildInput(f, "log"); // or "agenda"
const wire = K.toWire(b.input); // POST this to /estimate and /run
// then: const reply = R.normalize(R.parseReply(job.output.output), "log");
// 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://debrief-table.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://debrief-table.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"]
// debrief-table.mjs -- Node 18+ (global fetch)
const BASE = "https://api.skillsafe.ai/v1/app-api";
let TOKEN = "paste-your-token-here"; // from https://debrief-table.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://debrief-table.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
}
// DebriefTable.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 DebriefTable {
static final String BASE = "https://api.skillsafe.ai/v1/app-api";
static String token = "paste-your-token-here"; // from https://debrief-table.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://debrief-table.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://debrief-table.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://debrief-table.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":"debrief-table"}' | 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": "debrief-table"})["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: "debrief-table" })).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": "debrief-table"}, 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", "debrief-table"), 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: "debrief-table" })["token"])
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
$TOKEN = "";
$TOKEN = api("POST", "/guest", ["slug" => "debrief-table"])["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 = "debrief-table" }))!["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": "log", "edition": "Edition: ...; recurring for years; doors closed 2027-05-21 ...", "entries": "Draft entries, in order ...", "facts": "Depth: planned preread ..."}
# - 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": "log", "edition": "Edition: ...; recurring for years; doors closed 2027-05-21 ...", "entries": "Draft entries, in order ...", "facts": "Depth: planned preread ..."}
# - 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: "log" or "agenda", edition, entries, 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 debrief-table:<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 log carries summary, frame, entries, routed, reconciliations, depth, publication, tracking, signals and caveats; an agenda carries title, opening, prereads, segments, close and note. The code below prints the headline parts of either (list items are plain strings).
KEY="debrief-table:log:$(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 // .frame, ((.signals // .caveats)[] | "\(.signal // .caveat): \(.text // .text)")' reply.json
jq -r '.close // .note // empty' reply.json # the closing line (agenda)
import hashlib, time
key = "debrief-table:" + 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("frame", ""))
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("close"):
print("close:", reply["close"])
import { createHash } from "node:crypto";
const key = `debrief-table:${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.frame);
for (const s of reply.signals || reply.caveats || []) console.log(s.signal ?? s.caveat, "-", s.text ?? s.text);
if (reply.close) console.log("close:", reply.close);
sum := sha256.Sum256(raw) // add "crypto/sha256", "encoding/hex", "time" to the imports
key := "debrief-table:" + 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["frame"])
for _, x := range items {
c := x.(map[string]any)
fmt.Println(c["signal"], "-", c["status"])
}
if fix, ok := reply["close"].(string); ok && fix != "" {
fmt.Println("close:", fix)
}
var digest = java.security.MessageDigest.getInstance("SHA-256").digest(M.writeValueAsBytes(input));
String key = "debrief-table:" + 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("frame").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("close").asText().isEmpty()) System.out.println("close: " + reply.get("close").asText());
require "digest"
key = "debrief-table:#{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["frame"]
(reply["signals"] || reply["caveats"] || []).each { |s| puts "#{s["signal"] || s["caveat"]} - #{s["text"] || s["text"]}" }
puts "close: #{reply["close"]}" unless reply["close"].to_s.empty?
$key = "debrief-table:" . $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["frame"] ?? "", "\n";
foreach ($reply["signals"] ?? $reply["caveats"] ?? [] as $s) echo $s["signal"] ?? $s["caveat"], " - ", $s["text"] ?? $s["text"], "\n";
if (!empty($reply["close"])) echo "close: ", $reply["close"], "\n";
var digest = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(input.ToJsonString()));
var key = $"debrief-table:{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["frame"]}");
foreach (var s in (reply["signals"] ?? reply["caveats"]) as JsonArray ?? new JsonArray()) Console.WriteLine($"{s!["signal"] ?? s["caveat"]} - {s["text"] ?? s["text"]}");
if (reply["close"] is JsonNode fix && fix.GetValue<string>() != "") Console.WriteLine("close: " + 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: debrief-table:log:$(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": "log", "edition": "Edition: ...; recurring for years; doors closed 2027-05-21 ...", "entries": "Draft entries, in order ...", "facts": "Depth: planned preread ..."}
# - 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": "debrief-table:log:" + 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": `debrief-table:log:${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", "debrief-table:log:"+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", "debrief-table:log:" + 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" => "debrief-table:log:#{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: debrief-table:log:" . 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", $"debrief-table:log:{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);