Skip to main content
To test unpublished @reticlehq/* changes in a real external app, publish the workspace to a local Verdaccio with bash scripts/local-registry.sh, then point that app’s .npmrc at http://localhost:4873/ as the default registry, not scoped to @reticlehq, for the reason in step 2. That is the whole procedure; the rest of this page is the detail.
For normal use, Reticle is on public npm. Just npm i -D @reticlehq/react @reticlehq/vite-plugin (see Getting Started). You only need this guide to test local, unpublished changes to the Reticle packages in a real external app before they ship.
Because the @reticlehq/* packages depend on each other via the workspace protocol, plain npm pack tarballs don’t resolve cleanly. The reliable way to exercise your in-progress changes in a real app is a tiny local registry (Verdaccio), the same path CI uses to validate a publish.

1. Publish @reticlehq/* to a local registry

From the Reticle repo:
This starts a fresh Verdaccio on http://localhost:4873, creates a user/token, and publishes all @reticlehq/* packages there at the current workspace version: For a browser app, install @reticlehq/react plus the build plugin for your framework (@reticlehq/vite-plugin or @reticlehq/next); @reticlehq/server is what your agent runs. (Verified: an external npm i @reticlehq/react resolves its graph, including @reticlehq/core, and imports correctly.) Leave the registry running.
Note: pre-2.0 docs used a single @reticlehq/core umbrella package that re-exported everything; it’s been split into the audience-scoped packages above.

2. Point your app at the local registry

In your app’s project root, add an .npmrc pointing the default registry at Verdaccio. Verdaccio proxies npm for everything it does not hold, so the rest of your dependencies still resolve normally:
A scope-only line does not work, and fails in a way that reads as a Reticle bug. @reticlehq/core depends on open-verification, the protocol package, which is deliberately unscoped because the protocol is not ours to namespace. With @reticlehq:registry=… npm sends that one request to npmjs and the install dies:
reticle init then correctly reports ⚠ Install dependencies and skips wiring the build plugin, so the app is left un-instrumented by a registry mistake two steps earlier. There is no scoped form that fixes this: npm’s per-registry setting is @scope:registry, and an unscoped package has no scope to key on. The default-registry line above is the only thing that works. Point it back at npm (npm config delete registry, or delete the .npmrc) when you are done testing.

3. Install + wire it up

Install the SDK kit plus the Vite build plugin (source mapping + connect() injection):
Then follow Getting Started: embed reticle.connect() (dev only) from @reticlehq/react, add the MCP server to your agent, and (React) install() the adapter from @reticlehq/react. For the fastest agent loop, also do Step 6: make your app agent-legible (testids, reticle.signal, registerStore, registerCapabilities) and the integration patterns (createReticleEmitter for zero prod-bundle cost).
Upgrading. scripts/local-registry.sh resets Verdaccio and republishes at whatever version the workspace is on right now, so your app will not pick up a rebuild on its own. Pull it explicitly with @latest:
Run the MCP server from the local registry too; npx @reticlehq/server is the server:

Next.js specifics (verified on Next 15 / React 19)

next.config.mjs:
Mount the SDK from a dev-only client component (see the Next.js section in Getting Started).

Real input for hover/drag (optional)

Synthetic events can’t trigger native onMouseEnter/pointer state (hover menus, tooltips, pointer drag). Enable real input so the server drives genuine pointer input and reticle_act reports inputMode:"real":
  • Easiest (reticle drive): Reticle launches its own scriptable, headless-capable browser at your app URL (no flags to juggle):
  • Or attach to your own browser: launch it with --remote-debugging-port=9222, then point the MCP server at it via env:
With neither set, Reticle stays synthetic (zero extra deps) and says so via inputMode. See usage §18.

Write replayable specs + git-checked flows

  • Specs: with @reticlehq/test, turn checks into reticleTest("…", async t => { await t.act(...); await t.expectSignal(...) }). They are signal/testid-bound, reticle_clock for determinism, t.expectInputModeReal() to skip-with-reason when real input isn’t active. Run them headless via reticle drive (the same path CI uses).
  • Flows: record a flow once and Reticle writes it to a git-checked .reticle/flows/<name>.json (anchored on testid/signal); reticle_flow_replay re-resolves anchors at run time and reports legible drift with a nearest-match; reticle_verify { action: "heal" } proposes/applies the rebind. A fresh agent reads .reticle/contract.json to learn your testable surface without grepping source.

When you’re ready for real npm

The same packages publish to public npm unchanged: pnpm -r publish --access public after npm login. The Verdaccio run above is a faithful rehearsal of that.

Cleanup

Last modified on September 18, 2026