Install

This page walks through getting Hover into a project you already have. For the absolute fastest path, the Quick start is the shorter version of the same steps; come back here if anything goes sideways.

Before you start

You need three things:

  1. Node 22+ on your PATH. node --version should print v22.x or higher.
  2. A supported bundler in your project — Vite, Astro, Nuxt, Next.js 15 / 16, or Webpack 5 (incl. Rspack / Rsbuild / CRA / Vue CLI).
  3. One coding-agent CLI installed and logged in. Hover spawns whichever you have on PATH; it doesn't bundle an LLM and doesn't take API keys.

Don't have an agent CLI yet?

No .env file, no .npmrc for npm auth — every Hover package is public on npmjs.com.

Run inside your project root:

npx @hover-dev/cli setup

That single command:

  1. Reads package.json and detects your bundler (Vite / Astro / Nuxt / Next / Webpack).
  2. Sniffs your lockfile to pick the right package manager (pnpm / yarn / bun / npm).
  3. Installs the matching Hover package as a dev dependency (vite-plugin-hover, @hover-dev/astro, @hover-dev/nuxt, @hover-dev/next, or webpack-plugin-hover).
  4. Uses magicast to AST-mutate your bundler config so the plugin is registered.
  5. Is idempotent — running it twice is a no-op.

Preview without changing anything

npx @hover-dev/cli setup --dry-run

Prints what would be installed + which file would be edited, then exits clean. Useful when you're not sure what the CLI will pick.

Force a specific bundler

If auto-detect picks the wrong one (rare, but happens in projects with multiple bundlers in devDependencies):

npx @hover-dev/cli setup --vite
npx @hover-dev/cli setup --astro
npx @hover-dev/cli setup --nuxt
npx @hover-dev/cli setup --next
npx @hover-dev/cli setup --webpack

Option B — manual install

Skip the CLI entirely. You'll do exactly what the CLI does, by hand.

About `autoLaunchChrome: true` in the snippets below

Vite

pnpm add -D vite-plugin-hover
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import hover from 'vite-plugin-hover';

export default defineConfig({
  plugins: [
    react(),                     // or vue() / svelte() / solid() / qwik()…
    hover({ autoLaunchChrome: true }),
  ],
});

Astro 5+

Astro's HTML pipeline bypasses Vite's transformIndexHtml, so it needs its own integration shim.

pnpm add -D @hover-dev/astro
// astro.config.mjs
import { defineConfig } from 'astro/config';
import hover from '@hover-dev/astro';

export default defineConfig({
  integrations: [hover({ autoLaunchChrome: true })],
});

Nuxt 4+

Nuxt renders HTML through Nitro (not Vite), so it needs a Nitro module.

pnpm add -D @hover-dev/nuxt
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@hover-dev/nuxt'],
  hover: { autoLaunchChrome: true },
});

Next.js (15 / 16)

Three pieces because Next splits its dev-server lifecycle. Verified end-to-end on Next 15 + webpack, Next 15 + Turbopack, Next 16 + Turbopack, Next 16 + webpack — with any of next.config.{ts,mjs,js}.

pnpm add -D @hover-dev/next

1. Wrap your Next config — adds Hover's options-to-env serialisation. Pure config wrapper, no side effects, safe to run at next build too.

// next.config.ts
import { withHover } from '@hover-dev/next';
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // your existing Next config
};

export default withHover(nextConfig, { autoLaunchChrome: true });

2. Register the runtime hook — Next's blessed init point. Fires on next dev / next start, NOT on next build (so no orphan service from CI).

// instrumentation.ts        ← project root, OR under src/ if your app uses src/
import { register as registerHover } from '@hover-dev/next/instrumentation';

export async function register() {
  await registerHover();
}

3. Render the widget script — add <HoverScript /> to your root layout. The CLI prints this exact snippet for you to paste because AST-editing user JSX is fragile.

// app/layout.tsx
import { HoverScript } from '@hover-dev/next';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <HoverScript />
      </body>
    </html>
  );
}

Async server component

Webpack 5 (including Rspack / Rsbuild / CRA / Vue CLI)

pnpm add -D webpack-plugin-hover
// webpack.config.js
const Hover = require('webpack-plugin-hover');

module.exports = {
  // ... your config
  plugins: [
    new Hover({ autoLaunchChrome: true }),
  ],
};

Next.js with `--webpack`?

Monorepos (turbo / pnpm-workspace / yarn workspaces)

Hover's CLI knows about workspace monorepos. Run from the repo root, not from inside apps/*:

npx @hover-dev/cli setup

