feat(queen): MY RUNNERS cabinet on the leaderboard tab - #1205
Conversation
The LEADERBOARD tab invited people to "lend the swarm a key" and had no door. It now carries a cabinet where the person signed in on app.t27.ai mints, lists and revokes runner tokens (trios-agent-server /queen/me/runners). A runner runs on the lender's own machine with the lender's own provider key; this page has no field for a key and never sees one. - lib/queenRunners.ts: pure decisions with an injected fetch; the session token rides only as a bearer with credentials omitted and exactly two headers; a runner token is accepted only in the shape the Queen mints and shown once. - On t27.ai (bridge path) the panel points to app.t27.ai/queen instead of forwarding the read-only game token. - Leaderboard rows are keyed by lane kind + first lane, since a runner's Telegram name can equal an operator's lane name. - qa/queen-runners-contract.mjs wired into website-checks; the new sheet is registered with the contrast contract and uses opaque inner grounds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2
|
The same job fails the same way on #1204 (job 110364307888), which was opened two hours earlier and touches unrelated files. There is no code fix to port: the project-automation token used by that workflow needs to be rotated in the repository secrets. I have not re-run the job, because it will hit the same 401 until the token is replaced. Generated by Claude Code |
|
The same check fails the same way on #1204, and this PR does not touch the Zig CLI. There is no fix to port yet: the check stays red until Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2 # Conflicts: # apps/website/qa/queen-runners-contract.mjs # apps/website/src/components/QueenRunners.tsx # apps/website/src/lib/queenRunners.ts
feat(queen): MY RUNNERS cabinet on the leaderboard tab (#1205) The LEADERBOARD tab invited people to "lend the swarm a key" and had no door. It now carries a cabinet where the person signed in on app.t27.ai mints, lists and revokes runner tokens (trios-agent-server /queen/me/runners). A runner runs on the lender's own machine with the lender's own provider key; this page has no field for a key and never sees one. - lib/queenRunners.ts: pure decisions with an injected fetch; the session token rides only as a bearer with credentials omitted and exactly two headers; a runner token is accepted only in the shape the Queen mints and shown once. - On t27.ai (bridge path) the panel points to app.t27.ai/queen instead of forwarding the read-only game token. - Leaderboard rows are keyed by lane kind + first lane, since a runner's Telegram name can equal an operator's lane name. - qa/queen-runners-contract.mjs wired into website-checks; the new sheet is registered with the contrast contract and uses opaque inner grounds. Claude-Session: https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2 Co-authored-by: Claude <noreply@anthropic.com>
Description
The LEADERBOARD tab says "Lend the swarm a key and watch your bees work" but offered no way to do it. This PR adds a MY RUNNERS cabinet to that tab. A person signed in on
app.t27.aican create, list and revoke runner tokens.A runner is a lane that runs on the lender's own machine, under the lender's own provider account. The key never moves, which is the design
how-to-join-the-swarmrecommends because OpenAI, Anthropic and Google forbid handing a key to third parties. This page has no field for a provider key and never sees one.The server side is gHashTag/BrowserOS#518 (
/queen/me/runners,/queen/runner/heartbeat). It must be deployed first. Until then the panel shows "The Queen did not answer".{ "version": 1, "head_sha": "e7cc424ae7c7b76d382273805b9f044d8eaab9c8", "summary": "The LEADERBOARD tab invited people to lend the swarm a key but had no way to do it. It now has a MY RUNNERS cabinet. A signed-in person on app.t27.ai creates, lists and revokes runner tokens for runners that use their own provider key on their own machine. The page never takes a key.", "changes": [ "apps/website/src/lib/queenRunners.ts: pure cabinet logic with an injected fetch. The session token is sent only as a bearer, with credentials omitted and exactly two headers. A runner token is accepted only in the qr_ format the Queen issues, and is shown once.", "apps/website/src/components/QueenRunners.tsx and QueenRunners.css: the panel, with EN/RU copy, a one-time token display with setup lines, a revoke confirmation, and a pointer to app.t27.ai/queen when it is opened on t27.ai (bridge path).", "apps/website/src/components/QueenLeaderboard.tsx: renders the panel. Rows are keyed by lane kind plus first lane, so a runner whose Telegram name equals an operator lane name does not duplicate a React key.", "apps/website/qa/queen-runners-contract.mjs, package.json and .github/workflows/website-checks.yml: a new check:queen-runners contract wired into CI.", "apps/website/qa/queen-contrast-contract.mjs: registers the new stylesheet. The panel's inner grounds are opaque." ], "tests": [ { "command": "cd apps/website && npm run check:queen-runners", "status": "passed", "result": "queen-runners contract: ok", "evidence": "Local run on head e7cc424 in the authoring session" }, { "command": "cd apps/website && node --experimental-strip-types qa/queen-contrast-contract.mjs && npm run check:queen-fallback-parity", "status": "passed", "result": "Contrast: 24 pairs, worst 5.39:1. Fallback parity: PASS 218/218. Both initially failed on the new sheet and were fixed by registering it and making its grounds opaque.", "evidence": "Local run in the authoring session" }, { "command": "cd apps/website && npx vite build && npm run typecheck:ratchet && npx eslint src/components/QueenRunners.tsx src/lib/queenRunners.ts qa/queen-runners-contract.mjs", "status": "passed", "result": "Build succeeded. Ratchet: 179 errors across 26 files, the same as the baseline, and no file gained errors. ESLint clean on the new files. QueenLeaderboard.tsx keeps its existing react-refresh/only-export-components error, which is unchanged from main.", "evidence": "Local run in the authoring session" }, { "command": "Every npm run check:* step listed in .github/workflows/website-checks.yml, except build, lint, typecheck, render, deployed and mobile audit", "status": "passed", "result": "All passed locally after the fixes above.", "evidence": "Local run in the authoring session" }, { "command": "Manual check of the panel in a browser on https://app.t27.ai/queen/", "status": "not_run", "result": "The panel reads the session only on the app.t27.ai origin, and the server routes are not deployed yet, so it was not viewed live.", "evidence": "Not run: requires the app.t27.ai origin and a deployed server" } ], "limitations": [ "Runners can register and show as online, but cannot take tasks yet. Claim/complete, review of a branch pushed from outside the container, and a runner CLI are the next stage.", "Depends on gHashTag/BrowserOS#518 being deployed to trios-agent-server. Until then the panel reports that the Queen did not answer.", "To verify the person, the cabinet sends the app's full session token to the Queen, which forwards it only to vibee-render whoami. A narrower token is a possible follow-up." ], "tags": ["Engineering", "Security", "Queen"], "blog": { "title": "Lending a lane without lending a key", "summary": "The swarm's leaderboard now has a cabinet that issues runner tokens for runners that use the lender's own key on the lender's own machine, rather than a form that collects provider keys.", "outline": [ "The leaderboard invited people to lend a key, but most providers' terms forbid handing a key to a third party.", "The cabinet issues a runner token instead. It is shown once, stored only as a hash, cannot spend quota, and lets the person's own runner be credited on the leaderboard.", "Not done yet: handing tasks to runners and reviewing their branches, which is the next stage." ] } }Related Issue
None filed. Server counterpart: gHashTag/BrowserOS#518.
Specification Link
Not applicable. This is a hand-written React/TypeScript change in
apps/website, like the rest of that app.Changes Made
qa/queen-runners-contract.mjscontract and wired it into CI.Files Changed
apps/website/src/lib/queenRunners.ts- cabinet logic (pure, injected fetch)apps/website/src/components/QueenRunners.tsx,QueenRunners.css- the panelapps/website/src/components/QueenLeaderboard.tsx- renders the panel; row key fixapps/website/qa/queen-runners-contract.mjs- new contractapps/website/qa/queen-contrast-contract.mjs- registers the new sheetapps/website/package.json,.github/workflows/website-checks.yml-check:queen-runnersGolden Chain Checklist
apps/websiteis hand-written TSX, like its neighbours..tsx,.tsand.cssfiles inapps/website, where all existing UI lives.Testing Checklist
npx vite buildpassescheck:queen-runners, contrast and fallback-parity contracts, and the other website-checks steps pass locallyTest Results
Performance Impact
Breaking Changes
🔥 TOXIC VERDICT
What Works
credentials: 'omit'. A token is shown once.apiKey.What Doesn't Work
work: null).Tech Debt
Known Issues
Toxic Verdict
Overall Assessment: APPROVE once the server PR is merged and deployed.
Self-Score: 7/10. The cabinet is solid, but runners can't do anything useful yet.
🌳 TECH TREE Options
Option 1: Runner claim/complete protocol
/queen/runner/claimand/queen/runner/complete; the review reads the runner's pushed branch from GitHub.Option 2: Runner CLI
Option 3: Scoped cabinet token
Recommendation: Option 1. Without it, runners earn nothing.
Deployment Notes
Reviewer Notes
src/lib/queenRunners.tsagainst the rules inappSessionIdentity.ts.Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2
Generated by Claude Code