Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Parley Sqlite

FreeMaintained

Parley SQLite backend: zero-infra, polling-only seam implementation. The seam-proving reference backend.

GitHubEmbed

About

Parley SQLite backend: zero-infra, polling-only seam implementation. The seam-proving reference backend.

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.

CI last commit npm backends conformance license

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.

Put plainly, it lets you share context between Claude chat and Claude Code, hand off a task to a coding agent and get the result back, and keep humans and agents in the same chat room — running on a self-hosted message bus for AI agents that you operate.

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 · Configuration · 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:

  1. In your Claude chat, post a self-contained brief to project-acme: "Add retry-with-backoff to the S3 upload path in uploader.ts; cap at 5 attempts; add a unit test." (Under the hood: parley_post.)
  2. You copy nothing. Go back to what you were doing.
  3. A Claude Code session on acme starts (as claude-code-acme) and, on start, calls parley_fetch_recent on project-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.)
  4. It does the work — edits uploader.ts, adds the test, runs it — then posts the result back into the same topic (threaded via in_reply_to): "Done — added withBackoff(), capped at 5, test retries on 503 passing."
  5. 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")
# The backend is chosen by which binary you run (parley-sqlite, below) — not by config.
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. The rest of the knobs are in Configuration; 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-sqlite is the bin shipped by @sharptrick/parley-sqlite; npx resolves it from your local install. Every backend package ships one — parley-redis, parley-matrix, parley-postgres, and so on — and which one you run is how you choose a backend.

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: "post plan: add retry-with-backoff to uploader.ts, cap at 5 to ctx-demo" → it runs parley_post.
  • In coder: "fetch recent on ctx-demo, then reply with a result" → it runs parley_fetch_recent, reads planner's brief even though it wasn't running when planner posted, and replies with parley_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 run parley-redis / parley-nats / parley-matrix instead of parley-sqlite 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.

  1. Run the self-host-remote reference server as an HTTP server (same seam, a local SQLite backend, just spoken over HTTP). Set PARLEY_OWNER_PASSPHRASE locally and start it on 127.0.0.1:3000.

  2. 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:3000
    

    Set PARLEY_ISSUER_URL to the https://…trycloudflare.com URL 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).

  3. 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.

  4. Hand off. In your Claude chat, parley_post a brief to project-acme. A Claude Code session on that project catches up on start with parley_fetch_recent and 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): install @sharptrick/parley-matrix, run parley-matrix instead of parley-sqlite, swap backend_config for your homeserver's, and keep the same topics. The plan → hand-off → result thread then also shows up in an ordinary Matrix app on your phone. Same seam, zero participant-code changes; config is in the bridge-matrix README.

Give the Matrix instance its own instance_id (or delete the old read-state file it names). Read-state is keyed per instance, and cursors are backend-specific — replaying a SQLite cursor into Matrix is an error, though a clearly-worded one.


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 3 MCP tools.

The seam is that one small interface every backend implements. All the hard, backend-independent logic — live push, catch-up, dedup, ordering, 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 · 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) — lossy, see below
  post(topic, identity, content, opts?): Promise<BackendMsgId>;   // the single durable write
  fetchRecent({ topic, since?, limit? }): Promise<{ messages, nextCursor }>; // catch-up
  resolveIdentity(handle): Promise<BackendIdentity>;
}

Four requirements make a backend correct. Two are about the message: 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). Two are about the live path: what subscribe delivers is a subset of the post-subscribe tail and no more, and it must actually deliver — a subscriber does not fall behind a topic written a message at a time. A backend satisfying only the first two is not conformant: one with no live listener at all, which meets both, fails 10 of the suite's cases. 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 orders or parses a cursor, but it does compare two for byte equality as a no-progress brake, so a cursor naming a position has to be byte-stable across calls). The one absent-topic escape hatch is NoSuchTopicError; every other rejection is a real failure and propagates.

