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

intermind

v0.0.3

Published

MCP server that lets coding agents hold threaded conversations with each other. Pair programming for AI agents.

Readme


Why this exists

Claude Code and Codex are both MCP clients. They cannot talk to each other directly. The only protocol they all already speak is MCP, so the natural meeting point is a shared MCP server they both connect to.

That's Intermind. It does one thing — move messages between agents — and gets out of the way.

Whatever agents do with a conversation — break it into tasks, exchange diffs, plan a refactor — is their job, not Intermind's. They already know how to do that work; they just need a room to do it together in.

What you get

  • 💬 Direct messages and broadcasts between any agent in your room
  • 🧵 Threaded conversations so a back-and-forth review stays grouped
  • 📥 Inbox for catching up on pending messages
  • Long-poll wait so an agent can block until its peer replies
  • 🚪 Rooms so two pairs working on different features stay isolated — agents pick the room from the current git branch automatically
  • 🔒 Bearer-token auth so agents can't impersonate each other

Six tools, a thread model, rooms. That's the whole product.

Architecture in one picture

        ┌──────────────────┐         ┌──────────────────┐
        │   Claude Code    │         │     Codex CLI    │
        │   (MCP client)   │         │   (MCP client)   │
        └────────┬─────────┘         └─────────┬────────┘
                 │ stdio                       │ stdio
                 ▼                             ▼
       ┌──────────────────┐         ┌──────────────────┐
       │ Intermind subproc│         │ Intermind subproc│
       │   (MCP server)   │         │   (MCP server)   │
       └────────┬─────────┘         └─────────┬────────┘
                │                             │
                └──────────────┬──────────────┘
                               ▼
                    ┌────────────────────┐
                    │  Room "feature-x"  │
                    │  Room "feature-y"  │
                    │  Room "main"       │
                    └────────────────────┘

Each MCP client (Claude Code, Codex, …) launches its own Intermind subprocess over stdio. Every subprocess on this machine connects to the same Intermind state, so a Claude Code session in ~/projects/api and a Codex session in ~/projects/web can find each other without any extra config. They land in the same room when they pass the same room name to join — and the agent picks the room from your current git branch by default, so per-feature pairs stay isolated automatically.

Quick start

One-click install for the supported clients:

Or one command for Claude Code:

claude mcp add --scope project intermind -- bunx -y intermind

Restart your agent, ask it "list your MCP tools" — you should see the six Intermind tools. Run the same wire-up in any second agent on the same machine and they meet automatically: each picks the room from the current git branch, and agents on the same branch land in the same room.

For every other client (Codex, Cline, Windsurf, Zed, Continue, Claude Desktop) the snippet is one block away — see Wire-up.

You need Bun ≥ 1.1.0 so bunx exists. One-liner: curl -fsSL https://bun.com/install | bash. Bun handles the rest — bunx -y intermind fetches the package on first use, caches it, runs it.

Install

The default path (bunx -y intermind in your MCP config, see above) needs no install — your coding agent fetches Intermind on first run. Use one of the alternatives below only if you want a different setup.

bun install -g intermind

Now every wire-up snippet works with command: "intermind" instead of command: "bunx".

bun install -g github:monkfromearth/intermind

Use this if you want to track main instead of the latest npm release.

Each tagged release ships single-file binaries for macOS and Linux. Grab yours from the latest release, make it executable, drop it on your $PATH:

# macOS arm64
curl -L -o intermind https://github.com/monkfromearth/intermind/releases/latest/download/intermind-darwin-arm64
chmod +x intermind
sudo mv intermind /usr/local/bin/intermind

Available: intermind-darwin-arm64, intermind-darwin-x64, intermind-linux-x64, intermind-linux-arm64. Each binary bundles the Bun runtime, so the agent host doesn't need Bun installed.

git clone https://github.com/monkfromearth/intermind.git
cd intermind
bun install

In every wire-up snippet, replace "command": "bunx", "args": ["-y", "intermind"] with "command": "bun", "args": ["run", "/absolute/path/to/intermind/src/index.ts"]. See CONTRIBUTING.md for the dev loop.

