Web runs: the Chrome extension creates the cloud session through claude.ai's repo picker (#1328) - #1693
Merged
Merged
Conversation
…de.ai's repo picker (#1328) A session created through the page's repository picker is repo-bound and can push and open its pull request; `claude --cloud` has, on some accounts, produced a bundle upload that never could (#1320). So a web run now asks its daemon for an extension-created session first. Daemon: the session start-queue (`bridge-starts.ts`, re-landed from #1330) behind two faces on the one token — the extension's `GET /_bridge/start` (claim-on-read) + `POST /_bridge/started`, and the run's `POST /_web-start` + `GET /_web-start/<id>` (`web-start-endpoints.ts`), which answers 409 at once when no extension has called within three minutes. The daemon hands every spawned run its own URL in `TF_DAEMON_URL`. Driver: `CloudDriver` takes `extension: { daemonUrl, token }` (wired by the CLI from the env and the registry token); after the anchor push and trust check it posts the request — repo from the GitHub remote, the pushed ref, the whole hand-off prompt — and polls until created, then reports exactly as the CLI path does. 409/404, no GitHub remote or an unpushed ref fall back to the CLI's cloud mode with a notice; an extension that tried and failed fails the turn with its note. Extension 0.11.0 (daemon lockstep): the worker claims requests on the answer beat, one at a time, opens claude.ai/code pinned and inactive, and the content script drives the repo chip's searchable list, verifies the branch chip reads the pushed ref before sending, types the prompt, sends, and reads the session id off the address. A created session's tab is a watched tab; a failed attempt's tab is closed and the note says what the page lacked. Harness cases cover the drive, the wrong-branch refusal and the missing-picker report. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…membered repo's chip as the picker (#1328 dogfood 1) First live attempt: the page had remembered the last repo picked, so its chips (the-framework / main, as comboboxes) were already there — but they render after the composer, and createSession read the page before they did, then looked for a "Select repo" trigger that no longer exists once a repo is remembered. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ips in order, visible options only, React-safe search (#1328 dogfood 2) Run 2 clicked the repo chip itself as if it were a list entry (its text is the bare repo name) and then found no chip "afterwards". Read from the live page: the chips are combobox buttons in the order repo, branch, add; a picker is a dialog with a role=combobox search input and a listbox of options; a closed picker's options stay in the DOM, so only visible options are entries, and the trigger is never one. The branch list does offer a ref pushed seconds earlier (checked live), so verifying the chip before sending is enough. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ll back to the whole list, and say what the list showed on failure (#1328 dogfood 3) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…yphs (#1328 dogfood 4) In the content script's world the labels carry private-use glyphs — the chips read "\ue048the-framework" and "\ue078main", the chosen entry "framework/the-framework\ue03b" — so no exact match ever fired. The mirror already strips those; the control labels now do too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
suleimansh
marked this pull request as ready for review
August 24, 2026 16:25
Contributor
Author
|
@brillout the extension now creates the web session itself (repo picker, pushed ref) — dogfooded, session pushed. |
This was referenced Aug 24, 2026
suleimansh
added a commit
that referenced
this pull request
Aug 24, 2026
…one (#1694) With #1693 the extension creates every web session through claude.ai's repo picker, and that is the path that ends in a pull request; the CLI's `--cloud` flag could vanish at any release and produced bundle uploads that never pushed on some accounts (#1320). Rom: "remove it once the extension has proven itself" — it has. Gone: the `script` pty runner, `CLOUD_COMMAND`/`CLOUD_ENV`, the ANSI/URL scraping, and the whole trust write + trust-dialog detection (`claude-trust.ts`, #1493/#1314) — that existed only because the CLI asked its folder-trust question under the daemon's pty; no CLI runs for a web hand-off any more. The three fallbacks became named errors: a run no daemon started ("start web runs from the dashboard"), no GitHub remote, no extension around (409, "install or reload the extension, keep the bridge on"), bridge off (404). A failed anchor push fails the run, since the session must open on that ref. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 24, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 automated — the extension half of #1328, per the plan posted there. Dogfooded end to end on a real web run (see Verified). Draft only pending cleanup and a look from Rom. Refs #1328; supersedes #1330 (its daemon half is re-landed here on today's paths).
What
Daemon
bridge-starts.ts: the session start-queue — queued → claimed (90 s TTL) → created/failed; success without a session id is a failure; reports on unheld requests are ignored.GET /_bridge/start(claim-on-read) andPOST /_bridge/started, on the bridge token + version gate.POST /_web-start→{id}(202),GET /_web-start/<id>→ state; same token; 409 at once when no extension has called within 3 minutes, so a run without one hands off through the CLI in one round trip instead of after a timeout. Off with the bridge.TF_DAEMON_URLin its environment (daemon-runtime.tschildEnv;daemon.tshands the runtime a URL getter since the port is known only after listen).Driver / CLI
CloudDriverOptions.extension({ daemonUrl, token }), wired bycli.tsfrom the env var +readDaemonToken().CloudSession.prompt: same anchor push, same trust write; then post the request (repo = GitHub remote slug, branch = the pushed ref, prompt = the whole hand-off prompt), poll, andreport()exactly as the CLI path does. Falls back to--cloudwith a notice on 409/404, no GitHub remote, or an unpushed ref. An extension that tried and failed fails the turn with its note — no silent CLI retry.Extension 0.11.0 (daemon
EXPECTED_EXTENSION_VERSIONbumped in lockstep)background.js:pollStarts()on the answer alarm + at boot, serial (creatingguard), opensclaude.ai/codepinned/inactive, waits for load, retriestf-create-sessionuntil the content script answers, reports to/_bridge/started. Created → the tab is recorded as a watched tab; failed → tab closed.content.js:createSessiondrives the page as it actually is — combobox chips in the order repo / branch / add (the page remembers the last repo picked, so the chips are waited for and read), a picker = dialog → React-controlled search → listbox → option, only visible options count (a closed list's linger in the DOM), labels read through the page's icon-font glyphs, and the branch chip is verified to read the pushed ref before anything is sent. Session id read from the URL.probeNewSession+ a diagnostic in every failure note.Specs: new
bridge-starts,web-start-endpoints(+ test specs); updated bridge-endpoints, bridge-store, server, daemon, daemon-runtime, cli, cloud (+ test specs), extension SPEC/background/content/check; FEATURES-SPEC gets the feature line.Verified
typecheckclean; framework suite 1603/1603; dashboard 834/834; extension harness all cases, including seven for session creation (repo remembered / another repo remembered / none remembered / wrong branch refused / missing picker named / probe / glyphs).2026-08-24T16-20-39-042Zon gemstack → the extension createdsession_016nS9CGnCYKk5c17LCvyQZn(queue note: repo already the-framework; branch: clicked "cloud-1-baa05deb" via combobox; sent via button), the run reported the link and ended ok, the bridge mirrored the session at once, and the session committed and pusheddogfood-1693.mdtoclaude/dogfood-1693-marker-90n7z9— a branch descending from the pushed hand-off ref. That is the outcome--cloudcould not give on a bundle-upload account (Web runs complete their work but cannot push: cloud container has no GitHub write access unless the account's Claude GitHub app covers the repo #1320).de8e0530); the real markup (d4eff8a9); list-load wait, unfiltered fallback and a diagnostic in the note (07f00851); and the actual cause of every picker miss — icon-font glyphs inside every label in the content script's world (b29e6d9b). The branch list does offer a ref pushed seconds earlier — checked live.Not in this PR
--modelis ignored on the extension path).--cloud— Rom's call once this has proven itself.