Skip to content

Framework Detection

tavlean edited this page Jun 4, 2026 · 3 revisions

Framework Detection

How a project's framework/tool tag is derived and styled. Two different detection paths feed one shared display layer (src/tool-display.ts).

The two detection paths, and why

Path Input Where Used by
detectTool(command, cwd) the running process's command line src/servers.ts dashboard
guessFramework(cwd) the project's package.json dependencies src/start.tsx Start picker

This duplication is deliberate, and it's the first thing a contributor will question:

  • The dashboard has a live process to inspect. The command line is ground truth for what's actually running: e.g. node_modules/.bin/vite, or node node_modules/serve/build/main.js. So detectTool reads the command.
  • The Start picker shows stopped projects. There's no process to inspect, so the only signal available is what the project declares in package.json. So guessFramework reads dependencies.

They can disagree (a project may depend on Vite but be running something else), and that's fine: the tag is cosmetic. For a running server, process inspection is the source of truth; for a stopped project, the dependency guess is a best-effort hint. Don't try to unify them; they have genuinely different inputs.

detectTool algorithm (dashboard)

  1. Prefer explicit special cases that do not naturally live under node_modules, currently Shopify CLI dev commands. See Shopify Integration.
  2. Prefer the node_modules/.bin/<name> binary name (e.g. vite, next).
  3. Else the package name from node_modules/<pkg>/…: catches node node_modules/serve/build/main.js (→ serve) and scoped packages (@vitejs/…).
  4. Else, a bare Bun script → bun.
  5. Else → node.

SvelteKit special case: SvelteKit runs under Vite, so the binary is vite. When vite is detected and a svelte.config.{js,ts} exists in the cwd, the tool is promoted to sveltekit.

guessFramework algorithm (picker)

Reads merged dependencies + devDependencies and returns the first match in a priority order (next → @sveltejs/kit → svelte → astro → nuxt → remix → gatsby → vite → webpack → parcel → turbo → esbuild). Returns undefined when nothing matches, in which case the picker row shows a plain tinted folder.

Runs off the render path; see the cached-promise note in src/start.tsx. Reading up to 30 package.json files synchronously in a useMemo would block first paint, so detection happens inside a useCachedPromise keyed by the recents' cwds.

Display layer (tool-display.ts)

The internal tool value is kept lowercase everywhere (grouping key, color lookup, dropdown filter value) and only stylized on the way to the UI. Two functions:

  • toolLabel(tool): maps the lowercase key to a display name (sveltekitSvelteKit, nextNext.js). A few stay lowercase on purpose (esbuild, http-server) because that's the canonical brand/package spelling. Anything not in the map renders as-is.
  • toolColor(tool): returns a Raycast Color from the named palette, or a theme-adaptive { light, dark } hex pair for the cases where the named palette doesn't work.

Why hex color overrides exist

Raycast's named palette (Color.Purple, Color.Yellow, …) renders too muddy or too low-contrast against the translucent tag background in some themes, most visibly on selected rows in dark mode. The overrides fix the few offenders:

  • Purples (Vite, Astro, Gatsby): deepened in light mode for readable contrast.
  • Yellows (Parcel, esbuild, Bun): Color.Yellow is too pale in light mode, so a deeper amber there; a warm yellow in dark mode where it reads fine.
  • Next: Tailwind gray-900/gray-100 (a blue-tinted gray, not neutral).

Everything else falls through to the named palette, which works fine. When adding a new tool, start with a named Color; only add a hex override if it actually looks bad in one of the themes.

Adding a new tool

  1. Teach detection: add the binary/package name to detectTool's expectations (usually automatic, since it reads whatever node_modules name is running) and add the dependency to guessFramework's priority list if you want it tagged in the picker too.
  2. Add a toolLabel entry if the lowercase key isn't already a nice display name.
  3. Add a toolColor entry: named Color first, hex override only if needed.
  4. If it's also a dev-script tool the Start command should recognize, that's a separate list; see Script Picker.

If the tool is commonly launched as a global CLI outside node_modules, add a strict candidate detector too. The Shopify path is the example: it accepts only shopify theme dev, shopify app dev, and shopify hydrogen dev, not every process whose path happens to contain shopify.

Clone this wiki locally