Wire it into your coding agent

The shape is the same for every client: launch bunx -y intermind over stdio. Pick yours below.

Rooms control who sees whom. Each agent passes a room name to join. Two agents see each other only when they're in the same room. By default the agent reads your current git branch (git branch --show-current) and uses it as the room — so a backend pair on feature-auth and a frontend pair on feature-billing automatically split into separate rooms with zero config. Outside a git repo, the default is "main".

Claude Code

Project-scoped (commits .mcp.json so the whole team picks it up):

claude mcp add --scope project intermind -- bunx -y intermind

Or user-scoped (just you, every project):

claude mcp add --scope user intermind -- bunx -y intermind

Restart Claude Code, then claude mcp list to verify.

Edit ~/.codex/config.toml (or a project-scoped .codex/config.toml):

[mcp_servers.intermind]
command = "bunx"
args = ["-y", "intermind"]

Create .cursor/mcp.json at your project root (or ~/.cursor/mcp.json for global):

{
  "mcpServers": {
    "intermind": {
      "command": "bunx",
      "args": ["-y", "intermind"]
    }
  }
}

Verify in Settings → Features → MCP.

Edit ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "intermind": {
      "command": "bunx",
      "args": ["-y", "intermind"]
    }
  }
}

Then in Windsurf: Cascade panel → MCP servers → Refresh.

Create .vscode/mcp.json in your workspace:

{
  "servers": {
    "intermind": {
      "type": "stdio",
      "command": "bunx",
      "args": ["-y", "intermind"]
    }
  }
}

Open Copilot Chat, switch to Agent mode — the tools become available.

Open Cline's MCP settings (Cline icon → ⚙ → Edit MCP Settings):

{
  "mcpServers": {
    "intermind": {
      "command": "bunx",
      "args": ["-y", "intermind"]
    }
  }
}

Cline reloads when you save.

In ~/.config/zed/settings.json:

{
  "context_servers": {
    "intermind": {
      "command": {
        "path": "bunx",
        "args": ["-y", "intermind"]
      }
    }
  }
}

Restart Zed.

In ~/.continue/config.json:

{
  "experimental": {
    "modelContextProtocolServers": [
      {
        "transport": {
          "type": "stdio",
          "command": "bunx",
          "args": ["-y", "intermind"]
        }
      }
    ]
  }
}

Continue picks up changes without a restart.

Edit claude_desktop_config.json (~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on Windows, ~/.config/Claude/ on Linux):

{
  "mcpServers": {
    "intermind": {
      "command": "bunx",
      "args": ["-y", "intermind"]
    }
  }
}

Quit and re-launch Claude Desktop after saving.

command:    bunx
args:       ["-y", "intermind"]
transport:  stdio

For per-client notes (verify steps, restart behaviour, gotchas), see docs/guides/clients.md.

Verify it's wired up

After restarting your coding agent, ask it: "List the MCP tools you have access to." You should see join, whoami, peers, send, inbox, listen. If those show up, you're done.

Your first conversation

A backend agent in one repo, a frontend agent in another, both on the same feature branch. They join the same room automatically and start talking.

Step 1 — In ~/projects/api (a Claude Code session on feature-checkout):

"Hop on Intermind as the backend dev — see who else is around."

The agent runs git branch --show-current, reads feature-checkout, calls join({ room: "feature-checkout", role: "backend" }), then peers. It reports back: "I'm in Intermind room 'feature-checkout'. I'm the only one here so far."

Step 2 — In ~/projects/web (a Codex session on the same branch, feature-checkout):

"Hop on Intermind as the frontend and say hi to the backend."

Same trick — Codex reads its branch, joins feature-checkout, calls peers, finds the backend agent, fires a send introducing itself.

Step 3 — Back in the backend session:

"Anything new on Intermind?"

Claude Code calls inbox, finds the frontend's hello, replies on the same thread_id. From here on, they're a pair — one room, one thread, two agents passing diffs and review comments back and forth without you babysitting either side.

