Repository navigation
feat(lazurio): the Environment pairs its own browser - #84
Conversation
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty Exact-head QA: APPROVED for 6cb80ae. I traced the web bootstrap and legacy-session re-pairing, strict same-origin response validation, one-time operator grant scopes (without relay:write), and the Platform pingdotgg#486 contract. In an isolated clone I ran the release contract (34/34), focused web/server tests (21/21), and both typechecks; the exact-head CI is green and review threads are clear. Joint browser smoke on Ring 0 remains a release qualification, not evidence claimed by this review.
…urio/chat/pairing, operator scopes) (#486) * Launchpad: the Environment pairs its own browser into Chat (GET /.lazurio/chat/pairing) T3 Code's web client (Lazurio/t3code#84) asks for a pairing on its own origin whenever it has no session; the gateway already forwards GET and HEAD of /.lazurio/* from that origin to the Launchpad behind the unchanged admission. The new route answers only a page's own script fetch (Sec-Fetch-Site same-origin, Sec-Fetch-Mode cors or same-origin, no prefetch or prerender), only where Chat is T3 Code behind this Launchpad, with 200 and exactly {"kind":"chat-pairing","credential","expiresAt"}, JSON and Cache-Control no-store: the one answer the fork's client accepts. Everything else is refused (403 not-allowed, 400 for a query, 405 for HEAD and other methods, 404 on a workstation) and mints nothing. A bookmark, the shell's switch on another app, the Dashboard and another Environment's Chat no longer end on T3's pairing page. One function, mintChatPairing, mints for this route, POST /api/chat/pair and lazurio chat link. Where t3 lazurio capabilities says operatorPairing (read by t3Offers, the reader the provider refresh already uses) it runs t3 lazurio pairing, Team Environments included, without --json: the fork's command always prints JSON and its CLI refuses a flag it does not know. Otherwise, and always on a public Environment, which is not even asked, it runs today's t3 auth pairing create --json. The token is labelled with the admitted person, "Lazurio · <username>" ("Lazurio" without one), and T3's answer is read for its credential and expiry only; the Platform keeps no list of T3's scopes. A missing or failing t3 is a 409 with its reason. The Launchpad's Chat click keeps pairing on the way: harmless, and older T3 Code builds need it until every Environment's T3 Code pairs itself. Tests: the route's refusals (unadmitted, T3 Code's own Host, cross-site, same-site, typed address, navigation, subresource, prefetch, query, HEAD, POST, workstation, Recovery mode), the exact JSON, no redirect and no-store, the command chosen by capability and by audience with --json refused by the fake T3 as by the real one, the label, and a missing or failing t3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: the Environment pairs its own browser (decision of 2026-10-17) The Chat entry records the Organization Admin's decision of 2026-10-17, which replaces the rule of 2026-09-21 (root DEV-6616) that T3 Code opened directly shows its own pairing page and that the T3 Code fork stays untouched: an admitted browser is paired by the Environment itself, with T3's operator pairing where T3 Code offers it, Team Environments included, and the standard pairing for a public Environment's visitors. T3 Code's desktop and mobile apps pair with device tokens from T3's Settings -> Connections on Environments reached over the tailnet; a public lane has no native path, which is intended for now. The Chat entry's routes and the hosted entry describe GET /.lazurio/chat/pairing: how the gateway forwards it from T3 Code's origin (the Launchpad's Host, the session cookie alone, the browser's Fetch Metadata), the one fetch it answers, the exact answer the fork's client accepts within five seconds, its refusals and how the call is chosen and labelled (t3 lazurio pairing takes no --json), with the verification and what it did not exercise. The target shell's open question now says the switch keeps pairing T3 Code until every Environment's T3 Code pairs itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Organization Admin decided on 2026-10-17 that a Lazurio Environment
pairs its own browser, which replaces the rule of 2026-09-21 that a
direct visit shows T3's pairing page. Until now only a browser that came
through the Launchpad's Chat click was paired; a bookmark, the shell's
switch, the Dashboard or another Environment's Chat ended on the pairing
page and lost its deep link.
A page without a valid T3 session now asks its own origin for a pairing
credential, GET /.lazurio/chat/pairing, which the Lazurio gateway
forwards to the Environment's Launchpad behind its admission. The page
accepts only the exact answer {kind: "chat-pairing", credential,
expiresAt?} and exchanges the credential like any bootstrap credential,
as the third source after a link's credential and the desktop app's, so
the person never sees a token and stays on the page they opened.
Anything else (T3's own index.html outside Lazurio or with an older
Platform, another status, a redirect, a network error, no answer within
5 s) leaves upstream's pairing page. The desktop app and pages served
over plain HTTP never ask. A session paired on 0.0.45, which v0.1.0
reads as legacy scopes, asks too and keeps its session when that fails.
`t3 lazurio pairing [--base-dir] [--ttl] [--label]` mints the credential
through upstream's one-time pairing grant, as `t3 auth pairing create`
does, and prints the same JSON. Its scopes are the operator's: the
standard client scopes plus access:read and access:write, built from the
contracts' constants, so Settings → Connections shows the authorized
clients and can pair the desktop and mobile apps. Never relay:write,
which would open T3 Connect around the gateway and the tailnet.
`t3 lazurio capabilities` adds operatorPairing: true at contract
version 1.
The seam is two calls in upstream's bootstrapServerAuth, on the CI
allowlist and pinned by the release contract test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The runbook gets row 19 in the overlay table and the target stack, a short section on pairing, and the gates that change with it: the `t3 lazurio` commands now include `pairing`, whose output cli.test.ts holds against `t3 auth pairing create --json`; the CLI and the server on one version also carry the Launchpad's pairing; and a browser with legacy scopes now pairs again by itself, while a scope split that sessionHasLegacyPermissions does not recognise still needs a decision or a link. The canary checks and the announcement follow. The rule of 2026-09-21 that a direct visit shows T3's pairing page is gone. The overlay specification describes how the browser pairs, when it asks, the operator's scopes without relay:write, the second pairing of a session paired on 0.0.45, the desktop and mobile apps' links from Settings → Connections on tailnet Environments, and the seam. The distribution README lists pairing among the changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6cb80ae to
1b6dd39
Compare
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty Exact-head re-review: APPROVED for 1b6dd39 on main cd211fa. Range-diff against the previously approved head shows both patches identical after the conflict-free rebase. The combined CI allowlist retains SidebarChrome.tsx, leaves AppSidebarLayout.tsx intentionally absent/unchanged as #82 specified, and adds environments/primary/auth.ts for #84. The release contract and runbook preserve the #82 column-header/wordmark behavior and #84 browser pairing and operator scopes. Four required fork CI jobs passed on this head; both Macroscope checks were skipped. In an isolated checkout, targeted contract checks passed (4/4) and git diff --check passed. A local full contract invocation lacked installed workspace dependencies (33/34, module not found in an unrelated test); CI installed dependencies and passed its full contract check. Zero review threads; live head/base and reviewer lane rechecked immediately before this review. Browser smoke on Ring 0 remains release qualification, not evidence claimed here.
Problem
On a Lazurio Environment only the Launchpad's Chat click pairs a browser with T3: it mints a 60 s token and sends the browser to
/pair#token=…. Every other way into Chat ends on T3's "Pair with this environment" card, outside the app layout, with no way back:That token also carries only the standard scopes, so Settings → Connections hides "Authorized clients". A person can't create a pairing link for T3 Desktop or mobile there. Browsers paired on 0.0.45 keep legacy scopes on 0.1.0 (no terminal, files, Git, settings or Environment browser tab holds) until they come through the Launchpad again.
Change
The Organization Admin decided on 2026-10-17 that the Environment pairs its own browser. This replaces the 2026-09-21 rule that a direct visit shows T3's pairing page and the fork stays untouched.
apps/web/src/environments/primary/auth.ts, two calls; the code is inapps/web/src/lazurio/environmentPairing.ts).GET /.lazurio/chat/pairing.index.htmloutside Lazurio or with an older Platform, a non-200, a redirect, an error, or a 5 s timeout.t3 lazurio pairing(overlay CLI).t3 auth pairing createdoes, with the operator's scopes:AuthStandardClientScopes+access:read+access:write.relay:write: T3 Connect would be a public way in around the gateway and the tailnet.t3 auth pairing create --json.t3 lazurio capabilitiesgainsoperatorPairing: true. That is additive: Machines and the Platform check only their own keys.auth.ts, contract-test pins, overlay row 19 with its runbook section, the overlay spec and the public README.Scope and approval
Decided by the Organization Admin in the thread of #70 on 2026-10-17:
The Launchpad route is Lazurio/LazurioPlatform#486. Either side can ship first: without the route, this fork behaves as today. The Platform calls
t3 lazurio pairingwithout--json, because this command always prints JSON and the CLI refuses unknown flags.Verification
node --test scripts/lazurio-release-contract.test.mjs: 34/34.environmentPairing.test.ts11/11 together with upstream's auth bootstrap tests, 28 in all. It covers answer parsing and refusals, request options, the timeout, the origin, the plain-HTTP and desktop guards, and the decision table through upstream's real auth gate against a fake server.cli.test.ts10/10.relay:writeis absent.main. It is checked on Ring 0 with both, before the stable.Model and harness: Claude Opus 5.5 in Claude Code.
🤖 Generated with Claude Code
Note
Add Environment-owned browser pairing to Lazurio web authentication
t3 lazurio pairingCLI command in cli.ts that issues operator-scoped credentials (client scopes plus access-read/write, no relay-write or admin) with upstream-compatible JSON output;capabilitiesnow reports the operator-pairing capabilityMacroscope summarized 1b6dd39.