npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cursor-pair

v0.1.0

Published

A private local channel between a CLI agent (Claude Code, Codex) and your Cursor agent — edits arrive as native Cursor diffs you accept or decline.

Downloads

278

Readme

cursor-pair

Pair your CLI agent with your Cursor agent — edits arrive as native Cursor diffs you accept or decline.

CI npm coverage license

You run an agent in the terminal — Claude Code, Codex — and keep the same folder open in Cursor to review what it changed. The working-tree diff is your review queue: you read it, you don't commit yet. The problem: every new request mutates that one big diff, so you can't tell what the last step changed without re-reading everything.

The obvious workaround — git add what you already reviewed — trades one view for the other: staged-vs-unstaged shows you the earlier changes or the newest step, never both at once.

cursor-pair keeps both. It gives the two agents a private local channel: the CLI agent stops editing files itself and sends each edit as a diff, and your Cursor agent applies it with its own edit tools. Every step shows up in Cursor as a normal agent edit — you accept or decline it hunk by hunk — while the whole uncommitted diff stays in place. Chat flows both ways, so you can talk to your CLI agent without leaving Cursor.

The channel is a folder on your disk. No server, no network, nothing leaves your machine.

# In Claude Code, type /cursor — the agent runs:
cursor-pair new
# => ./.cursor-pair/1

# In Cursor chat, paste:
#   /pair ./.cursor-pair/1
# From now on the CLI agent sends diffs, Cursor applies them, you review.

Install

bun add -g cursor-pair
# or: npm install -g cursor-pair

Then install the prompt files — they teach each agent its role:

cursor-pair init cursor # .cursor/commands/pair.md       → /pair in Cursor
cursor-pair init claude # .claude/skills/cursor/SKILL.md → /cursor in Claude Code
cursor-pair init claude --global # …or into ~/.claude for all projects
cursor-pair init codex  # prints a snippet for AGENTS.md

How a session works

  1. /cursor in Claude Code — the agent creates a channel and gives you the /pair line for Cursor.
  2. /pair ./.cursor-pair/1 in Cursor — the agent connects and listens.
  3. Ask Claude for changes. Instead of editing files, it sends unified diffs into the channel; Cursor applies each one with its own edit tools and confirms with an ack (or an error saying why not). You review every step in Cursor as usual.
  4. Type into either chat. In Cursor the agent is usually inside a listen, so send your message with ⌘⏎ (Ctrl+Enter on Windows/Linux) — "send immediately": Cursor interrupts the listen, the agent forwards your message to the CLI agent and goes right back to listening. A plain Enter queues the message until the current listen step ends instead (Cursor Settings → Chat → Queue messages picks the default). The CLI agent does the thinking; the Cursor side stays on a fast, cheap model and just applies.

Escape hatch, same on both sides: start a message with .. and that agent handles it itself instead of going through the channel — ..+ turns that mode on for everything, ..- turns it back off. Plain words work too — "do it yourself" always wins. (Why not !? In Claude Code ! opens bash mode, the message would never reach the agent.) To end a session, tell either agent to stop pairing (e.g. ..stop in Cursor).

Changes are pulled, not pushed

The core trick. Nothing streams disk changes at the CLI agent — it would wake on every keystroke. Instead each side has a private accumulator it reads when it decides — normally right after waking up on a message:

cursor-pair changes ./.cursor-pair/1 --as external
# --- one merged unified diff of everything since this role last looked:
# the diffs Cursor applied, your declines (a decline reverts the file),
# your hand edits — folded together by git. Empty? "# no changes".

Reading consumes it: the baseline advances, the next call starts from now. Each role has its own baseline, so the two agents stay in sync independently. The CLI agent seeing its own applied edit come back is by design — that is how it confirms what actually landed after your review. Under the hood it is a git tree snapshot per role (your real index is never touched), so .gitignored noise — builds, node_modules — never shows up. Needs the project to be a git repository.

The channel on disk

.cursor-pair/1/
  channel.json       # protocol version, id, created at
  to-cursor.jsonl    # written by the CLI agent, read only by Cursor
  to-external.jsonl  # written by Cursor, read only by the CLI agent
  cursor.offset      # how far Cursor has read — only new messages are ever read
  external.offset
  external.baseline  # each role's "last seen" tree for `changes`
  cursor.baseline
  draft/             # the CLI agent's working copies (cleared by send-diff)

One writer and one reader per file, byte offsets instead of re-reading, and the folder is added to .git/info/exclude so it never shows up in your diff. Messages are JSONL:

{ "seq": 2, "ts": "2026-07-05T12:00:00Z", "from": "external", "type": "diff", "patch": "--- a/src/app.ts\n+++ b/src/app.ts\n@@ …" }
{ "seq": 1, "ts": "2026-07-05T12:00:03Z", "from": "cursor", "type": "ack", "ref": 2 }

| type | meaning | | ------- | ------------------------------------------------- | | chat | text for the other side (user words, questions) | | diff | a unified diff to apply exactly as given | | ack | the diff in ref is applied | | error | the diff in ref is not applied; text says why |

CLI reference

cursor-pair new [id]                     # create a channel, print its path
cursor-pair send <channel> --as <role> [--type chat|diff|ack|error]
                [--text "..."] [--patch-file file|-] [--ref N]
cursor-pair listen <channel> --as <role> [--timeout 480] [--heartbeat 30]
cursor-pair changes <channel> --as <role> [--keep]
cursor-pair draft <channel> <file...>    # copy files into the channel's draft dir
cursor-pair send-diff <channel> [--as external] # diff drafts vs project → one diff message
cursor-pair status <channel>             # message counts per side
cursor-pair init <claude|cursor|codex> [--global]

Roles: external (the CLI agent) and cursor (the IDE agent). listen blocks until a message arrives, prints it as JSONL and exits 0; on timeout it exits 2. Lines starting with # are heartbeats that keep IDE terminals from killing a "silent" process. changes is read-once; --keep peeks without consuming.

draft + send-diff are how the CLI agent authors edits without writing diffs by hand: it edits draft copies with its normal edit tools, and send-diff computes one clean unified diff (machine-perfect hunks, paths normalized to a/<file> b/<file>), sends it, and clears the drafts. Drafting a path that does not exist creates a new file.

Scope and notes

  • The IDE side is Cursor today because Cursor renders agent edits with an accept/decline review UI. The protocol itself is editor-agnostic — any agent that can run a CLI can take either role.
  • Not affiliated with Cursor (Anysphere) or Anthropic.

Requirements

  • Bun 1+ or Node.js 20+ (ESM only)
  • gitchanges and send-diff are built on it
  • TypeScript 5+ (optional — works in plain JS too)

Community

Questions, bugs, or want to hang with other builders? Join the 1gr14 community — one hub for all our open-source projects, this one included. Get help, share what you built, or just say hi: 1gr14.dev/#community

Contributing

Issues and PRs welcome. See CONTRIBUTING.md and the Code of Conduct. Commits follow Conventional Commits. Security reports: SECURITY.md.

License

MIT


Made by 1gr14, driven by community