All jobs

Convert a SvelteKit App from JavaScript to TypeScript

Yes. An agent converts your SvelteKit app's load functions, actions, hooks and components to TypeScript, adds svelte-check, and opens a pull request with it passing.

Run this on RushIn a Project that has your repository.

What the agent does

The agent lists what has to change before it renames a file. In a SvelteKit app like sveltejs/realworld, src holds sixteen .js files and no .ts: src/lib/api.js, src/lib/constants.js, src/hooks.server.js, a +layout.server.js, and the +page.server.js and +page.js loaders and form actions for the home page, articles, the editor, login, register, settings and profiles. Every Svelte component has a plain <script> block that uses Svelte 5 runes, since svelte.config.js sets runes: true. jsconfig.json extends ./.svelte-kit/tsconfig.json, and the loaders already carry JSDoc types such as /** @type {import('./$types').PageServerLoad} */, which tells the agent the generated $types are in use and the conversion can keep them. package.json already lists typescript as a dev dependency beside @sveltejs/kit 2 and vite 7, runs on pnpm@10.20.0, and has lint and format scripts for Prettier but no check script and no svelte-check. .nvmrc pins Node 20.

It starts with the shared pieces, because the route files depend on them. src/lib/api.js becomes api.ts with a typed send options object and typed get, post, put and del helpers; the response shapes for users, profiles, articles, comments and the paginated article list go in a new src/lib/types.ts, taken from the RealWorld API this app calls at api.realworld.show. src/hooks.server.js parses a base64 jwt cookie into event.locals.user, so the agent adds src/app.d.ts declaring App.Locals with a user that can be null, which is what makes locals.user typed in every loader. src/lib/constants.js becomes a .ts file with page_size as a number.

Then the routes. Each +page.server.js becomes +page.server.ts with the JSDoc replaced by satisfies PageServerLoad and satisfies Actions, and the form actions in login, register, settings and editor type their formData reads and the fail(401, body) return. The conversion surfaces real issues rather than only adding annotations: in src/routes/+page.server.js the loader calls q.set('limit', page_size) with a number where URLSearchParams.set takes a string, which the compiler now reports and the agent fixes with an explicit conversion. Components get <script lang="ts">, and $props() destructures are typed with PageData and ActionData from ./$types.

Last, the tooling: jsconfig.json is replaced by a tsconfig.json that extends the same generated file with strict on, svelte-check is added as a dev dependency with a check script, and the agent runs pnpm check, pnpm build and pnpm lint until all three pass. Prettier's prettier-plugin-svelte is already configured in .prettierrc, so formatting of the new lang="ts" blocks follows the repository's tabs and single quotes.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Convert this SvelteKit app from JavaScript to TypeScript with strict mode. First list every .js file under src, the JSDoc types they already use, the svelte.config.js options and the scripts in package.json. Add src/app.d.ts declaring App.Locals for what hooks.server.js puts on locals, convert src/lib/api.js to a typed module with response types in src/lib/types.ts, then convert every +page.server.js, +page.js, +layout.server.js and hooks.server.js to .ts using satisfies with the generated $types, and add lang=\"ts\" to every component script with typed $props(). Replace jsconfig.json with a tsconfig.json that extends the generated one with strict on, add svelte-check and a check script, fix every error the compiler reports instead of widening types to any, and run the check, the build and the Prettier lint until all pass. Open a pull request that lists each file converted and each real bug the types found.",
  "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 on its own branch in which every .js under src is renamed to .ts with its content converted, each .svelte file's script block carries lang="ts", and src/app.d.ts, src/lib/types.ts and tsconfig.json are new, with jsconfig.json removed. package.json and pnpm-lock.yaml add svelte-check and the check script. The description lists the files and, separately, the places where the compiler found a real mismatch such as a number passed where a string was required.

The transcript shows pnpm check failing with the first list of errors, the fixes, and the run where it reports none, followed by pnpm build and pnpm lint. Git shows the renames as renames, so the diff of each route file is the type annotations and the fixes, not a whole-file replacement.

A reviewer checks that no any or non-null assertion was used to silence an error, that App.Locals matches what hooks.server.ts sets, and that the response types in src/lib/types.ts match the API the app calls. A follow-up message to the same session can ask to add the check script to a CI workflow, and the sandbox runs it again.

Run it on every route directory still in JavaScript

A large app converts in slices. Start one run per route directory with the prompt narrowed to that path, each with the repository in resources and its own Idempotency-Key, so each pull request is small enough to review in one sitting and a retried request returns the run already started.

A webhook_url on the API key receives run.completed for each slice with the session_url to read its pull request from. Runs that would conflict on the shared files can be sequenced by starting the shared src/lib slice first and the route slices after its pull request merges.

The use case this job follows, with its automation and trigger: Hand off from your terminal.

Why run it on Rush?

The conversion is a loop of check, fix and check again, and svelte-check over a whole app is not fast. On a laptop that loop blocks the afternoon. In a Rush sandbox the agent installs with pnpm, runs the loop as often as it takes, and parks the sandbox with its disk when the turn ends, so a follow-up the next morning continues without reinstalling.

The proof is in the pull request: the first failing check and the last passing one are both in the transcript, and the description separates mechanical annotations from the real bugs the compiler found. A reviewer reads the few lines that changed behaviour instead of auditing every annotation.

Frequently asked questions

Will it use any to make svelte-check pass?

No. The prompt forbids it, and the reviewer can grep the diff. Where a value's shape is unknown, the agent writes the type from the API response it reads in src/lib/api.ts, or narrows with a check, and lists any place it was unsure in the description.

Does this change how the app runs on Vercel?

No. Vite compiles TypeScript during vite build and the adapter in svelte.config.js is unchanged, so the deployed output is the same code with types removed. The only new build-time dependency is svelte-check, which runs in the check script and not in the build.

Why keep the generated $types instead of writing my own?

Because SvelteKit generates PageServerLoad, Actions, PageData and ActionData per route from the files themselves, and the JSDoc in the existing loaders already references them. Using satisfies with those types gives each loader's return the right shape in its page's data prop without a hand-written interface that would drift.

What if the app has tests?

They are converted in the same way, with their imports updated to the renamed files. This app has no test runner, so the checks that gate the pull request are svelte-check, the production build and Prettier, which are what the repository already relies on.