Browser extension
The extension puts a Run button where you already are: next to the branch dropdown on a repository page, in a pull request header, and on every row of the branch list.
Without the extension there is still the README badge: a link a repository owner puts in their own README, which reaches the same local window through an https page.
Why it needs the local listener
A browser cannot be asked whether a URL scheme has a handler. That is deliberate — it would be a fingerprinting vector — and there is no API for it. So an extension whose only channel is quickrun:// can never know whether QuickRun is installed, and can never receive progress back from a run it triggered.
The localhost listener is therefore the main channel, and quickrun:// has exactly one job left: starting a daemon that is installed but not running.
| Ping result | The button shows |
|---|---|
| QuickRun answers | Run this — clicking prepares a run |
no answer, then quickrun:// works | Starting QuickRun…, then Run this |
| no answer at all | Install QuickRun — links to the download page |
Button states
- ready — QuickRun answered. Click to prepare a run.
- running — the current phase and, where a real number exists, a percentage.
- done — the run finished.
- error — hovering shows why.
The confirmation window
Clicking Run does not start anything. QuickRun checks the repository out, builds the plan, and the extension opens a window listing the repository, ref, resolved commit and the exact commands that will run. Only the button in that window starts them.
The window also shows the description from the config when it has one, the folder the repository was checked out into, and — once a task reports one — the address it is listening on, as a link.
If the config declares inputs, the window asks for them before there is anything to approve: labels, descriptions, defaults, a dropdown for a select, a checkbox for a bool, a masked field for a password. A changed value applies itself a moment later and the command list is rebuilt from it, so the list on screen is always the one those values produce — what you approve is what runs, and it stays one click on Run. The button says Continue only while required values are still missing, because until they are there is no command list to approve. Values marked with an env are passed to the run as that environment variable, and a secret is never sent back to the window.
While a run of that branch is going, the button is the way into it rather than a way to start a second one. Clicking it opens the actions:
- Show log — brings the log window back, or opens a new one attached to the run. Closing that window never stopped anything, so getting back to it has to be possible
- Open … — the address the run reported, once it has reported one
- Stop — stops the run, and ends what it left running if a task exited and left a server behind
The button finds its run again after a page reload: the tab forgets, the daemon does not. A branch that is already running therefore cannot be started twice by accident.
After you approve, that window stays open and becomes the run's log: the checkout with its real progress counters, every setup step, and everything the repository's own commands print. The button on the page shows only a percentage and a coarse phase — a toolbar button is no place for a hundred lines of build output.
Once the run starts, every task gets a line of its own: what it is doing - starting, ready, exited - the address it reported, as a link, and the process id of what it started. For a desktop application that pid is the whole handle you have on it, and it is what a task with readyWhen: {window: true} is waiting on. "Running" for a whole run says nothing about which of five services came up.
Stop stops the run and says so: the button turns to Stopping… with a spinner the moment it is clicked, the banner turns to Stopped when the processes are gone, and the window closes itself a moment later. "When the processes are gone" is meant literally: if the run left something running in the background, the window says how many and stops again rather than calling it stopped - you asked for it to stop, not for a window to tidy up. It is only clickable while something is actually running: a run whose processes have all exited has nothing left to stop.
That window is an extension page, not part of the GitHub page, and that is on purpose: a web page can draw a convincing fake panel over its own content, and nobody should ever approve one set of commands while a different set runs.
Why no web page can drive it
There is nothing to pair. A browser attaches an Origin header to every cross-origin request and a page cannot change it, so QuickRun simply refuses anything that does not come from a browser extension. https://github.com is not on that list: a script running on GitHub itself cannot start a run.
A program on your own machine — curl, QuickRun's own CLI — sends no Origin and is allowed. It already runs with your privileges, so the daemon grants it nothing it did not have.
Options
| Setting | Default |
|---|---|
| Port | 9876 |
Try quickrun:// when QuickRun does not answer | on |
| Where the button appears | on every repository |
Installing it from QuickRun itself
QuickRun's own window has a Browser extension tab that lists the browsers it finds on this machine and says, for each one, whether the extension is there. An unpacked build counts: it is recognised by the folder it was loaded from, which is what the browser records.
The Install button goes as far as a browser allows, and no further. Where a store listing exists it opens that listing in that browser, and the last click is the browser's own Add button. Where none exists yet it downloads the packaged extension from the newest release, unpacks it, opens the browser's extensions page and the folder next to it - leaving "Load unpacked, pick this folder".
It stops one click short deliberately. Chrome removed inline installation in 2018, and the only way left for a program to put an extension into Chrome or Edge is an enterprise policy that force-installs it and takes away your ability to remove it. That is a thing malware does, and QuickRun does not do it. Firefox is the exception in the other direction: a temporary add-on can be loaded from about:debugging, but Firefox forgets it when it closes.
Where the button appears
QuickRun can start almost any repository: with no configuration it reads the files and works out a plan itself. That plan is a considered guess - a good one, and you always see the exact commands before anything runs - but you may prefer the button only where the repository has said how it wants to be started.
- On every repository. Including the ones QuickRun would have to work out for itself.
- Where there are instructions to follow. A
quickrun.yml, or scripts written for Pinokio. - Only with a quickrun.yml. The repository has committed a QuickRun configuration.
The last two ask QuickRun on your machine whether those files exist, once per repository and cached for half an hour. The extension does not reach GitHub itself for this: that would need a permission for raw.githubusercontent.com, and the daemon can answer without one. When QuickRun is not running the check cannot be made, and the button appears anyway - vanishing because a check failed would be indistinguishable from the extension being broken.
The confirmation window names the source for every run, so you always know which of the four you are looking at: the repository's own quickrun.yml, a config you saved for that repository, another launcher's scripts, or QuickRun's reading of the files.
Running a pull request means running the branch it comes from, fetched as refs/pull/<n>/head. That works for pull requests from forks too, and it is what the button on a pull request page does.
Building it yourself
cd extension
sh build.shOne source tree, two builds: dist/chromium for Chrome, Edge and Opera, and dist/firefox, which differs only in its manifest.
When GitHub changes its DOM
The button is anchored on data-testid attributes and ARIA labels where GitHub provides them, and every lookup fails silently: a missing button is acceptable, a broken GitHub page is not. GitHub does redesign these pages, so a missing button usually means the extension needs an update rather than that something is wrong with your setup.