The CLI:

  • Detects the monorepo from pnpm-workspace.yaml, the workspaces field in package.json, or turbo.json.
  • Enumerates declared workspaces (apps/*, packages/*, explicit paths).
  • Looks for a supported bundler in each.

What happens next depends on how many apps matched:

Match countBehaviour
0"No supported bundler" — you're at a monorepo root with only tooling; point the CLI at an app: --cwd apps/web
1Installs into that workspace automatically. Tells you which one it picked.
2+ in a TTYInteractive picker (↑/↓ or j/k to move, Enter to select, Esc to cancel)
2+ in CI / pipedLists candidates and exits 1, asks you to re-run with --cwd <path>

Skip auto-detect entirely and target a specific workspace:

npx @hover-dev/cli setup --cwd apps/web

Path is absolute or relative to where you ran the command.

Single root lockfile

Run dev however you already run it

A worked, committed example lives at examples/turbo-monorepo/ — turbo + pnpm-workspace + two Next.js 15 apps + next.config.ts, exactly the shape that surfaced the v0.7.3 / v0.7.4 install bugs.

Verify the install worked

Start your dev server the way you already do:

pnpm dev          # or npm run dev / yarn dev / bun dev / turbo run dev

You should see one or two new log lines from Hover. The first one always appears:

[@hover-dev/<bundler>] service ready · ws://127.0.0.1:51789 · agent=claude model=sonnet

If you set autoLaunchChrome: true, a second line appears as Hover pre-warms the isolated debug Chrome:

[hover] launching debug Chrome on :9222

Hover's debug Chrome is a separate, temp-profile Chrome — not your everyday browser. Different cookies, different sessions, no shared extensions. If 9222 already has a debug Chrome (e.g. from a previous pnpm dev whose window you didn't close), Hover reuses it and skips the launch, which is why you'll only see the launch log once per Chrome lifetime.

If those are present, open your dev URL. The floating ✨ launcher appears in the bottom-right corner of every page. Click it; the panel slides up. That's it — install is done.

What the ✨ colour tells you on first click:

ColourMeansWhat to do
🔵 BlueYou're already in a debug Chrome.Click and start chatting.
🟠 AmberNo debug Chrome yet.Click; the widget spawns one (isolated profile under <tmpdir>/hover-chrome, port 9222), navigates it to your dev URL. Switch over.
⚪ GrayA debug Chrome is running but you're not in it.Click to bring the right window to the front.

The debug Chrome is completely separate from your everyday browser. Different profile dir, no shared cookies, no shared extensions. Hover never touches your normal Chrome session.

Skip ahead to First session to send your first prompt.

Troubleshooting

Couldn't detect a supported bundler in package.json

You ran the CLI from a directory whose package.json declares no bundler dep. Either:

  • You're at a monorepo root and the actual app is in apps/web — re-run with --cwd apps/web, or just run from the monorepo root (Hover will detect the workspaces).
  • Your project's bundler isn't in our list — open an issue, or pass an explicit --vite / --next / etc. if you're using one of the supported bundlers but have an unusual dep graph.

EADDRINUSE: address already in use :::5173 (or 5183, etc.)

Something else is on the port. Most often: a prior next dev / vite that didn't shut down cleanly. Kill it:

lsof -i :5173 -t | xargs kill         # replace 5173 with your dev port

If lsof shows a stale Hover service on 51789–51798 too, kill those: lsof -i :51789 -t | xargs kill.

Widget doesn't appear in the page

Open browser devtools → Console. If you see a WebSocket connection error to ws://127.0.0.1:51789, the Hover service didn't boot. Common causes:

  • The bundler integration wasn't registered. Re-run npx @hover-dev/cli setup --dry-run to confirm the config has the plugin / integration.
  • You ran pnpm build instead of pnpm dev — Hover is deliberately a no-op in production builds.
  • For Next.js: forgot to add <HoverScript /> to app/layout.tsx. The CLI prints this snippet at the end of add; if you missed it, see Option B → Next.js.

Next 15 + next.config.ts previously errored with ERR_PACKAGE_PATH_NOT_EXPORTED

Fixed in v0.7.3 (dual ESM + CJS build). Make sure you're on @hover-dev/next@>=0.7.3.

Next 15 instrumentation errored with Cannot find module './register-node.js'

Fixed in v0.7.4 (package-subpath specifier + opaque dynamic import that webpack can't stub). Upgrade to @hover-dev/next@>=0.7.4.

What gets installed

Whichever bundler shim you pick pulls these as transitive deps:

PackagePurpose
@hover-dev/coreNode service — agent invocation, Playwright CDP preflight, WebSocket bridge between the widget and the agent.
@hover-dev/widget-bootstrapShared widget assets — every bundler emits a byte-identical widget bundle so behaviour stays uniform across Vite / Astro / Nuxt / Next / Webpack.
vite-plugin-hover (or your bundler's shim — @hover-dev/astro, @hover-dev/nuxt, @hover-dev/next, webpack-plugin-hover)Wires the service + widget into your dev server.

Optional extras:

  • @hover-dev/security — adds Security testing mode (MITM proxy + replay) to the same widget.
  • @hover-dev/cli — what npx @hover-dev/cli setup runs. You don't need to install it explicitly; npx runs the latest published version on demand.

See Plugin options for the full configuration surface (port, agent, model, budget, source-attribution, …).