What the agent does
The agent starts with what the app already tests and how its tests are configured. In a Vue 3 app like antfu-collective/vitesse it reads package.json and finds packageManager: pnpm@10.30.2, every dependency pinned through catalogs in pnpm-workspace.yaml (Vitest ^5.0.3, @vue/test-utils ^2.5.1, jsdom, Vue ^3.5.43, Pinia ^4.0.3, vue-i18n ^11.4.13), and test:unit set to plain vitest. There is no separate Vitest config: the test block in vite.config.ts includes test/**/*.test.ts with the jsdom environment, so tests run through the same plugins as the app, including unplugin-auto-import, which makes ref, useI18n, useRouter and the stores in src/stores available without imports. The test/ folder holds basic.test.ts, which checks 1 + 1, and component.test.ts, which mounts TheCounter.vue and clicks .inc and .dec. Everything else is untested.
From src/ it lists what has no test: the useUserStore store in src/stores/user.ts, the TheInput.vue and TheFooter.vue components, the index.vue and hi/[name].vue pages, and the dark composable. The store gets direct tests with a fresh createPinia() set active before each one: setNewName sets savedName, the previous name moves into otherNames, a name used twice is stored once because previousNames is a Set, and otherNames never contains the current name. TheInput.vue uses defineModels from Vue Macros, so the test checks that typing emits update:modelValue and that attributes such as placeholder reach the <input> through v-bind="$attrs".
The language switch is the part most apps leave untested. TheFooter.vue calls loadLanguageAsync from src/modules/i18n.ts with the next entry of availableLocales, which the module builds from import.meta.glob('../../locales/*.yml') over the 19 locale files. The test mounts the footer with the app's real i18n instance, installed through the module's own install function, and a memory-history router for its RouterLinks, clicks the language button, and checks that locale changed, that the <html> element's lang attribute changed (which setI18nLanguage sets), and that a translated title such as button.home now reads from the new locale's YAML. The index.vue test types a name into the input, checks that the Go button is disabled while it is empty, and that pressing Enter pushes /hi/<name> with the name URL-encoded.
It runs pnpm install --frozen-lockfile, then pnpm test:unit --run so Vitest exits after one pass, then pnpm typecheck (vue-tsc --noEmit) and pnpm lint, which uses @antfu/eslint-config, so the new files follow the repository's style. The existing TheCounter snapshot in test/__snapshots__ must still match.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Write Vitest and Vue Test Utils tests for every component and Pinia store in this Vue app that has none, including the i18n language switch. Read package.json, the workspace catalog, the vite.config.ts test block and the existing tests first, and put new tests where the test include pattern finds them. Use a real Pinia instance per test and the app's own i18n module and locale files, not stubs of them; use a memory-history router where a component needs one. Cover store actions and getters, component props, emitted events and v-model, and for the language switch check the locale, the html lang attribute and a translated string. Run pnpm test:unit --run, pnpm typecheck and pnpm lint, and fix what they report in the new files. Do not change application code. Open a pull request.",
"resources": [
{
"url": "https://github.com/your-org/your-vue-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
The pull request adds test files under test/, for an app shaped like Vitesse typically user-store.test.ts, the-input.test.ts, the-footer.test.ts and one file each for the index and hi/[name] pages, plus a small helper that mounts a component with Pinia, i18n and a router so each test does not repeat that setup. It changes nothing under src/. The description lists every component, page and store with the cases now covered and the ones it did not test, with the reason.
The evidence is the run output and the checks. The session keeps the agent's pnpm test:unit --run, pnpm typecheck and pnpm lint from its sandbox in full. Vitesse's own workflow runs pnpm run lint, pnpm run typecheck and pnpm run test:unit on the pull request, so the same three commands run there as well.
Before merging, a reviewer checks that the language-switch test reads its expected string from the locale file rather than hardcoding a translation that will drift, that the router in the page tests uses the app's real routes where the assertion depends on them, and that no test relies on the order of availableLocales beyond what the module guarantees.
Run it on every new component
When a pull request adds a .vue file under src/components/ or src/pages/, or a store under src/stores/, and nothing under test/, have a GitHub pull_request webhook send this request with the pull request URL in resources. The agent checks out that branch and writes tests for what it adds, in its own session and sandbox.
Set a webhook URL on the API key and Rush POSTs run.completed or run.failed when the turn ends, with the session URL, so your server can link the tests from the original pull request.
The use case this job follows, with its automation and trigger: Write the missing tests.
Why run it on Rush?
Testing a Vue app that leans on auto-imports, Vue Macros and lazy-loaded locale files takes a few rounds of mounting, reading a resolve or injection error, and adding the missing plugin to the mount options, with vue-tsc and the linter run after each. On Rush the agent does those rounds in its own sandbox with a clean pnpm install --frozen-lockfile, and your working tree and dev server are not touched.
What comes back is checkable. Each Vitest, vue-tsc and ESLint run the agent made is kept in the session with its output, and the pull request's own workflow repeats them. The same request can cover several Vue apps at once, each in its own sandbox, each with a pull request someone reviews.
Frequently asked questions
Will it use @pinia/testing and createTestingPinia?
Not by default. The prompt asks for a real Pinia instance per test, so actions run and getters compute as they do in the app. createTestingPinia stubs actions unless told otherwise, which suits a component test that only cares that an action was called; if your repository already uses it, the agent follows that.
How does it test components that rely on auto-imports?
In Vitesse the test block lives in vite.config.ts, so Vitest runs the same unplugin-auto-import and unplugin-vue-components plugins as the app and the auto-imports resolve in tests too. If your app keeps a separate vitest.config.ts, the agent checks that it includes those plugins before writing tests that depend on them.
Does it work with Vuex or Nuxt?
Yes. For Vuex the agent creates a real store with your modules for each test. For Nuxt it reads whether the repository uses @nuxt/test-utils and writes tests in that environment, so composables like useFetch and auto-imports work the way Nuxt sets them up.
Will it update my snapshots?
No. The prompt forbids changes to application code, and the agent does not run Vitest with -u. If an existing snapshot fails, it reports which one and why in the pull request rather than overwriting it.