Install

Edityy is a dev dependency. It runs on your dev server only, and it never ships in a production build.

terminal

npm install -D edityy

One command

terminal

npx edityy init

It reads the framework from package.json and writes every file the project needs: the Vite plugin, or the Next.js client file and proxy.ts. It also adds the MCP server to the agent config it finds, and the rules an agent needs to answer vartest to AGENTS.md.

A second run changes nothing. npx edityy init --remove takes it back out, and npx edityy doctor checks the setup again, MCP server included.

The sections below set the same thing up by hand.

Add one line to your dev server. The middleware serves the launcher and injects the tag into the HTML that server returns.

Vite

vite.config.ts

import { defineConfig } from "vite";
import { edityy } from "edityy/vite";

export default defineConfig({
  plugins: [edityy()],
});

The plugin runs on the dev server only, so vite build never includes the launcher. It works for every framework that runs on a Vite dev server: React, Vue, Svelte, Solid, SvelteKit, Astro, Nuxt, Remix and React Router.

Source locations

On Vite 8 or later the plugin also marks where each element was written. Every DOM element in a .jsx or .tsx file gets a data-edityy-src attribute, so an edit can name the exact line to change.

  • Components are skipped. A component can drop the attribute.
  • Turn the attribute off with edityy({ source: false }).
  • An older Vite cannot parse TSX in a plugin, so it does nothing there.

Connect, Express, or a plain server

Anything that takes (req, res, next) works.

server.js

import { createServer } from "node:http";
import { edityy } from "edityy";

createServer(edityy()).listen(3000);

Next.js

Next renders the page itself, so a dev-server middleware cannot patch its HTML. Load the client bootstrap instead. Next runs it before hydration, so there is no route handler and no script tag in the layout.

instrumentation-client.ts

if (process.env.NODE_ENV === "development") import("edityy/client");

Put the file in the project root, or in src/ if your app is there. This works on Next.js 15.3 and later. The check keeps the launcher out of next build.

Next.js 16.3 and later

You can set the option in your config instead of the file.

next.config.ts

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  ...(process.env.NODE_ENV === "development" && {
    instrumentationClientInject: ["edityy/client"],
  }),
};

export default nextConfig;

Do not use the option on Next.js 16.2 or earlier

Those versions do not know it. They print Unrecognized key(s) in object: 'instrumentationClientInject', ignore it, and show no launcher. Use the instrumentation-client.ts file there.

Serving the script over HTTP

The launcher script is bundled into the page, so nothing extra is requested at runtime. If you would rather serve it over HTTP, to keep it out of your client bundle, add a script tag to your layout instead.

app/layout.tsx

<script src="/__edityy/edityy.js" defer />

Serve that path with a route handler that returns launcher from edityy/inject. Next treats a folder that starts with an underscore as private and never routes it, so the route lives in a folder with an ordinary name, and the app rewrites the path onto it.

app/edityy/edityy.js/route.ts

import { launcher } from "edityy/inject";

export function GET() {
  return new Response(launcher, {
    headers: { "content-type": "text/javascript; charset=utf-8" },
  });
}

next.config.ts

async rewrites() {
  return [{ source: "/__edityy/edityy.js", destination: "/edityy/edityy.js" }];
}

Use this approach on Next.js before 15.3, which has no instrumentation-client file.

Next

Reload the page. The launcher is in the bottom-right corner.