@insitue/claude-plugin
v0.7.7
Published
Drive Claude (Code AND Desktop) from the InSitue browser overlay — pick an element in your app, claude reads the file and proposes the edit.
Maintainers
Readme
InSitue Dev — Claude plugin (Code + Desktop)
Drive a Claude session — Code or Desktop — from your running app. Pick an element in the browser, describe what you want changed, hit Send. claude reads the file at exactly the right line and proposes the edit. No copy-pasting file paths. No fumbling for line numbers. The picker IS the prompt.
┌────────────────────────────────┐ ┌────────────────────┐
│ Your app (any dev server) │ │ claude (terminal) │
│ ┌──────────────────────────┐ │ │ │
│ │ InSitue widget │ │ │ /insitue:connect │
│ │ · Pick │ │ pipe │ │
│ │ · Describe │ ├────────►│ receives pick │
│ │ · Send │ │ │ + description │
│ └──────────────────────────┘ │ │ │
└────────────────────────────────┘ │ → reads file │
│ → proposes diff │
│ → awaits approval │
│ → writes │
└────────────────────┘Setup (60 seconds, one-time)
Pick your runtime:
- Claude Code (the CLI / terminal app) → §1A below.
- Claude Desktop (the macOS / Windows app) → §1B below.
If you use both, do both — same MCP, same widget, same picks.
1A. Claude Code — install via the marketplace
In any claude session:
/plugin marketplace add InSitue/insitue
/plugin install insitue@insitue-pluginsThat's it for the plugin side. The MCP server it ships will
auto-start the InSitue companion process in the background of
your claude session — no separate terminal to babysit. The
slash command /insitue:connect enters the loop.
The plugin ships five slash commands:
| Command | What it does |
|---|---|
| /insitue:connect | Enter the pick→edit loop (responsive): act on picks, never blocks your typing — a pick is grabbed on your next message. |
| /insitue:watch | Hands-free pick mode (proactive): act on every pick the instant you make it. Press Esc once to chat; the watch resumes after. |
| /insitue:disconnect | Leave the loop: close the WS, stop receiving picks, and kill the companion the plugin spawned. |
| /insitue:login | Browser sign-in (PKCE) to InSitue Cloud, then auto-link this repo to its project. |
| /insitue:logout | Revoke the token server-side and clear local credentials. |
Two watch modes, because polling forces a trade-off. /insitue:connect
keeps your chat fully responsive but a pick waits for your next message;
/insitue:watch acts on picks instantly but you press Esc to interject. You
can't have both on a poll — only push (channels, below) gives instant +
non-blocking, and that's still a research preview.
1B. Claude Desktop — one-command setup
Claude Desktop doesn't have a plugin marketplace, but it does
load MCP servers from claude_desktop_config.json. The package
ships an insitue CLI that writes the right entry for you:
# from your project directory
npx -y @insitue/claude-plugin setup --desktopWhat it does (all idempotent + backed up):
- Detects your OS and finds the Desktop config file
(
~/Library/Application Support/Claude/claude_desktop_config.jsonon macOS,%APPDATA%\Claude\…on Windows,$XDG_CONFIG_HOME/Claude/…on Linux). - Backs up the existing file with an
.insitue-backup-<timestamp>suffix. - Adds (or updates) a
mcpServers["insitue-<projectname>"]entry pointing atnpx -y @insitue/claude-plugin@latestwithINSITUE_PROJECT_DIRset to your project.
Restart Claude Desktop, open a new chat, and type:
Use the InSitue MCP — call
start_session.
claude fetches the operating instructions, attaches to the
companion, and enters the loop. The slash command on Code and
start_session on Desktop deliver the exact same content.
Multi-project? Run setup --desktop --project=/path/to/other
in each project root. Each gets its own MCP entry
(insitue-<dirname>), so switching between projects in Desktop
is just picking the right server-prefix in chat.
Want to see what would change first? Append --dry-run. The
CLI prints the JSON entry without touching the file.
Diagnose a setup that's misbehaving:
npx -y @insitue/claude-plugin diagnoseReports project dir, session file freshness, companion reachability, SDK + SWC-plugin versions + wiring, and concrete recommendations.
2. Mount the widget in your app
Install the SDK:
npm install -D @insitue/sdk
# or pnpm add -D / yarn add -DAdd one line to your app's dev mount. Next.js / Vite / Remix — any framework with a React tree works.
Next.js (app/layout.tsx):
import { InSitueCapture } from "@insitue/sdk";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
{children}
{process.env.NODE_ENV !== "production" && <InSitueCapture />}
</body>
</html>
);
}Vite (src/main.tsx):
import { InSitueCapture } from "@insitue/sdk";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
{import.meta.env.DEV && <InSitueCapture />}
</StrictMode>,
);With no projectKey, the widget connects to the local
companion. (Pass projectKey and it ships to InSitue Cloud
instead — same widget, different sink. See
@insitue/sdk.)
Use it
Two terminals. That's it.
# Terminal A — your normal dev server, any port
pnpm dev # or `npm run dev`, `next dev`, `vite`, whatever
# Terminal B — claude, in the project root
claude
> /insitue:connectThen in your browser:
- Look for the InSitue Dev pill in the bottom-right corner.
- Click it. The picker activates — hover any element on the page to highlight it.
- Click the element you want to change.
- The panel pops up with the target, a screenshot, and a focused textbox.
- Type your instruction: "make the padding bigger", "this should be red on hover", "swap these two for me" — anything.
- Press Enter (or click Send to claude).
Back in your terminal, claude has the pick + your description and starts working. It'll show you the diff and wait for "yes" before writing. After it writes, your dev server's HMR picks up the change and you see it live in the browser. Pick the next thing.
Hands-free picks — /insitue:watch now, channels later
By default (/insitue:connect) the chat stays fully responsive and a pick
is grabbed on your next message. For a heads-down session where you want
every pick acted on the instant you make it, run /insitue:watch (press
Esc once to chat; the watch resumes after).
Neither polling mode is both instant and non-blocking — that needs picks pushed into an idle session, which Claude Code supports today only as a research-preview "channel":
claude --dangerously-load-development-channels plugin:insitue@insitue-pluginsWith that flag, every browser pick wakes Claude immediately via a channel
notification — instant and the chat stays free. Claude still buffers picks
for next_pick in parallel, so a missing channel listener falls back to
polling automatically.
Notes:
- Channels are a Claude Code research preview, and the flag must be
passed every launch — there's no settings-level enable for individual
users yet, so it isn't an "opt in once" experience. Until it graduates,
/insitue:watchis the no-flag way to get hands-free picks. - The flag
--dangerously-load-development-channelsmay change or be renamed during the preview. - Org allowlist: on Team/Enterprise an admin can add
insitueto theallowedChannelPluginspolicy — then it runs with justclaude --channels plugin:insitue@insitue-plugins. Once channels leave research preview, no flag will be needed at all. - It works only with the CLI (
claude), not Claude Desktop. - The standard
/insitue:connectworkflow (plainclaude, no extra flags) continues to work exactly as before via polling — channels are purely an opt-in upgrade, not a requirement.
What gets shipped to claude
Every pick that claude receives includes:
| Field | What it is |
|---|---|
| source.file + source.line | Resolved JSX site (via React fiber _debugSource or the @insitue/sdk/babel plugin) |
| target | Component name (e.g. HubHeroPoster) or selector fallback |
| componentStack | Top-down owner chain |
| userNote | Your typed description |
| screenshot | A real bitmap of what you picked |
| runtime | URL, recent console/network/errors |
The widget refuses to send a pick whose source can't be resolved (selector-only confidence). You get an inline "couldn't resolve the source file — try a parent" prompt, and claude never gets a useless tip.
Troubleshooting
The pill says "InSitue Dev · offline"
The companion isn't up yet — check the claude terminal for
output from [insitue-mcp] or [companion]. First run can take
~10 seconds while npx downloads the package. After that, it's
instant.
/insitue:connect says the plugin isn't installed
Run /plugin marketplace update insitue-plugins then /plugin
install insitue@insitue-plugins again. Restart claude (/exit,
then claude) so the MCP server reloads with the new version.
Picks land but claude doesn't act
Verify with mcp__insitue__list_recent_picks inside the claude
session — that confirms the bridge is delivering. If they're
there but ignored, you may have closed the /insitue:connect
loop. Restart it.
I want to run the companion myself
You can — npx @insitue/companion@latest dev in any terminal.
The MCP server detects an existing companion at
.insitue/session.json and reuses it instead of spawning its
own. Use this when you want to see the companion's logs
directly, or for debugging.
It's still not working
Open an issue at https://github.com/InSitue/insitue/issues
with the contents of .insitue/session.json and the last ~20
lines from the claude transcript. The MCP server logs
extensively to stderr; claude surfaces them in the transcript.
Fix cloud issues from Claude
Requires a paid InSitue Cloud plan and the
@insitue/companionCLI.
If your project uses InSitue Cloud, bug reports captured in production land in your Cloud issue queue. The four cloud_issue_* MCP tools let Claude list those issues, claim one, read the full repro, fix it locally, and mark it resolved — all without leaving the terminal.
Prerequisites
- Authenticate: run
insitue login(from the@insitue/companionCLI), or/insitue:logininside Claude Code. Bareinsitue loginis a tokenless browser sign-in via PKCE — it opens your browser, prints an authorize URL + a short code to confirm, and on success prints✓ Signed in as <login>. Credentials are saved to~/.insitue/auth.json. A token minted this way from inside a repo is project-scoped (it can only act on that project's issues). On SSH/remote where no browser or loopback redirect is available, the flow auto-switches to the device flow — or force it withinsitue login --device. As a CI / headless fallback, paste a Personal Access Token directly withinsitue login --token pat_live_…(mint PATs at https://app.insitue.com/app/settings/developer); PATs are account-wide. - Link your project:
insitue loginalready best-effort auto-links the current repo to its InSitue project, so this is usually unnecessary. If you need to link manually, runinsitue link(auto-detects the project from the git remote) orinsitue link <projectId>in your project root. The tools read the linked project from.insitue/project.json.
The loop
list_cloud_issues ← what's open?
↓
claim_cloud_issue(id) ← lock the issue; receive full repro
↓
(Claude reads source file, applies fix, opens a PR)
↓
resolve_cloud_issue(id, prUrl, branch?) ← attach the PR; close the issueIf you claim an issue and decide not to fix it, call release_cloud_issue(id) to return it to the queue so someone else can pick it up.
MCP tools
| Tool | Arguments | What it does |
|---|---|---|
| list_cloud_issues | — | Lists open bug reports for the linked project. |
| claim_cloud_issue | id | Claims the issue and returns the full repro: description (note), source file:line, page URL, and top console errors. |
| resolve_cloud_issue | id, prUrl, branch? | Marks the issue resolved and attaches the GitHub PR URL. branch is optional — include it when the fix isn't on the default branch yet. |
| release_cloud_issue | id | Returns a claimed issue to the open queue without resolving it. |
Typical Claude session
> /insitue:connect
# (pick-and-edit loop starts as normal)
# Switch to cloud issues:
> list open cloud issues
# Claude calls list_cloud_issues, picks one.
> claim issue <id>
# Claude calls claim_cloud_issue — gets note, file:line, page URL, console errors.
# Claude opens the source file at the reported line, reads context, writes a fix.
# Claude opens a PR via gh or the normal git flow.
> resolve issue <id> with PR https://github.com/…/pull/42
# Claude calls resolve_cloud_issue(id, "https://github.com/…/pull/42").The cloud-issue tools compose naturally with the pick→edit loop — you can interleave browser picks and issue fixes in the same session.
See Fix cloud issues locally for a full walkthrough.
Architecture (skip unless curious)
The plugin is a stdio MCP server that:
- On startup, resolves the project dir (
--project-dirargv →INSITUE_PROJECT_DIRenv →CLAUDE_PROJECT_DIRenv → walk-up for.insitue/session.json→ walk-up forpackage.json→ cwd). - Reads
.insitue/session.jsonto find a running companion. If one's alive (PID up + port responsive), reuse it. - Otherwise spawns
npx -y @insitue/companion@latest devas a child process, polls for the newsession.jsonto appear (8 s ceiling), then connects. - Subscribes to the companion's WS broadcast channel. Every pick the browser sends arrives here, gets summarised, and buffers (cap: 32) for the polling loop to pull.
- Auto-reconnects if the companion restarts (HMR, manual stop). The widget reconnects too.
- Cleans up on
process.exit/SIGTERM— kills only the companion it spawned, leaves user-started companions untouched.
MCP tools exposed
| Tool | Purpose |
|---|---|
| next_pick | Long-poll for the next browser pick (default 8 s; max 30 min). |
| list_recent_picks | Up to N buffered picks since the MCP server started. |
| start_session | Returns the operating instructions + current state. Desktop entry point. |
| end_session | Cleanly disconnect: close WS, suppress reconnect, kill spawned companion, drop session file. |
| diagnose | Health check — companion reachability, SDK + SWC-plugin versions + wiring, recommendations. |
| read_file | Project-scoped file read. Desktop fallback (Code has native Read). |
| apply_edit | Project-scoped string-replacement edit. Desktop fallback (Code has native Edit). |
| write_file | Project-scoped full-file write. Desktop fallback. |
| list_cloud_issues | List open InSitue Cloud bug reports for the linked project. Paid plan + insitue link required. |
| claim_cloud_issue | Claim an issue by id; returns note, source file:line, page URL, and top console errors. |
| resolve_cloud_issue | Mark an issue resolved; attach prUrl and optional branch. |
| release_cloud_issue | Return a claimed issue to the open queue. |
| authenticate | Start browser sign-in (PKCE): chooses the device vs loopback flow automatically and returns the authorize URL + code to confirm. |
| complete_authentication | Poll for approval (~5 min), then save credentials and best-effort auto-link the current repo to its project. |
| logout | Revoke the token server-side and clear local credentials. |
All file tools resolve paths against the project dir and refuse
anything that resolves outside it (realpath-checked, so .. games
are blocked). On Claude Code the agent prefers its native tools;
the project-scoped ones exist primarily for Claude Desktop, which
has no built-in file tools.
Trust boundary
The companion is the only process that holds the user's edit
authority — it spawns from the project dir, writes only inside it,
and is gated by the WS handshake's loopback bind + per-session
token. The MCP bridge here is a read-side subscriber that
broadcasts picks into the chat. Writes still require the human
in the terminal to say "yes" before the agent calls apply_edit
(or its native equivalent).
Stability
The plugin's MCP tool surface is what consumers depend on. We treat tool name/argument changes as breaking; descriptions and internal behaviour can evolve in patch releases.
Versioning
- Major — backwards-incompatible changes to the MCP tool
surface (renames, removed tools, argument shape changes), or
changes that require the user to re-run
setup. - Minor — additive tools, optional new arguments, new env vars, new CLI subcommands.
- Patch — bug fixes, docs, internal refactors, version-pin bumps for transitive deps.
The plugin pins the InSitue WS protocol version (5 at the time
of writing) against the companion. A mismatch is rejected at the
handshake rather than silently degraded.
Security
Report vulnerabilities privately — see SECURITY.md
in the repo root. Especially relevant for this package: anything
that lets the bridge accept frames over a non-loopback bind, that
lets apply_edit / write_file escape the resolved project dir,
or that leaks the session token outside the local machine.
License
MIT. Same as the rest of InSitue.
