Parley Nats
БесплатноНе проверен@sharptrick/parley-nats — subject->topic, JetStream seq->cursor, wildcard->subscribe. Skeleton against the frozen Parley seam — planned v0.5.
Описание
@sharptrick/parley-nats — subject->topic, JetStream seq->cursor, wildcard->subscribe. Skeleton against the frozen Parley seam — planned v0.5.
README
Plan a task in your Claude chat, hand it to a Claude Code session that catches up on the shared thread and does the work, then read the result back in a chat app you already keep open.
Parley is an MCP server — the standard way Claude connects to outside tools — that turns your Claude chat, your Claude Code sessions, and you into one shared, durable thread over a messaging backend you choose.
Contents: The loop · Two ways in · Quickstart A — local, 5 min · Quickstart B — chat→Code, 15 min · Today vs. preview · How it works · Backends · Tools · Remote / chat mode · Compare · Status · Docs
The loop
Your Claude chat and your Claude Code sessions can't talk to each other. Right now you are the cable: you copy a plan out of one window, paste it into the other, wait, then ferry the answer back. Parley is the shared thread that lets them confer over a durable backend while you watch from an ordinary chat app.
Keep Matrix open on your phone, run a Claude Code session on your acme project, and wire a Claude chat to the same topic — project-acme:
- In your Claude chat, post a self-contained brief to
project-acme: "Add retry-with-backoff to the S3 upload path inuploader.ts; cap at 5 attempts; add a unit test." (Under the hood:parley_post.) - You copy nothing. Go back to what you were doing.
- A Claude Code session on
acmestarts (asclaude-code-acme) and, on start, callsparley_fetch_recentonproject-acme— catch-up-on-start over the durable backend, not a live push — reading your brief as if it had been in the room the whole time, though it wasn't running when you posted. (The chat-handoff skill is what wires this fetch to fire automatically on session start.) - It does the work — edits
uploader.ts, adds the test, runs it — then posts the result back into the same topic (threaded viain_reply_to): "Done — addedwithBackoff(), capped at 5, testretries on 503passing." - You read the answer where you asked it — the whole plan → hand-off → result thread lands in your ordinary Matrix app. No terminal, no copy-paste.
Two ways in
The full chat→Code loop above needs remote mode: a Claude chat lives in Anthropic's cloud and can't reach a stdio server on your laptop, so chat joins the thread over an HTTP connector, not a local file. Two on-ramps — price the gap before you start:
- Kick the tires in 5 minutes — no accounts, no domain, no server; Node ≥ 22. A local taste on one SQLite file, Code↔Code. It proves the whole shared-thread spine end to end; the only thing left off is the chat seat.
- The real hand-off — needs a public HTTPS URL + a claude.ai connector; ~15 min. chat→Code over remote/OAuth mode. The maintainer runs this remote-mode hand-off in production, in a hardened Keycloak/OIDC + Zulip variant (see Remote / chat mode); Quickstart B is the lighter built-in-OAuth + SQLite on-ramp to the same mode.
About the phone. The hero's "read it back in a chat app you already keep open" is the full loop — remote mode plus a chat backend — so it's Quickstart B with one swap, not the 5-minute path. Today the honest, live-proven phone pick is Matrix (or XMPP with a MAM server); the consumer apps most people keep open are still fake-conformance (details). Quickstart B lands chat→Code and reads back in Claude chat; its Land it on your phone step swaps SQLite for Matrix to also drop the thread onto your phone.
Quickstart A: the local taste (5 min, zero infra)
The deliberate local taste — two Claude Code sessions, two directories, one SQLite file — the shared-thread spine with the chat seat left off (that's Quickstart B). No broker, no server, no flags.
Prereqs: Node ≥ 22, two Claude Code sessions, ~5 min — no accounts, no domain, no server.
Give each session its own directory so their configs and .mcp.json don't collide; both point at the same db_path, which is the bus.
1. Install core plus the SQLite backend (in each directory):
npm install @sharptrick/parley-core @sharptrick/parley-sqlite
2. Write a parley.config.yaml in each directory — identical except the handle:
# planner/parley.config.yaml (coder/ is identical but handle: "coder")
backend: local-sqlite # selects the @sharptrick/parley-sqlite plugin
identity:
handle: "planner" # session B uses "coder"
topics:
- "ctx-demo"
backend_config:
db_path: "../parley-demo.db" # BOTH sessions point at this one file — it is the bus
Defaults are catch-up-only and safe (no live push,
skip_permissions: false). The rest of the knobs live in DESIGN.md; you need none of them for the aha.
3. Point a .mcp.json in each directory at the stdio server:
{
"mcpServers": {
"parley": {
"command": "npx",
"args": ["parley-sqlite", "--config", "parley.config.yaml"]
}
}
}
parley-sqliteis the bin shipped by@sharptrick/parley-sqlite— the only runnable binary Parley ships;npxresolves it from your local install.
4. Run the hand-off. Open two Claude Code sessions, one per directory (planner and coder), both resolving to the same parley-demo.db:
- In
planner: "postplan: add retry-with-backoff to uploader.ts, cap at 5to ctx-demo" → it runsparley_post. - In
coder: "fetch recent on ctx-demo, then reply with a result" → it runsparley_fetch_recent, readsplanner's brief even though it wasn't running when planner posted, and replies withparley_post+in_reply_to. - Back in
planner: "fetch recent on ctx-demo" → the coder's threaded reply is right there.
Here you trigger each fetch by hand to watch it work; in a wired session the on-start catch-up from The loop fires automatically.
That's the round-trip. parley_fetch_recent hands back the message plus the bookmark that makes catch-up durable:
{
"messages": [
{
"topic": "ctx-demo",
"senderHandle": "planner",
"content": "plan: add retry-with-backoff to uploader.ts, cap at 5",
"backendMsgId": "1",
"cursor": "1",
"mentions": [],
"timestamp": "2026-07-12T18:03:11.204Z"
}
],
"nextCursor": "1"
}
Why this survives a restart (optional)
nextCursor is the whole trick: persist it, pass it back as since, and the next catch-up returns only messages newer than it — never re-sending one you already read. Kill coder mid-hand-off and start it again: it catches up from its bookmark, re-reads the thread, and loses nothing. Then swap backend: local-sqlite for Redis / NATS / Matrix and the same participants run across machines with zero code changes — correctness lives in the seam, not in any one host. The mechanics (cursor, backendMsgId) are spelled out in How it works.
Quickstart B: the chat-to-Code hand-off (remote mode, ~15 min)
The loop the hero promised — a Claude chat plans, a Claude Code session does the work — over the built-in OAuth front door. No external identity provider for this light path.
Prereqs: a public HTTPS URL (a one-command tunnel works) and a claude.ai connector, ~15 min. Node ≥ 22 for the server; no external IdP on this light path.
Run the self-host-remote reference server as an HTTP server (same seam, a local SQLite backend, just spoken over HTTP). Set
PARLEY_OWNER_PASSPHRASElocally and start it on127.0.0.1:3000.Put it behind HTTPS. Claude requires a public HTTPS endpoint. The fastest way is one tunnel command (install cloudflared first):
cloudflared tunnel --url http://127.0.0.1:3000Set
PARLEY_ISSUER_URLto thehttps://…trycloudflare.comURL it prints. That URL is ephemeral — for a stable one, front the server with Caddy/nginx instead (there's a ready Caddyfile in the self-host README).Add a claude.ai connector pointed at
https://parley.example.com/mcp(your HTTPS URL +/mcp). Claude runs discovery → dynamic client registration → PKCE; on the consent page, enter your owner passphrase to authorize. Backend creds never leave the server — Claude holds only a consented token.Hand off. In your Claude chat,
parley_posta brief toproject-acme. A Claude Code session on that project catches up on start withparley_fetch_recentand does the work — so the brief is waiting whether or not any session was live when you posted.
Step 4 is the real, in-production shape: chat→Code lands over the durable catch-up path. The other half — an already-running session reacting the instant you post — is the live-push preview (below), not needed here. Full recipe + connector gotchas + the optional Keycloak/OIDC front door: examples/self-host-remote/README.md.
Optional — land it on your phone. Quickstart B reads back in Claude chat. To get the hero's phone experience, swap the SQLite backend for Matrix — the live-proven phone pick (backends): point
backend:at the Matrix plugin, keep the same topics, and the plan → hand-off → result thread also shows up in an ordinary Matrix app on your phone. Same seam, zero participant-code changes; config is in the bridge-matrix README.
What runs today, and what's still preview
Two delivery paths — one is the product, one is a preview. Stated once, here:
Tier 1 — durable catch-up (the product, works today). parley_post + parley_fetch_recent over standard MCP: a session catches up on start from the backend's own store, with ordering and dedup from the cursor + backendMsgId, never timestamps. Live-tested on 6 of 10 backends against real implementations — SQLite as a real on-disk file, plus real Redis/NATS/Postgres servers and live Matrix/XMPP homeservers — with no subscription, no flag, and on the SQLite path no server at all. This is what buys restart-survival, a swappable backend, and a human reading in a real chat app — and it's what the remote hand-off in Quickstart B rides.
Tier 2 — live <channel> push (research preview). Proactive events into an already-running Code session, riding Claude Code's native claude/channel capability. Verified headless-only — an InMemoryTransport harness plus a human manual checklist — and not yet demonstrated in a real interactive Claude Code session. It needs Claude Code v2.1.80+, a claude.ai subscription or a Console API key (not Bedrock, Vertex, or Foundry), and the --dangerously-load-development-channels flag against the fakechat loopback (--channels plugin:fakechat@claude-plugins-official). It rides Anthropic's research preview and may break on any Claude Code release — treat it as experimental, never load-bearing: a dropped or duplicated push is reconciled by the next parley_fetch_recent, and Tier 1 stands on its own.
Reading on your phone. Of the 6 live backends, Matrix is a mainstream chat app with clients on every phone — the honest end-to-end pick right now (XMPP is the other, given a MAM-enabled server). The consumer apps most people already keep open — Zulip, Slack, Discord, Telegram — are fake-conformance today (see the table below; Zulip is additionally the maintainer's operator-run production backend). So for the loop end-to-end on live-proven code, reach for Matrix.
How it works
Three numbers: 10 backends, each implementing the same 6 seam methods; Claude itself calls just 4 MCP tools.
The seam is that one small interface every backend implements. All the hard, backend-independent logic — live push, catch-up, dedup, ordering, presence, reply fan-out, OAuth mode — is written once above it in @sharptrick/parley-core. Dependencies point one way: a plugin depends on core, never the reverse.
Messaging backend SQLite · Redis · Postgres · Matrix · XMPP · NATS · Zulip · Discord · Slack · Telegram
│ backend-native protocol
Backend plugin implements the seam (the six methods below)
│ normalized Message (topic · sender · content · backendMsgId · cursor · mentions)
@sharptrick/parley-core reactive tools (post · fetchRecent) + proactive push (<channel> events)
│ dedup + ordering via cursor · reply fan-out · presence · topic allowlist · OAuth mode
┌────┴───────────────────────────┐
Claude Code Claude chat · you, in a normal chat client
catch-up + live push (preview) post + fetchRecent
The whole product is these six seam methods:
interface BackendPlugin {
connect(config): Promise<void>;
disconnect(): Promise<void>;
subscribe(topic, handler): Promise<void>; // live path (push)
post(topic, identity, content, opts?): Promise<BackendMsgId>; // the single durable write
fetchRecent({ topic, since?, limit? }): Promise<{ messages, nextCursor }>; // catch-up
resolveIdentity(handle): Promise<BackendIdentity>;
}
Two invariants make a backend correct: a stable, unique backendMsgId (the dedup key — how core throws away a message it has already seen) and a monotonic cursor (an opaque, ever-advancing per-topic position). Catch-up is exclusive on since: it returns only messages newer than the cursor you pass, never re-sending it (ordering is the plugin's job; core never compares cursor values, so the cursor stays opaque). The one absent-topic escape hatch is NoSuchTopicError; every other rejection is a real failure and propagates.
Adding every backend after SQLite changed zero lines of @sharptrick/parley-core — check the git log — and one shared conformance suite proves each against the same contract.
Add a backend. Implement the six methods, point the shared conformance suite (
@sharptrick/parley-conformance) at your plugin, and ship it as its own package — core never has to know it exists. The Redis backend is a complete, conformant example in one small file:post=XADD,fetchRecent=XRANGE(stream id as the cursor),subscribe= a blockingXREADloop. Every transport maps its native position onto the cursor (SQLiterowid, Redis stream id, PostgresBIGSERIAL, … — full mapping in the table below). → packages/bridge-redis/src/index.ts
Backends
Ten backends — six live-tested against real implementations, four proven against in-process API fakes of the vendor protocol. The Verified column tells you which is which, so "10 backends" never reads as "10 live-tested backends."
| Backend | Transport / mechanism | Cursor | Verified |
|---|---|---|---|
| SQLite | local file, polling-only (WAL, no broker) | rowid |
live |
| Redis | Redis Streams, blocking XREAD push |
stream id | live |
| Postgres | table + LISTEN / NOTIFY push |
BIGSERIAL |
live |
| Matrix | hand-rolled Client-Server HTTP + /sync |
sync token | live |
| XMPP | MUC + MAM archive (server must enable MAM) | MAM id | live |
| NATS | JetStream (persistent streams) | stream sequence | live |
| Zulip | event-queue long-poll (raw fetch) |
message id | fake-conformance + operator-run |
| Discord | gateway websocket (raw ws) |
snowflake (Discord's time-sortable id) | fake-conformance |
| Slack | Socket Mode websocket (raw ws) |
ts |
fake-conformance |
| Telegram | Bot API getUpdates + local observed store |
per-chat message_id |
fake-conformance |
live— exercised against real implementations in CI/dev: SQLite on a real on-disk file, real Redis/NATS binaries, live Synapse/Prosody homeservers, and Postgres 16 (SQLite, Redis, Matrix, NATS, XMPP, Postgres — 6 of 10).fake-conformance— the same shared suite run against in-process fakes of the vendor API, not live vendor accounts: Zulip, Discord, Slack, Telegram (4 of 10). Zulip is additionally operator-run (the maintainer's own instance, below) and ships an env-gated real-credential suite (PARLEY_ZULIP_URL/_EMAIL/_API_KEY) that runs the identical seam suite against a live Zulip server. Telegram's Bot API has no pre-join history endpoint, so that backend documents the gap rather than faking backfill.
Every backend clears the identical seam contract — cursor monotonicity, exclusive-since catch-up, and double-delivery dedup — plus multi-process write safety wherever the transport allows concurrent writers (Telegram is single-writer by design: one bridge per bot token, since a second getUpdates poller gets HTTP 409, so that one conformance case is deliberately skipped). No vendor SDKs: Matrix is a hand-rolled HTTP client (not matrix-js-sdk), Discord and Slack use raw ws, Telegram and Zulip use raw fetch.
The four MCP tools
Distinct from the six seam methods a backend implements, these are the 4 tools Claude actually calls:
parley_fetch_recent— catch a topic up from the durable backend.{topic, since?, limit?}→{messages, nextCursor}.parley_post— publish or hand off into a topic (thread with optionalin_reply_to).{topic, content, in_reply_to?}→{backendMsgId}.parley_reply— reply into the topic an inbound<channel>event arrived from. Likeparley_post, it's written durably to the backend — the live channel is only the fast inbound hop, so a reply survives restart and shows up in the next catch-up.parley_list_users— the reachability roster for hand-off: who's online now plus recently-seen-but-offline peers, derived above the seam (bridges beat hello/heartbeat/goodbye on one shared presence topic) so it works identically on every backend, with no new seam method.
Remote / chat mode
The same codebase runs as a public HTTP MCP server so a Claude chat connector can reach it directly — the mechanism behind Quickstart B. It sits behind a standards-compliant built-in OAuth 2.1 + PKCE front door (dynamic client registration; standards-based discovery (RFC 9728) and audience binding (RFC 8707) — details in the docs), or delegates to an external IdP in OIDC mode (Keycloak is the tested target). It's single-tenant: backend credentials stay server-side, and Claude only ever holds a consented, audience-bound token.
For a hardened setup, the maintainer runs Parley as their own single-tenant instance behind a Keycloak/OIDC front door (issuer at auth.example.com) fronting a self-hosted Zulip backend (zulip.example.com), TLS terminated at a reverse proxy and reachable over a private tailnet — shipped infrastructure, not a roadmap slide. That's optional hardening; the built-in OAuth front door in Quickstart B is the light path.
Security posture: secrets live in backend_config / .env, never in core and never committed. A client-side topic allowlist plus anchored post_topics regexes bound each instance (e.g. general + project-.*). Inbound messages are treated as untrusted data, never as privileged instructions. SQLite uses WAL for safe concurrent multi-process writes, and retention_days pruning is opt-in on SQLite/Redis/NATS.
How it compares
- vs. localhost agent buses (xats, claude-peers-mcp, AgentBus): the one thing they fundamentally can't do is put a human reading and replying in an ordinary chat app — on their phone, off the machine. Those buses are localhost-only and agents-only. Parley is the same primitives — topics, presence,
claude/channelpush — but off one machine and carrying a human plus a Claude chat too. Should you switch from xats today? Not for live push: xats rides the same experimentalclaude/channelcapability, and Parley's is still preview-grade (above) — concede that. Switch when you want a human in a real chat app, cross-host sessions, or a durable backend you can swap: the same participants run on a local SQLite file today and Redis / NATS / Matrix / Zulip across machines tomorrow with zero participant-code changes. - vs. a plain MCP server: Parley is dual-role. A request/response server can answer
post/fetch_recent; it can't proactively push a<channel>event into a session that's already running. Parley does both (the push half is the research preview above). - What it isn't: not an agent framework (A2A, AutoGen, MindRoom) — deliberately just the seam. No built-in chat UI.
Project status & maintenance
- Single maintainer, MIT, no hosted service. It runs on infrastructure you operate — no lock-in, deliberately just the seam.
- Pre-1.0 (
v0.8.0), actively developed. See the GitHub Releases for cadence; the last-commit badge up top is the live pulse. Per project convention, early breaking changes land asfeat:until 1.0 is deliberately cut. - The one risk to price in. The product (Tier 1 durable catch-up) stands alone and depends on nothing unstable — six methods, ten backends, and zero core changes are the evidence the seam is stable. The only experimental dependency is Tier 2 live push, which rides Anthropic's
claude/channelresearch preview and may break on any Claude Code release — scoped above, never load-bearing. - Releases are automated. A merge to
mainis a release: CI runs the test gate, thensemantic-releasepicks the version bump from the PR title and publishes every package to npm in lockstep with provenance (OIDC — no tokens). See CONTRIBUTING.md. - Contributing. Dev setup, running the shared conformance suite, and the pre-PR checklist are in CONTRIBUTING.md; extending Parley with a new backend is the Add a backend callout above.
- Support: open a GitHub issue; report vulnerabilities via SECURITY.md.
Docs & license
- DESIGN.md — the source of truth for the seam, cursors, delivery paths, and security model.
- docs/CONVENTIONS.md — catch-up-on-start and the hand-off conventions.
- docs/keycloak-integration.md — OIDC / Keycloak remote-mode setup.
- skills/chat-handoff/SKILL.md — the chat-handoff skill (the full, runnable chat→code walkthrough).
- examples/fakechat-loopback/MANUAL-CHECKLIST.md — the headless live-push loopback and its manual checklist.
- examples/self-host-remote/README.md — the public remote-MCP reference deployment (the ~15-minute recipe behind Quickstart B).
- examples/dev-compose/docker-compose.yml — throwaway backends for testing (point at upstream canonical Docker setups for production).
- Per-backend details live in each packages/*/README.md.
A parley is a conference between parties to reach an understanding — which is all Parley is: one durable thread where your Claude chat, your Claude Code sessions, and you confer.
MIT licensed.
Установить Parley Nats в Claude Desktop, Claude Code, Cursor
unyly install parley-natsСтавит в Claude Desktop, Claude Code, Cursor и VS Code — сам разбирается с npx, uvx и сборкой из исходников.
Впервые? Поставь CLI: curl -fsSL https://unyly.org/install | sh
Или настроить вручную
Выполни в терминале:
claude mcp add parley-nats -- npx -y @sharptrick/parley-natsFAQ
Parley Nats MCP бесплатный?
Да, Parley Nats MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Parley Nats?
Нет, Parley Nats работает без API-ключей и переменных окружения.
Parley Nats — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Parley Nats в Claude Desktop, Claude Code или Cursor?
Открой Parley Nats на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Gmail
Read, send and search emails from Claude
автор: GoogleSlack
Send, search and summarize Slack messages
автор: SlackRunbear
No-code MCP client for team chat platforms, such as Slack, Microsoft Teams, and Discord.
Discord Server
A community discord server dedicated to MCP by [Frank Fiegel](https://github.com/punkpeye)
Compare Parley Nats with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории communication
