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 edityyOne command
terminal
npx edityy initIt 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
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.
Edityy