Order Up at the Level Up Lounge: a five-minute, app-only naming competition. Invent one coffee that carries mona, ducky, or copilot, get it scored out of 5,000 by a local rubric, and put it on the house menu for the rest of the event.
Commit & Sip was built with GitHub Copilot, working in the GitHub Copilot App. It has three parts:
- The booth canvas. The screen attendees use is a canvas: a small web app that runs inside the GitHub Copilot App as a project extension (
.github/extensions/commit-and-sip/), built on the Copilot SDK's canvas API. It runs on the booth machine and keeps its data there. - The score. A fixed rubric in the code (
services/name-score.mjs) scores each name out of 5,000. No AI model judges it. - The leaderboard. A small Node.js service that uses only Node's built-in modules (
leaderboard-service/), hosted on Azure App Service and described in Bicep (infra/). Each booth sends its drinks to it, and staff can take one down.
Every pull request was reviewed with Copilot code review, and GitHub Actions validates the repository. The booth's served screen and the public leaderboard both carry this summary and a QR code for https://gh.io/commit-and-sip, which leads here.
Audience: beginners and GitHub-curious booth attendees. Goal: invent a drink name nobody has served here yet. Duration: about five minutes, with no speed or hint penalties.
You need only the booth's preconfigured Copilot App. No coding, cloning, account setup, GitHub sign-in, terminal, or external editor is required, and the attendee never opens a pull request. Staff supply the device and handle setup and recovery.
Open: click Commit & Sip with no input. The booth canvas is the default canvas and takes no open input; the counter opens idle and ready.
Start: choose Start my order. The station mints a barista handle, then follow Step 1: Name a drink for the house menu: pick a mascot and where it sits, type your name, and choose Add it to the menu. The canonical learner step matches what the screen tells you.
Finish: read the score breakdown, take your place on the leaderboard, then choose I'm done - hand over to the next barista. That clears the counter for the next attendee; your drink stays on the menu and your entry stays on the leaderboard. See the reset procedure.
Mona Latte, Copilot Cortado, and Ducky Cold Brew are worked examples. They are never scored and never appear on the leaderboard. The menu is first come, first served, so a name already taken is reported back and you try another.
This is a canvas-led adaptation of a GitHub Skills exercise: one learner step with several activities, not a five-step course. Staff setup is outside the learner step. Actions validate the repository; they do not drive learner transitions, create exercise issues, or gate play on workflow queue time. There is no Step 2 or automatic issue closure.
Commit & Sip is a project-local Copilot App canvas extension, registered as commit-and-sip. The booth flow runs end to end today: handle, name validation, rubric score, house menu, standings, and hand-over all work locally and persist across panel closure and extension reload.
It is not event-ready. Two human reviews are outstanding, and neither is code:
- The moderation blocklist is an unreviewed placeholder.
booth/blocked-terms.jsonships with no real terms, and the extension logs a warning on every start while that is true. A human must review and approve the list before attendee names go on a public menu. Staff can take a drink down after the fact withnpm run remove, which is what makes an imperfect list survivable, but that is a response and not a substitute. - Brand, trademark, and privacy review of the mascot names and artwork has not happened, and the attendee screen already carries the official Mona mascot in the cup. See the asset checklist for its provenance and what happens if review says no.
Already in place:
- The leaderboard service is live, but its moderation is not. The service runs at https://commit-and-sip-leaderboard.azurewebsites.net (short link https://gh.io/commit-and-sip-leader). It was redeployed on 2026-10-01 from this branch and verified end to end through the canvases, so the current booth client works against it. Changes to
leaderboard-service/made after that deploy reach the live site only when someone with Contributor redeploys (see the runbook). The board and the names on it are moderated with the same placeholder blocklist, so the attendee QR (leaderboardUrl) stays a gated setting: leave it unset until the blocklist is reviewed. The event owner has switched it on for one booth machine, ahead of that review, as a deliberate exception for staff testing; staff takedown is the only moderation there until the review is done. Publishing is local-first, so an unreachable service never blocks an attendee. - Both short links resolve. https://gh.io/commit-and-sip-leader redirects to the leaderboard service and keeps the query string, so each attendee's personal code (
?handle=…&ref=…) still opens their own row onceleaderboardUrlis set. https://gh.io/commit-and-sip points at this repository, which is public.
The earlier pull-request review flow, its live and canvas-pilot modes, and its provisioning scripts have been removed. No code path in this repository reads or writes GitHub.
Staff need Node.js 22 or newer and a Copilot App/CLI build supporting project canvas extensions. The pinned version lives in .nvmrc; run nvm use before npm scripts. Open this repository in that host.
- Reload extensions after checking out or changing extension files.
- List extensions and confirm the project
commit-and-sipextension is loaded. If it fails, inspect its entry and log before continuing. - Watch the log on start. A moderation warning means the blocklist is still unreviewed.
- Inspect the registered
commit-and-sipcanvas capabilities. - Open the canvas with no input, or
{}. The counter opens idle and ready for the next attendee.
Staff operations live on a second canvas, commit-and-sip-admin: event totals, results export, drink takedown, closing an abandoned station, the end-of-event archive and reset, and, on a staff machine, clearing the shared public leaderboard. It is deliberately not part of the attendee screen, which faces a queue. See the staff dashboard, taking a drink down, and ending an event.
An agent driving the host uses extensions_reload, extensions_manage (list/inspect), list_canvas_capabilities, open_canvas, and invoke_canvas_action. These are host tools, not shell commands. Discover the loaded extension and provider identifiers instead of inventing them. Choose a panel instanceId when opening, then reuse that panel handle for actions.
The host resolves @github/copilot-sdk/extension automatically. Do not install an SDK package to run the extension. Maintainers use:
nvm use
npm ci
npm test
npm run checknpm ci installs development dependencies, including the QR generator; it is not an attendee step.
npm test and npm run check refuse to start on Node older than the engines floor, and npm ci fails the same way because engine-strict is enabled. That guard is deliberate: on Node 18 the loopback fetch suites leave experimental undici handles open, so the run hangs forever instead of reporting failures. The suite also runs with a per-test timeout and forced exit, so a leaked handle cannot stall it.
- Read the constraints before submitting: one mascot, a chosen placement, an allowed character set, and no duplicate already on the menu.
- Treat a published rubric as something you can reason about and improve against, rather than guessing at a black box.
- See their own contribution land on a shared artifact that the rest of the event can see.
Scores run from 1 to 5,000 and come from a deterministic rubric in code, not a language model. The same name always scores the same. Speed, retries, and accessibility assistance do not reduce a score. Mona Latte, Copilot Cortado, and Ducky Cold Brew are worked examples: never scored, never ranked.
| Document | Audience |
|---|---|
| Step 1: Name a drink for the house menu | Canonical learner instructions |
| Learner entry guide | Attendees and facilitators |
| Booth runbook | Setup, moderation, recovery, reset, and event staff |
| Blocklist sourcing proposal | Whoever owns the moderation decision |
| Leaderboard service | Whoever deploys or operates the event leaderboard |
| Integration contract | Leaderboard and service implementers |
| Architecture and validation | Maintainers |
| Asset capture checklist | Authentic screenshots, accessible QR, branding |
| Order Up skill | In-app guided facilitation |
| Approved exercise outline | Preserved design source |
The approved outline is preserved verbatim, including its original proposals and open questions. It describes the original pull-request shape of this exercise. The booth naming competition supersedes it; current decisions live in this README, the architecture notes, and the integration contract, not in edits to that preserved source.
The booth reads one optional ignored file, booth/local-config.json, with two independent settings:
{
"leaderboardApi": {"url": "https://<app>.azurewebsites.net", "boothKey": "<64 hex>", "staffKey": "<64 hex>"},
"leaderboardUrl": "https://<app>.azurewebsites.net/"
}leaderboardApimakes the booth publish to the leaderboard service, and lets takedowns retract from it. Write it withnpm run leaderboard:configure, never by hand. OmitstaffKeyon a machine that should not take drinks down.leaderboardUrlputs a QR code in front of attendees, linking to their own place on a public page of attendee names. Leave it unset until the moderation blocklist is reviewed. Then set it to the short linkhttps://gh.io/commit-and-sip-leader.
Both URLs must be public HTTPS with no credentials, fragment, or nonstandard port. The file is readable only by its owner and is never packaged or committed. Retired pull-request keys such as mode, runs, repo, and requiredChecks are rejected on start rather than ignored, so a stale config cannot look configured. The two API keys belong in that file and nowhere else: not in the renderer, the repository, or a QR URL.
State persists in $COPILOT_HOME/extensions/commit-and-sip/artifacts/ledger.json; COPILOT_HOME defaults to ~/.copilot. Staff may set COMMIT_AND_SIP_DATA_DIR to an absolute directory before the host launches. The store uses ledger.lock and atomic, fsynced writes. Closing or reloading a panel does not reset the booth, and hand-over does not erase the house menu.
Exports and archives are written beside the ledger, under exports/, and never into the repository. Deleting the cloned repository does not delete attendee data — it deletes the reviewed blocklist and staff configuration while leaving every name and removal record on the machine. End an event through the dashboard, then copy the archive off the device.
Neither a device's loopback renderer nor repository assets are public phone destinations. Do not publish an event QR until an approved, publicly reachable HTTPS leaderboard exists.