fix(api+cli): topic post messageId is the durable historyId (v1.9.2)
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

Previously POST /v1/messages returned the message_queue row id as
`messageId`. Topic posts ARE durable (in topic_message); the queue
entry drains on delivery. Pasting that id into `--reply-to` failed
because the broker validates parents against topic_message, not the
queue. Now `messageId` aliases `historyId` for topic posts; both
`historyId` and `queueId` remain available as explicit fields.

Roadmap and CLI README updated with v0.3.1 reply-to + v0.3.2
multi-session entries.
This commit is contained in:
Alejandro Gutiérrez
2026-05-02 22:10:13 +01:00
parent 716e674473
commit 8697c1c032
4 changed files with 33 additions and 3 deletions

View File

@@ -2,7 +2,9 @@
Peer mesh for Claude Code sessions. Connect multiple Claude Code instances into a shared mesh with real-time messaging, shared state, memory, file sharing, vector store, scheduled jobs, and more — all driven from the `claudemesh` CLI. The MCP server is a tool-less push-pipe that delivers inbound peer messages to Claude as `<channel>` interrupts; everything else lives behind CLI verbs that Claude learns from the auto-installed `claudemesh` skill. Peer mesh for Claude Code sessions. Connect multiple Claude Code instances into a shared mesh with real-time messaging, shared state, memory, file sharing, vector store, scheduled jobs, and more — all driven from the `claudemesh` CLI. The MCP server is a tool-less push-pipe that delivers inbound peer messages to Claude as `<channel>` interrupts; everything else lives behind CLI verbs that Claude learns from the auto-installed `claudemesh` skill.
> **What's new in 1.8.0:** per-topic end-to-end encryption (v0.3.0 phase 3, CLI side). `claudemesh topic post <topic> <msg>` encrypts the body with `crypto_secretbox` under the topic's symmetric key — broker stores ciphertext only. `claudemesh topic tail` now decrypts v2 messages on render and runs a background re-seal loop every 30s, so new topic joiners get their sealed keys without manual action. `topic-key` cache is process-only — kill the CLI, the key forgets. Web dashboard reads v1 plaintext for now (phase 3.5 brings browser-side identity). > **What's new in 1.9.x:** topic threading + multi-session reliability fixes. `claudemesh topic post <topic> <msg> --reply-to <id>` threads a reply onto a previous topic message (full id or 8+ char prefix); `topic tail` renders `↳ in reply to <name>: "<snippet>"` above replies and shows a copyable `#xxxxxxxx` short id on every row. `<channel>` MCP attrs now carry `from_member_id`, `from_pubkey` (stable), `from_session_pubkey` (ephemeral), `message_id`, `topic`, `reply_to_id` — everything the recipient needs to reply directly. Broker fixes (v0.3.2): replies to a stale session pubkey now resolve to the owning member's live session instead of bouncing with "not online", and broadcast `*` no longer loopbacks decrypt-fail warnings to the sender's sibling sessions.
>
> **What was new in 1.8.0:** per-topic end-to-end encryption (v0.3.0 phase 3, CLI side). `claudemesh topic post <topic> <msg>` encrypts the body with `crypto_secretbox` under the topic's symmetric key — broker stores ciphertext only. `claudemesh topic tail` now decrypts v2 messages on render and runs a background re-seal loop every 30s, so new topic joiners get their sealed keys without manual action. `topic-key` cache is process-only — kill the CLI, the key forgets. Web dashboard reads v1 plaintext for now (phase 3.5 brings browser-side identity).
> >
> **What was new in 1.7.0:** terminal parity for the v1.6.x server features. New verbs: `claudemesh topic tail` (live SSE message stream — Ctrl-C to exit), `claudemesh notification list` (recent `@you` mentions across topics), `claudemesh member list` (mesh roster with online dots, distinct from `peer list`'s live-session view). Each command auto-mints a 5-minute read-only apikey via the WebSocket and revokes it on exit, so no token plumbing is needed. > **What was new in 1.7.0:** terminal parity for the v1.6.x server features. New verbs: `claudemesh topic tail` (live SSE message stream — Ctrl-C to exit), `claudemesh notification list` (recent `@you` mentions across topics), `claudemesh member list` (mesh roster with online dots, distinct from `peer list`'s live-session view). Each command auto-mints a 5-minute read-only apikey via the WebSocket and revokes it on exit, so no token plumbing is needed.
> >

View File

@@ -1,6 +1,6 @@
{ {
"name": "claudemesh-cli", "name": "claudemesh-cli",
"version": "1.9.1", "version": "1.9.2",
"description": "Peer mesh for Claude Code sessions — CLI + MCP server.", "description": "Peer mesh for Claude Code sessions — CLI + MCP server.",
"keywords": [ "keywords": [
"claude-code", "claude-code",

View File

@@ -223,6 +223,28 @@ level, or wire claudemesh to messaging surfaces beyond Claude Code.
web chat encrypt-on-send / decrypt-on-render. Web stays on v1 web chat encrypt-on-send / decrypt-on-render. Web stays on v1
plaintext until this lands; the existing CLI re-seal loop will pick plaintext until this lands; the existing CLI re-seal loop will pick
up web members the moment they have a real pubkey. up web members the moment they have a real pubkey.
- **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.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, - **Self-hosted broker packaging** — one-command Docker compose,
Postgres included. The new migration runner (v1.6.x) makes this Postgres included. The new migration runner (v1.6.x) makes this
practical. practical.

View File

@@ -254,9 +254,15 @@ export const v1Router = new Hono<Env>()
} }
} }
// For topic posts the durable identity is the topic_message row;
// the message_queue row is ephemeral (drains on delivery). Return
// historyRow.id as `messageId` so callers that paste the response
// back into `--reply-to` actually find the parent in history.
// `historyId` and `queueId` are kept as explicit aliases.
return c.json({ return c.json({
messageId: queueRow?.id ?? null, messageId: historyRow?.id ?? queueRow?.id ?? null,
historyId: historyRow?.id ?? null, historyId: historyRow?.id ?? null,
queueId: queueRow?.id ?? null,
topic: body.topic, topic: body.topic,
topicId: topic.id, topicId: topic.id,
notifications, notifications,