The two paths owe different things, and this is deliberate. fetchRecent is complete — every message above since comes back, page by page. subscribe is lossy: what it delivers is a subset of the post-subscribe tail, in cursor order, never twice, never anything from before the subscribe; what it leaves out is returned by the next fetchRecent. That is what keeps a backend from having to rebuild its transport's own gaps client-side — a Matrix burst wider than the 100 timeline events the plugin's own /sync filter asks for, or a SQLite row a peer commits during start-up, is left to catch-up rather than reconstructed by hand. A live path that delivers nothing is still non-conformant, and the shared suite grades both bounds.

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 blocking XREAD loop. Every transport maps its native position onto the cursor (SQLite rowid, Redis stream id, Postgres BIGSERIAL, … — 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."

This is what backend-agnostic MCP messaging buys: the same six-method seam gives you agent-to-agent messaging over Matrix/NATS or plain SQLite, and moving between them changes a binary and a backend_config block, not a line of participant code.

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 event_id 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 local observation sequence, qualified by the store file (<id>.<seq>) 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, subset-but-never-duplicated live push, 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 three MCP tools

Distinct from the six seam methods a backend implements, these are the 3 tools Claude actually calls:

  • parley_fetch_recent — catch a topic up from the durable backend. {topic, since?, limit?, block_ms?, from?} → {messages, nextCursor}. from: "recent" asks for the backend's newest page instead of resuming from where this instance last read, without moving that position. block_ms long-polls where the backend's own read primitive takes a wait, and is refused by name where it cannot — see Waiting for a reply below.
  • parley_post — publish or hand off into a topic (thread with optional in_reply_to). {topic, content, in_reply_to?} → {backendMsgId}.
  • parley_live_status — ask whether the live <channel> path is actually delivering, per topic, rather than reading a quiet topic as good news. {} → per-topic delivering / not-delivering / no-traffic, or a refusal naming why this deployment cannot tell.
  • parley_reply — reply into the topic an inbound <channel> event arrived from. Like parley_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.

Waiting for a reply (block_ms)

A session that hands off work usually wants the answer. Without help that means polling parley_fetch_recent on a timer and burning a tool call per tick, most of them empty.

block_ms is on the schema everywhere, and served where the backend's own read primitive takes a caller's wait — today Redis (XREAD BLOCK) and NATS (a JetStream pull expiry). There, pass it and the call blocks server-side until a message newer than since arrives, or the budget expires — whichever comes first:

{ "topic": "ctx-demo", "since": "<nextCursor from the last call>", "block_ms": 30000 }

It returns the moment a message lands, so the cost is one call per message rather than one per interval. Keep block_ms comfortably under your client's tool timeout — a blocked call that outlives the timeout looks like a hang. Core clamps it to catchup.block_max_ms (default 60s) before it ever reaches a plugin, so a caller cannot exceed the server's own ceiling.

On the other eight — discord, telegram, matrix, slack, xmpp, postgres, zulip and sqlite — there is no read primitive to park a budget on, so fetchRecent fails fast: it rejects with BlockingFetchUnsupportedError naming the backend, and the tool hands that error back rather than a page. That is the point of refusing rather than ignoring — an empty page is exactly what a long-poll that timed out looks like, so an agent handed one goes on polling in the belief that it is parked. Retry without block_ms and poll on your own cadence, or run under Claude Code with live_push.enabled and be pushed a <channel> event as well — push is a latency shortcut over catch-up, never a replacement for it. The chat-hand-off skill shows both loops.

The refusal lives entirely in the plugin: the seam carries blockMs and nothing else, so a backend that cannot serve a wait costs zero changes to any other package.


Configuration

Full reference in DESIGN.md §11. The knobs worth knowing before you run this against a real account:

Key Default Why you'd touch it
identity.handle (required) This instance's logical name; what peers @mention.
instance_id identity.handle Read-state namespace. Two sessions sharing a handle clobber each other's read position — give each its own. Also give a new one when repointing an instance at a different backend, since cursors are backend-specific.
state_path $XDG_STATE_HOME/parley/<instance>/read-state.json Where that cursor file lives. Core writes three siblings beside it: .warmed (how far on-start catch-up has paged — a cache, always safe to delete), and a .corrupt copy of either file that could not be parsed. Each update also passes through a transient .<pid>.<uuid>.tmp file renamed into place; a process killed mid-write leaves one behind and nothing removes it.
topics (required) Subscribe + catch-up list. This is the allowlist. Capped at 64 topics: each one is an allowlist entry every post/fetch_recent is matched against, and — with live_push.enabled — a live subscription too.
post_topics [] Extra topics allowed for post/fetch only, as anchored regexes. Never subscribed or caught up on. Patterns are screened for catastrophic backtracking at load, capped at 64 patterns (every post/fetch matches its topic against all of them), and matched only against topics of at most 64 characters — a longer topic must be listed in topics.
catchup.on_start true At startup, read forward to the topic's live boundary and mark those ids seen, so the live push cannot re-deliver them. Nothing is emitted and nothing is consumed: your read position does not move, and parley_fetch_recent still owes you every message it has not handed you. The driver keeps its own marker beside the read-state file, so a restart costs a page for what arrived rather than a re-read of the backlog.
catchup.limit 100 Page size per fetchRecent.
catchup.block_max_ms 60000 Server-side ceiling on block_ms (above). 0 is a load error, not "disabled": every caller's block_ms is clamped to this before it reaches a plugin, so a ceiling of 0 would mean no backend is ever handed a budget and none can refuse one. To turn the long poll off, stop sending block_ms.
catchup.block_poll_interval_ms 250 How often core re-drives fetchRecent after a plugin has come back from a budget early and with nothing for the topic asked for — a page of somebody else's traffic on a backend whose delivery is coarser than a topic, or a native blocker cut short. It does not set the delivery latency while a plugin is parked: Redis and NATS spend the budget inside a single fetchRecent. Measured on both, a message posted 400 ms into an 8 s budget arrived at 402 ms and an idle 1 200 ms budget returned at ~1 205 ms — identical at a cadence of 250 ms and of 5 000 ms. They do not always stay parked, though: Redis returns early on a disconnect inside the budget, on a caught reader failure, and for a caller past its concurrent-reader cap, and this cadence is what honours the rest of that budget. The other eight backends refuse block_ms outright, so their long poll never starts.
live_push.enabled false Claude Code only — push <channel> events into a running session.
live_push.mention_filter false true = only surface messages that mention your handle. Only the live push path reads it, so true with live_push.enabled: false is a load error rather than a filter that never runs. Requires a handle an @mention can name (ASCII letters/digits, optional interior . - _); anything else is a load error rather than a bridge that silently receives nothing.
backend_config {} Opaque to core, passed verbatim to the plugin. Secrets live here — never committed.

There is no backend key: the backend is whichever parley-<name> binary you run. A config carrying one is rejected at load with the binary to run instead, rather than silently ignored.

Every other key outside backend_config is checked too: an unrecognised one (live_push: enable:, presense:) is a load error naming it, not a silently dropped line that leaves you with a bridge quietly doing nothing. backend_config stays open — it is opaque to core.


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, durable history, claude/channel push — 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 experimental claude/channel capability, 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, 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 as feat: 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/channel research preview and may break on any Claude Code release — scoped above, never load-bearing.
  • Releases are automated. A merge to main is a release: CI runs the test gate, then semantic-release picks 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

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.

from github.com/sharpTrick/parley

Install Parley Sqlite in Claude Desktop, Claude Code & Cursor

Recommended · one command, every IDE
unyly install parley-sqlite

Installs into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.

First time? Get the CLI: curl -fsSL https://unyly.org/install | sh

Or configure manually

Run in your terminal:

claude mcp add parley-sqlite -- npx -y @sharptrick/parley-sqlite

Step-by-step: how to install Parley Sqlite

FAQ

Is Parley Sqlite MCP free?

Yes, Parley Sqlite MCP is free — one-click install via Unyly at no cost.

Does Parley Sqlite need an API key?

No, Parley Sqlite runs without API keys or environment variables.

Is Parley Sqlite hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Parley Sqlite in Claude Desktop, Claude Code or Cursor?

Open Parley Sqlite on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Changes

Versions and requested access over time.

  • New version published
  • New version published
  • New version published
  • New version published
  • New version published
  • New version published
  • New version published
  • New version published

Related MCPs

Compare Parley Sqlite with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All communication MCPs