What the agent does
The agent starts from the issue text and the repository it names, not from a template. In a starter like chibat/chrome-extension-typescript-starter it opens public/manifest.json and finds a Manifest V3 extension whose permissions array holds only storage, whose background is the service worker js/background.js, and whose popup is popup.html. It checks package.json and finds build running webpack --config webpack/webpack.prod.js, test running npx jest, TypeScript pinned at ^5.0.4, jest ^29.5.0 with ts-jest, and @types/chrome at 0.0.158, so it can type the new chrome API calls without adding a dependency.
Then it wires the feature through the three files the starter already has. It adds contextMenus to the permissions array in public/manifest.json, the one line the browser requires before any menu call. In src/background.ts, which today only keeps the service worker alive with a setTimeout polling loop, it registers chrome.contextMenus.create with contexts: ["selection"] at install time and a chrome.contextMenus.onClicked listener that takes info.selectionText. To move the selection into src/popup.tsx, which is a React component rendered from public/popup.html, it writes the text with chrome.storage.local, since the storage permission is already granted and Manifest V3 service workers are ephemeral. The popup reads the stored value on open and shows it where the starter currently lists the current URL and time.
The agent tests what it can run headlessly. jest.config.js sets roots: ["src"] and transforms TypeScript through ts-jest with tsconfig.test.json, so it adds a test file under src/__tests__ next to the starter's sum.ts test and mocks the chrome global (contextMenus, storage, runtime) the way @types/chrome types them. Because tsconfig.json sets strict and noEmitOnError, the build is also a type check: npm run build compiles all four webpack entries (popup, options, background, content_script) through ts-loader and fails on any type error, and the CopyPlugin step copies the edited public/manifest.json into dist. The agent runs npm test and npm run build in its sandbox before pushing, so a red check on the pull request is a surprise, not a habit.
When both commands pass, it commits on a new branch and opens a pull request whose description quotes the issue and links back to it. The repository's own .github/workflows/build.yml then runs on the pull request: npm ci, npm run build --if-present and npm test across Node 20.x and 22.x, so the PR shows green checks from the project's existing CI, not from a claim in the description.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "A Linear issue labeled agent says: \"Add a Context Menu Item to a Chrome Extension. Add a right-click menu item on selected text that sends the selection to the background worker and shows it in the popup, with the contextMenus permission in the manifest.\" Do the work in this repository, add tests for it, run npm test and npm run build, and open a pull request that links back to the issue.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
- Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
- Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.
What comes back
What comes back is a pull request on a new branch. In a repository shaped like chrome-extension-typescript-starter the diff is small and scoped: public/manifest.json gains one entry in permissions, src/background.ts gains the menu registration and the click listener that stores the selection, src/popup.tsx renders the stored text, and a new file under src/__tests__ covers the handler. No new npm dependency appears, because @types/chrome already types the API and jest is already configured.
The pull request description links back to the Linear issue and says what it verified: that npm test and npm run build both passed in the sandbox before pushing, and that the project's own build.yml workflow ran on the pull request across Node 20.x and 22.x. The session's trajectory at GET /o/{org}/sessions/{id}/messages keeps every command the agent ran with its output, including the jest run and the webpack build, so a reviewer can replay the verification instead of trusting it.
Before merging, a reviewer checks that the only new permission is contextMenus, that the selection reaches the popup through chrome.storage.local rather than a long-lived service worker state that Manifest V3 would drop, that the tests mock the chrome global rather than calling a real browser, and that dist/ artifacts were not committed.
Run it on every Linear issue labeled agent
Set up a Linear automation that fires when an issue gets the agent label and have it call your server, which POSTs this same request to POST /o/{org}/sessions with the issue's repository in resources. Each labeled issue becomes its own run in its own sandbox with its own pull request, so triage in Linear is the only step a person does. The Rush GitHub App must be installed on the repository for resources to clone it, and the issue text has to carry enough detail for the agent to work from, since the run only sees what the label hands it.
Set a webhook URL on the API key and Rush POSTs run.completed or run.failed when each run's turn finishes, with the session URL, so your server can move the issue or post the pull request link where the team watches. Send an Idempotency-Key header on each start so a retry after a timeout does not open two runs for one label. A key runs at most max_concurrent sessions at once (4 by default) and answers 429 past that, so a burst of labeled issues should be queued rather than fired in parallel.
The use case this job follows, with its automation and trigger: Turn a Linear label into a PR.
Why run it on Rush?
Verifying a Chrome extension change on a laptop means loading dist/ into a browser profile, right-clicking around, and remembering to re-run npx jest after each edit. On Rush the loop happens in the sandbox: the agent edits public/manifest.json and src/background.ts, runs npm test and npm run build, and the webpack build plus the strict tsconfig.json catch type errors before anything is pushed. Your browser, your loaded extension, and your working tree are not involved.
The result is reviewable instead of claimed. The pull request is small enough to read in one pass, its checks come from the repository's own build.yml on Node 20.x and 22.x, and the trajectory keeps every command with its output, so the reviewer sees the jest run and the webpack build, not a summary of them. And because each labeled issue is an independent run, five labeled issues become five branches and five pull requests at once, each waiting on a person to merge.
Frequently asked questions
Does the agent add any npm packages?
No. The starter already has @types/chrome at 0.0.158 for typing the chrome API, and jest with ts-jest is already in devDependencies. The diff stays limited to the manifest, the background worker, the popup, and a test file, so package-lock.json does not change.
How does the selection survive the popup being closed?
Through chrome.storage.local. Manifest V3 service workers are torn down when idle, so the background listener writes the selection to storage, which the popup reads when it opens. The manifest already grants the storage permission, so no extra permission dialog is added for the data path.
What do the tests actually run in a sandbox with no Chrome?
They mock the chrome global. The new test under src/__tests__ stubs contextMenus.create, the onClicked listener, and storage.local, then calls the handler the way the browser would and asserts the selection is stored and read back. jest.config.js already points roots at src and transforms TypeScript with tsconfig.test.json, so no test setup changes are needed.
Can it pick the issue up from Linear on its own?
The trigger is yours: a Linear automation on the agent label calls your server, which starts the run. The issue text becomes part of the input, and the pull request links back to the issue. Keep the label off issues that are not ready, because the run starts the moment the label lands.