Files
claudemesh/docs/roadmap.md
Alejandro Gutiérrez 1b28550f30
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled
docs(roadmap): v1.34.16 + broker — continuous presence shipped
Watchdogs (75s stale detect) and lease model (90s grace window for
silent reconnects) both shipped 2026-05-05.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 11:41:25 +01:00

39 KiB
Raw Permalink Blame History

claudemesh roadmap

v0.1.0 — shipped

The public launch. Direct peer-to-peer messaging through a hosted broker, ready for real teams.

  • Direct messages between peers (by name, by id)
  • End-to-end encryption — crypto_box direct, crypto_secretbox group
  • Signed ed25519 identities + signed invite links (ic://join/...)
  • Hello-sig handshake auth against the broker
  • Hosted broker at wss://ic.claudemesh.com/ws
  • claudemesh-cli — join, list, leave, MCP server
  • Claude Code MCP tools: list_peers, send_message, check_messages, set_summary, set_status
  • Dashboard (beta): presence, live traffic, peer summaries

v1.0.0-alpha — shipping now

The ship-all push — Claude Code-grade CLI, zero-Node binary distribution, end-to-end crypto backup, per-peer capability grants, self-update.

  • Single-binary distributioncurl -fsSL claudemesh.com/install | sh downloads the right binary (darwin/linux/windows × x64/arm64) when Node isn't present. GitHub Releases auto-publishes on each cli-v* tag.
  • claudemesh:// URL scheme — invite emails become one-click. claudemesh url-handler install registers the scheme per-OS.
  • claudemesh <url> — join + launch in one command. -y makes it fully non-interactive for CI.
  • Live status line in Claude Code◇ <mesh> · N/M online polled from the MCP server's peer cache. Enable with claudemesh install --status-line.
  • Per-peer capability grantsclaudemesh grant/revoke/block/grants. Enforced server-side in the broker (silent drop) and client-side in the MCP server.
  • Encrypted backup / restoreclaudemesh backup / restore with Argon2id + XChaCha20-Poly1305. Portable .cmb recovery file.
  • Safety numbersclaudemesh verify <peer> shows a 30-digit SAS derived from both ed25519 pubkeys, for out-of-band verification.
  • Shell completionsclaudemesh completions zsh|bash|fish.
  • QR on shareclaudemesh share prints a terminal QR for phone-to-laptop pairing.
  • Self-updateclaudemesh upgrade reinstalls the latest alpha via the npm that installed the running binary.
  • Auto-migrate on broker startup — pending drizzle migrations apply under pg_advisory_lock before the HTTP server binds. Exits non-zero on failure so Coolify fails the healthcheck closed.
  • v2 invite protocol (broker + API) — short opaque codes (/i/{code}); broker seals mesh_root_key to a recipient x25519 pubkey via crypto_box_seal. CLI migration tracked at .artifacts/specs/2026-04-15-invite-v2-cli-migration.md.
  • Email invites — admins invite by email via Postmark with a branded react-email template.

v1.5.0 — shipped

CLI-first architecture lock-in. The CLI becomes the API; MCP becomes a tool-less push-pipe. Spec: .artifacts/specs/2026-05-02-architecture-north-star.md.

  • Tool-less MCPtools/list returns []. Inbound peer messages still arrive as experimental.claude/channel notifications mid-turn. Bundle size -42% (250 KB → 146 KB).
  • Resource-noun-verb CLIpeer list, message send, memory recall, etc. Legacy flat verbs (peers, send, remember) remain as aliases.
  • Bundled claudemesh skill — installed to ~/.claude/skills/claudemesh/ by claudemesh install. Sole CLI-discoverability surface for Claude.
  • Unix-socket bridge — CLI invocations dial ~/.claudemesh/sockets/<slug>.sock to reuse the push-pipe's warm WS (~220 ms warm vs ~600 ms cold).
  • --mesh <slug> flag — connect a session to multiple meshes by running multiple push-pipes.
  • Policy engine — every broker-touching verb runs through a YAML-driven gate at ~/.claudemesh/policy.yaml (auto-created with sensible defaults). Destructive verbs prompt; non-TTY auto-denies. Audit log at ~/.claudemesh/audit.log.
  • --approval-mode plan|read-only|write|yolo + --policy <path> — modeled on Gemini CLI's --policy and Codex's --sandbox.

v1.6.0 — shipped

The v0.2.0 backend cut. Topics, REST gateway, and bridge peers — all in one CLI release.

  • Topics (channel pub/sub)claudemesh topic create|list|join|leave|send. Mesh = trust boundary, group = identity tag, topic = conversation scope. Three orthogonal axes. Broker persists per-topic message history.
  • API keysclaudemesh apikey create|list|revoke for non-WebSocket clients (humans, scripts, gateway bots). Scoped per-mesh with read,send capabilities.
  • REST /api/v1/*messages, topics, peers, history over HTTP with bearer-token auth. Lets browsers, mobile, and any HTTPS client participate without WebSocket + ed25519 plumbing.
  • Bridge peersclaudemesh bridge run <config.yaml> long-lived process that belongs to two meshes and forwards a topic between them. Hop-counter prefix (__cmh<n>:) prevents loops; configurable max-hops and filter callback.
  • Humans-as-peerspeer_type: "human" plumbed end-to-end. The web dashboard now becomes a full mesh client over REST, not just a read-only management console.

Spec: .artifacts/specs/2026-05-02-v0.2.0-scope.md.


v1.6.x — patch line, polish what shipped

Closes loose ends from the v1.6.0 cut so the v0.2.0 backend feels production-grade before any new architectural work.

  • Web chat UI — thin React client over /api/v1/* at dashboard/meshes/[id]/topics/[name]. Auto-issues an apikey for the signed-in dashboard user. Every mesh ships with a default #general topic auto-created on creation. Shipped 2026-05-02.
  • Custom migration runner — drizzle's _journal.json replaced with filename + sha256 in mesh.__cmh_migrations. Unblocks every future schema change. Shipped 2026-05-02.
  • Owner peer-identity at mesh creation — web-first owners get a mesh.member row at sign-up time. Shipped 2026-05-02.
  • Real-time push (SSE)GET /api/v1/topics/:name/stream replaces 5s polling. Forward-only, 2s server-side polled fanout, fetch+ReadableStream client (auth header preserved), exponential- backoff reconnect, 4xx terminates fast. Shipped 2026-05-02.
  • Unread counts via last_read_atPATCH /v1/topics/:name/read
    • per-topic unread on GET /v1/topics; clay-rounded badges on the per-mesh topic list and aggregate badge per mesh on the dashboard universe page. Shipped 2026-05-02.
  • /v1/peers includes humans — recently-active apikey holders (5-minute window) appear alongside WS-connected sessions, so the dashboard chat user is visible to CLI peers calling list_peers. Shipped 2026-05-02.
  • Bridge end-to-end smoke test — two-mesh forwarding validated before any external demo.

v1.7.0 — the demo cutshipped

The release that turns claudemesh into a thing you can record and show to non-technical audiences. CLI v1.7.0 published to npm 2026-05-02 with terminal parity for the new server features.

  • Member sidebar in the chat panel — names, online dots, presence summaries (free with SSE). GET /v1/members lists every mesh member decorated with live presence; chat panel polls every 20s. Shipped 2026-05-02.
  • Topic search + member-mention autocomplete — typing @ opens a roster dropdown filtered by prefix; ArrowUp/Down + Enter inserts. Search toggle in chat header client-filters loaded messages. Shipped 2026-05-02.
  • Notification feed at /dashboard — "Recent mentions" section on the universe page lists every @<your-name> reference across all your meshes (last 7 days). GET /v1/notifications mirrors for api-key clients. Shipped 2026-05-02.
  • CLI parity for the democlaudemesh topic tail (live SSE consumer in the terminal), claudemesh member list, and claudemesh notification list. Each auto-mints + revokes a 5-minute apikey. Shipped in CLI v1.7.0, 2026-05-02.
  • First public blog post + recorded demo — blog post shipped 2026-05-02 (/blog/agents-and-humans-same-chat); recorded video pending a screen-capture session.
  • Marketing site refresh — timeline next block updated. Screenshots pending a Chrome session.

v0.9.0 — daemon foundationshipped

The bridge release that lands the persistent local runtime without the v2.0.0 surgery. Existing flows (claudemesh launch, MCP, cold sends) keep working unchanged; opt-in by running claudemesh daemon up and the rest of the CLI starts routing through the local socket.

  • claudemesh daemon up — long-lived process holding one broker WS per attached mesh, durable outbox/inbox in SQLite, IPC over UDS (+ optional loopback TCP w/ bearer), SSE event stream.
  • Caller-stable idempotency — every send carries a client_message_id and a canonical request_fingerprint (sha256 over envelope shape). Broker persists both on mesh.message_queue and echoes them on push. Receiving daemons dedupe their inbox by client_message_id.
  • §4.5.1 IPC duplicate-lookup table — 11 cases × 5 statuses × match/mismatch covered by 15 unit tests.
  • claudemesh send daemon routing — daemon path tried first when its UDS exists; falls back to bridge / cold path otherwise. JSON output gains via:"daemon".
  • Service installdaemon install-service --mesh <slug> writes a launchd LaunchAgent on macOS / systemd-user unit on Linux. Refuses CI envs unless --allow-ci-persistent.
  • Outbox CLIdaemon outbox list [--failed|--pending|...], daemon outbox requeue <id>. Atomic abort+insert with superseded_by chain on requeue.
  • Host-fingerprint pindaemon accept-host records a sha256(machine-id || first-stable-mac) on first run; later restarts refuse if the fingerprint shifts (accidental-clone detection).
  • Sprint 7 deferred — broker-side dedupe enforcement (partial unique index on (mesh_id, client_message_id), mesh.client_message_dedupe atomic-accept table) intentionally postponed; tracked at .artifacts/shipped/2026-05-03-daemon-spec- broker-hardening-followups.md.

Locked spec: .artifacts/shipped/2026-05-03-daemon-spec-v0.9.0.md.


v0.9.x — daemon promotion: required + thin MCPshipped

The v0.9.0 foundation got promoted in three quick releases:

  • 1.24.0 — daemon required for in-Claude-Code use. MCP server shrinks from 979 to ~200 LoC of push-pipe (rest is the unrelated mesh-service proxy mode). claudemesh install auto-installs and starts the daemon service. claudemesh launch ensures daemon is running before spawning Claude.
  • 1.25.0 — Sprint 4 outbound routing fix. Daemon was sending every outbox row as broadcast (*); now resolves and encrypts at IPC accept time, drain is a forwarder. Adds mesh, target_spec, nonce, ciphertext, priority columns to the outbox.
  • 1.25.0 — CLI thin-client routing for peer list, skill list, skill get.
  • 1.25.0 — ambient mode: raw claude Just Works after claudemesh install.

What this leaves on the v2.0.0 redesign is documented at .artifacts/specs/2026-05-04-v2-roadmap-completion.md.


v1.26.0 → v1.30.0 — Sprint A toward v2shipped

The Sprint A push completed everything spec'd for v2.0.0 except HKDF identity (deferred for security review).

  • 1.26.0 — multi-mesh daemon. One process attaches to every joined workspace simultaneously. Aggregate read routes (/v1/peers, /v1/skills) tag each record with its mesh; explicit ?mesh=<slug> narrows server-side. Outbox dispatch picks the right broker via the mesh column.
  • 1.27.0 — thin-client expansion to state + memory. state get, state set, state list, remember, recall, forget all route through /v1/state and /v1/memory. First teaser of the claudemesh workspace <verb> alias surface.
  • 1.27.1 — wired six previously-dead launch flags through the CLI entrypoint (--role, --groups, --message-mode, --system-prompt, --continue, --quiet). Pure plumbing fix.
  • 1.27.2 — bundled SKILL.md gains a canonical fully-populated spawn template + per-flag annotation table for unattended scripting.
  • 1.27.3 — self-healing daemon lifecycle. Every CLI verb probes /v1/version (no more stale-socket false positives), auto-spawns a detached daemon up under a file-lock when down, polls until live. 30 s recently-failed marker prevents thundering-herd retries.
  • 1.28.0 — bridge tier deletion (~600 LoC dead code removed) + per-process daemon policy: --strict (refuse cold fallback) and --no-daemon (skip daemon entirely). Single chokepoint at withMesh. Env equivalents.
  • 1.29.0 — per-session IPC tokens. Every claudemesh launch mints a 32-byte token under tmpdir mode-0600, registers it with the daemon, exposes the path via CLAUDEMESH_IPC_TOKEN_FILE to children. Daemon resolves Authorization: ClaudeMesh-Session <hex> to a SessionInfo. CLI invocations from inside a launched session auto-scope to its workspace instead of aggregating across all joined meshes (verified: peer list returns 1 workspace's peers with token, all 3 without). Server-side meshFromCtx() plumbing on every read route.
  • 1.30.0 — per-session broker presence. Two claudemesh launch sessions in the same cwd finally see each other in peer list. Each launched session has a long-lived broker presence row owned by the daemon, identified by a per-launch ephemeral keypair vouched by the member's stable key (OAuth-refresh-vs-access shape). Broker gains a session_hello handler with parent-attestation TTL ≤24h + session- signature checks; daemon adds a slim SessionBrokerClient and registry lifecycle hooks. Also fixes a latent 1.29.0 TDZ bug where claudemesh launch's IPC session-token registration was silently failing every run. Side-cleanup: 87 accumulated TS errors (77 broker, 10 CLI) paid down to zero. Shipped 2026-05-04 in CLI v1.30.0. Spec at .artifacts/specs/2026-05-04-per-session-presence.md.

What's left for true v2.0.0 (next sessions):

  • 1.31.0 — launch wizard refactor (single render loop, daemon-as- step probe panel, last-used persistence, drop @ts-nocheck).
  • 1.32.0 — setup wizard refactor (state-detection snapshot, four- branch flow, daemon install offer, post-join panel).
  • 1.33.0 — full mesh→workspace public-surface rename in help/docs/ site; mesh aliases tagged deprecated; protocol/DB stay mesh_*.

v1.31.0 → v1.32.0 — multi-session UX bundleshipped

The Sprint B push that made multiple Claude Code sessions on the same daemon actually pleasant — self-identity via session pubkey, --self fan-out, broker welcome.

  • 1.31.x — peer list shows profile.role and groups; resolves hex prefixes to full pubkeys before send; clean rebuild path with correct VERSION baked in.
  • 1.32.0 — multi-session UX bundle (self-identity, --self fan-out, broker welcome). Shipped 2026-05-04 in CLI v1.32.0.

v1.34.x — multi-session correctness trainshipped

The 2026-05-04 ship train — seven releases over a few hours that took claudemesh from "works for one session" to "internally consistent for N sessions on one daemon." Every layer that was shared between sessions either grew per-recipient scoping or demuxed at its boundary.

The throughline: any time the daemon held shared state — bus, inbox, broker fan-out — two sessions belonging to the same member silently saw each other's traffic. Each release fixed one layer, each release exposed the next gap.

  • 1.34.7 — inbox flush + delete commands. First-class CLI cleanup for the persisted inbox; previously you had to drop into raw sqlite3. claudemesh inbox flush --mesh|--before|--all with --all confirmation guard, plus claudemesh inbox delete <id>. Shipped 2026-05-04.
  • 1.34.8 — read-state + TTL prune + first echo guard. New seen_at column on inbox; live channel emits + interactive listings flip it; welcome filters on seen_at IS NULL instead of an arbitrary 24h window. Hourly prune deletes rows older than 30 days. First attempt at a self-echo guard at the WS boundary (later proven incomplete in 1.34.13). Shipped 2026-05-04.
  • 1.34.9 — broader echo guard + system event polish. Daemon-WS guard relaxed (1.34.8 required both axes; session-attributed echoes carry session pubkey on senderPubkey so the strict filter never triggered). Session-WS skips system events to dedupe peer_join broadcasts. Richer peer-join channel render (pubkey prefix + groups + last-seen for peer_returned). Daemon-staleness warning when CLI ≠ running daemon version. Shipped 2026-05-04.
  • 1.34.10 — per-session SSE demux + universal daemon. The bus stays single-shot; demux happens at the SSE bind layer via SseFilterOptions. Each subscriber's session token resolves server-side to a session pubkey + member pubkey, and shouldDeliver filters on recipient_pubkey + recipient_kind. Also: daemon up and install-service deprecate --mesh / --name (universal daemon attaches to every joined mesh automatically); daemon_started boot log stamps the version. Shipped 2026-05-04.
  • 1.34.11 — inbox per-recipient column. Storage half of 1.34.10. New recipient_pubkey + recipient_kind columns on inbox (indexed, non-destructive migration; legacy rows land NULL and stay visible to everyone). listInbox accepts recipientPubkey + recipientMemberPubkey; /v1/inbox resolves them from the session token. Welcome auto-fixes — it already passed the token. Shipped 2026-05-04.
  • 1.34.12 — daemon up detaches by default. Pre-1.34.12 ran in foreground and streamed JSON logs to the terminal until Ctrl-C. Now spawns a detached child re-execing daemon up --foreground with stdout/stderr → ~/.claudemesh/daemon/ daemon.log; parent exits cleanly with pid + log path. Service units (launchd plist, systemd-user) explicitly pass --foreground so the service manager owns lifecycle. Shipped 2026-05-04.
  • 1.34.13 — MCP forwards session token on /v1/events. The actual fix that activated 1.34.10's demux. The MCP server's SSE subscription wasn't sending the session token, so the daemon's /v1/events resolved session to null and the demux filter was empty — every MCP received the unfiltered global stream. subscribeEvents now passes Authorization: ClaudeMesh-Session <token>. Shipped 2026-05-04.

Architecture invariant after 1.34.13

Every shared store / channel on the daemon now scopes by recipient. Single bus + single tables remain canonical; demux is isolated to one chokepoint per layer.

Layer Scoping mechanism Shipped
EventBus SSE demux at bind layer + token forwarding 1.34.10 + 1.34.13
inbox.db recipient_pubkey / recipient_kind columns 1.34.11
outbox.db sender_session_pubkey for routing 1.34.0

Known gaps — status after the 2026-05-04 follow-up sprint

Three of the four 1.34.x triage gaps shipped in 1.34.14 + 1.34.15 (2026-05-04). Gap #4 is spec'd and queued.

  • Stale CLAUDEMESH_CONFIG_DIR falls back (1.34.14). The env var no longer silently breaks subsequent CLI calls. When the inherited path points at a tmpdir that no longer exists, paths.ts warns once on stderr (TTY-only) with a shell-specific unset hint and falls back to ~/.claudemesh. The dir-existence check (not config.json) keeps fresh-launch first-write working.
  • peer list --mesh <slug> actually scopes (1.34.15). Diagnosis from the original triage was wrong — broker has been scoping correctly since 1.26.0 via conn.meshId. Bug was CLI- side: tryListPeersViaDaemon() was called with no argument in commands/peers.ts:140 and commands/launch.ts:407. Both now forward the slug as ?mesh=<slug>. send.ts cross-mesh hex- prefix resolution intentionally untouched.
  • kick refuses no-op kicks on control-plane (1.34.15). Broker now skips peers where peerRole === "control-plane" and surfaces them in a new additive ack field skipped_control_plane; CLI reads it and points the user at ban (remove member) or daemon down (take a daemon offline locally). Soft disconnect keeps old behavior — useful when intentionally nudging a control-plane peer to re-authenticate. PeerConn gains a peerRole slot populated at both connections.set sites. The richer presence pause [--mesh X] verb (option (b) from the triage) deferred as its own feature.
  • 📋 Session capabilities — spec only. Launched sessions still inherit all member grants transitively. Spec at .artifacts/specs/2026-05-04-session-capabilities.md covers a v2 parent attestation alongside v1 with an allowed_caps[] subset, broker enforcement as intersection(member.peerGrants, session. allowed_caps), and a bonus state-write cap to close the "any session can clobber shared keys like current-pr" footgun. Default when no caps subset is declared = full member set (today's behavior; opt-in restriction). Ships behind a 1-week dry-run window before flipping enforcement, mirroring the original per-peer-capabilities rollout. ~1 sprint of focused work; queued behind v0.3.0 topic-encryption.

v1.34.16 + broker — continuous presenceshipped

User report on 2026-05-05: claudemesh peer list returned zero peers despite running sessions. Diagnosis: half-dead WS connections that NAT/CGNAT silently dropped, with no application-layer staleness detection on either side. Linux TCP keepalive default ≈ 2hrs idle

  • 11min probes — sessions stayed zombie for hours before the kernel RST'd the socket and the daemon's existing close-handler reconnect fired.

Two layers shipped together:

  • Liveness watchdogs (broker + CLI 1.34.16). Both sides now detect stalled WS in 75s instead of waiting for the kernel.
    • Broker: PeerConn.lastPongAt bumped on every pong. The 30s ping loop also calls ws.terminate() on conns whose pong is

      75s stale, firing the close handler → existing peer_left cleanup.

    • Daemon: ws-lifecycle.ts adds an idle watchdog at 30s cadence, started after hello-ack. Bumps lastActivity on incoming message + ping + pong frames. Sends its own sock.ping() if activity is recent, sock.terminate() if idle >75s. Watchdog cleared on close + explicit close().
    • 100x improvement on detection time (2hrs → 75s).
  • Lease model (broker only, no protocol change). Peers no longer see peer_left/peer_joined for transient reconnects.
    • PeerConn gains leaseState ("online"|"offline"), leaseUntil, evictionTimer. On WS close, the conn enters offline-leased state for 90s instead of immediate cleanup.
    • handleHello and handleSessionHello check for an offline- leased entry matching the stable identity before running session- id dedup. On match: clear evictionTimer, swap ws, restore online state, drain queued DMs, return silent: true. The hello dispatcher skips the peer_joined broadcast.
    • evictPresenceFully extracted from the close handler — runs the peer_left broadcast + cleanup (URL watches, streams, MCP registry, clock auto-pause). Called by evictionTimer after 90s grace, or directly when no lease was online (defensive).
    • broker.ts exports restorePresence(presenceId) — clears disconnectedAt + bumps lastPingAt, called on reattach to undo the DB-level stale-presence sweeper if it fired during grace.
    • DMs sent during grace fall through to the existing message_queue path (sendToPeer no-ops on dead WS, queue row stays with deliveredAt=NULL, drained on reattach). Backward compatible with old daemons.

Spec at .artifacts/specs/2026-05-05-continuous-presence.md. Layer 3 (resume token to skip full attestation on reconnect) deferred — pure optimization, not needed for the user-visible "no invisibility moment" goal.

Shipped 2026-05-05.


v2.0.0 — HKDF cross-machine identity

The remaining v2 promise after Sprint A: the user's account secret derives a deterministic ed25519 keypair per workspace. Same identity across laptop + desktop + server, no key copy ritual.

  • HKDF(account_secret, info: "claudemesh/mesh/<mesh_id>/peer", salt: <user_id>) — derived per-workspace.
  • Broker account_secret distribution — vended on first authenticated install over TLS. Needs design review on key compromise recovery story.
  • Migration — existing keypairs in config keep working. Opt-in re-enrollment for users who want cross-machine sync.
  • Hello-sig protocol — unchanged.

Reserved as its own sprint with an explicit security-review window. Estimated 2-3 weeks.


v0.3.0 — the operator layer

For teams that want to run their own broker, encrypt at the topic level, or wire claudemesh to messaging surfaces beyond Claude Code.

  • Per-topic encryption — phase 1: notification table — write- time @-mention fan-out via mesh.notification, replacing the regex-on-decoded-ciphertext scan. Survives the cutover to real ciphertext. Shipped 2026-05-02 (migration 0025).
  • Per-topic encryption — phase 2: schema + creator seal — topics generate a 32-byte symmetric key on creation; broker seals via crypto_box for the creator. New columns: topic.encrypted_key_pubkey, topic_message.body_version, and a topic_member_key table for sealed per-member copies. New API: GET /v1/topics/:name/key. Shipped 2026-05-02 (migration 0026). Spec at .artifacts/specs/2026-05-02-topic-key-onboarding.md.
  • Per-topic encryption — phase 3 (CLI) — pending-seals endpoint, seal POST, CLI services/crypto/topic-key.ts, claudemesh topic post for encrypted REST sends, decrypt-on-render in topic tail, 30s background re-seal loop. Wire format: <32-byte sender x25519 pubkey> || crypto_box(topic_key) so re-sealed copies decode like creator-sealed copies. Shipped 2026-05-02 in CLI v1.8.0.
  • Per-topic encryption — phase 3.5 (web) — browser-side persistent ed25519 identity in IndexedDB + POST /v1/me/peer-pubkey sync + web chat encrypt-on-send / decrypt-on-render. The dashboard's throwaway pubkey is replaced on first chat-panel mount with one whose secret the browser actually holds; the existing CLI re-seal loop seals the topic key against it within 30s. Composer shows 🔒 v0.3.0 when keyed and "waiting for a CLI peer to share the topic key" while not_sealed. Shipped 2026-05-02.
  • v0.3.1 — topic message threading (reply-to)topic_message gains a self-FK reply_to_id column (migration 0027); REST POST /v1/messages and the WS send envelope accept replyToId; broker validates same-topic membership. CLI: topic post --reply-to <id> (full id or 8+ char prefix), topic tail renders ↳ in reply to <name>: "<snippet>" above replies and emits #xxxxxxxx short ids per row for copy-paste. WS push envelope + MCP <channel> channel attributes now carry senderMemberId, senderName, topic, message_id, reply_to_id so the recipient has everything needed to thread a reply without a follow-up query. Shipped 2026-05-02 in CLI v1.9.0.
  • v0.4.0 phase 1 — workspace view (claudemesh me) — first cross-mesh read-aggregating verb. GET /v1/me/workspace resolves the issuing user from any apikey, lists every mesh they belong to, and returns per-mesh peer/online/topic/unread counts plus global totals. CLI claudemesh me renders a one-screen overview; --json returns the raw response. Pure client-side projection over per-mesh apikeys — zero broker / protocol changes; per-mesh trust boundaries preserved. Shipped 2026-05-02 in CLI v1.10.0. Spec at .artifacts/specs/2026-05-02-workspace-view.md.
  • v0.4.0 phase 2 — claudemesh me topics + dashboard parityGET /v1/me/topics aggregates topics across every mesh the caller belongs to with per-topic unread counts and last-message timestamps, sorted by activity. CLI verb renders the feed with --unread filter and --json output. Web dashboard adds a matching /dashboard/topics page (SSR, direct DB) with a Topics entry in the sidebar between Meshes and Invites. Shipped 2026-05-03 in CLI v1.11.0.
  • v0.4.0 phase 3 — claudemesh me notifications + dashboard parityGET /v1/me/notifications aggregates @-mention rows across every joined mesh in a 7-day window (?since=ISO override, ?include=all to surface already-read). CLI verb prints unread feed with sender + topic + snippet (or [encrypted] for v2 ciphertext). Web dashboard adds /dashboard/notifications with a "show all" toggle, matching the universe page's mention card aesthetic. Shipped 2026-05-03 in CLI v1.12.0.
  • v0.4.0 phase 4 — claudemesh me activity + dashboard parityGET /v1/me/activity returns recent topic messages across every joined mesh in a 24h default window (?since=ISO), excluding messages the caller authored themselves ("what's happening that I missed"). CLI verb prints a condensed feed; web /dashboard/activity clusters consecutive messages from the same topic into thread blocks with sender + relative timestamp. Shipped 2026-05-03 in CLI v1.13.0.
  • v0.4.0 phase 5 — claudemesh me search + dashboard parity — final aggregating verb. GET /v1/me/search?q=...&limit=N matches against topic names + sender display names + v1 message snippets (server-side base64 decode + ILIKE). v2 messages match only on topic/sender (server doesn't hold their topic keys). 30-day window for messages keeps the scan bounded. CLI verb yellow-highlights matches inline; web /dashboard/search adds a focused search input + <mark> highlighting + 30-day scan note. Shipped 2026-05-03 in CLI v1.14.0. v0.4.0 substrate is complete — every aggregating read verb now has CLI + web parity.
  • v0.5.0 phase 1 — default-aggregation for topic list + notification list — when no --mesh is passed these verbs now route through /v1/me/topics and /v1/me/notifications instead of prompting. --mesh foo keeps the per-mesh behavior. Shipped 2026-05-03 in CLI v1.15.0.
  • v0.5.0 phase 2 — default-aggregation for task list, state list, memory recall — three new aggregator endpoints land: /v1/me/tasks (open + claimed by default, ?status=all|open|claimed|completed), /v1/me/state (every key/value across meshes, ?key=foo filters), and /v1/me/memory?q= (ILIKE on content + tags, no-query default returns last 30d). CLI: omitting --mesh on each verb routes through the matching aggregator. Shipped 2026-05-03 in CLI v1.16.0.
  • v0.7.0 — collapse mesh.name and mesh.slug into one identifier — pre-launch correction of a piece of generic SaaS scaffolding that was earning no keep here. Every visible surface (CLI picker, --mesh flag, dashboard sidebar, broker presence rows) already keyed on slug; name was a parallel string that confused users on rename ("I renamed it but nothing visible changed"). Now: slug IS the identifier. claudemesh rename <old-slug> <new-slug> is the entire rename surface — there is no separate display name. CLI picker drops the (parens). Server PATCH /api/cli/meshes/:slug body becomes { slug }; the route writes both columns to keep them in sync. New mesh creation derives slug from input.name and stores name = slug. The mesh.name DB column is kept for now (avoids touching ~25 reader sites in queries.ts / v1-router.ts / dashboard pages) and always equals slug; a follow-up migration drops it. The just-shipped claudemesh slug verb (v0.6.2) is removed — its semantics merge into rename. Shipped 2026-05-03 in CLI v1.21.0 + web.
  • v0.6.2 — claudemesh slug <old> <new> — change a mesh's URL-safe slug (the identifier the CLI picker, --mesh flag, and dashboard sidebar all key on). Slugs are NOT globally unique — mesh.id is canonical — so the route only validates the regex (^[a-z0-9][a-z0-9-]{1,31}$); it does not enforce cross-user uniqueness. The CLI does refuse a local collision (two joined meshes with the same slug would make the picker ambiguous). On success, local config rewrites the slug in place; other peers heal on next claudemesh sync. Server-side reuses the existing PATCH /api/cli/meshes/:slug route — body now accepts { name?, slug? }. Shipped 2026-05-03 in CLI v1.20.0 + web.
  • v0.6.1 — claudemesh rename actually works — adds the missing endpoint PATCH /api/cli/meshes/:slug on the web app. Lives under /api/cli/* (not /api/my/*) because the CLI's device-code JWT is signed with CLI_SYNC_SECRET and can't authenticate against better-auth's enforceAuth middleware — the new route validates the JWT inline using the same HMAC-SHA256 pattern as /api/cli-sync-token. Owner-only (matches on mesh.slug AND mesh.ownerUserId). CLI calls the new path instead of the old /api/my/meshes/:slug. Closes the "API error 401: Unauthorized" the user hit after a successful claudemesh login. Shipped 2026-05-03 in CLI v1.19.1 + web.
  • v0.6.0 — claudemesh file share / get + same-host fast path — CLI parity for the file-sharing surface that was already on the broker side (HTTP /upload, WS get_file / list_files) but reachable only through MCP-style docstrings that referenced unimplemented tools. Two new verbs:
    • claudemesh file share <path> [--to peer] [--message "..."] [--upload]
    • claudemesh file get <id> [--out path] When --to <peer> resolves to a session running on the same hostname, the CLI skips MinIO entirely and DMs the absolute filepath — receiver reads it directly off disk. Saves bandwidth and bucket space for the common "two Claude sessions on one laptop" case. Falls back to encrypted upload when the target is remote, when sharing with the whole mesh (no --to), or when --upload forces it. Cap: 50 MB on the network path (broker- enforced); same-host fast path has no cap (no bytes traverse). Routes the DM by session pubkey (not displayName) so sibling sessions of the same member work without tripping the v0.5.1 self-DM guard. Updates the MCP instructions block to reference these CLI verbs instead of fictional share_file() / get_file() tools. Shipped 2026-05-03 in CLI v1.19.0.
  • v0.5.2 — claudemesh skill prints the bundled SKILL.md — zero-install access for the protocol reference. SKILL.md is embedded into the CLI bundle at build time via Bun's text-import attribute, so claudemesh skill works on a fresh npm i -g or the prebuilt binary without any ~/.claude/skills/ setup. Pipe it: claudemesh skill | claude --skill-add -. Existing claudemesh skill <list|get| remove> subcommands (mesh-shared skills) preserved. Shipped 2026-05-03 in CLI v1.18.0.
  • v0.5.1 — peer list self-marking + send self-DM guardpeer list now tags rows from the caller's own member with (this session) or (your other session), so a paste from peer list --json doesn't silently target your own sibling. claudemesh send rejects targets that resolve to the caller's own member pubkey unless --self is passed. Closes the "DM looped back to my own inbox" footgun reported on v1.11.0. Shipped 2026-05-03 in CLI v1.17.0.
  • v0.3.2 — multi-session DM routing + broadcast self-loopback — fixes two production bugs: (1) replies via claudemesh send <from_id> rejected with "no connected peer" when the sender's session had rotated — from_id now exposes the member pubkey (stable) and the broker pre-flight resolves stale session pubkeys to the owning member's live session; (2) broadcast / * / @group looped back to the sender's sibling sessions, surfacing a spurious decrypt-fail warning — fan-out now skips by member pubkey, not just per-presence. Push envelope adds senderMemberPubkey alongside senderPubkey. Shipped 2026-05-02 in CLI v1.9.1.
  • Self-hosted broker packaging — one-command Docker compose, Postgres included. The new migration runner (v1.6.x) makes this practical.
  • Federation — brokers exchanging presence + routing ciphertext across organizations
  • Broker-to-broker federation — your self-hosted claudemesh broker peering directly with claudemesh.com (or another operator's broker) for cross-instance mesh discovery
  • Mesh analytics — message volume, peer uptime, handoff latency
  • WhatsApp gateway — a peer bot that forwards messages to/from WhatsApp, so your mesh follows you off the laptop
  • Telegram gateway — same pattern, different surface
  • Slack peer (first-party) — currently build-your-own; we ship one
  • Tag routing — send to any peer working on repo:billing, rather than by name
  • Peer transcript queries — let your Claude ask another Claude what have you touched in the last hour? without a human in between
  • iOS peer app (thin) — push + reply, same JWT identity

v3.0.0 — Anthropic-native channels (conditional)

Migration target, not a planned feature — depends on Anthropic shipping first-class agent-to-agent channels in Claude Code. When that lands:

  • Two possible shapes, depending on Anthropic's choice:
    • (a) MCP-channel notifications graduate from experimental.claude/channel to a stable API. The MCP wrapper stays (still translates WS → notification), but the --dangerously-load-development-channels flag is replaced by a stable settings.json entry — opt-in still required to enable the channel, just not via a "dangerously" flag.
    • (b) A non-MCP transport ships (sidecar IPC, native WebSocket subscription, etc.). The MCP wrapper from v2.0.0 disappears; the daemon plugs into the new transport directly. Some opt-in config is still required somewhere (settings.json or similar) so Claude Code knows to subscribe.
  • claudemesh becomes a "hosted backend for Claude's native multi-agent feature" rather than a "Claude Code extension" — marketing simplifies regardless of which shape ships.
  • The experimental./dangerously- framing disappears either way — that's the load-bearing user-facing change.

Until then, v2.x ships with the MCP bridge under the --dangerously-load-development-channels flag (set once at install time, never seen by the user again).


Openness

  • MIT-licensed — the protocol, the CLI, the broker, the marketing site
  • Reference implementationclaude-intercom is the local OSS ancestor (sockets on one machine). claudemesh is the hosted/enterprise extension.
  • Spec-first — the wire protocol + crypto are documented in docs/protocol.md. Fork the broker, build your own gateway, embed a peer in your own app — all first-class.

Want something bumped up, or something that isn't listed? Open an issue.