What the agent does for you on join:

| You don't pass | Agent picks | | --- | --- | | room | The current git branch (git branch --show-current). Outside a git repo, "main". | | Anything else | Nothing — the agent prompts you for display_name and role if it doesn't already know them. |

The agent tells you the room name in plain words right after joining (rule 3 of the system prompt). That's your cue to tell the other agent "join room X" if it picked a different default — for example, if it ran outside a git repo and landed in "main".

Teach your agent how to use Intermind

Coding agents won't use Intermind unless their system prompt tells them to. Drop one block in once and they call inbox at the start of every turn, pick the room from your git branch, and reply on the right thread — without you babysitting.

The block lives in one file: docs/agent-system-prompt.md.

Recommended install — @-include the raw URL so updates land automatically:

@https://raw.githubusercontent.com/monkfromearth/intermind/main/docs/agent-system-prompt.md

Paste that line (or the full block from the file, if your agent doesn't support @-includes) into the file your agent reads as its persistent prompt. Pick yours:

Project-scoped (commits to the repo, picked up by the whole team):

CLAUDE.md

User-scoped (every project, just you):

~/.claude/CLAUDE.md

As a Claude Skill (loaded on demand):

~/.claude/skills/intermind/SKILL.md

User-scoped:

~/.codex/AGENTS.md

Project-scoped:

.codex/AGENTS.md
.cursor/rules/intermind.mdc

Or the legacy single-file form:

.cursorrules
AGENTS.md

(in the project root)

~/.codeium/windsurf/memories/global_rules.md

Edit ~/.continue/config.json and set the block as the value of systemMessage.

Edit ~/.config/zed/settings.json and add the block to the assistant configuration.

Drop it into whatever file your agent treats as its persistent system prompt. The block is intentionally generic — no client-specific phrasing — so the same text works in every prompt file format.

The system-prompt block is the universal floor. Coding agents are turn-based, though, so a peer message that lands mid-turn waits until the next inbox call. Stack these on top, weakest to strongest:

  • Floor (every client). The system-prompt block + the imperative descriptions baked into the tool surface (the inbox tool's description literally starts with "Call this at the START of every turn …"). Works on Cursor, Cline, Windsurf, VS Code, Zed, Continue — anywhere with no host-side hooks.
  • Claude Code mid-turn (Monitor + intermind watch). The agent spawns intermind watch --token <tok> once at session start; each new peer message becomes a notification in the agent's context while it's mid-turn, without blocking. See docs/guides/examples.md.
  • Hooks (Claude Code & Codex). Claude Code's UserPromptSubmit and Stop hooks; Codex's [hooks] block. They make "did you check the inbox" no longer a question — it runs before every prompt and after every turn. See docs/guides/examples.md.

No MCP client today routes arbitrary server-initiated notifications to the agent's context, so each client gets its own delivery path. Full reasoning: docs/decisions/0001-message-delivery.md.

Tools

The full surface — six tools, no resources, no prompts.

| Tool | Purpose | Returns | | --- | --- | --- | | join | Enter a room (display_name, role, optional room — defaults to "main") and receive a session token. | { agent_id, token, display_name, role, room, room_size, hint? } | | whoami | Confirm your identity from the session token. | { agent_id, display_name, role, connected_at } | | peers | List the other agents currently in your room (excludes you). Tokens are never returned. | { room, agents: [{ id, display_name, role, room, connected_at, last_seen }] } | | send | DM another agent by agent_id, or broadcast with to: "*" (room-scoped). Optional thread_id to continue a conversation. | { thread_id, message_ids, delivered, warning? } | | inbox | Pull pending (unread) messages addressed to you. Marks them read by default. | { messages, count } | | listen | Long-poll for the next unread message on a thread. Blocks up to timeout_sec (default 25s, max 120). | { message, timeout } |

For the full reference — every parameter, return shape, error condition, and example — see docs/guides/tools.md.

Every call after join requires the token you got back. The server derives identity from the token, so a misbehaving agent can't impersonate someone else by passing a different agent_id in arguments.

A real conversation under the hood

What the JSON-RPC actually looks like when Claude asks Codex to review a patch.

1. Both agents join the same room. Each picks the room from its current git branch — both repos are on feature-checkout.

claude  → join { display_name: "Claude",  role: "implementer", room: "feature-checkout" }
        ← { agent_id: "agt_a1b2…", token: "tok_…", room: "feature-checkout", room_size: 0 }

codex   → join { display_name: "Codex",   role: "reviewer",    room: "feature-checkout" }
        ← { agent_id: "agt_c3d4…", token: "tok_…", room: "feature-checkout", room_size: 1 }

2. Claude finds Codex and sends the patch.

claude  → peers { token: "tok_…" }
        ← { room: "feature-checkout", agents: [{ id: "agt_c3d4…", display_name: "Codex", … }] }

claude  → send { token: "tok_…", to: "agt_c3d4…", body: "please review:\n```diff\n…\n```" }
        ← { thread_id: "thr_e5f6…", delivered: ["agt_c3d4…"], message_ids: […] }

3. Codex was long-polling for work — the message is already there.

codex   → listen { token: "tok_…", thread_id: "thr_e5f6…", timeout_sec: 60 }
        ← { message: { body: "please review …", from_agent: "agt_a1b2…" }, timeout: false }

4. Codex reads, thinks, replies on the same thread.

codex   → send {
            token:     "tok_…",
            to:        "agt_a1b2…",
            thread_id: "thr_e5f6…",
            body:      "line 42 should use unwrap_or; counter-patch:\n```diff\n…\n```"
          }

5. Claude was already long-polling; the reply lands immediately.

claude  → listen { token: "tok_…", thread_id: "thr_e5f6…", timeout_sec: 60 }
        ← { message: { body: "line 42 should …", from_agent: "agt_c3d4…" }, timeout: false }

That's the whole loop. No special tools for diffs, reviews, or tasks — just messages on a thread.

Use cases

Real workflows people actually run, with the prompt you give the agent. The full prompt-by-prompt walkthroughs (with the JSON each tool call sends) live in docs/guides/examples.md.

| Use case | What happens | When to reach for it | | --- | --- | --- | | Review loop | Implementer sends a patch, reviewer replies with line-level fixes on the same thread, repeat until both agree. | Two agents, same feature, one writes and one critiques. The classic pair-programming dance. | | Backend ↔ frontend on a feature | Backend agent on the API repo and frontend agent on the web repo join the same room (auto-picked from the branch name) and trade contracts: "new endpoint shape is X", "got it, here's how I'm calling it". | Two agents in two repos working on one user-visible change. | | Async coordination | Implementer keeps coding while the reviewer reads in another window. Both inbox at the start of every turn instead of blocking on listen. | When you don't want one agent stuck waiting on the other. | | Hand-off | Agent A wraps a chunk of work, posts a status message on a hand-off thread; agent B was long-polling on that thread, picks up where A left off. | Long-running tasks where the user wants to swap who's driving. | | Broadcast | One agent fires send({ to: "*", … }) — every other agent in the room gets it. | "I'm refactoring parser/, heads up if you're touching it." | | Parallel threads | Same two agents hold multiple conversations at once, isolated by thread_id — one for the parser bug, one for the migration. | When the same pair is juggling more than one topic. | | Catching up after a crash | Your MCP client crashed mid-session. The new session calls peers to find its old agent_id, then inbox with mark_read: false to peek at the history. | Recovery — sessions are ephemeral, messages are persisted. |

Troubleshooting

The three most common issues:

| Symptom | Likely cause | | --- | --- | | Agent doesn't see the tools | Forgot to restart the agent after editing config; or intermind isn't on $PATH. Run which intermind to check. | | Two agents can't see each other | They joined different room names. Each agent picks its room from the current git branch — if one agent ran outside a git repo it landed in "main" instead. Ask both agents what room they're in (rule 3 of the system prompt makes them announce it on join) and re-join the laggard with the right name. | | listen always times out | Your peer replied without thread_id (so it started a new thread), or they aren't actually working. Fall back to inbox. |

For the full troubleshooting guide and how to get help, see docs/troubleshooting.md.

Documentation

The docs/ folder splits into guides (how to use Intermind) and a knowledge base (why it's built this way).

Guides — how to use Intermind:

Knowledge base — why Intermind looks this way:

  1. MCP primer — what the protocol actually is, in 5 minutes.
  2. Coding-agent MCP clients — how Claude Code and Codex use MCP.
  3. Transports — stdio vs Streamable HTTP.
  4. Why Intermind — the gap in MCP that this fills.
  5. Coordination model — the mailbox, threads, broadcasts.
  6. Prior art — Agent-MCP, A2A, and how we relate.
  7. Glossary — quick reference for every term.

Non-goals

Saying no is half the design. Intermind will not do any of these:

  • ❌ Tasks, todos, or workflow orchestration. Each agent already has its own task tracking.
  • ❌ A shared key/value or document store. If agents want shared notes, they post to a thread.
  • ❌ First-class diff/review/PR types. Diffs are text inside messages.
  • ❌ Editing the user's working tree. Receiving agents apply diffs with their own Edit tool.
  • ❌ A2A protocol bridging. (Complementary protocol; not in scope.)
  • ❌ A web dashboard or hosted observer.
  • ❌ Hosting or running the agents themselves.

If you want any of those, see CONTRIBUTING.md and ROADMAP.md for what's on the table and what isn't.

FAQ

No. 0.0.3 is stdio-only and assumes local trust (same machine, same user) — it covers "two agents on my laptop" but stops there. Cross-machine support via Streamable HTTP is in ROADMAP.md under "later" — no schedule.

A2A is a peer-to-peer protocol between agents. Intermind is an MCP server — every agent connects through MCP, the protocol they already speak. No new protocol surface for the agents to learn. See docs/knowledge-base/06-prior-art.md.

SQLite WAL mode allows concurrent reads and serialises writes. The message volume here — text messages between two or three agents — is far below SQLite's single-writer limits.

Yes — pass a different room value to join. One pair of agents in room: "feature-auth", another in room: "feature-billing", and they're invisible to each other. The agent defaults to the current git branch name (per the system prompt), so per-feature isolation is usually automatic — you don't have to think about it.

Not today. 0.0.3 covers everything on one laptop; cross-machine support via Streamable HTTP is in ROADMAP.md under "later" — no schedule.

Short answer: today, on Claude Code only, via the Monitor tool plus a one-line subcommand intermind watch --token <your_token>. The system-prompt block tells the agent to spawn that watcher once at session start; it tails the SQLite file and prints one JSON line per new message addressed to you. Claude Code's Monitor surfaces each line as a notification in the agent's context, mid-turn. The agent reads it, replies on the same thread_id, and goes back to whatever it was doing.

On every other client (Cursor, Cline, Windsurf, Continue, Zed, Codex), the floor is listen (long-poll, blocks the turn) plus inbox at turn start. That's not as snappy as mid-turn delivery, but it's universal.

The protocol-correct answer — server-push over MCP — doesn't have a delivery path to the agent's context on any client today (elicitation is a server-to-user dialog, not a server-to-agent-context channel). It's on the roadmap; the day a client routes arbitrary server notifications to the agent, we drop the watch subprocess. Full reasoning: docs/decisions/0001-message-delivery.md.

Check last_seen on the agent row — it bumps on every authenticated tool call. There's no presence ping; if an agent hasn't called anything in a while, you can't tell whether it's thinking or gone.

No. Intermind moves bytes. Whatever you put in body arrives at the recipient unchanged. Diffs, JSON, prose — all just text.

Contributing

PRs welcome. Read CONTRIBUTING.md first — Intermind is small on purpose, so there's a high bar for "more code." If your idea is a new tool, open an issue before sending a PR.

License

MIT © 2026 monkfromearth.