All jobs

Add Dark Mode to a Vue App

Yes. A team can watch an agent add dark mode to a Vue app, check contrast in the browser, and steer the theme before the pull request.

Run this on RushIn a Project that has your repository.

What the agent does

The Vue RealWorld client does not own its colours. package.json has vue ^3.5.0, vue-router ^5.1.0, pinia ^3.0.0, vite ^8.0.16 and @playwright/test ^1.60.0. The scripts that matter are serve (vite), build, lint (eslint src) and test (playwright test). The lockfile is bun.lock. src/main.js imports the theme with import "../realworld/assets/theme/styles.css", and index.html says that file comes from the spec submodule so it cannot drift from the templates. .gitmodules points realworld at realworld-apps/realworld. App.vue's style block is empty. Views are src/views/Home.vue, Login.vue, Register.vue, Settings.vue, Profile.vue, Article.vue and ArticleEdit.vue, wired in src/router/index.js. Auth redirects live in main.js after auth.checkAuth(), and settings, the editor and the following feed require a session.

Dark mode is a variable layer on that shared sheet, plus a toggle, not a new CSS framework. The agent initializes the submodule, adds a dark palette as variables, and overrides them under a class or data attribute on the document. prefers-color-scheme supplies the first value. The toggle stores the reader's choice in localStorage and applies it in main.js before app.mount("#app"), so the first frame matches. The control goes in src/components/TheHeader.vue, which is the navbar App.vue always renders, rather than only on Settings.vue, so a signed-out reader on /login can switch too. The agent does not replace the submodule import with a hand-copied styles.css in src, because the Playwright suite loads the same theme.

Playwright is how this repo already opens a browser: playwright.config.ts sets baseURL to http://localhost:8080 and webServer.command to bun run serve. The agent uses the sandbox browser for the design captures, on the same port, for Home, a tag feed, Login, Register, Settings, Profile, an article and the editor, each in both themes. Contrast covers the article title, the muted dates, the green primary buttons and the form-control borders on the auth pages. The existing test:e2e script greps out tests tagged @security, and test:e2e:security runs only those. The agent runs the non-security suite after the theme change so a selector the spec still expects has not moved.

While those screenshots are on the run, a teammate can reject a grey. The follow-up says which variable. The agent updates the dark set, reloads the article and the settings form, and captures them again. The pull request includes both sets and says the submodule path is still what main.js imports.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "codex",
  "input": "Add dark mode that follows prefers-color-scheme and a toggle that remembers the choice. The theme is the realworld submodule imported by src/main.js from ../realworld/assets/theme/styles.css. Init the submodule. Add CSS variables for the dark palette and do not duplicate the class rules or replace that import. Apply the stored choice in main.js before mount, and put the toggle in src/components/TheHeader.vue. Screenshot Home, Login, Register, Settings, Profile, an article and the editor in both themes, check contrast, and post the screenshots. Apply follow-ups. Run bun run serve the way playwright.config.ts does, and run the Playwright suite that is not tagged @security. Then open the pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  1. 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.
  2. 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.
  3. 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 touching the theme file the submodule provides, src/main.js and src/components/TheHeader.vue. The description states that the import path is unchanged, lists the variables, and shows light and dark captures of the seven views. Those images are also session artifacts, each downloaded from its own URL on api.prix.dev until url_expires_at, an hour after the read.

A reviewer compares the article page and the login form across the two themes, because those are where muted text and input borders usually fail. They confirm the header toggle works signed out, that a reload keeps the stored choice, and that removing it follows the system again. They look at the Playwright output in the transcript, the suite playwright.config.ts already runs with bun run serve on port 8080.

That review can be a follow-up rather than a note after merge. The stream is the session events endpoint. A message posted while the turn is running gets 409 TURN_ACTIVE. The console queues one sent then, and POST /o/{org}/sessions/{id}/messages wakes the parked sandbox once the turn has finished, with the Vite server and the branch as they were.

Run it on every design change

One design change, one session: POST the body with the repository URL. The org sees the run and who started it. The starter or an org admin steers with follow-ups, and can take the sandbox browser on a five-minute lease that only one person holds.

Set a webhook URL on the API key to receive run.completed, run.failed or run.cancelled when each turn ends. A resumable run sends one delivery per turn, so the screenshot turn and the later correction are both notified. Idle parked sandboxes last 7 days. More than max_concurrent active runs, 4 by default, answers 429.

The use case this job follows, with its automation and trigger: Steer a run as a team.

Why run it on Rush?

The theme file is shared with the conformance suite, so a local edit that looks fine and drifts from the submodule is worse than a slow review. The sandbox initializes the submodule, serves vite on the port Playwright expects, and keeps the captures next to the diff. A designer does not need the repo cloned to point at a failing border.

The pull request is what merges. The transcript shows the Playwright command and the follow-up that changed a variable. Another Vue app can be in its own sandbox at the same time, with its own branch, and neither run writes the other's files.

Frequently asked questions

Will it copy styles.css into src to avoid the submodule?

No. src/main.js imports ../realworld/assets/theme/styles.css, and index.html says that path is the contract with the templates. The agent initializes the submodule and edits that file. A pull request that deletes the import is a miss, and you send it back with a follow-up if the run is still parked.

Which Playwright command does it run?

The suite that playwright.config.ts already defines: bun run serve on http://localhost:8080, tests in ./realworld/specs/e2e. package.json splits test:e2e, which greps out @security, from test:e2e:security. The prompt asks for the non-security run. Add the security script to the prompt if you want both.

Does the toggle work on the login page?

Yes. TheHeader is rendered from App.vue for every route, including Login and Register, which have no requiresAuth meta. Settings alone would hide the control from a signed-out reader. The stored choice is applied in main.js before mount, so the login form does not paint light and then switch.

Can two people send follow-ups?

The starter and an org admin can. Everyone else in the org can watch. One browser lease is held at a time, for five minutes. A second follow-up waits until the first turn finishes, because a message during a running turn is 409 TURN_ACTIVE.