Run Mentor Roster from your own code
Both metered lanes are available over HTTP and each returns one JSON object. The division of labour: the page sets coverage depth per track against the brief's tracks, tags every mentor in the brief's vocabulary, counts the coverage hour by hour and lists every gap, states the mentor-judge conflict, re-ranks the recruitment, request-mechanic and briefing-depth menus, and writes the constraint handed to the shift plan - all free, in mentorkit.js. The run writes the mentor plan, or the request mechanic with the mentor briefing; the page then holds the reply to its own board (mentorreply.js). It never invents a mentor-to-participant ratio, a staffing formula or a response-time target, and never infers anyone's identity or seniority from a name.
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":"mentor-roster"}), so no slug header is needed afterwards. Send it as Authorization: Bearer YOUR_TOKEN. 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, tracks, mentors, facts) is missing. notes may be an empty string. |
| 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, chosen by task:
plan- the mentor plan for the organizer to act on: the verdict, coverage per track with its rung and a reason naming the commitment, every mentor's tags and unmatched tags, every gap by track and hour with its fix, the mentor-judge conflict and the contact log, the recruitment channels that fit the deadline, the rotation, the hand-off to the shift plan and the caveats.brief- the request mechanic exactly as participants will read it (how to recognise a mentor and ask, where it is published, the hours, what to expect) and the mentor briefing (the help-versus-build boundary, the conflict note, interruption discipline, escalation, the slot and the rotation, who knows what per track), with a note.
A missing or unknown task is answered as plan. Both lanes send the same six fields; for the brief, the facts also carry the plan's rungs, tags and gaps (the page fills these from the plan). The notes field may be an empty string.
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 event basics and the interview answers Q1 to Q10: name, dates, as-of date, format, rooms, the hacking window, overnight and the overnight decision, teams, participants, the organizing team, theme, the signed sponsor agreement, who judges and the contact log keeper, prizes, the edition and who mentored before, the effort ceiling, the roster and mechanic dates, what already exists, the request route and the rotation settings. |
tracks | yes | one line per challenge track: its vocabulary, its sponsor-integration depth, its sponsor technology and the hours it is worked. |
mentors | yes | one line per mentor: source, tags, slots, also judging, mentored before, sponsor employer. |
notes | no | pasted notes such as a sponsor's email; may be empty. A request in the notes is never a commitment. |
facts | yes | the page's verdict, the self-set lines, the one published ratio with its scope, the window, the coverage menu, the coverage row per track with a must line under each, the tags per mentor with a must line under each, the coverage by hour, the gaps with a must line under each, the conflict rows with a must line under each, the recruitment menu, the deadline, the channels and the recruitment must line, the mechanic and briefing menus, the boundary, the engagement rule, the escalation route, the rotation, the interruption rules, the hand-off, the plan's and the brief's must lines, the per-track mentor list with a must line under each, for the brief task the plan carried over, 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
- A mentor is not a volunteer, and not a judge. Mentors help teams build during the hacking window; judges evaluate finished projects afterwards. Write "mentor briefing" wherever a reader could confuse it with a jury briefing. Conduct policy and enforcement belong to event-code-of-conduct; the briefing points at it and never drafts a second one.
- Coverage is set against the tracks, not a headcount. Four rungs: Rostered mentor shifts (the default), Expertise-matched roster, On-call from organizers, No mentor programme. A sponsor technology required for one track or deeper, or a themed event, promotes the Expertise-matched roster. A sole-substrate or required sponsor integration raises that track's bar from "a mentor is available" to "a mentor is guaranteed on the floor whenever that track is being worked". No mentor programme is deleted as soon as the brief names a sponsor technology at required depth or deeper. Commitments per track: guaranteed or available.
- Tags use the brief's own words, name the sponsor technology by product name, and record depth honestly: built with it, or read the docs. A tag nobody can match to a track does no routing work; unmatched tags are listed, never dropped.
- Quantities to refuse: never invent a mentor-to-participant ratio, a mentors-per-team or mentor-to-shift formula, an unblock latency target, or evidence linking mentor availability to completion or satisfaction. The one published ratio - hackathon.guide, "at least one subject matter expert + workable project for about every four non-expert participants" - scopes to themed events, counts non-expert participants, describes domain experts inside projects, and is about project supply. Never convert it into mentors per participant or per team.
- The mentor-judge conflict is stated from one side: a mentor who materially helped a team recuses from judging that team. hackathon-judging owns the rule and the recusal ladder; this work owns only the mentor-team contact log, kept whenever a confirmed mentor is also on the judge list and handed over before the judge pool is fixed.
- Recruitment source rungs: Community and alumni only, Mixed pool with a written rule, Mixed pool, Sponsor staff only. A named sponsor technology promotes the Mixed pool with a written rule; Sponsor staff only is deleted when a general track runs alongside the sponsor track. A close roster date promotes community and alumni (a warm list answers in days, a sponsor staffing negotiation runs weeks). Sponsor staff are a sponsorship deliverable negotiated in event-sponsor-agreement; a missing sponsor mentor is a fulfilment failure, never a no-show.
- The request mechanic rungs: Identifiable mentors (the default), Staffed mentor area, Request channel with routing, Scheduled office hours, Find someone informally. Routing every request through one organizer's direct messages is deleted. Scheduled office hours as the sole route is deleted when the window runs overnight. Any routing rung needs at least two people who can work it. Publish the mechanic where the brief is published, before the window opens.
- The mentor briefing depth rungs: Boundary stated (the default), Logistics only, No briefing, Boundary plus scenario walkthrough. No briefing is deleted when a prize carries cash value or a sponsor funds one. The boundary: mentors explain, diagnose, unblock and demonstrate; they do not write code that ships in a submission; code shown is written outside the team's repository and the team types what lands; a commit a mentor already made is declared in the submission. Ask before touching the laptop, the keyboard or the repository; leave the project unevaluated; name the limit of your own knowledge. Sponsor staff get the engagement rule: no pitching, no recruiting, not a demo.
- Rotation and the shift plan: event-volunteers owns roster sizing, arrival buffers, sign-up confirmation, the no-show and replacement protocol and shift-linked recognition. Hand it only the expertise constraint - which tags must be present in which hours. A slot is the commitment; presence beyond it is a courtesy. Stagger specialty coverage against when teams need each one. Decide the overnight hours deliberately - staffed, thinly staffed or published as unstaffed - and publish it. Rate-limit roaming: a per-visit time cap with a visible timer, a do not disturb signal the team controls, a published list of who knows what, a shared view of blocked teams.
- When no mentor covers a skill, the route is published in advance: the roster's second level (someone who has read the docs, saying so), the sponsor's channel, ask the room (a request, never an assignment), then tell the team plainly, early enough to change approach.
House rules
- Use only the input and the rules above. Copy the page's short facts exactly: the verdict, track names, rungs, mentor names, tags, hours, channel names, the place the brief is published and the escalation route. Every number in your text must appear in the input.
- Every "must: [...]" line in the facts applies to the item directly above it - every track, every mentor, every gap and every judging mentor, not only the first. Do every item it lists.
- Label anything that is not one of the rules above, and is not in the input, as your own design; label the page's self-set numbers self-set.
- Never invent a mentor, a skill, an availability, a ratio, a sponsor commitment or a time. Never state a ratio, a mentors-per-team or per-participant figure, a shift length or a response-time target.
- Never infer anyone's identity or seniority from a name - mentored before is asked, never inferred. Refer to people by name, as they; never use he, she, him, her, his or hers.
- 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 40 words: the verdict, the most important open item, and the next step.verdict- the page's verdict, exactly:map tracks first,fix coverage,fix firstorready to publish the mechanic.coverage- one object per row of the page's coverage per track, in its order, every track, not only the first:trackandrungexactly as the page gives them;reason(one sentence) that uses the page's commitment word for that track - "guaranteed" or "available" - and, for a guaranteed track, names its sponsor technology exactly.[]when the page lists no track.tags- one object per mentor in the page's order, every mentor, not only the first:mentorexactly;tracks- the page's tracks for that mentor, every one, each exactly;unmatched- the page's unmatched tags for that mentor, every one, each exactly (listed, never dropped). Use[]for an empty list. Never add a mentor.gaps- one object per gap the page lists, in its order:trackexactly,hours- the page's hours text exactly,fix(one sentence) saying how those hours get covered; when the gap runs overnight, use the word "overnight".[]when the page lists none.conflict- one object per mentor the page lists as also judging, every one:mentorexactly andhandling(one sentence) that names the contact log (use the word "log") and states the recusal - a mentor who materially helped a team recuses from judging that team (use the word "recuse").[]when nobody judges.recruitment-picks: every channel the page lists whose fit is yes or unknown, in the page's order, each name exactly;reason: one or two sentences that name the page's recruitment pick exactly and the roster deadline.rotation- one or two sentences: stagger specialty coverage against when teams need each one (use the word "stagger"), with the guaranteed tracks' sponsor technology present in the hours the track is worked.handoff_to_shifts- one or two sentences handing the expertise constraint to event-volunteers (use the word "volunteer") as text: which tags must be present in which hours. Never compute a rota, a shift length or a headcount.caveats- at most 5 short strings: the[fix]findings first in the page's order, then the most important[check]findings. Never empty when the page has a[fix]finding;[]otherwise when there is nothing to say.
{
"task": "plan",
"summary": "one sentence",
"verdict": "fix coverage",
"coverage": [ { "track": "the page's track", "rung": "the page's rung", "reason": "one sentence" } ],
"tags": [ { "mentor": "the page's mentor", "tracks": [ "the page's track" ], "unmatched": [ "an unmatched tag" ] } ],
"gaps": [ { "track": "the page's track", "hours": "the page's hours", "fix": "one sentence" } ],
"conflict": [ { "mentor": "the page's mentor", "handling": "one sentence" } ],
"recruitment": { "picks": [ "the page's channel" ], "reason": "one or two sentences" },
"rotation": "one or two sentences",
"handoff_to_shifts": "one or two sentences",
"caveats": [ "a caveat" ]
}
The page holds it to its own board: the verdict exactly; every track's rung exactly with "guaranteed" or "available" in its reason and the sponsor technology named for a guaranteed track; every mentor's tracks and unmatched tags; every gap's track and hours, with "overnight" in the fix when it is; every judging mentor with the "log" and the recusal; the channels that fit the deadline, in order, with the recruitment pick named; "stagger" in the rotation; "volunteer" in the hand-off; caveats when the page has a fix; and no number, ratio, rota, pronoun or identity the input does not hold. Required words are read tolerantly: "recused", "steps aside" and "will not judge" all state the recusal.
brief
mechanic- one object:title- it must contain the page's event name exactly.how_to_ask- two to four sentences, written to participants: how to recognise a mentor and how to ask, for the page's request mechanic pick - use the page's word for it: "marker" for Identifiable mentors, "area" for a Staffed mentor area, "channel" for a Request channel with routing, "office hours" for Scheduled office hours; and what happens when nobody covers it (use the word "nobody").where_published- the page's place of publication, exactly ("not set" when the page has none).hours- the page's hacking window, its start and its end exactly as the page writes them.response_expectation- one or two sentences: somebody will come, roughly how a request is picked up, and that asking early is normal (use the word "early"). Never state a time target - no minutes, no hours.briefing- one object, the mentor briefing:boundary- two to four sentences: the help-versus-build boundary and what a mentor may touch in a team's repository (use the word "repository"); a commit a mentor already made is declared in the submission (use the word "declare"); ask before touching the laptop, the keyboard or the repository (use the word "ask"). When the page lists sponsor staff, add the engagement rule: no pitching, no recruiting (use the word "pitch").conflict_note- when the page lists a mentor who also judges: one or two sentences naming the contact log (use the word "log") and the recusal (use the word "recuse"). When nobody judges, exactly "None.".interruption- one or two sentences: the per-visit time cap with a visible timer (use the word "cap") and the do not disturb signal (use the word "disturb").escalation- one or two sentences: who is asked when no mentor covers a skill - the page's escalation route exactly ("not named" when the page has none) - and the code-of-conduct pointer for anything that is not technical (use the words "code of conduct").rotation_note- one or two sentences: a slot is the commitment, presence beyond it is a courtesy (use the word "slot"); when the window runs overnight, say what the overnight hours are (use the word "overnight").per_track- one object per row of the page's per-track mentor list, in its order, every track, not only the first:trackexactly andmentors- the page's mentors for that track, every one, each exactly.[]when the page lists none.note- one sentence: when the page says "ready: no", begin with "Not ready to publish:" and say what to fix first; otherwise say what happens next.
{
"task": "brief",
"mechanic": {
"title": "the event name - how to reach a mentor",
"how_to_ask": "two to four sentences",
"where_published": "the page's place",
"hours": "the page's window start to the page's window end",
"response_expectation": "one or two sentences"
},
"briefing": {
"boundary": "two to four sentences",
"conflict_note": "None.",
"interruption": "one or two sentences",
"escalation": "one or two sentences",
"rotation_note": "one or two sentences",
"per_track": [ { "track": "the page's track", "mentors": [ "the page's mentor" ] } ]
},
"note": "one sentence"
}
The page requires the event name in the title; the pick's word ("marker", "area", "channel" or "office hours") and "nobody" in how to ask; the place of publication; the window's start and end exactly; "early" and no time target in what to expect; "repository", "declare" and "ask" in the boundary ("pitch" too when sponsor staff mentor); "log" and the recusal in the conflict note when a mentor judges, "None." otherwise; "cap" and "disturb" in the interruption rules; the escalation route and "code of conduct"; "slot" (and "overnight" for an overnight window) in the rotation note; every track's mentors; and a note beginning "Not ready to publish:" unless the page is ready.
Worked examples - both lanes
Four of the page's five free samples (fictional events, organizations, products and people). Each input is exactly what the page sends; each reply is the saved reply the sample replays, shipped unedited; the last line is the page's own check. The brief inputs carry their sample's saved plan, as the handoff does.
A 36-hour overnight hackathon, two tracks short at night - plan
Verdict: fix coverage; ready: no; window: 2027-03-13 09:00 to 2027-03-14 21:00; coverage pick: Expertise-matched roster; recruitment: Mixed pool with a written rule; mechanic: Staffed mentor area; briefing: Boundary plus scenario walkthrough; 4 tracks, 14 mentors, 2 gaps, 2 judging; 3 fix-level findings.
Input:
{
"task": "plan",
"event": "Event: \"Harbourline Hack 2027\" | dates: 2027-03-13 to 2027-03-14 | as of: 2027-02-01\nQ1 format: \"in person\" | rooms: 3 | hacking window: \"2027-03-13 09:00\" to \"2027-03-14 21:00\" (36 hours) | overnight: yes | overnight decision: \"not decided\"\nExpected: teams: 40 | participants: 160 | organizing team: 6\nQ3 theme: \"open - participants bring their own projects\"\nQ4 sponsor staffing in a signed agreement: no | sponsor staff on the roster: 3\nQ5 mentors also judging: 2 | contact log keeper: \"not named\"\nQ6 a prize carries cash value: yes | a sponsor funds a prize: yes\nQ7 edition: \"a one-off edition\" | mentored before - yes: 10 | no: 4 | not asked: 0\nQ8 organizer hours before the event: 40 | live coordination during the window: yes | a shift grid exists: no\nQ9 roster close: 2027-02-26 | mechanic reaches participants: 2027-03-06 | briefing session: 2027-03-10 | marker order: 2027-02-24\nQ10 last edition's mentor list: no | a department or user group: yes | sponsor staff on site for a booth: yes | organizers built against the API: no\nRequest route: brief published at: \"the hacker guide on harbourline.example\" | people who can work the routing: [\"Rosa Diazmere\"; \"Tom Leeford\"] | asked when no mentor covers a skill: \"Rosa Diazmere at the mentor desk\" | non-technical escalation: \"the conduct team on the safety channel\"\nRotation: mentors roam: yes | per-visit cap in minutes: 15 | check-in every (hours): 3 | shared blocked-team view: yes | general stack: [\"git\"; \"deployment\"; \"python\"; \"javascript\"]",
"tracks": "Tracks (Q2) (4), one per line:\n- track 1: \"Open Payments\" | vocabulary: [\"payments\"; \"checkout\"; \"wallets\"] | depth: \"sole substrate\" | sponsor technology: \"Lumenquay API\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]\n- track 2: \"Climate Data\" | vocabulary: [\"climate\"; \"emissions\"; \"open data\"] | depth: \"required for this track\" | sponsor technology: \"Terraquill SDK\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]\n- track 3: \"Accessibility\" | vocabulary: [\"accessibility\"; \"screen readers\"; \"WCAG\"] | depth: \"optional bonus challenge\" | sponsor technology: \"Vocalorn speech API\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]\n- track 4: \"Open Innovation\" | vocabulary: [\"web\"; \"mobile\"; \"games\"] | depth: \"no sponsor\" | sponsor technology: \"none named\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]",
"mentors": "Mentors (14), one per line:\n- mentor 1: \"Aiko Tanavelle\" | source: sponsor staff | tags: [\"Lumenquay API\"; \"payments\"] | slots: [2027-03-13 09:00 to 21:00; 2027-03-14 07:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"Lumenquay\"\n- mentor 2: \"Ben Okaformi\" | source: sponsor staff | tags: [\"Lumenquay API\"; \"checkout\"; \"javascript\"] | slots: [2027-03-13 12:00 to 2027-03-14 00:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"Lumenquay\"\n- mentor 3: \"Carla Mendrova\" | source: sponsor staff | tags: [\"Terraquill SDK\"; \"climate\"] | slots: [2027-03-13 09:00 to 23:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"Terraquill\"\n- mentor 4: \"Dev Patelmoor\" | source: community | tags: [\"emissions\"; \"open data\"; \"python\"] | slots: [2027-03-14 07:00 to 21:00] | also judging: yes | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 5: \"Eva Lindqvarn\" | source: community | tags: [\"Terraquill SDK\"; \"climate\"; \"data viz\"] | slots: [2027-03-14 07:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 6: \"Farah Haddrell\" | source: alumni | tags: [\"accessibility\"; \"WCAG\"; \"screen readers\"] | slots: [2027-03-13 09:00 to 18:00] | also judging: yes | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 7: \"Gus Morravin\" | source: community | tags: [\"Vocalorn speech API (read the docs)\"; \"accessibility\"] | slots: [2027-03-14 09:00 to 17:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"none\"\n- mentor 8: \"Hana Kimsel\" | source: university | tags: [\"python\"; \"deployment\"; \"git\"] | slots: [2027-03-13 09:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 9: \"Ian Brookwyn\" | source: community | tags: [\"mobile\"; \"web\"; \"javascript\"] | slots: [2027-03-13 18:00 to 2027-03-14 02:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 10: \"Jo Achembre\" | source: alumni | tags: [\"git\"; \"deployment\"; \"cloud\"] | slots: [2027-03-14 00:00 to 08:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"none\"\n- mentor 11: \"Kofi Mensavo\" | source: community | tags: [\"frontend frameworks\"; \"design systems\"] | slots: [2027-03-13 09:00 to 17:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"none\"\n- mentor 12: \"Lea Novarek\" | source: university | tags: [\"web\"; \"payments\"] | slots: [2027-03-14 09:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 13: \"Mo Rahimor\" | source: community | tags: [\"climate\"; \"open data\"] | slots: [2027-03-13 09:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 14: \"Nia Owusanne\" | source: other | tags: [\"accessibility\"; \"mobile\"] | slots: [2027-03-14 12:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"",
"notes": "From the Lumenquay sponsorship email: our two engineers can cover the payments track during the day. Could one of them also judge the payments prizes?",
"facts": "Verdict: \"fix coverage\" | ready: no | fix-level findings: 3 | coverage fixes: 2\nSelf-set lines: overnight hours from 00:00 to 06:00 | a mentor counts as present in an hour with at least 30 minutes of their slot in it | a roster deadline under 21 days away is close | a warm list needs at least 3 days and a sponsor staffing negotiation at least 21 | scheduled visits stop 3 hours before the window closes | a summary cap of 40 words. The skill's own: at least 2 people work any routing rung. Never invented: a mentor-to-participant ratio, a mentors-per-team or mentor-to-shift formula, an unblock latency target, any evidence linking mentor availability to completion or satisfaction.\nThe one published ratio: hackathon.guide (Joshua Tauberer), At Themed Hackathons: \"at least one subject matter expert + workable project for about every four non-expert participants\" | scope: themed events only, non-expert participants not teams, domain experts inside projects not floating mentors, project supply not staffing | use: evidence that expertise, not headcount, is scarce | never converted into mentors per participant or per team | this event is themed: no\nWindow (Q1): \"2027-03-13 09:00\" to \"2027-03-14 21:00\" (36 hours) | overnight hours in the window: 6 | overnight decision: \"not decided\"\nCoverage depth menu (step 2), re-ranked - pick: \"Expertise-matched roster\"\n- rung 1: \"Expertise-matched roster\" | moved: made the pick by Q2: \"Open Payments\" at sole substrate (Lumenquay API) and \"Climate Data\" at required for this track (Terraquill SDK) - required for one track or deeper\n- rung 2: \"Rostered mentor shifts\"\n- rung 3: \"On-call from organizers\" | moved: demoted by Q1: the window runs through the night - on-call routes every question to the people running the schedule at the hour it is hardest to run; demoted by the mentor crew (14) is larger than the organizing team (6)\n- deleted, not demoted: \"No mentor programme\" | reason: Q2: the brief names a sponsor technology at required-for-one-track depth or deeper - it has promised support the event must staff\nCoverage per track - one row per track, in this order - 5:\n- row 1: \"Open Payments\" | depth: \"sole substrate\" | sponsor technology: \"Lumenquay API\" | rung: \"Expertise-matched roster\" | commitment: \"guaranteed\" | why: Q2: sole substrate - Lumenquay API raises the bar from a mentor is available to a mentor is guaranteed on the floor whenever the track is worked | counts toward it: [\"Aiko Tanavelle\"; \"Ben Okaformi\"] | read the docs only: [none]\n must: [track \"Open Payments\" exactly; rung \"Expertise-matched roster\" exactly; reason uses the word \"guaranteed\"; reason names \"Lumenquay API\" exactly]\n- row 2: \"Climate Data\" | depth: \"required for this track\" | sponsor technology: \"Terraquill SDK\" | rung: \"Expertise-matched roster\" | commitment: \"guaranteed\" | why: Q2: required for this track - Terraquill SDK raises the bar from a mentor is available to a mentor is guaranteed on the floor whenever the track is worked | counts toward it: [\"Carla Mendrova\"; \"Eva Lindqvarn\"] | read the docs only: [none]\n must: [track \"Climate Data\" exactly; rung \"Expertise-matched roster\" exactly; reason uses the word \"guaranteed\"; reason names \"Terraquill SDK\" exactly]\n- row 3: \"Accessibility\" | depth: \"optional bonus challenge\" | sponsor technology: \"Vocalorn speech API\" | rung: \"Rostered mentor shifts\" | commitment: \"available\" | why: Q2: an optional bonus challenge needs available | counts toward it: [\"Farah Haddrell\"; \"Gus Morravin\"; \"Nia Owusanne\"] | read the docs only: [none]\n must: [track \"Accessibility\" exactly; rung \"Rostered mentor shifts\" exactly; reason uses the word \"available\"]\n- row 4: \"Open Innovation\" | depth: \"no sponsor\" | sponsor technology: \"none named\" | rung: \"Rostered mentor shifts\" | commitment: \"available\" | why: below required depth, general technical coverage is what teams actually consume | counts toward it: [\"Ian Brookwyn\"; \"Lea Novarek\"; \"Nia Owusanne\"] | read the docs only: [none]\n must: [track \"Open Innovation\" exactly; rung \"Rostered mentor shifts\" exactly; reason uses the word \"available\"]\n- row 5: \"General stack\" | depth: \"no sponsor\" | sponsor technology: \"none named\" | rung: \"Rostered mentor shifts\" | commitment: \"available\" | why: the general stack every team touches regardless of track | counts toward it: [\"Ben Okaformi\"; \"Dev Patelmoor\"; \"Hana Kimsel\"; \"Ian Brookwyn\"; \"Jo Achembre\"] | read the docs only: [none]\n must: [track \"General stack\" exactly; rung \"Rostered mentor shifts\" exactly; reason uses the word \"available\"]\nExpertise tags (step 4) - one per mentor, in this order - 14:\n- mentor 1: \"Aiko Tanavelle\" | tracks: [\"Open Payments\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Aiko Tanavelle\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 2: \"Ben Okaformi\" | tracks: [\"Open Payments\"; \"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Ben Okaformi\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 3: \"Carla Mendrova\" | tracks: [\"Climate Data\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Carla Mendrova\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 4: \"Dev Patelmoor\" | tracks: [\"Climate Data\"; \"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Dev Patelmoor\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 5: \"Eva Lindqvarn\" | tracks: [\"Climate Data\"] | unmatched: [\"data viz\"] | read the docs: [none]\n must: [mentor \"Eva Lindqvarn\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 6: \"Farah Haddrell\" | tracks: [\"Accessibility\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Farah Haddrell\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 7: \"Gus Morravin\" | tracks: [\"Accessibility\"] | unmatched: [none] | read the docs: [\"Vocalorn speech API (read the docs)\"]\n must: [mentor \"Gus Morravin\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 8: \"Hana Kimsel\" | tracks: [\"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Hana Kimsel\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 9: \"Ian Brookwyn\" | tracks: [\"Open Innovation\"; \"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Ian Brookwyn\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 10: \"Jo Achembre\" | tracks: [\"General stack\"] | unmatched: [\"cloud\"] | read the docs: [none]\n must: [mentor \"Jo Achembre\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 11: \"Kofi Mensavo\" | tracks: [none] | unmatched: [\"frontend frameworks\"; \"design systems\"] | read the docs: [none]\n must: [mentor \"Kofi Mensavo\" exactly; tracks copies the tracks list above, every one, an empty list; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 12: \"Lea Novarek\" | tracks: [\"Open Payments\"; \"Open Innovation\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Lea Novarek\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 13: \"Mo Rahimor\" | tracks: [\"Climate Data\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Mo Rahimor\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 14: \"Nia Owusanne\" | tracks: [\"Accessibility\"; \"Open Innovation\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Nia Owusanne\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\nCoverage by hour - tagged mentors present (built level; for a guaranteed track, those who have built with its sponsor technology):\n- \"Open Payments\": [2027-03-13 09:00 to 12:00: 1; 2027-03-13 12:00 to 21:00: 2; 2027-03-13 21:00 to 2027-03-14 00:00: 1; 2027-03-14 00:00 to 07:00: 0; 2027-03-14 07:00 to 21:00: 1]\n- \"Climate Data\": [2027-03-13 09:00 to 23:00: 1; 2027-03-13 23:00 to 2027-03-14 07:00: 0; 2027-03-14 07:00 to 21:00: 1]\n- \"Accessibility\": [2027-03-13 09:00 to 18:00: 1; 2027-03-13 18:00 to 2027-03-14 09:00: 0; 2027-03-14 09:00 to 12:00: 1; 2027-03-14 12:00 to 17:00: 2; 2027-03-14 17:00 to 21:00: 1]\n- \"Open Innovation\": [2027-03-13 09:00 to 18:00: 0; 2027-03-13 18:00 to 2027-03-14 02:00: 1; 2027-03-14 02:00 to 09:00: 0; 2027-03-14 09:00 to 12:00: 1; 2027-03-14 12:00 to 21:00: 2]\n- \"General stack\": [2027-03-13 09:00 to 12:00: 1; 2027-03-13 12:00 to 18:00: 2; 2027-03-13 18:00 to 21:00: 3; 2027-03-13 21:00 to 2027-03-14 02:00: 2; 2027-03-14 02:00 to 07:00: 1; 2027-03-14 07:00 to 08:00: 2; 2027-03-14 08:00 to 21:00: 1]\nGaps - hours below each track's commitment, in this order - 2:\n- gap 1: \"Open Payments\" | hours: \"2027-03-14 00:00 to 07:00\" | overnight: yes | commitment: \"guaranteed\" | nobody holds it: no\n must: [track \"Open Payments\" exactly; hours \"2027-03-14 00:00 to 07:00\" exactly; fix uses the word \"overnight\"]\n- gap 2: \"Climate Data\" | hours: \"2027-03-13 23:00 to 2027-03-14 07:00\" | overnight: yes | commitment: \"guaranteed\" | nobody holds it: no\n must: [track \"Climate Data\" exactly; hours \"2027-03-13 23:00 to 2027-03-14 07:00\" exactly; fix uses the word \"overnight\"]\nThin hours on available tracks (a check, not a gap): \"Accessibility\" [2027-03-13 18:00 to 2027-03-14 09:00] | \"Open Innovation\" [2027-03-13 09:00 to 18:00; 2027-03-14 02:00 to 09:00]\nMentor-judge conflict (Q5, step 8) - stated from one side - 2:\n- mentor: \"Dev Patelmoor\" | also judging: yes | contact log keeper: \"not named\"\n must: [mentor \"Dev Patelmoor\" exactly; handling uses the words \"log\" and \"recuse\"]\n- mentor: \"Farah Haddrell\" | also judging: yes | contact log keeper: \"not named\"\n must: [mentor \"Farah Haddrell\" exactly; handling uses the words \"log\" and \"recuse\"]\nThe rule, declaratively: a mentor who materially helped a team recuses from judging that team. hackathon-judging owns the rule and the recusal ladder; this page supplies only the mentor-team contact log, kept whenever a confirmed mentor is also on the judge list.\nRecruitment source (step 3) - pick: \"Mixed pool with a written rule\"\n- rung 1: \"Mixed pool with a written rule\" | moved: made the pick by Q2: the brief names \"Lumenquay API\", \"Terraquill SDK\" and \"Vocalorn speech API\" - a community mentor cannot be assumed to know it, and the sponsor's own staff are the only people who reliably do; promoted by Q10: sponsor staff are already on site for a booth\n- rung 2: \"Community and alumni only\" | moved: promoted by Q10: a university department or user group would send several people\n- rung 3: \"Mixed pool\"\n- deleted, not demoted: \"Sponsor staff only\" | reason: Q2: a general track (\"Open Innovation\") runs alongside the sponsor track - a pool that only knows one platform leaves every general-track team with nobody\n- notes: The mixed pool without the rule is what happens by default when nobody writes the paragraph - naming it is how you notice it happened.\nRoster deadline (Q9): 2027-02-24 | from: \"marker or badge order\" | days from the as-of date: 23 | close: no\nChannels - in this order - 2:\n- channel 1: \"Community and alumni\" | lead time: days (a warm list) | fits the deadline: yes | why: a warm-list ask to the department or user group, not an open call\n- channel 2: \"Sponsor technical staff\" | lead time: weeks (a staffing negotiation) | fits the deadline: yes | why: a sponsorship deliverable negotiated in event-sponsor-agreement: named people or a named count with the technology they cover, their hours against the hours the track is worked, and the engagement rule; staff are already on site for a booth\n recruitment must: [picks lists every channel above whose fit is yes or unknown, in this order, each exactly; reason names the pick \"Mixed pool with a written rule\" exactly]\nRequest mechanic (step 6) - pick: \"Staffed mentor area\"\n- rung 1: \"Staffed mentor area\" | moved: promoted by Q1: the hacking space runs to 3 rooms\n- rung 2: \"Identifiable mentors\"\n- rung 3: \"Request channel with routing\" | moved: promoted by Q1: several rooms\n- rung 4: \"Find someone informally\"\n- deleted, not demoted: \"Routing every request through one organizer's direct messages\" | reason: always - it looks like the cheapest queue and is a single point of failure at the exact hour it is needed, because that person is asleep\n- deleted, not demoted: \"Scheduled office hours as the sole route\" | reason: Q1: the window runs through the night - a blocker at three in the morning does not wait for a ten o'clock slot; office hours may still supplement\nMechanic details: published at: \"the hacker guide on harbourline.example\" | reaches participants by: 2027-03-06 | window opens: \"2027-03-13 09:00\" | window closes: \"2027-03-14 21:00\" | people who can work the routing: [\"Rosa Diazmere\"; \"Tom Leeford\"] | asked when no mentor covers a skill: \"Rosa Diazmere at the mentor desk\"\nMentor briefing depth (step 7) - pick: \"Boundary plus scenario walkthrough\"\n- rung 1: \"Boundary plus scenario walkthrough\" | moved: made the pick by Q4: sponsor staff (Aiko Tanavelle, Ben Okaformi and Carla Mendrova) mentor on a codebase their employer has a commercial interest in\n- rung 2: \"Boundary stated\"\n- rung 3: \"Logistics only\"\n- deleted, not demoted: \"No briefing\" | reason: Q6: a prize carries cash value - an unbriefed mentor's commit becomes an eligibility question nobody can answer\nThe boundary - the skill's workable formulation, to be edited into the event's own voice, not a standard to cite: \"Mentors explain, diagnose, unblock and demonstrate. Mentors do not write code that ships in a submission. If a mentor needs to show something in code, it is written outside the team's repository - a scratch file, a message, a whiteboard - and the team types the version that lands. If a mentor has already committed to a team's repository, the team declares it in the submission.\"\nSponsor engagement rule - for [\"Aiko Tanavelle\"; \"Ben Okaformi\"; \"Carla Mendrova\"]: \"While mentoring, you are helping the team in front of you with the problem they brought. Not a sales conversation, not a recruiting conversation, not a demo. If a participant asks about your company, your product's pricing, or working for you, answer briefly and point them at your booth or your team's channel.\"\nPower dynamics: ask before touching anything (the laptop, the keyboard, the repository) | leave the project unevaluated | name the limit of your own knowledge out loud.\nEscalation when no mentor covers a skill: [the roster's second level - someone who has read the docs, saying so; the sponsor's channel, for the sponsor's technology; ask the room - a request, never an assignment; tell the team plainly, early enough to change approach] | asked: \"Rosa Diazmere at the mentor desk\" | non-technical escalation: \"the conduct team on the safety channel\" | the code-of-conduct script belongs to event-code-of-conduct\nRotation by expertise: constraints: [Open Payments - a mentor who has built with Lumenquay API present every hour of 2027-03-13 09:00 to 2027-03-14 21:00; Climate Data - a mentor who has built with Terraquill SDK present every hour of 2027-03-13 09:00 to 2027-03-14 21:00; Accessibility - the Accessibility tag on the roster, reachable through the request mechanic; Open Innovation - the Open Innovation tag on the roster, reachable through the request mechanic; General stack - the General stack tag on the roster, reachable through the request mechanic] | stagger: Stagger specialty coverage against when teams need each one: problem-definition and validation mentors early, debugging mentors mid-window, completion mentors once teams should already be writing code, presentation mentors in the final stretch - never one flat open-to-close roster. | scheduled visits stop from: \"2027-03-14 18:00\" | check-in cadence: each assigned mentor checks in on each of their teams at least every 3 hours (the event's own number, self-set)\nInterruption discipline: [a per-visit time cap with a timer the team can see - 15 minutes (the event's own number, self-set), relaxed only for hands-on work that cannot be boxed; a do not disturb signal the team controls, visible from across the room; a published list of what each present mentor actually knows, so a team reaches the right person by name; a shared, live view of which teams are blocked and on what]\nHand-off to the shift plan: For event-volunteers' shift plan - it owns roster sizing from posts and hours, arrival buffers, sign-up confirmation, the no-show and replacement protocol and shift-linked recognition; this page computes none of them. The expertise constraint it schedules against: Open Payments: a mentor who has built with Lumenquay API present every hour of 2027-03-13 09:00 to 2027-03-14 21:00; Climate Data: a mentor who has built with Terraquill SDK present every hour of 2027-03-13 09:00 to 2027-03-14 21:00. Take each mentor's slot at sign-up: a slot is the commitment, presence beyond it is a courtesy. The coverage rule applies to a mentor shift unchanged: do not leave your post until you have confirmation of a replacement. No shift grid exists yet - the volunteer plan builds it.\nPlan must: [summary at most 40 words; verdict \"fix coverage\" exactly; rotation uses the word \"stagger\"; handoff_to_shifts names event-volunteers (the word \"volunteer\"); caveats carry the fix findings first, at most 5]\nBrief must: [title contains \"Harbourline Hack 2027\"; how_to_ask uses the words \"area\" and \"nobody\"; where_published contains \"the hacker guide on harbourline.example\"; hours contains \"2027-03-13 09:00\" and \"2027-03-14 21:00\"; response_expectation says asking early is normal (the word \"early\") and states no time target; boundary uses the words \"repository\", \"declare\", \"ask\" and \"pitch\"; conflict_note uses the words \"log\" and \"recuse\"; interruption uses the words \"cap\" and \"disturb\"; escalation names \"Rosa Diazmere at the mentor desk\" exactly and says \"code of conduct\"; rotation_note uses the word \"slot\" and the word \"overnight\"] | brief note must: [begin \"Not ready to publish:\" and say what to fix first]\nPer-track mentor list for the briefing (built level), in this order - 5:\n- track: \"Open Payments\" | mentors: [\"Aiko Tanavelle\"; \"Ben Okaformi\"; \"Lea Novarek\"]\n must: [track \"Open Payments\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"Climate Data\" | mentors: [\"Carla Mendrova\"; \"Dev Patelmoor\"; \"Eva Lindqvarn\"; \"Mo Rahimor\"]\n must: [track \"Climate Data\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"Accessibility\" | mentors: [\"Farah Haddrell\"; \"Gus Morravin\"; \"Nia Owusanne\"]\n must: [track \"Accessibility\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"Open Innovation\" | mentors: [\"Ian Brookwyn\"; \"Lea Novarek\"; \"Nia Owusanne\"]\n must: [track \"Open Innovation\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"General stack\" | mentors: [\"Ben Okaformi\"; \"Dev Patelmoor\"; \"Hana Kimsel\"; \"Ian Brookwyn\"; \"Jo Achembre\"]\n must: [track \"General stack\" exactly; mentors copies the mentors list above, every one, each exactly]\nFindings (17):\n[fix] gap_1 (coverage): \"Open Payments\" is guaranteed, and no mentor who has built with \"Lumenquay API\" is on the floor 2027-03-14 00:00 to 07:00 - the overnight hours, when the most teams are blocked. Roster a tagged mentor into those hours, or ask the sponsor's channel: that is what the commitment was for.\n[fix] gap_2 (coverage): \"Climate Data\" is guaranteed, and no mentor who has built with \"Terraquill SDK\" is on the floor 2027-03-13 23:00 to 2027-03-14 07:00 - the overnight hours, when the most teams are blocked. Roster a tagged mentor into those hours, or ask the sponsor's channel: that is what the commitment was for.\n[fix] log_none (conflict): Q5: \"Dev Patelmoor\" and \"Farah Haddrell\" are also judging and nobody keeps the mentor-team contact log - name who records which mentor spent meaningful time with which team, and hand the log to hackathon-judging before the judge pool is fixed.\n[check] night_undecided (rotation): Q1: the window runs through the night (6 hours between 00:00 and 06:00, self-set) - decide deliberately whether those hours are staffed, thinly staffed or published as unstaffed, and publish whichever it is.\n[check] notrack_11 (tags): \"Kofi Mensavo\"'s tags [\"frontend frameworks\"; \"design systems\"] match no track in the brief's vocabulary - a tag nobody can match to a track does no routing work. Ask what they actually know, in the brief's words.\n[check] thin_3 (coverage): \"Accessibility\" is available, and no tagged mentor is present 2027-03-13 18:00 to 2027-03-14 09:00 - overnight, 2027-03-14 00:00 to 06:00 - reachable only through the escalation route then; record it as a coverage gap.\n[check] docs_3 (tags): \"Accessibility\": nobody has built with \"Vocalorn speech API\" - Gus Morravin has read the docs; a roster full of the second kind reads as covered and is not.\n[check] thin_4 (coverage): \"Open Innovation\" is available, and no tagged mentor is present 2027-03-13 09:00 to 18:00 and 2027-03-14 02:00 to 09:00 - overnight, 2027-03-14 02:00 to 06:00 - reachable only through the escalation route then; record it as a coverage gap.\n[check] sponsor_unsigned (recruit): Q4: \"Aiko Tanavelle\", \"Ben Okaformi\" and \"Carla Mendrova\" come from a sponsor with nothing signed - negotiate it in event-sponsor-agreement: named people, their hours against the track's hours, and the engagement rule.\n[info] unmatched_5 (tags): \"Eva Lindqvarn\": \"data viz\" match no track - listed, never dropped.\n[info] unmatched_10 (tags): \"Jo Achembre\": \"cloud\" match no track - listed, never dropped.\n[info] units (coverage): Coverage is sized by units - one per track, the sponsor technology by name, and the general stack - never by a ratio: a ratio says nothing about which tag is unstaffed at 03:00.\n[info] recuse (conflict): The rule, stated declaratively: a mentor who materially helped a team recuses from judging that team. hackathon-judging owns the rule and the recusal ladder; this page supplies only the contact log it reaches for.\n[info] engage (recruit): Every sponsor-supplied mentor gets the engagement rule in writing (no pitching, no recruiting while mentoring), mirrored into the sponsorship commitment. A sponsor mentor who does not appear is a fulfilment failure handled with the sponsor - never a no-show.\n[info] handoff (rotation): Hand the expertise constraint to event-volunteers as text - which tags must be present in which hours. Sizing, buffers, confirmation and the replacement protocol are that skill's arithmetic.\n[info] threshold (scope): The skill's one pass threshold (structural): before the window opens, five exist in writing with zero blanks - the tags mapped onto the tracks, the coverage commitment per track, the request mechanic as teams will read it, the mentor briefing with the boundary sentence, and the escalation route. Of the three the page can see, 3 of 3 exist; the brief run writes the mechanic and the briefing.\n[info] scope (scope): A mentor is not a volunteer, and not a judge. The page never invents a mentor-to-participant ratio, a staffing formula, an unblock latency target or evidence about outcomes, and never infers anyone's identity or seniority from a name."
}
Reply:
{
"task": "plan",
"summary": "Fix coverage: Open Payments and Climate Data are guaranteed and uncovered overnight, and nobody keeps the contact log - roster the overnight hours, name a log keeper, then publish the mechanic.",
"verdict": "fix coverage",
"coverage": [
{
"track": "Open Payments",
"rung": "Expertise-matched roster",
"reason": "Guaranteed: the track is sole substrate, so a mentor who has built with Lumenquay API is on the floor whenever it is worked."
},
{
"track": "Climate Data",
"rung": "Expertise-matched roster",
"reason": "Guaranteed: the track is required for this track, so a mentor who has built with Terraquill SDK is on the floor whenever it is worked."
},
{
"track": "Accessibility",
"rung": "Rostered mentor shifts",
"reason": "Available: somebody on the roster holds the tag and is reachable through the request mechanic."
},
{
"track": "Open Innovation",
"rung": "Rostered mentor shifts",
"reason": "Available: somebody on the roster holds the tag and is reachable through the request mechanic."
},
{
"track": "General stack",
"rung": "Rostered mentor shifts",
"reason": "Available: somebody on the roster holds the tag and is reachable through the request mechanic."
}
],
"tags": [
{
"mentor": "Aiko Tanavelle",
"tracks": [
"Open Payments"
],
"unmatched": []
},
{
"mentor": "Ben Okaformi",
"tracks": [
"Open Payments",
"General stack"
],
"unmatched": []
},
{
"mentor": "Carla Mendrova",
"tracks": [
"Climate Data"
],
"unmatched": []
},
{
"mentor": "Dev Patelmoor",
"tracks": [
"Climate Data",
"General stack"
],
"unmatched": []
},
{
"mentor": "Eva Lindqvarn",
"tracks": [
"Climate Data"
],
"unmatched": [
"data viz"
]
},
{
"mentor": "Farah Haddrell",
"tracks": [
"Accessibility"
],
"unmatched": []
},
{
"mentor": "Gus Morravin",
"tracks": [
"Accessibility"
],
"unmatched": []
},
{
"mentor": "Hana Kimsel",
"tracks": [
"General stack"
],
"unmatched": []
},
{
"mentor": "Ian Brookwyn",
"tracks": [
"Open Innovation",
"General stack"
],
"unmatched": []
},
{
"mentor": "Jo Achembre",
"tracks": [
"General stack"
],
"unmatched": [
"cloud"
]
},
{
"mentor": "Kofi Mensavo",
"tracks": [],
"unmatched": [
"frontend frameworks",
"design systems"
]
},
{
"mentor": "Lea Novarek",
"tracks": [
"Open Payments",
"Open Innovation"
],
"unmatched": []
},
{
"mentor": "Mo Rahimor",
"tracks": [
"Climate Data"
],
"unmatched": []
},
{
"mentor": "Nia Owusanne",
"tracks": [
"Accessibility",
"Open Innovation"
],
"unmatched": []
}
],
"gaps": [
{
"track": "Open Payments",
"hours": "2027-03-14 00:00 to 07:00",
"fix": "Roster a mentor who has built with Lumenquay API into the overnight hours, or ask the sponsor's channel - that is what the commitment was for."
},
{
"track": "Climate Data",
"hours": "2027-03-13 23:00 to 2027-03-14 07:00",
"fix": "Roster a mentor who has built with Terraquill SDK into the overnight hours, or ask the sponsor's channel - that is what the commitment was for."
}
],
"conflict": [
{
"mentor": "Dev Patelmoor",
"handling": "Name a keeper for the mentor-team contact log now; Dev Patelmoor will recuse from judging any team they materially helped, under hackathon-judging's rule."
},
{
"mentor": "Farah Haddrell",
"handling": "Name a keeper for the mentor-team contact log now; Farah Haddrell will recuse from judging any team they materially helped, under hackathon-judging's rule."
}
],
"recruitment": {
"picks": [
"Community and alumni",
"Sponsor technical staff"
],
"reason": "Mixed pool with a written rule is the pick, and the roster deadline is 2027-02-24 (marker or badge order)."
},
"rotation": "Stagger specialty coverage against when teams need each one, with mentors who have built with Lumenquay API and Terraquill SDK present in every hour those tracks are worked.",
"handoff_to_shifts": "Hand event-volunteers the expertise constraint as text - which tags must be present in which hours - and let the volunteer plan size, buffer, confirm and backfill the shifts.",
"caveats": [
"\"Open Payments\" is guaranteed, and no mentor who has built with \"Lumenquay API\" is on the floor 2027-03-14 00:00 to 07:00 - the overnight hours, when the most teams are blocked.",
"\"Climate Data\" is guaranteed, and no mentor who has built with \"Terraquill SDK\" is on the floor 2027-03-13 23:00 to 2027-03-14 07:00 - the overnight hours, when the most teams are blocked.",
"\"Dev Patelmoor\" and \"Farah Haddrell\" are also judging and nobody keeps the mentor-team contact log - name who records which mentor spent meaningful time with which team, and hand the log to hackathon-judging before the judge pool is fixed.",
"the window runs through the night (6 hours between 00:00 and 06:00, self-set) - decide deliberately whether those hours are staffed, thinly staffed or published as unstaffed, and publish whichever it is.",
"\"Kofi Mensavo\"'s tags [\"frontend frameworks\"; \"design systems\"] match no track in the brief's vocabulary - a tag nobody can match to a track does no routing work."
]
}
The page's check: kept - nothing to flag
The same, gaps filled and the judges handled - brief
Verdict: ready to publish the mechanic; ready: yes; window: 2027-03-13 09:00 to 2027-03-14 21:00; coverage pick: Expertise-matched roster; recruitment: Mixed pool with a written rule; mechanic: Staffed mentor area; briefing: Boundary plus scenario walkthrough; 4 tracks, 14 mentors, 0 gaps, 2 judging; 0 fix-level findings.
Input:
{
"task": "brief",
"event": "Event: \"Harbourline Hack 2027\" | dates: 2027-03-13 to 2027-03-14 | as of: 2027-02-01\nQ1 format: \"in person\" | rooms: 3 | hacking window: \"2027-03-13 09:00\" to \"2027-03-14 21:00\" (36 hours) | overnight: yes | overnight decision: \"thinly staffed\"\nExpected: teams: 40 | participants: 160 | organizing team: 6\nQ3 theme: \"open - participants bring their own projects\"\nQ4 sponsor staffing in a signed agreement: no | sponsor staff on the roster: 3\nQ5 mentors also judging: 2 | contact log keeper: \"Rosa Diazmere at the mentor desk\"\nQ6 a prize carries cash value: yes | a sponsor funds a prize: yes\nQ7 edition: \"a one-off edition\" | mentored before - yes: 10 | no: 4 | not asked: 0\nQ8 organizer hours before the event: 40 | live coordination during the window: yes | a shift grid exists: no\nQ9 roster close: 2027-02-26 | mechanic reaches participants: 2027-03-06 | briefing session: 2027-03-10 | marker order: 2027-02-24\nQ10 last edition's mentor list: no | a department or user group: yes | sponsor staff on site for a booth: yes | organizers built against the API: no\nRequest route: brief published at: \"the hacker guide on harbourline.example\" | people who can work the routing: [\"Rosa Diazmere\"; \"Tom Leeford\"] | asked when no mentor covers a skill: \"Rosa Diazmere at the mentor desk\" | non-technical escalation: \"the conduct team on the safety channel\"\nRotation: mentors roam: yes | per-visit cap in minutes: 15 | check-in every (hours): 3 | shared blocked-team view: yes | general stack: [\"git\"; \"deployment\"; \"python\"; \"javascript\"]",
"tracks": "Tracks (Q2) (4), one per line:\n- track 1: \"Open Payments\" | vocabulary: [\"payments\"; \"checkout\"; \"wallets\"] | depth: \"sole substrate\" | sponsor technology: \"Lumenquay API\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]\n- track 2: \"Climate Data\" | vocabulary: [\"climate\"; \"emissions\"; \"open data\"] | depth: \"required for this track\" | sponsor technology: \"Terraquill SDK\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]\n- track 3: \"Accessibility\" | vocabulary: [\"accessibility\"; \"screen readers\"; \"WCAG\"] | depth: \"optional bonus challenge\" | sponsor technology: \"Vocalorn speech API\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]\n- track 4: \"Open Innovation\" | vocabulary: [\"web\"; \"mobile\"; \"games\"] | depth: \"no sponsor\" | sponsor technology: \"none named\" | hours worked: [2027-03-13 09:00 to 2027-03-14 21:00]",
"mentors": "Mentors (14), one per line:\n- mentor 1: \"Aiko Tanavelle\" | source: sponsor staff | tags: [\"Lumenquay API\"; \"payments\"] | slots: [2027-03-13 09:00 to 21:00; 2027-03-14 07:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"Lumenquay\"\n- mentor 2: \"Ben Okaformi\" | source: sponsor staff | tags: [\"Lumenquay API\"; \"checkout\"; \"javascript\"] | slots: [2027-03-13 12:00 to 2027-03-14 07:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"Lumenquay\"\n- mentor 3: \"Carla Mendrova\" | source: sponsor staff | tags: [\"Terraquill SDK\"; \"climate\"] | slots: [2027-03-13 09:00 to 17:00; 2027-03-13 23:00 to 2027-03-14 07:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"Terraquill\"\n- mentor 4: \"Dev Patelmoor\" | source: community | tags: [\"emissions\"; \"open data\"; \"python\"] | slots: [2027-03-14 07:00 to 21:00] | also judging: yes | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 5: \"Eva Lindqvarn\" | source: community | tags: [\"Terraquill SDK\"; \"climate\"; \"data viz\"] | slots: [2027-03-13 17:00 to 23:00; 2027-03-14 07:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 6: \"Farah Haddrell\" | source: alumni | tags: [\"accessibility\"; \"WCAG\"; \"screen readers\"] | slots: [2027-03-13 09:00 to 18:00] | also judging: yes | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 7: \"Gus Morravin\" | source: community | tags: [\"Vocalorn speech API (read the docs)\"; \"accessibility\"] | slots: [2027-03-14 09:00 to 17:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"none\"\n- mentor 8: \"Hana Kimsel\" | source: university | tags: [\"python\"; \"deployment\"; \"git\"] | slots: [2027-03-13 09:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 9: \"Ian Brookwyn\" | source: community | tags: [\"mobile\"; \"web\"; \"javascript\"] | slots: [2027-03-13 18:00 to 2027-03-14 02:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 10: \"Jo Achembre\" | source: alumni | tags: [\"git\"; \"deployment\"; \"cloud\"] | slots: [2027-03-14 00:00 to 08:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"none\"\n- mentor 11: \"Kofi Mensavo\" | source: community | tags: [\"frontend frameworks\"; \"design systems\"] | slots: [2027-03-13 09:00 to 17:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"none\"\n- mentor 12: \"Lea Novarek\" | source: university | tags: [\"web\"; \"payments\"] | slots: [2027-03-14 09:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 13: \"Mo Rahimor\" | source: community | tags: [\"climate\"; \"open data\"] | slots: [2027-03-13 09:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 14: \"Nia Owusanne\" | source: other | tags: [\"accessibility\"; \"mobile\"] | slots: [2027-03-14 12:00 to 21:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"",
"notes": "From the Lumenquay sponsorship email: our two engineers can cover the payments track during the day. Could one of them also judge the payments prizes?",
"facts": "Verdict: \"ready to publish the mechanic\" | ready: yes | fix-level findings: 0 | coverage fixes: 0\nSelf-set lines: overnight hours from 00:00 to 06:00 | a mentor counts as present in an hour with at least 30 minutes of their slot in it | a roster deadline under 21 days away is close | a warm list needs at least 3 days and a sponsor staffing negotiation at least 21 | scheduled visits stop 3 hours before the window closes | a summary cap of 40 words. The skill's own: at least 2 people work any routing rung. Never invented: a mentor-to-participant ratio, a mentors-per-team or mentor-to-shift formula, an unblock latency target, any evidence linking mentor availability to completion or satisfaction.\nThe one published ratio: hackathon.guide (Joshua Tauberer), At Themed Hackathons: \"at least one subject matter expert + workable project for about every four non-expert participants\" | scope: themed events only, non-expert participants not teams, domain experts inside projects not floating mentors, project supply not staffing | use: evidence that expertise, not headcount, is scarce | never converted into mentors per participant or per team | this event is themed: no\nWindow (Q1): \"2027-03-13 09:00\" to \"2027-03-14 21:00\" (36 hours) | overnight hours in the window: 6 | overnight decision: \"thinly staffed\"\nCoverage depth menu (step 2), re-ranked - pick: \"Expertise-matched roster\"\n- rung 1: \"Expertise-matched roster\" | moved: made the pick by Q2: \"Open Payments\" at sole substrate (Lumenquay API) and \"Climate Data\" at required for this track (Terraquill SDK) - required for one track or deeper\n- rung 2: \"Rostered mentor shifts\"\n- rung 3: \"On-call from organizers\" | moved: demoted by Q1: the window runs through the night - on-call routes every question to the people running the schedule at the hour it is hardest to run; demoted by the mentor crew (14) is larger than the organizing team (6)\n- deleted, not demoted: \"No mentor programme\" | reason: Q2: the brief names a sponsor technology at required-for-one-track depth or deeper - it has promised support the event must staff\nCoverage per track - one row per track, in this order - 5:\n- row 1: \"Open Payments\" | depth: \"sole substrate\" | sponsor technology: \"Lumenquay API\" | rung: \"Expertise-matched roster\" | commitment: \"guaranteed\" | why: Q2: sole substrate - Lumenquay API raises the bar from a mentor is available to a mentor is guaranteed on the floor whenever the track is worked | counts toward it: [\"Aiko Tanavelle\"; \"Ben Okaformi\"] | read the docs only: [none]\n must: [track \"Open Payments\" exactly; rung \"Expertise-matched roster\" exactly; reason uses the word \"guaranteed\"; reason names \"Lumenquay API\" exactly]\n- row 2: \"Climate Data\" | depth: \"required for this track\" | sponsor technology: \"Terraquill SDK\" | rung: \"Expertise-matched roster\" | commitment: \"guaranteed\" | why: Q2: required for this track - Terraquill SDK raises the bar from a mentor is available to a mentor is guaranteed on the floor whenever the track is worked | counts toward it: [\"Carla Mendrova\"; \"Eva Lindqvarn\"] | read the docs only: [none]\n must: [track \"Climate Data\" exactly; rung \"Expertise-matched roster\" exactly; reason uses the word \"guaranteed\"; reason names \"Terraquill SDK\" exactly]\n- row 3: \"Accessibility\" | depth: \"optional bonus challenge\" | sponsor technology: \"Vocalorn speech API\" | rung: \"Rostered mentor shifts\" | commitment: \"available\" | why: Q2: an optional bonus challenge needs available | counts toward it: [\"Farah Haddrell\"; \"Gus Morravin\"; \"Nia Owusanne\"] | read the docs only: [none]\n must: [track \"Accessibility\" exactly; rung \"Rostered mentor shifts\" exactly; reason uses the word \"available\"]\n- row 4: \"Open Innovation\" | depth: \"no sponsor\" | sponsor technology: \"none named\" | rung: \"Rostered mentor shifts\" | commitment: \"available\" | why: below required depth, general technical coverage is what teams actually consume | counts toward it: [\"Ian Brookwyn\"; \"Lea Novarek\"; \"Nia Owusanne\"] | read the docs only: [none]\n must: [track \"Open Innovation\" exactly; rung \"Rostered mentor shifts\" exactly; reason uses the word \"available\"]\n- row 5: \"General stack\" | depth: \"no sponsor\" | sponsor technology: \"none named\" | rung: \"Rostered mentor shifts\" | commitment: \"available\" | why: the general stack every team touches regardless of track | counts toward it: [\"Ben Okaformi\"; \"Dev Patelmoor\"; \"Hana Kimsel\"; \"Ian Brookwyn\"; \"Jo Achembre\"] | read the docs only: [none]\n must: [track \"General stack\" exactly; rung \"Rostered mentor shifts\" exactly; reason uses the word \"available\"]\nExpertise tags (step 4) - one per mentor, in this order - 14:\n- mentor 1: \"Aiko Tanavelle\" | tracks: [\"Open Payments\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Aiko Tanavelle\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 2: \"Ben Okaformi\" | tracks: [\"Open Payments\"; \"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Ben Okaformi\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 3: \"Carla Mendrova\" | tracks: [\"Climate Data\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Carla Mendrova\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 4: \"Dev Patelmoor\" | tracks: [\"Climate Data\"; \"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Dev Patelmoor\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 5: \"Eva Lindqvarn\" | tracks: [\"Climate Data\"] | unmatched: [\"data viz\"] | read the docs: [none]\n must: [mentor \"Eva Lindqvarn\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 6: \"Farah Haddrell\" | tracks: [\"Accessibility\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Farah Haddrell\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 7: \"Gus Morravin\" | tracks: [\"Accessibility\"] | unmatched: [none] | read the docs: [\"Vocalorn speech API (read the docs)\"]\n must: [mentor \"Gus Morravin\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 8: \"Hana Kimsel\" | tracks: [\"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Hana Kimsel\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 9: \"Ian Brookwyn\" | tracks: [\"Open Innovation\"; \"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Ian Brookwyn\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 10: \"Jo Achembre\" | tracks: [\"General stack\"] | unmatched: [\"cloud\"] | read the docs: [none]\n must: [mentor \"Jo Achembre\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 11: \"Kofi Mensavo\" | tracks: [none] | unmatched: [\"frontend frameworks\"; \"design systems\"] | read the docs: [none]\n must: [mentor \"Kofi Mensavo\" exactly; tracks copies the tracks list above, every one, an empty list; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 12: \"Lea Novarek\" | tracks: [\"Open Payments\"; \"Open Innovation\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Lea Novarek\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 13: \"Mo Rahimor\" | tracks: [\"Climate Data\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Mo Rahimor\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 14: \"Nia Owusanne\" | tracks: [\"Accessibility\"; \"Open Innovation\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Nia Owusanne\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\nCoverage by hour - tagged mentors present (built level; for a guaranteed track, those who have built with its sponsor technology):\n- \"Open Payments\": [2027-03-13 09:00 to 12:00: 1; 2027-03-13 12:00 to 21:00: 2; 2027-03-13 21:00 to 2027-03-14 21:00: 1]\n- \"Climate Data\": [2027-03-13 09:00 to 2027-03-14 21:00: 1]\n- \"Accessibility\": [2027-03-13 09:00 to 18:00: 1; 2027-03-13 18:00 to 2027-03-14 09:00: 0; 2027-03-14 09:00 to 12:00: 1; 2027-03-14 12:00 to 17:00: 2; 2027-03-14 17:00 to 21:00: 1]\n- \"Open Innovation\": [2027-03-13 09:00 to 18:00: 0; 2027-03-13 18:00 to 2027-03-14 02:00: 1; 2027-03-14 02:00 to 09:00: 0; 2027-03-14 09:00 to 12:00: 1; 2027-03-14 12:00 to 21:00: 2]\n- \"General stack\": [2027-03-13 09:00 to 12:00: 1; 2027-03-13 12:00 to 18:00: 2; 2027-03-13 18:00 to 21:00: 3; 2027-03-13 21:00 to 2027-03-14 00:00: 2; 2027-03-14 00:00 to 02:00: 3; 2027-03-14 02:00 to 08:00: 2; 2027-03-14 08:00 to 21:00: 1]\nGaps - hours below each track's commitment, in this order - 0: none - an empty list\nThin hours on available tracks (a check, not a gap): \"Accessibility\" [2027-03-13 18:00 to 2027-03-14 09:00] | \"Open Innovation\" [2027-03-13 09:00 to 18:00; 2027-03-14 02:00 to 09:00]\nMentor-judge conflict (Q5, step 8) - stated from one side - 2:\n- mentor: \"Dev Patelmoor\" | also judging: yes | contact log keeper: \"Rosa Diazmere at the mentor desk\"\n must: [mentor \"Dev Patelmoor\" exactly; handling uses the words \"log\" and \"recuse\"]\n- mentor: \"Farah Haddrell\" | also judging: yes | contact log keeper: \"Rosa Diazmere at the mentor desk\"\n must: [mentor \"Farah Haddrell\" exactly; handling uses the words \"log\" and \"recuse\"]\nThe rule, declaratively: a mentor who materially helped a team recuses from judging that team. hackathon-judging owns the rule and the recusal ladder; this page supplies only the mentor-team contact log, kept whenever a confirmed mentor is also on the judge list.\nRecruitment source (step 3) - pick: \"Mixed pool with a written rule\"\n- rung 1: \"Mixed pool with a written rule\" | moved: made the pick by Q2: the brief names \"Lumenquay API\", \"Terraquill SDK\" and \"Vocalorn speech API\" - a community mentor cannot be assumed to know it, and the sponsor's own staff are the only people who reliably do; promoted by Q10: sponsor staff are already on site for a booth\n- rung 2: \"Community and alumni only\" | moved: promoted by Q10: a university department or user group would send several people\n- rung 3: \"Mixed pool\"\n- deleted, not demoted: \"Sponsor staff only\" | reason: Q2: a general track (\"Open Innovation\") runs alongside the sponsor track - a pool that only knows one platform leaves every general-track team with nobody\n- notes: The mixed pool without the rule is what happens by default when nobody writes the paragraph - naming it is how you notice it happened.\nRoster deadline (Q9): 2027-02-24 | from: \"marker or badge order\" | days from the as-of date: 23 | close: no\nChannels - in this order - 2:\n- channel 1: \"Community and alumni\" | lead time: days (a warm list) | fits the deadline: yes | why: a warm-list ask to the department or user group, not an open call\n- channel 2: \"Sponsor technical staff\" | lead time: weeks (a staffing negotiation) | fits the deadline: yes | why: a sponsorship deliverable negotiated in event-sponsor-agreement: named people or a named count with the technology they cover, their hours against the hours the track is worked, and the engagement rule; staff are already on site for a booth\n recruitment must: [picks lists every channel above whose fit is yes or unknown, in this order, each exactly; reason names the pick \"Mixed pool with a written rule\" exactly]\nRequest mechanic (step 6) - pick: \"Staffed mentor area\"\n- rung 1: \"Staffed mentor area\" | moved: promoted by Q1: the hacking space runs to 3 rooms\n- rung 2: \"Identifiable mentors\"\n- rung 3: \"Request channel with routing\" | moved: promoted by Q1: several rooms\n- rung 4: \"Find someone informally\"\n- deleted, not demoted: \"Routing every request through one organizer's direct messages\" | reason: always - it looks like the cheapest queue and is a single point of failure at the exact hour it is needed, because that person is asleep\n- deleted, not demoted: \"Scheduled office hours as the sole route\" | reason: Q1: the window runs through the night - a blocker at three in the morning does not wait for a ten o'clock slot; office hours may still supplement\nMechanic details: published at: \"the hacker guide on harbourline.example\" | reaches participants by: 2027-03-06 | window opens: \"2027-03-13 09:00\" | window closes: \"2027-03-14 21:00\" | people who can work the routing: [\"Rosa Diazmere\"; \"Tom Leeford\"] | asked when no mentor covers a skill: \"Rosa Diazmere at the mentor desk\"\nMentor briefing depth (step 7) - pick: \"Boundary plus scenario walkthrough\"\n- rung 1: \"Boundary plus scenario walkthrough\" | moved: made the pick by Q4: sponsor staff (Aiko Tanavelle, Ben Okaformi and Carla Mendrova) mentor on a codebase their employer has a commercial interest in\n- rung 2: \"Boundary stated\"\n- rung 3: \"Logistics only\"\n- deleted, not demoted: \"No briefing\" | reason: Q6: a prize carries cash value - an unbriefed mentor's commit becomes an eligibility question nobody can answer\nThe boundary - the skill's workable formulation, to be edited into the event's own voice, not a standard to cite: \"Mentors explain, diagnose, unblock and demonstrate. Mentors do not write code that ships in a submission. If a mentor needs to show something in code, it is written outside the team's repository - a scratch file, a message, a whiteboard - and the team types the version that lands. If a mentor has already committed to a team's repository, the team declares it in the submission.\"\nSponsor engagement rule - for [\"Aiko Tanavelle\"; \"Ben Okaformi\"; \"Carla Mendrova\"]: \"While mentoring, you are helping the team in front of you with the problem they brought. Not a sales conversation, not a recruiting conversation, not a demo. If a participant asks about your company, your product's pricing, or working for you, answer briefly and point them at your booth or your team's channel.\"\nPower dynamics: ask before touching anything (the laptop, the keyboard, the repository) | leave the project unevaluated | name the limit of your own knowledge out loud.\nEscalation when no mentor covers a skill: [the roster's second level - someone who has read the docs, saying so; the sponsor's channel, for the sponsor's technology; ask the room - a request, never an assignment; tell the team plainly, early enough to change approach] | asked: \"Rosa Diazmere at the mentor desk\" | non-technical escalation: \"the conduct team on the safety channel\" | the code-of-conduct script belongs to event-code-of-conduct\nRotation by expertise: constraints: [Open Payments - a mentor who has built with Lumenquay API present every hour of 2027-03-13 09:00 to 2027-03-14 21:00; Climate Data - a mentor who has built with Terraquill SDK present every hour of 2027-03-13 09:00 to 2027-03-14 21:00; Accessibility - the Accessibility tag on the roster, reachable through the request mechanic; Open Innovation - the Open Innovation tag on the roster, reachable through the request mechanic; General stack - the General stack tag on the roster, reachable through the request mechanic] | stagger: Stagger specialty coverage against when teams need each one: problem-definition and validation mentors early, debugging mentors mid-window, completion mentors once teams should already be writing code, presentation mentors in the final stretch - never one flat open-to-close roster. | scheduled visits stop from: \"2027-03-14 18:00\" | check-in cadence: each assigned mentor checks in on each of their teams at least every 3 hours (the event's own number, self-set)\nInterruption discipline: [a per-visit time cap with a timer the team can see - 15 minutes (the event's own number, self-set), relaxed only for hands-on work that cannot be boxed; a do not disturb signal the team controls, visible from across the room; a published list of what each present mentor actually knows, so a team reaches the right person by name; a shared, live view of which teams are blocked and on what]\nHand-off to the shift plan: For event-volunteers' shift plan - it owns roster sizing from posts and hours, arrival buffers, sign-up confirmation, the no-show and replacement protocol and shift-linked recognition; this page computes none of them. The expertise constraint it schedules against: Open Payments: a mentor who has built with Lumenquay API present every hour of 2027-03-13 09:00 to 2027-03-14 21:00; Climate Data: a mentor who has built with Terraquill SDK present every hour of 2027-03-13 09:00 to 2027-03-14 21:00. Take each mentor's slot at sign-up: a slot is the commitment, presence beyond it is a courtesy. The coverage rule applies to a mentor shift unchanged: do not leave your post until you have confirmation of a replacement. No shift grid exists yet - the volunteer plan builds it.\nPlan must: [summary at most 40 words; verdict \"ready to publish the mechanic\" exactly; rotation uses the word \"stagger\"; handoff_to_shifts names event-volunteers (the word \"volunteer\"); caveats carry the fix findings first, at most 5]\nBrief must: [title contains \"Harbourline Hack 2027\"; how_to_ask uses the words \"area\" and \"nobody\"; where_published contains \"the hacker guide on harbourline.example\"; hours contains \"2027-03-13 09:00\" and \"2027-03-14 21:00\"; response_expectation says asking early is normal (the word \"early\") and states no time target; boundary uses the words \"repository\", \"declare\", \"ask\" and \"pitch\"; conflict_note uses the words \"log\" and \"recuse\"; interruption uses the words \"cap\" and \"disturb\"; escalation names \"Rosa Diazmere at the mentor desk\" exactly and says \"code of conduct\"; rotation_note uses the word \"slot\" and the word \"overnight\"] | brief note must: [say what happens next]\nPer-track mentor list for the briefing (built level), in this order - 5:\n- track: \"Open Payments\" | mentors: [\"Aiko Tanavelle\"; \"Ben Okaformi\"; \"Lea Novarek\"]\n must: [track \"Open Payments\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"Climate Data\" | mentors: [\"Carla Mendrova\"; \"Dev Patelmoor\"; \"Eva Lindqvarn\"; \"Mo Rahimor\"]\n must: [track \"Climate Data\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"Accessibility\" | mentors: [\"Farah Haddrell\"; \"Gus Morravin\"; \"Nia Owusanne\"]\n must: [track \"Accessibility\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"Open Innovation\" | mentors: [\"Ian Brookwyn\"; \"Lea Novarek\"; \"Nia Owusanne\"]\n must: [track \"Open Innovation\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"General stack\" | mentors: [\"Ben Okaformi\"; \"Dev Patelmoor\"; \"Hana Kimsel\"; \"Ian Brookwyn\"; \"Jo Achembre\"]\n must: [track \"General stack\" exactly; mentors copies the mentors list above, every one, each exactly]\nCarried from the plan: summary: \"Ready to publish the mechanic: both guaranteed tracks are covered through the night, the contact log has a keeper, and the overnight hours are thinly staffed - publish it with the brief.\" | parts matching the page: 3 of 3\nFindings (14):\n[check] notrack_11 (tags): \"Kofi Mensavo\"'s tags [\"frontend frameworks\"; \"design systems\"] match no track in the brief's vocabulary - a tag nobody can match to a track does no routing work. Ask what they actually know, in the brief's words.\n[check] thin_3 (coverage): \"Accessibility\" is available, and no tagged mentor is present 2027-03-13 18:00 to 2027-03-14 09:00 - overnight, 2027-03-14 00:00 to 06:00 - reachable only through the escalation route then; record it as a coverage gap.\n[check] docs_3 (tags): \"Accessibility\": nobody has built with \"Vocalorn speech API\" - Gus Morravin has read the docs; a roster full of the second kind reads as covered and is not.\n[check] thin_4 (coverage): \"Open Innovation\" is available, and no tagged mentor is present 2027-03-13 09:00 to 18:00 and 2027-03-14 02:00 to 09:00 - overnight, 2027-03-14 02:00 to 06:00 - reachable only through the escalation route then; record it as a coverage gap.\n[check] sponsor_unsigned (recruit): Q4: \"Aiko Tanavelle\", \"Ben Okaformi\" and \"Carla Mendrova\" come from a sponsor with nothing signed - negotiate it in event-sponsor-agreement: named people, their hours against the track's hours, and the engagement rule.\n[info] night_decided (rotation): Q1: the overnight hours are thinly staffed - publish that with the request mechanic.\n[info] unmatched_5 (tags): \"Eva Lindqvarn\": \"data viz\" match no track - listed, never dropped.\n[info] unmatched_10 (tags): \"Jo Achembre\": \"cloud\" match no track - listed, never dropped.\n[info] units (coverage): Coverage is sized by units - one per track, the sponsor technology by name, and the general stack - never by a ratio: a ratio says nothing about which tag is unstaffed at 03:00.\n[info] recuse (conflict): The rule, stated declaratively: a mentor who materially helped a team recuses from judging that team. hackathon-judging owns the rule and the recusal ladder; this page supplies only the contact log it reaches for.\n[info] engage (recruit): Every sponsor-supplied mentor gets the engagement rule in writing (no pitching, no recruiting while mentoring), mirrored into the sponsorship commitment. A sponsor mentor who does not appear is a fulfilment failure handled with the sponsor - never a no-show.\n[info] handoff (rotation): Hand the expertise constraint to event-volunteers as text - which tags must be present in which hours. Sizing, buffers, confirmation and the replacement protocol are that skill's arithmetic.\n[info] threshold (scope): The skill's one pass threshold (structural): before the window opens, five exist in writing with zero blanks - the tags mapped onto the tracks, the coverage commitment per track, the request mechanic as teams will read it, the mentor briefing with the boundary sentence, and the escalation route. Of the three the page can see, 3 of 3 exist; the brief run writes the mechanic and the briefing.\n[info] scope (scope): A mentor is not a volunteer, and not a judge. The page never invents a mentor-to-participant ratio, a staffing formula, an unblock latency target or evidence about outcomes, and never infers anyone's identity or seniority from a name."
}
Reply:
{
"task": "brief",
"mechanic": {
"title": "Harbourline Hack 2027 - how to reach a mentor",
"how_to_ask": "Mentors wear a marker and staff the mentor area: walk up to the area with your question, or ask there for the mentor listed for your track. If nobody covers it, the area asks the escalation route and tells you plainly, early enough to change approach.",
"where_published": "the hacker guide on harbourline.example",
"hours": "2027-03-13 09:00 to 2027-03-14 21:00",
"response_expectation": "Somebody will come: a mentor picks up each request as soon as they are free. Asking early is normal - it is not an admission of anything."
},
"briefing": {
"boundary": "Mentors explain, diagnose, unblock and demonstrate; they never write code that ships in a submission - anything shown in code is written outside the team's repository and the team types what lands. Mentors ask before touching the laptop, the keyboard or the repository, and a commit a mentor already made is declared in the submission. Sponsor staff help with the problem the team brought - no pitch, no recruiting, not a demo.",
"conflict_note": "Dev Patelmoor and Farah Haddrell also judge: every team they spend meaningful time with goes in the mentor-team contact log, kept by Rosa Diazmere at the mentor desk, and a mentor who materially helped a team will recuse from judging that team.",
"interruption": "Each visit has a cap with a timer the team can see - 15 minutes, the event's own number (self-set); a team's do not disturb signal is respected from across the room.",
"escalation": "When no mentor covers a skill, ask Rosa Diazmere at the mentor desk; for anything that is not technical, follow the code of conduct escalation to the conduct team on the safety channel.",
"rotation_note": "Your slot is the commitment; staying beyond it is a courtesy. The overnight hours are thinly staffed.",
"per_track": [
{
"track": "Open Payments",
"mentors": [
"Aiko Tanavelle",
"Ben Okaformi",
"Lea Novarek"
]
},
{
"track": "Climate Data",
"mentors": [
"Carla Mendrova",
"Dev Patelmoor",
"Eva Lindqvarn",
"Mo Rahimor"
]
},
{
"track": "Accessibility",
"mentors": [
"Farah Haddrell",
"Gus Morravin",
"Nia Owusanne"
]
},
{
"track": "Open Innovation",
"mentors": [
"Ian Brookwyn",
"Lea Novarek",
"Nia Owusanne"
]
},
{
"track": "General stack",
"mentors": [
"Ben Okaformi",
"Dev Patelmoor",
"Hana Kimsel",
"Ian Brookwyn",
"Jo Achembre"
]
}
]
},
"note": "Publish this mechanic in the hacker guide before the window opens, repeat it at the opening, and brief the mentors on the boundary."
}
The page's check: kept - nothing to flag
A digital 24-hour jam, no tracks entered yet - plan
Verdict: map tracks first; ready: no; window: 2027-05-08 12:00 to 2027-05-09 12:00; coverage pick: Rostered mentor shifts; recruitment: Community and alumni only; mechanic: Request channel with routing; briefing: Boundary stated; 0 tracks, 4 mentors, 0 gaps, 0 judging; 2 fix-level findings.
Input:
{
"task": "plan",
"event": "Event: \"Nightline Online Jam 2027\" | dates: 2027-05-08 to 2027-05-09 | as of: 2027-04-10\nQ1 format: \"digital\" | rooms: not set | hacking window: \"2027-05-08 12:00\" to \"2027-05-09 12:00\" (24 hours) | overnight: yes | overnight decision: \"not decided\"\nExpected: teams: 25 | participants: 90 | organizing team: 4\nQ3 theme: \"open - participants bring their own projects\"\nQ4 sponsor staffing in a signed agreement: no | sponsor staff on the roster: 0\nQ5 mentors also judging: 0 | contact log keeper: \"not named\"\nQ6 a prize carries cash value: no | a sponsor funds a prize: no\nQ7 edition: \"a one-off edition\" | mentored before - yes: 3 | no: 1 | not asked: 0\nQ8 organizer hours before the event: 12 | live coordination during the window: yes | a shift grid exists: no\nQ9 roster close: 2027-04-24 | mechanic reaches participants: 2027-05-01 | briefing session: not set | marker order: not set\nQ10 last edition's mentor list: no | a department or user group: no | sponsor staff on site for a booth: no | organizers built against the API: no\nRequest route: brief published at: \"the start-here channel on the event server\" | people who can work the routing: [\"Sam Ortizan\"] | asked when no mentor covers a skill: \"the mentors-lead channel\" | non-technical escalation: \"Sam Ortizan by direct message\"\nRotation: mentors roam: yes | per-visit cap in minutes: not set | check-in every (hours): not set | shared blocked-team view: no | general stack: [none]",
"tracks": "Tracks (Q2): none entered.",
"mentors": "Mentors (4), one per line:\n- mentor 1: \"Priya Nandakor\" | source: community | tags: [\"python\"; \"data pipelines\"] | slots: [2027-05-08 12:00 to 20:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 2: \"Tomas Silvarne\" | source: community | tags: [\"web\"; \"accessibility\"] | slots: [2027-05-08 18:00 to 2027-05-09 02:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 3: \"Wen Zhaovey\" | source: alumni | tags: [\"mobile\"; \"git\"] | slots: [2027-05-09 06:00 to 12:00] | also judging: no | mentored before (Q7): no | sponsor employer: \"none\"\n- mentor 4: \"Olu Adebrayo\" | source: community | tags: [\"cloud\"; \"deployment\"] | slots: [2027-05-08 12:00 to 2027-05-09 12:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"",
"notes": "",
"facts": "Verdict: \"map tracks first\" | ready: no | fix-level findings: 2 | coverage fixes: 0\nSelf-set lines: overnight hours from 00:00 to 06:00 | a mentor counts as present in an hour with at least 30 minutes of their slot in it | a roster deadline under 21 days away is close | a warm list needs at least 3 days and a sponsor staffing negotiation at least 21 | scheduled visits stop 3 hours before the window closes | a summary cap of 40 words. The skill's own: at least 2 people work any routing rung. Never invented: a mentor-to-participant ratio, a mentors-per-team or mentor-to-shift formula, an unblock latency target, any evidence linking mentor availability to completion or satisfaction.\nThe one published ratio: hackathon.guide (Joshua Tauberer), At Themed Hackathons: \"at least one subject matter expert + workable project for about every four non-expert participants\" | scope: themed events only, non-expert participants not teams, domain experts inside projects not floating mentors, project supply not staffing | use: evidence that expertise, not headcount, is scarce | never converted into mentors per participant or per team | this event is themed: no\nWindow (Q1): \"2027-05-08 12:00\" to \"2027-05-09 12:00\" (24 hours) | overnight hours in the window: 6 | overnight decision: \"not decided\"\nCoverage depth menu (step 2), re-ranked - pick: \"Rostered mentor shifts\"\n- rung 1: \"Rostered mentor shifts\"\n- rung 2: \"Expertise-matched roster\" | moved: demoted by Q9: the roster closes in 14 days - under the 21-day line (self-set); the tagging and alignment pass are the last work to finish\n- rung 3: \"No mentor programme\"\n- rung 4: \"On-call from organizers\" | moved: demoted by Q1: the window runs through the night - on-call routes every question to the people running the schedule at the hour it is hardest to run\nCoverage per track - one row per track, in this order - 0: none - an empty list\nExpertise tags (step 4) - one per mentor, in this order - 4:\n- mentor 1: \"Priya Nandakor\" | tracks: [none] | unmatched: [\"python\"; \"data pipelines\"] | read the docs: [none]\n must: [mentor \"Priya Nandakor\" exactly; tracks copies the tracks list above, every one, an empty list; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 2: \"Tomas Silvarne\" | tracks: [none] | unmatched: [\"web\"; \"accessibility\"] | read the docs: [none]\n must: [mentor \"Tomas Silvarne\" exactly; tracks copies the tracks list above, every one, an empty list; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 3: \"Wen Zhaovey\" | tracks: [none] | unmatched: [\"mobile\"; \"git\"] | read the docs: [none]\n must: [mentor \"Wen Zhaovey\" exactly; tracks copies the tracks list above, every one, an empty list; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 4: \"Olu Adebrayo\" | tracks: [none] | unmatched: [\"cloud\"; \"deployment\"] | read the docs: [none]\n must: [mentor \"Olu Adebrayo\" exactly; tracks copies the tracks list above, every one, an empty list; unmatched copies the unmatched list above, every one, each exactly]\nCoverage by hour - tagged mentors present (built level; for a guaranteed track, those who have built with its sponsor technology):\nGaps - hours below each track's commitment, in this order - 0: none - an empty list\nThin hours on available tracks (a check, not a gap): none\nMentor-judge conflict (Q5, step 8) - stated from one side - 0: none - an empty list\nThe rule, declaratively: a mentor who materially helped a team recuses from judging that team. hackathon-judging owns the rule and the recusal ladder; this page supplies only the mentor-team contact log, kept whenever a confirmed mentor is also on the judge list.\nRecruitment source (step 3) - pick: \"Community and alumni only\"\n- rung 1: \"Community and alumni only\" | moved: promoted by Q9: the roster deadline is 14 days away (under 21, self-set) - a warm list answers in days while a sponsor staffing negotiation runs weeks\n- rung 2: \"Mixed pool with a written rule\"\n- rung 3: \"Mixed pool\"\n- rung 4: \"Sponsor staff only\"\n- notes: The mixed pool without the rule is what happens by default when nobody writes the paragraph - naming it is how you notice it happened.\nRoster deadline (Q9): 2027-04-24 | from: \"roster close (Q9)\" | days from the as-of date: 14 | close: yes\nChannels - in this order - 1:\n- channel 1: \"Community and alumni\" | lead time: days (a warm list) | fits the deadline: yes | why: a warm-list ask, not an open call: tutors and teaching assistants first, then alumni, industry professionals and professors - a community or corporate event substitutes a user group, a past-participant list or a partner company\n recruitment must: [picks lists every channel above whose fit is yes or unknown, in this order, each exactly; reason names the pick \"Community and alumni only\" exactly]\nRequest mechanic (step 6) - pick: \"Request channel with routing\"\n- rung 1: \"Request channel with routing\" | moved: made the pick by Q1: a digital event - there is no floor to walk\n- rung 2: \"Identifiable mentors\"\n- rung 3: \"Staffed mentor area\"\n- rung 4: \"Find someone informally\"\n- deleted, not demoted: \"Routing every request through one organizer's direct messages\" | reason: always - it looks like the cheapest queue and is a single point of failure at the exact hour it is needed, because that person is asleep\n- deleted, not demoted: \"Scheduled office hours as the sole route\" | reason: Q1: the window runs through the night - a blocker at three in the morning does not wait for a ten o'clock slot; office hours may still supplement\nMechanic details: published at: \"the start-here channel on the event server\" | reaches participants by: 2027-05-01 | window opens: \"2027-05-08 12:00\" | window closes: \"2027-05-09 12:00\" | people who can work the routing: [\"Sam Ortizan\"] | asked when no mentor covers a skill: \"the mentors-lead channel\"\nMentor briefing depth (step 7) - pick: \"Boundary stated\"\n- rung 1: \"Boundary stated\"\n- rung 2: \"Logistics only\"\n- rung 3: \"No briefing\"\n- rung 4: \"Boundary plus scenario walkthrough\"\nThe boundary - the skill's workable formulation, to be edited into the event's own voice, not a standard to cite: \"Mentors explain, diagnose, unblock and demonstrate. Mentors do not write code that ships in a submission. If a mentor needs to show something in code, it is written outside the team's repository - a scratch file, a message, a whiteboard - and the team types the version that lands. If a mentor has already committed to a team's repository, the team declares it in the submission.\"\nSponsor engagement rule - for nobody (no sponsor staff on the roster): \"While mentoring, you are helping the team in front of you with the problem they brought. Not a sales conversation, not a recruiting conversation, not a demo. If a participant asks about your company, your product's pricing, or working for you, answer briefly and point them at your booth or your team's channel.\"\nPower dynamics: ask before touching anything (the laptop, the keyboard, the repository) | leave the project unevaluated | name the limit of your own knowledge out loud.\nEscalation when no mentor covers a skill: [the roster's second level - someone who has read the docs, saying so; the sponsor's channel, for the sponsor's technology; ask the room - a request, never an assignment; tell the team plainly, early enough to change approach] | asked: \"the mentors-lead channel\" | non-technical escalation: \"Sam Ortizan by direct message\" | the code-of-conduct script belongs to event-code-of-conduct\nRotation by expertise: constraints: [] | stagger: Stagger specialty coverage against when teams need each one: problem-definition and validation mentors early, debugging mentors mid-window, completion mentors once teams should already be writing code, presentation mentors in the final stretch - never one flat open-to-close roster. | scheduled visits stop from: \"2027-05-09 09:00\" | check-in cadence: not set\nInterruption discipline: [a per-visit time cap with a timer the team can see, relaxed only for hands-on work that cannot be boxed; a do not disturb signal the team controls, visible from across the room; a published list of what each present mentor actually knows, so a team reaches the right person by name; a shared, live view of which teams are blocked and on what - not set up yet]\nHand-off to the shift plan: For event-volunteers' shift plan - it owns roster sizing from posts and hours, arrival buffers, sign-up confirmation, the no-show and replacement protocol and shift-linked recognition; this page computes none of them. The expertise constraint it schedules against: no track is guaranteed - every tag needs only to be on the roster. Take each mentor's slot at sign-up: a slot is the commitment, presence beyond it is a courtesy. The coverage rule applies to a mentor shift unchanged: do not leave your post until you have confirmation of a replacement. No shift grid exists yet - the volunteer plan builds it.\nPlan must: [summary at most 40 words; verdict \"map tracks first\" exactly; rotation uses the word \"stagger\"; handoff_to_shifts names event-volunteers (the word \"volunteer\"); caveats carry the fix findings first, at most 5]\nBrief must: [title contains \"Nightline Online Jam 2027\"; how_to_ask uses the words \"channel\" and \"nobody\"; where_published contains \"the start-here channel on the event server\"; hours contains \"2027-05-08 12:00\" and \"2027-05-09 12:00\"; response_expectation says asking early is normal (the word \"early\") and states no time target; boundary uses the words \"repository\", \"declare\" and \"ask\"; conflict_note is exactly \"None.\"; interruption uses the words \"cap\" and \"disturb\"; escalation names \"the mentors-lead channel\" exactly and says \"code of conduct\"; rotation_note uses the word \"slot\" and the word \"overnight\"] | brief note must: [begin \"Not ready to publish:\" and say what to fix first]\nPer-track mentor list for the briefing (built level), in this order - 0: none - an empty list\nFindings (12):\n[fix] no_tracks (map): Q2: no challenge track entered - coverage is set against the brief's tracks, not a headcount. Copy each track from the published brief with its vocabulary and sponsor-integration depth.\n[fix] routers (mechanic): Any routing rung needs at least two people who can work it, or an unrouted fallback participants already know about - only \"Sam Ortizan\" is named.\n[check] night_undecided (rotation): Q1: the window runs through the night (6 hours between 00:00 and 06:00, self-set) - decide deliberately whether those hours are staffed, thinly staffed or published as unstaffed, and publish whichever it is.\n[check] visit_cadence (rotation): Set a minimum check-in frequency per assigned team - a number this event sets for itself, said self-set - and stop scheduled visits ahead of the final stretch (from 2027-05-09 09:00, 3 hours out, self-set).\n[check] visit_cap (rotation): Mentors roam: set a per-visit time cap with a timer the team can see (the event's own number, self-set) - otherwise a team re-pitches its project to every mentor who wanders past.\n[check] blocked_view (rotation): Mentors roam with no shared view of who visited whom - several mentors cluster on the loudest team while another goes untouched for hours. That is a coordination gap, not a coverage gap.\n[info] unmatched_1 (tags): \"Priya Nandakor\": \"python\" and \"data pipelines\" match no track - listed, never dropped.\n[info] unmatched_2 (tags): \"Tomas Silvarne\": \"web\" and \"accessibility\" match no track - listed, never dropped.\n[info] unmatched_3 (tags): \"Wen Zhaovey\": \"mobile\" and \"git\" match no track - listed, never dropped.\n[info] unmatched_4 (tags): \"Olu Adebrayo\": \"cloud\" and \"deployment\" match no track - listed, never dropped.\n[info] threshold (scope): The skill's one pass threshold (structural): before the window opens, five exist in writing with zero blanks - the tags mapped onto the tracks, the coverage commitment per track, the request mechanic as teams will read it, the mentor briefing with the boundary sentence, and the escalation route. Of the three the page can see, 1 of 3 exist; the brief run writes the mechanic and the briefing.\n[info] scope (scope): A mentor is not a volunteer, and not a judge. The page never invents a mentor-to-participant ratio, a staffing formula, an unblock latency target or evidence about outcomes, and never infers anyone's identity or seniority from a name."
}
Reply:
{
"task": "plan",
"summary": "Map tracks first: no challenge track is entered, so coverage cannot be set - copy the brief's tracks with their vocabulary and depth, then name a second person to route requests.",
"verdict": "map tracks first",
"coverage": [],
"tags": [
{
"mentor": "Priya Nandakor",
"tracks": [],
"unmatched": [
"python",
"data pipelines"
]
},
{
"mentor": "Tomas Silvarne",
"tracks": [],
"unmatched": [
"web",
"accessibility"
]
},
{
"mentor": "Wen Zhaovey",
"tracks": [],
"unmatched": [
"mobile",
"git"
]
},
{
"mentor": "Olu Adebrayo",
"tracks": [],
"unmatched": [
"cloud",
"deployment"
]
}
],
"gaps": [],
"conflict": [],
"recruitment": {
"picks": [
"Community and alumni"
],
"reason": "Community and alumni only is the pick, and the roster deadline is 2027-04-24 (roster close (Q9)) - close, so the warm list leads: it answers in days."
},
"rotation": "Stagger specialty coverage against when teams need each one.",
"handoff_to_shifts": "Hand event-volunteers the expertise constraint once the tracks are mapped; the volunteer plan sizes, buffers, confirms and backfills the shifts.",
"caveats": [
"no challenge track entered - coverage is set against the brief's tracks, not a headcount.",
"Any routing rung needs at least two people who can work it, or an unrouted fallback participants already know about - only \"Sam Ortizan\" is named.",
"the window runs through the night (6 hours between 00:00 and 06:00, self-set) - decide deliberately whether those hours are staffed, thinly staffed or published as unstaffed, and publish whichever it is.",
"Set a minimum check-in frequency per assigned team - a number this event sets for itself, said self-set - and stop scheduled visits ahead of the final stretch (from 2027-05-09 09:00, 3 hours out, self-set).",
"Mentors roam: set a per-visit time cap with a timer the team can see (the event's own number, self-set) - otherwise a team re-pitches its project to every mentor who wanders past."
]
}
The page's check: kept - nothing to flag
A themed one-day hackathon, five mentors - brief
Verdict: ready to publish the mechanic; ready: yes; window: 2027-06-12 09:00 to 2027-06-12 19:00; coverage pick: Expertise-matched roster; recruitment: Community and alumni only; mechanic: Identifiable mentors; briefing: Boundary stated; 2 tracks, 5 mentors, 0 gaps, 0 judging; 0 fix-level findings.
Input:
{
"task": "brief",
"event": "Event: \"Civic Health Day 2027\" | dates: 2027-06-12 | as of: 2027-05-01\nQ1 format: \"in person\" | rooms: 1 | hacking window: \"2027-06-12 09:00\" to \"2027-06-12 19:00\" (10 hours) | overnight: no | overnight decision: \"not decided\"\nExpected: teams: 8 | participants: 30 | organizing team: 6\nQ3 theme: \"themed - organizer-supplied problems from one domain\"\nQ4 sponsor staffing in a signed agreement: no | sponsor staff on the roster: 0\nQ5 mentors also judging: 0 | contact log keeper: \"not named\"\nQ6 a prize carries cash value: no | a sponsor funds a prize: no\nQ7 edition: \"a one-off edition\" | mentored before - yes: 5 | no: 0 | not asked: 0\nQ8 organizer hours before the event: 20 | live coordination during the window: yes | a shift grid exists: no\nQ9 roster close: 2027-05-28 | mechanic reaches participants: 2027-06-05 | briefing session: 2027-06-09 | marker order: not set\nQ10 last edition's mentor list: no | a department or user group: no | sponsor staff on site for a booth: no | organizers built against the API: no\nRequest route: brief published at: \"the challenge page on civichealth.example\" | people who can work the routing: [none] | asked when no mentor covers a skill: \"Nadia Parkhollow at the help desk\" | non-technical escalation: \"Nadia Parkhollow, in person or by text\"\nRotation: mentors roam: yes | per-visit cap in minutes: 20 | check-in every (hours): 2 | shared blocked-team view: yes | general stack: [\"git\"; \"deployment\"]",
"tracks": "Tracks (Q2) (2), one per line:\n- track 1: \"Clinic Wait Times\" | vocabulary: [\"clinics\"; \"scheduling\"; \"wait times\"] | depth: \"no sponsor\" | sponsor technology: \"none named\" | hours worked: [2027-06-12 09:00 to 19:00]\n- track 2: \"Air Quality\" | vocabulary: [\"air quality\"; \"sensors\"; \"pollution\"] | depth: \"named funder only\" | sponsor technology: \"none named\" | hours worked: [2027-06-12 09:00 to 19:00]",
"mentors": "Mentors (5), one per line:\n- mentor 1: \"Ama Boatengwe\" | source: community | tags: [\"scheduling\"; \"clinics\"] | slots: [2027-06-12 09:00 to 19:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 2: \"Luis Ortevald\" | source: university | tags: [\"air quality\"; \"sensors\"] | slots: [2027-06-12 09:00 to 14:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 3: \"Mei Chenwick\" | source: alumni | tags: [\"wait times\"; \"data analysis\"] | slots: [2027-06-12 12:00 to 19:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 4: \"Sara Lindmere\" | source: community | tags: [\"pollution\"; \"mapping\"] | slots: [2027-06-12 13:00 to 19:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"\n- mentor 5: \"Raj Iyermont\" | source: university | tags: [\"git\"; \"deployment\"; \"clinics\"] | slots: [2027-06-12 09:00 to 19:00] | also judging: no | mentored before (Q7): yes | sponsor employer: \"none\"",
"notes": "",
"facts": "Verdict: \"ready to publish the mechanic\" | ready: yes | fix-level findings: 0 | coverage fixes: 0\nSelf-set lines: overnight hours from 00:00 to 06:00 | a mentor counts as present in an hour with at least 30 minutes of their slot in it | a roster deadline under 21 days away is close | a warm list needs at least 3 days and a sponsor staffing negotiation at least 21 | scheduled visits stop 3 hours before the window closes | a summary cap of 40 words. The skill's own: at least 2 people work any routing rung. Never invented: a mentor-to-participant ratio, a mentors-per-team or mentor-to-shift formula, an unblock latency target, any evidence linking mentor availability to completion or satisfaction.\nThe one published ratio: hackathon.guide (Joshua Tauberer), At Themed Hackathons: \"at least one subject matter expert + workable project for about every four non-expert participants\" | scope: themed events only, non-expert participants not teams, domain experts inside projects not floating mentors, project supply not staffing | use: evidence that expertise, not headcount, is scarce | never converted into mentors per participant or per team | this event is themed: yes\nWindow (Q1): \"2027-06-12 09:00\" to \"2027-06-12 19:00\" (10 hours) | overnight hours in the window: 0 | overnight decision: \"not decided\"\nCoverage depth menu (step 2), re-ranked - pick: \"Expertise-matched roster\"\n- rung 1: \"Expertise-matched roster\" | moved: made the pick by Q3: a themed event whose problems come from one domain\n- rung 2: \"Rostered mentor shifts\"\n- rung 3: \"On-call from organizers\"\n- rung 4: \"No mentor programme\"\nCoverage per track - one row per track, in this order - 3:\n- row 1: \"Clinic Wait Times\" | depth: \"no sponsor\" | sponsor technology: \"none named\" | rung: \"Expertise-matched roster\" | commitment: \"available\" | why: Q3: a themed event - the roster is matched to the brief's tracks by expertise | counts toward it: [\"Ama Boatengwe\"; \"Mei Chenwick\"; \"Raj Iyermont\"] | read the docs only: [none]\n must: [track \"Clinic Wait Times\" exactly; rung \"Expertise-matched roster\" exactly; reason uses the word \"available\"]\n- row 2: \"Air Quality\" | depth: \"named funder only\" | sponsor technology: \"none named\" | rung: \"Expertise-matched roster\" | commitment: \"available\" | why: Q3: a themed event - the roster is matched to the brief's tracks by expertise | counts toward it: [\"Luis Ortevald\"; \"Sara Lindmere\"] | read the docs only: [none]\n must: [track \"Air Quality\" exactly; rung \"Expertise-matched roster\" exactly; reason uses the word \"available\"]\n- row 3: \"General stack\" | depth: \"no sponsor\" | sponsor technology: \"none named\" | rung: \"Rostered mentor shifts\" | commitment: \"available\" | why: the general stack every team touches regardless of track | counts toward it: [\"Raj Iyermont\"] | read the docs only: [none]\n must: [track \"General stack\" exactly; rung \"Rostered mentor shifts\" exactly; reason uses the word \"available\"]\nExpertise tags (step 4) - one per mentor, in this order - 5:\n- mentor 1: \"Ama Boatengwe\" | tracks: [\"Clinic Wait Times\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Ama Boatengwe\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 2: \"Luis Ortevald\" | tracks: [\"Air Quality\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Luis Ortevald\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\n- mentor 3: \"Mei Chenwick\" | tracks: [\"Clinic Wait Times\"] | unmatched: [\"data analysis\"] | read the docs: [none]\n must: [mentor \"Mei Chenwick\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 4: \"Sara Lindmere\" | tracks: [\"Air Quality\"] | unmatched: [\"mapping\"] | read the docs: [none]\n must: [mentor \"Sara Lindmere\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, each exactly]\n- mentor 5: \"Raj Iyermont\" | tracks: [\"Clinic Wait Times\"; \"General stack\"] | unmatched: [none] | read the docs: [none]\n must: [mentor \"Raj Iyermont\" exactly; tracks copies the tracks list above, every one, each exactly; unmatched copies the unmatched list above, every one, an empty list]\nCoverage by hour - tagged mentors present (built level; for a guaranteed track, those who have built with its sponsor technology):\n- \"Clinic Wait Times\": [2027-06-12 09:00 to 12:00: 2; 2027-06-12 12:00 to 19:00: 3]\n- \"Air Quality\": [2027-06-12 09:00 to 13:00: 1; 2027-06-12 13:00 to 14:00: 2; 2027-06-12 14:00 to 19:00: 1]\n- \"General stack\": [2027-06-12 09:00 to 19:00: 1]\nGaps - hours below each track's commitment, in this order - 0: none - an empty list\nThin hours on available tracks (a check, not a gap): none\nMentor-judge conflict (Q5, step 8) - stated from one side - 0: none - an empty list\nThe rule, declaratively: a mentor who materially helped a team recuses from judging that team. hackathon-judging owns the rule and the recusal ladder; this page supplies only the mentor-team contact log, kept whenever a confirmed mentor is also on the judge list.\nRecruitment source (step 3) - pick: \"Community and alumni only\"\n- rung 1: \"Community and alumni only\"\n- rung 2: \"Mixed pool with a written rule\"\n- rung 3: \"Mixed pool\"\n- rung 4: \"Sponsor staff only\"\n- notes: The mixed pool without the rule is what happens by default when nobody writes the paragraph - naming it is how you notice it happened.\nRoster deadline (Q9): 2027-05-28 | from: \"roster close (Q9)\" | days from the as-of date: 27 | close: no\nChannels - in this order - 1:\n- channel 1: \"Community and alumni\" | lead time: days (a warm list) | fits the deadline: yes | why: a warm-list ask, not an open call: tutors and teaching assistants first, then alumni, industry professionals and professors - a community or corporate event substitutes a user group, a past-participant list or a partner company\n recruitment must: [picks lists every channel above whose fit is yes or unknown, in this order, each exactly; reason names the pick \"Community and alumni only\" exactly]\nRequest mechanic (step 6) - pick: \"Identifiable mentors\"\n- rung 1: \"Identifiable mentors\"\n- rung 2: \"Staffed mentor area\"\n- rung 3: \"Request channel with routing\"\n- rung 4: \"Scheduled office hours\"\n- rung 5: \"Find someone informally\"\n- deleted, not demoted: \"Routing every request through one organizer's direct messages\" | reason: always - it looks like the cheapest queue and is a single point of failure at the exact hour it is needed, because that person is asleep\nMechanic details: published at: \"the challenge page on civichealth.example\" | reaches participants by: 2027-06-05 | window opens: \"2027-06-12 09:00\" | window closes: \"2027-06-12 19:00\" | people who can work the routing: [none] | asked when no mentor covers a skill: \"Nadia Parkhollow at the help desk\"\nMentor briefing depth (step 7) - pick: \"Boundary stated\"\n- rung 1: \"Boundary stated\"\n- rung 2: \"Logistics only\"\n- rung 3: \"No briefing\"\n- rung 4: \"Boundary plus scenario walkthrough\"\nThe boundary - the skill's workable formulation, to be edited into the event's own voice, not a standard to cite: \"Mentors explain, diagnose, unblock and demonstrate. Mentors do not write code that ships in a submission. If a mentor needs to show something in code, it is written outside the team's repository - a scratch file, a message, a whiteboard - and the team types the version that lands. If a mentor has already committed to a team's repository, the team declares it in the submission.\"\nSponsor engagement rule - for nobody (no sponsor staff on the roster): \"While mentoring, you are helping the team in front of you with the problem they brought. Not a sales conversation, not a recruiting conversation, not a demo. If a participant asks about your company, your product's pricing, or working for you, answer briefly and point them at your booth or your team's channel.\"\nPower dynamics: ask before touching anything (the laptop, the keyboard, the repository) | leave the project unevaluated | name the limit of your own knowledge out loud.\nEscalation when no mentor covers a skill: [the roster's second level - someone who has read the docs, saying so; the sponsor's channel, for the sponsor's technology; ask the room - a request, never an assignment; tell the team plainly, early enough to change approach] | asked: \"Nadia Parkhollow at the help desk\" | non-technical escalation: \"Nadia Parkhollow, in person or by text\" | the code-of-conduct script belongs to event-code-of-conduct\nRotation by expertise: constraints: [Clinic Wait Times - the Clinic Wait Times tag on the roster, reachable through the request mechanic; Air Quality - the Air Quality tag on the roster, reachable through the request mechanic; General stack - the General stack tag on the roster, reachable through the request mechanic] | stagger: Stagger specialty coverage against when teams need each one: problem-definition and validation mentors early, debugging mentors mid-window, completion mentors once teams should already be writing code, presentation mentors in the final stretch - never one flat open-to-close roster. | scheduled visits stop from: \"2027-06-12 16:00\" | check-in cadence: each assigned mentor checks in on each of their teams at least every 2 hours (the event's own number, self-set)\nInterruption discipline: [a per-visit time cap with a timer the team can see - 20 minutes (the event's own number, self-set), relaxed only for hands-on work that cannot be boxed; a do not disturb signal the team controls, visible from across the room; a published list of what each present mentor actually knows, so a team reaches the right person by name; a shared, live view of which teams are blocked and on what]\nHand-off to the shift plan: For event-volunteers' shift plan - it owns roster sizing from posts and hours, arrival buffers, sign-up confirmation, the no-show and replacement protocol and shift-linked recognition; this page computes none of them. The expertise constraint it schedules against: no track is guaranteed - every tag needs only to be on the roster. Take each mentor's slot at sign-up: a slot is the commitment, presence beyond it is a courtesy. The coverage rule applies to a mentor shift unchanged: do not leave your post until you have confirmation of a replacement. No shift grid exists yet - the volunteer plan builds it.\nPlan must: [summary at most 40 words; verdict \"ready to publish the mechanic\" exactly; rotation uses the word \"stagger\"; handoff_to_shifts names event-volunteers (the word \"volunteer\"); caveats carry the fix findings first, at most 5]\nBrief must: [title contains \"Civic Health Day 2027\"; how_to_ask uses the words \"marker\" and \"nobody\"; where_published contains \"the challenge page on civichealth.example\"; hours contains \"2027-06-12 09:00\" and \"2027-06-12 19:00\"; response_expectation says asking early is normal (the word \"early\") and states no time target; boundary uses the words \"repository\", \"declare\" and \"ask\"; conflict_note is exactly \"None.\"; interruption uses the words \"cap\" and \"disturb\"; escalation names \"Nadia Parkhollow at the help desk\" exactly and says \"code of conduct\"; rotation_note uses the word \"slot\"] | brief note must: [say what happens next]\nPer-track mentor list for the briefing (built level), in this order - 3:\n- track: \"Clinic Wait Times\" | mentors: [\"Ama Boatengwe\"; \"Mei Chenwick\"; \"Raj Iyermont\"]\n must: [track \"Clinic Wait Times\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"Air Quality\" | mentors: [\"Luis Ortevald\"; \"Sara Lindmere\"]\n must: [track \"Air Quality\" exactly; mentors copies the mentors list above, every one, each exactly]\n- track: \"General stack\" | mentors: [\"Raj Iyermont\"]\n must: [track \"General stack\" exactly; mentors copies the mentors list above, every one, each exactly]\nCarried from the plan: summary: \"Ready to publish the mechanic: both themed tracks hold tagged mentors all day, nobody judges, and identifiable mentors suit one room - publish it on the challenge page.\" | parts matching the page: 3 of 3\nFindings (7):\n[info] unmatched_3 (tags): \"Mei Chenwick\": \"data analysis\" match no track - listed, never dropped.\n[info] unmatched_4 (tags): \"Sara Lindmere\": \"mapping\" match no track - listed, never dropped.\n[info] ratio (coverage): Q3 themed: hackathon.guide's one published ratio - \"at least one subject matter expert + workable project for about every four non-expert participants\" - scopes to themed events, counts non-expert participants (not teams) and domain experts inside projects (not floating mentors), and is about project supply. It is evidence that expertise, not headcount, is scarce - never a mentors-per-participant number, and the page computes none.\n[info] units (coverage): Coverage is sized by units - one per track, the sponsor technology by name, and the general stack - never by a ratio: a ratio says nothing about which tag is unstaffed at 03:00.\n[info] handoff (rotation): Hand the expertise constraint to event-volunteers as text - which tags must be present in which hours. Sizing, buffers, confirmation and the replacement protocol are that skill's arithmetic.\n[info] threshold (scope): The skill's one pass threshold (structural): before the window opens, five exist in writing with zero blanks - the tags mapped onto the tracks, the coverage commitment per track, the request mechanic as teams will read it, the mentor briefing with the boundary sentence, and the escalation route. Of the three the page can see, 3 of 3 exist; the brief run writes the mechanic and the briefing.\n[info] scope (scope): A mentor is not a volunteer, and not a judge. The page never invents a mentor-to-participant ratio, a staffing formula, an unblock latency target or evidence about outcomes, and never infers anyone's identity or seniority from a name."
}
Reply:
{
"task": "brief",
"mechanic": {
"title": "Civic Health Day 2027 - how to reach a mentor",
"how_to_ask": "Mentors wear a marker you can spot across the room and carry the mentor role in the event's channels: ask any of them, or the mentor listed for your track. If nobody covers your question, we tell you plainly and early, so you can change approach.",
"where_published": "the challenge page on civichealth.example",
"hours": "2027-06-12 09:00 to 2027-06-12 19:00",
"response_expectation": "Somebody will come: a mentor picks up each request as soon as they are free. Asking early is normal - it is not an admission of anything."
},
"briefing": {
"boundary": "Mentors explain, diagnose, unblock and demonstrate; they never write code that ships in a submission - anything shown in code is written outside the team's repository and the team types what lands. Mentors ask before touching the laptop, the keyboard or the repository, and a commit a mentor already made is declared in the submission.",
"conflict_note": "None.",
"interruption": "Each visit has a cap with a timer the team can see - 20 minutes, the event's own number (self-set); a team's do not disturb signal is respected from across the room.",
"escalation": "When no mentor covers a skill, ask Nadia Parkhollow at the help desk; for anything that is not technical, follow the code of conduct escalation to Nadia Parkhollow, in person or by text.",
"rotation_note": "Your slot is the commitment; staying beyond it is a courtesy.",
"per_track": [
{
"track": "Clinic Wait Times",
"mentors": [
"Ama Boatengwe",
"Mei Chenwick",
"Raj Iyermont"
]
},
{
"track": "Air Quality",
"mentors": [
"Luis Ortevald",
"Sara Lindmere"
]
},
{
"track": "General stack",
"mentors": [
"Raj Iyermont"
]
}
]
},
"note": "Publish this mechanic on the challenge page before the window opens and repeat it at the opening."
}
The page's check: kept - nothing to flag
The free mechanic draft for the themed sample
# Civic Health Day 2027 - how to reach a mentor (draft from the page)
_Verdict: ready to publish the mechanic. Publish it where the brief is published (the challenge page on civichealth.example), before the window opens, and repeat it at the opening._
**The mechanic:** Identifiable mentors.
**When:** 2027-06-12 09:00 to 2027-06-12 19:00.
## How to recognise a mentor
Mentors wear a marker you can spot across the room and carry the mentor role in the event's channels.
## How to ask
Ask any mentor you can see, or the person whose name is listed below for your track.
## What to expect
Somebody will come. Asking early is normal - it is not an admission of anything.
## When nobody covers it
We ask Nadia Parkhollow at the help desk. If nobody covers it, we tell you plainly and early, so you can change approach.
## Who knows what
- Clinic Wait Times: Ama Boatengwe, Mei Chenwick, Raj Iyermont
- Air Quality: Luis Ortevald, Sara Lindmere
- General stack: Raj Iyermont
Made with Mentor Roster - https://mentor-roster.skillsafe.ai/
Build the input yourself
Load the engine in node (global.window = global; require("./mentorkit.js"); require("./mentorreply.js")), then:
const K = MentorKit, R = MentorReply;
const f = K.form({ name: "My Hack 2027", winStart: "2027-05-20 09:00", winEnd: "2027-05-21 09:00", rooms: "2", asOf: "2027-04-01",
tracks: "Maps | maps; geodata | required | Atlas SDK",
mentors: "A. Mentor | sponsor staff | Atlas SDK; maps | 2027-05-20 09:00-21:00 | no | yes | Atlas",
escalate: "the help desk lead", briefWhere: "the hacker guide", mechanicBy: "2027-05-13" });
// f.units (coverage per track), f.mentors[i].units / .unmatched (tags), f.gaps, f.conflict, f.cover, f.recruit, f.channels, f.mech, f.brief, f.handoff, f.verdict, f.findings
K.coverageCsv(f); K.tagsCsv(f); K.ics(f); K.mechanicMd(f) // the free exports
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}
// R.carryText(reply) // the lines the brief lane carries - set them as the carry field
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="YOUR_TOKEN" # from https://mentor-roster.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 = "YOUR_TOKEN" # from https://mentor-roster.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"]
// mentor-roster.mjs -- Node 18+ (global fetch)
const BASE = "https://api.skillsafe.ai/v1/app-api";
let TOKEN = "YOUR_TOKEN"; // from https://mentor-roster.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 = "YOUR_TOKEN" // from https://mentor-roster.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
}
// MentorRoster.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 MentorRoster {
static final String BASE = "https://api.skillsafe.ai/v1/app-api";
static String token = "YOUR_TOKEN"; // from https://mentor-roster.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 = "YOUR_TOKEN" # from https://mentor-roster.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 = "YOUR_TOKEN"; // from https://mentor-roster.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 = "YOUR_TOKEN"; // from https://mentor-roster.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":"mentor-roster"}' | 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": "mentor-roster"})["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: "mentor-roster" })).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": "mentor-roster"}, 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", "mentor-roster"), 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: "mentor-roster" })["token"])
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
$TOKEN = "";
$TOKEN = api("POST", "/guest", ["slug" => "mentor-roster"])["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 = "mentor-roster" }))!["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: ... | dates: ... | as of: ...", "tracks": "Tracks (Q2) (4) ...", "mentors": "Mentors (14) ...", "notes": "", "facts": "Verdict: ..."}
# - 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: ... | dates: ... | as of: ...", "tracks": "Tracks (Q2) (4) ...", "mentors": "Mentors (14) ...", "notes": "", "facts": "Verdict: ..."}
# - 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, tracks, mentors, notes, 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 mentor-roster:<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, verdict, coverage, tags, gaps, conflict, recruitment, rotation, handoff_to_shifts and caveats; a brief carries mechanic, briefing and note. The code below prints the headline of either.
KEY="mentor-roster: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 '.verdict // .note, .summary // empty' reply.json
jq -r '.coverage[]? | "\(.track): \(.rung)"' reply.json # a plan; a brief has .mechanic and .briefing
import hashlib, time
key = "mentor-roster:" + 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("verdict") or reply.get("note"))
for row in reply.get("coverage") or (reply.get("briefing") or {}).get("per_track") or []:
print("-", row["track"], row.get("rung") or ", ".join(row.get("mentors") or []))
import { createHash } from "node:crypto";
const key = `mentor-roster:${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.verdict ?? reply.note);
for (const row of reply.coverage || (reply.briefing || {}).per_track || []) console.log("-", row.track, row.rung || (row.mentors || []).join(", "));
sum := sha256.Sum256(raw) // add "crypto/sha256", "encoding/hex", "time" to the imports
key := "mentor-roster:" + 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)
fmt.Println(j["charged_credits"], j["truncated"], reply["verdict"], reply["note"])
coverage, _ := reply["coverage"].([]any) // a plan's coverage; a brief has mechanic and briefing
for _, row := range coverage {
fmt.Println("-", row.(map[string]any)["track"], row.(map[string]any)["rung"])
}
var digest = java.security.MessageDigest.getInstance("SHA-256").digest(M.writeValueAsBytes(input));
String key = "mentor-roster:" + 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.path("verdict").asText(reply.path("note").asText()));
for (JsonNode row : reply.path("coverage")) System.out.println("- " + row.path("track").asText() + " " + row.path("rung").asText());
require "digest"
key = "mentor-roster:#{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["verdict"] || reply["note"]].inspect
(reply["coverage"] || []).each { |row| puts "- #{row["track"]} #{row["rung"]}" }
$key = "mentor-roster:" . $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["verdict"] ?? $reply["note"] ?? ""), "\n";
foreach ($reply["coverage"] ?? [] as $row) echo "- ", $row["track"], " ", $row["rung"], "\n";
var digest = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(input.ToJsonString()));
var key = $"mentor-roster:{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!["verdict"] ?? reply["note"]}");
foreach (var row in reply["coverage"] as JsonArray ?? new JsonArray()) Console.WriteLine("- " + row!["track"] + " " + row["rung"]);
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: mentor-roster: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: ... | dates: ... | as of: ...", "tracks": "Tracks (Q2) (4) ...", "mentors": "Mentors (14) ...", "notes": "", "facts": "Verdict: ..."}
# - 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": "mentor-roster: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": `mentor-roster: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", "mentor-roster: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", "mentor-roster: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" => "mentor-roster: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: mentor-roster: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", $"mentor-roster: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);