Files
simplex-chat/docs/contributing/RELEASES.md
T
Evgeny @ SimpleX Chatandshum 9d3241b06c mcp: Claude Code plugin, a SimpleX group per session (0.3.0) (#8116)
* mcp: remove HTTP serve and register modes

* mcp: read plugin options

* mcp: add daemon data root layout

* mcp: keep actions per session

* mcp: serve tools for one session profile

* mcp: add plain QR code text

* mcp: share the Main group across sessions

* mcp: promote only the first joiner to owner

* mcp: add the daemon socket protocol

* mcp: fix socket UTF-8 and late error handling

* mcp: open session agents and the hub

* mcp: order hub control work on one chain

* mcp: add the daemon

* mcp: fix daemon disconnects, stop and idle calls

* mcp: create the socket token atomically

* mcp: add the daemon client

* mcp: handle spawn errors and a stopped daemon

* mcp: add the stdio session server

* mcp: retry session calls after a daemon restart

* mcp: add the SessionStart hook and link commands

* mcp: remove unused shell quoting

* mcp: wire session, daemon and hook commands

* mcp: reject inherited names as commands

* mcp: add the Claude Code plugin

* mcp: add the plugin marketplace

* mcp: test the daemon end to end

* mcp: say Main group in tool descriptions

* mcp: document the plugin and the daemon

* mcp: record session titles from the hook

* mcp: allow long tool calls

* mcp: name the SimpleX daemon in texts

* mcp: quote no-owner texts and cite hook docs

* mcp: drop the project from title requests

* mcp: record Claude Code plugin checks

* mcp: qualify Claude Code check evidence

* mcp: start new profiles without preset contact

* mcp: remove unit test temp folders

* mcp: fix preset contact review findings

* mcp: expire each action with its own timer

* mcp: wait for decisions without a tick

* mcp: expire actions on core events and requests

* mcp: document the delivery poll at stop

* mcp: assert the socket handler error log

* mcp: complete only the session's own connects

* mcp: move closeServer to the test fixtures

* mcp: drop the name from session requests

* mcp: listen before the hub opens

* mcp: keep the approval mode per session

* mcp: pre-approve the skill commands

* mcp: a group per session under one Claude profile, approved by owners

* mcp: prompts, answers and tool-use approval in the session group, 0.3.0

* mcp: reply to prompts of stopped sessions, skip prompts echoed in a tag

* mcp: document the Claude Code plugin of 0.3.0

* mcp: name one-line commands in the plugin reference

* mcp: real-session checks without a channel command

* mcp: specify the Claude Code plugin, and serve as built in 0.3.0

* mcp: run the plugin from its own build and shrinkwrap, without npx

* mcp: start with a torn session file, and on file systems without links

* mcp: start the daemon with only the environment variables it uses

* mcp: one group per Claude Code process, re-attach, late contacts

* mcp: document one session per process, re-attach and the plugin launch

* mcp: hold prompts after a daemon start until the session attaches

* mcp: document prompts held after a daemon start

* mcp: pack production dependencies only, for a faster plugin install

* mcp: keep resumed sessions' groups, quote by hook start, order prompts

* mcp: document resumed sessions, turn records and ordered prompts

* mcp: quote each prompt once, post without refused quotes, answer first

* mcp: wait for a stopping daemon to release the lock

* mcp: double the re-attach delay once per attempt

* mcp: read a token file of another user as serve 0.2 did

* mcp: cut long prompts and answers to fit the daemon's body limit

* mcp: document quotes, refused quotes, the lock wait and long prompts

* mcp: open a titled new session only after its process registers

* mcp: document titles held until the session server registers

* mcp: skip late turn records and tag-only prompts, describe after failures

* mcp: take over the lock atomically, keep held titles across stops

* mcp: document turn records, tag-only prompts, the lock and held titles

* mcp: delete groups of sessions closed 7 days; no group for claude -p

* mcp: keep the approved mode in the session group, the link off /status

* mcp: apply leaving, removal and demotion in the Main group to sessions

* mcp: reply sends a file after an owner's approval when non-owners see it

* mcp: spec of closed groups, -p runs, mode, membership and reply cards

* mcp: resume after a running group deletion, continue past failed ones

* mcp: post terminal prompts in the current group of a resumed session

* mcp: show only the file's name and size on a reply card

* mcp: the hooks of a run Claude Code marks unattended post nothing

* mcp: serve lists its tools with the metadata of 0.2

* mcp: list leaves out the session's tool-use and mode cards

* mcp: one starter takes over a stale lock also without hard links

* mcp: test a resume after deletion, reply cards and demotion end to end

* mcp: document resumes after deletion, unattended runs and reply cards

* mcp: spec of round 5 fixes, with source links at their lines

* mcp: no permission relay in a run without a group or with invalid options

* mcp: spec of the permission relay of a run without a group

* mcp: every session keeps its group, claude -p runs included

* mcp: changes of the Main group's members leave session groups as they are

* mcp: every member who joins from the Main group prompts and approves

* mcp: reply cards match send cards; /approve N all sends later files too

While a session group has a guest, a member added without the Main group, the card of a reply shows its caption, the file's type, path and size, and an image's or a video's preview, as a card of send does. /approve N all approves that file, the other pending reply files and every later one of the group, until /revoke; the approval is kept in the group's custom data and counts while its approver joined from the Main group and stays in the group.

* mcp: the Main group says everyone in it is trusted with all sessions

The short description and the welcome message of the Main group, also of an existing one at the daemon's start, and a message at each member's join say that everyone in the group is trusted with all Claude Code sessions of the hub: they can join each session's group by /join N, prompt Claude and approve its actions.

* mcp: a session group says whether each joiner came from the Main group

When a member joins a session's group, Claude posts there that the member joined from the Main group, and their messages are prompts and they can approve actions, or that the member joined as a guest, whose messages are not prompts and who gets Claude's files only after an approval. The welcome message of a new session group says that members who join from the Main group prompt the session and approve its actions.

* mcp: test Main group members, guests and reply approvals end to end

A member who joins the Main group by an owner's link and a session's group by /join prompts and approves there, also after removal from the Main group; a guest added by a group link gets reply files after an approval, /approve N all sends later files at once, and /revoke ends it. The Main group and the session group post the join statements.

* mcp: document the trust of the Main group, guests and kept session groups

REFERENCE, README and TESTING describe that every member of the Main group prompts and approves in the sessions' groups, that changes in the Main group leave the sessions' groups as they are, the join statements, guests and the reply card with /approve N all and /revoke. The texts about deleted groups of closed sessions, runs without a group and the cascade of Main group changes are removed, as their behaviour was reverted.

* mcp: spec of the trust of the Main group, guests and kept session groups

The spec describes approvers as the members invited through the Main group, the statements of trust and standing, the reply card with /approve N all and /revoke, and Main group changes that leave the session groups as they are. The sections on deleted groups of closed sessions, runs without a group and the cascade are removed, flow 30 among them, and the source links point at the lines of this commit.

* mcp: claude -p and unattended runs get no session and no group again

A run whose CLAUDE_CODE_ENTRYPOINT is sdk-cli, sdk-ts or sdk-py, or whose CLAUDE_CODE_SESSION_ATTENDED is 0, gets no session and no group: its hooks post nothing, and its session server answers every call with the text of a run that is not interactive, without the daemon. Only the deletion of the groups of closed sessions stays removed.

* mcp: no group for the server of a claude -p run under a VS Code session

A claude -p run started by a command of a session of the VS Code extension or the desktop app keeps that session's entrypoint, and its MCP server gets the session's CLAUDE_CODE_SESSION_ATTENDED 1; only its hooks get 0. Its SessionStart hook now sends /title with unattended for its Claude Code process, and the daemon refuses /session from that process with status 403 for 10 seconds, before or after the title; the session server then answers every call with the text of a run that is not interactive and registers no more. The tests take the environments of a recorded run of Claude Code 2.1.319.

* mcp: Claude's channel and reply texts name members from the Main group

The channel instructions and the description of reply say that prompts come from the members who joined the session's group from the Main group, and that one of them approves a file while the group has a guest, in place of the owners.

* mcp: test that the session server stays out of the modern MCP era

Claude Code 2.1.319 registers no channel for a server that negotiates the modern protocol revision 2026-07-28. The test sends Claude Code's server/discover probe and its initialize, and expects Method not found and the revision 2025-11-25, so that an SDK upgrade that turns the modern era on fails the tests.

* mcp: document runs without a group and the refused server of claude -p

REFERENCE describes again the runs that are not interactive, and the refusal of the session server of a claude -p run under a VS Code session; TESTING restores the real-session checks of such runs, adds the one under a VS Code session, and names the recorded environments and the protocol era test.

* mcp: spec of runs without a group, the unattended mark and the MCP era

The spec describes again the runs that are not interactive, in flow 30 and the tables, with the mark of the process of a claude -p run under a VS Code session, the 403 of its session server and the end of its retries; it states the revision 2025-11-25 and the server/discover answer that keep the channel registered, and the channel instructions in their new words. Source links point at the lines of this commit.

* mcp: // passes a / command to Claude, /! an owner's ! command

In a session's group, every one-line message that starts with / is a command of the group. A message that starts with // reaches Claude without its first /, so //model sonnet arrives as /model sonnet. A message that starts with /! from a member whose member in the Main group is an owner reaches Claude as !...; from another member it gets the reply Only owners of the Main group can send ! commands to Claude. A message that starts with ! is not passed, and gets the reply Messages starting with ! reach Claude only from owners, as /!command.

* mcp: an unknown command in a session's group gets Unknown command.

The reply to a one-line / message that is not a command of a session's group no longer lists the commands, which the group's menu and the cards show; its text Unknown command. waits for the user's wording. The agent control chat of serve keeps its commands reply.

* mcp: guests' messages reach Claude as prompts

Every member of a session's group but User prompts the session, a guest added to the group directly too; approvals and tool-use verdicts still count only from members who joined from the Main group. Claude's channel instructions and the description of reply name the members of the group.

* mcp: split answers and terminal prompts at the size of a message

Answers and terminal prompts are posted in parts that each fit one message by the size check of send, fitsMessage, with the quote in the first part of an answer, in place of parts of 12000 encoded bytes: a Latin part holds 14962 characters, a Cyrillic part 7481 and a CJK part 4987. An answer quotes its prompt when the quote fits with an empty text.

* mcp: the option approve_guest_files turns the guests' file cards off

The plugin option approve_guest_files, a boolean on by default, passed to the session server as CLAUDE_PLUGIN_OPTION_APPROVE_GUEST_FILES: on, a file of reply waits for its card while the group has a guest, and /approve N all works as before; off, reply sends the file at once. The daemon applies the option of each /session and /title to all sessions, as the expiry, and refuses a config without it.

* mcp: test end to end that a guest prompts and each join is posted once

The trust test checks that the guest's message reaches the session as a prompt, and that the Main group and the session's group hold one join post for each member: the core raises joinedGroupMember for a member the hub hosts and connectedToGroupMember for one another member hosts, one of the two for each connection, in the same case of its CON handler.

* mcp: document //, /!, Unknown command., guest prompts, parts and the option

REFERENCE describes the commands and prompts of a session's group with // and /!, the reply Unknown command., the guests' prompts, the parts of a message's size, and the option approve_guest_files; README states the guests' prompts; TESTING adds a real-session check of // and /! and the e2e checks of guest prompts and single join posts.

* mcp: a space in the prompt queue of a session

Formatting of the line that queues a prompt.

* mcp: an answer drops the quote that leaves no room for its first character

The quote of an answer is kept when it fits with the answer's first character, so that the first part fits one message.

* mcp: spec of //, /!, guest prompts, parts and approve_guest_files

The spec describes the commands and prompts of a session's group with // and /!, the reply Unknown command., the guests' prompts, the parts that each fit one message with a quote that fits the first character, the option approve_guest_files, and one post for each join.

* mcp: document an answer without the quote that leaves it no room

REFERENCE states that an answer is posted without the quote when the quote leaves no room for its first character.

* mcp: a reply too large with its quote is posted without it

Claude's posts with a quote are sent again without it also when the core refuses them with largeMsg, as replies that quote a message near the size limit are.

* mcp: no command reply to a one-line / part that User posts

The control of a session's group drops the commands of User, the member of the hub's contact marked simplexMcpUser, in the order of the other commands, so a part of a terminal prompt that starts with / gets no reply.

* mcp: a part of a long text is searched within one message size

textParts searches each part among the next 15602 characters, the most a message holds, in place of the whole rest of the text; the parts stay the same.

* mcp: reply refuses a caption too long for a message with its file

reply checks the file's message with its caption as send does, before the post and before the card: text: too long for a message with this TYPE; shorten it.

* mcp: the daemon forgets the unattended marks older than 10 s

Each new mark of an unattended run removes the marks of 10 seconds ago and older, which no longer refuse a session server.

* mcp: test end to end the reply to a prompt as long as a message

The mirroring test sends the longest text the member's core sends to a session without Claude Code and waits for Session 1 is not running. without the quote; before 193f03f6c the core refused the reply with largeMsg and nothing was posted.

* mcp: document large replies, User's / parts, reply size, check 6

REFERENCE states that a reply too large with its quote is posted without it, that User's posts are never commands, and that reply refuses a caption too long for its message; TESTING records check 6 with Claude Code 2.1.319, which runs no command or shell command from a channel prompt, and the e2e reply to a long prompt.

* mcp: spec of large replies, User's commands, reply size, the marks

The spec describes replies sent again without the quote on largeMsg, User's commands dropped, the search of a part within one message size, the reply's message size check and the removal of old unattended marks; the source links follow the new lines.

* mcp: send and reply share the text of a message too long

tooLongText gives the refusal of send and reply: the text too long for the message with its quote, or for a message with the file.

* mcp: spec links of the shared refusal text

The spec names tooLongText and follows the lines of tools.ts after it.

* mcp: a reset of the owners leaves the session groups as they are

A replaced Main group keeps every session group and its invited records, so the members who joined from the old Main group keep prompting and approving there, as rule 4 of the trust model states for every change in the Main group.

* mcp: test end to end that the members stay after a reset of owners

The trust test approves a reset of the owners and checks that Alice and Bob, who joined from the old Main group, stay in the session's group, prompt there and get No pending actions. for /pending.

* mcp: document the reset of the owners and a hand-edited approve

REFERENCE states that a reset of the owners keeps the sessions' groups and the standing of their members, with /! from owners of the new Main group, and that a hand-edited approve outside requests and host is shown only at the session start while the tools run in mode requests; TESTING lists the reset in the trust test.

* mcp: spec of a reset of the owners that keeps the session groups

The spec describes the replacement of the Main group without changes to the session groups and their invited lists, with /! from owners of the new Main group, drops removeOwners and its log context, and follows the new lines of hub.ts and main-group.ts.

* mcp: every member controls a session; Main group owners approve files

Every member of a session group but User and observers prompts the session and approves its actions and tool use, whatever way they joined; each joiner gets the post NAME can send prompts to Claude and approve tool use, with the command that makes them an observer. A file of reply waits for an owner of the Main group in every session group, while the option is on; other members' approvals of files are refused, and a group without such an owner refuses the reply. The hub keeps the contact of User from its start.

* mcp: the option approve_files turns the file cards off

The plugin option approve_guest_files is renamed approve_files, variable CLAUDE_PLUGIN_OPTION_APPROVE_FILES and config field approveFiles, on by default; its title and description name the owner of the Main group who approves Claude's files.

* mcp: the reply to an unknown command names // for Claude's commands

A one-line / text outside the requests of a session group gets Unknown command. To send a command to Claude, start it with //.

* mcp: /observer #G ID makes a member of a session group an observer

The command is accepted from a member whose role lets them change that member's role in SimpleX: admin or owner, and not below the member's role; the member, Claude, the sender, a relay and a pending member are refused, and so is another group. The end-to-end test makes Carol an observer by the command of her join post, and her app then refuses to send.

* mcp: a session without an approver names members who can approve

The refusal of a new action in a session group without an approver says it has no member who can approve actions, a proposed text.

* mcp: document that every member of a session group controls it

REFERENCE and README state that every member but User and observers prompts and approves, the join post with /observer, the files approved by owners of the Main group, the option approve_files and the reply to an unknown command; TESTING lists the trust test as it now runs.

* mcp: spec of session groups that every member controls

The spec describes approvers as every member but User and observers, the join post with /observer and the command, files decided by owners of the Main group, the option approve_files, the reply to an unknown command and the refusal texts, and follows the new lines of the source.

* mcp: Claude's files reach a session group without approval

reply sends its file at once, and the core refuses it when the group's preference for files and media forbids it; the option approve_files, the reply cards, /approve N all and the bare /revoke of a session group are removed.

* mcp: rights in a session group follow the member's role there

Admins and owners of a session group approve actions and tool use and send // and /! commands to Claude; members, moderators and authors send prompts, and their // and /! commands get a reply. /join N invites a member of the Main group as admin, and an owner of the Main group as owner.

* mcp: Claude posts a member's rights at each join and role change

At each join and each change of a member's role in a session group, User excepted, Claude posts the rights of that role: admins and owners send prompts and // and /! commands and approve tool use; members, moderators and authors send prompts; observers can't send. The posts of sending roles end with the /observer command for that member, and the reply to /observer states the observer's rights.

* mcp: session groups keep no record of their invited members

Rights follow the role in the session group, so the invitations through the Main group are no longer recorded in the group's custom data.

* mcp: session groups keep the profile their owners changed

A session group's Control takes the group's profile from each groupUpdated event, so the updates of the model, the effort level and the name keep what owners changed, the preference for files and media included.

* mcp: document rights by role in session groups and files without cards

REFERENCE and README state the rights of each role in a session group, /join N as admin, the rights posts at joins and role changes, the replies to // and /! and to approvals from other roles, files of reply sent at once under the group's preference for files and media, and the removed option approve_files; TESTING lists the trust test as it now runs.

* mcp: spec of rights by role in session groups

The spec describes approvers as admins and owners of the session group, the replies to // and /! from other roles, /join N as admin, the rights posts at joins and role changes and the /observer reply, files of reply sent at once under the group's preference for files and media, the profile kept from groupUpdated, the session group's data without invited members and the options without approve_files, and follows the new lines of the source.

* mcp: spec flow 28 messages without semicolons

Mermaid ends a sequence message at a semicolon, so the join and rights messages of flow 28 use commas and a shortened post.

* mcp: group profile updates start from the group's current profile

Control and the Main group read the group's profile from the chat database before each update, and change only their own fields: the name, the short description, the Main group's description and the commands. The preferences owners set, files and media included, stay. This replaces the profile taken from groupUpdated events, which covered session groups only.

* mcp: / commands in a session group come from admins and owners

A one-line / text, a // text or a /! text from a moderator, member or author gets one reply, Only admins and owners of this group can send / commands., and reaches neither Control nor Claude. The check is Session.refusesCommand in Session.onMessage; without it, the replies of Control and Session.prompt apply as before.

* mcp: document / commands from admins and owners and profile updates

REFERENCE and README state that every message of a member who can send is a prompt except / commands, // and /!, that the / commands of moderators, members and authors get one refusal, and that Claude changes only its own fields of a group's profile, from the profile as it stands; TESTING lists the trust test as it now runs.

* mcp: spec of / commands from admins and owners and profile updates

The spec describes the one refusal of the / commands, // and /! of moderators, members and authors before Control and the prompt, the profile updates of Control and the Main group from the group's current profile, the removal of the groupUpdated handling, and follows the new lines of the source.

* mcp: spec summary of / commands from admins and owners

* mcp: spec diagrams render whole on GitHub

Mermaid ends a sequence message, a note and a block label at a semicolon and treats # as the start of a comment; the diagrams write them as #59; and #35;, which render as ; and #. All 36 diagrams of the spec render with GitHub's Mermaid viewer, each message, note and label in full.

* mcp: /observer ends the observer's standing approvals at once

Control reads the group's members again after /observer sets the role, as after a role change in the app, so the approvals of all messages to a chat and of all files from it that the new observer gave count no more.

* mcp: /observer answers that a member who has not joined is no member

A member invited to a session group who has not joined yet is neither current nor pending, so /observer #G ID answers No member ID in this group. and changes nothing; the member joins with the role of the invitation, and its role can change after the join.

* mcp: a session's rename and model change keep both in the group

Control makes its profile updates of a group one at a time, each from the profile the one before it wrote, so a rename and a change of the model or effort that overlap both stay in the group's profile.

* mcp: test the mode host card after a role change to the first admin

A session that requested mode host while its group had no admin or owner posts the mode card once a member becomes the group's first admin by a role change, after the post of the member's rights.

* mcp: no code comments

The code and tests carry no comments; the facts they stated are in the spec: an expiry timer that fires before the expiry time, the listener before the hub opens, the exit after the /stop reply, the stop timer cleared by a new entry, the socket path limit, the repeated call of an unknown session, and the request without a connection pool.

* mcp: document /observer and the Main group observer

REFERENCE states that a Main group observer can't send /join N, that /observer ends the observer's standing approvals at once, and the reply for a member who has not joined yet; TESTING lists the /observer test.

* mcp: spec of /observer, profile updates one at a time, removed comments

The spec describes the members read again after /observer, the reply for a member who is neither current nor pending, Control's profile updates one at a time, and the facts the removed code comments stated, and follows the new lines of the source.

* mcp: rights posts name / commands, without the observer hint for owners

The rights of admins and owners read can send prompts and / commands to Claude, and approve tool use; those of moderators, members and authors read can send prompts to Claude; / commands and approvals need the role admin or owner. The post for an owner ends without the /observer command, as an admin can't change an owner's role.

* mcp: session group description names prompts, / commands and approvals

A new session group's description reads The Claude Code session N. Members send it prompts; admins and owners also send / commands and approve tool use. Existing groups keep theirs, as Control sets only the name and the commands.

* mcp: Main group welcome and join post state what members can do

* mcp: Main group short description states what members can do

* mcp: Main group replies Unknown command. to an unknown command

* mcp: architecture names the Main group's texts as they now stand

* mcp: reply answers that files and media are off in the session group

* mcp: Main group texts are set at its creation, so owners' edits stay

* mcp: plugin texts name admins and owners where they decide

* mcp: commands of members past the one refusal get no reply

* mcp: overview link labels of the architecture match their lines

* mcp: actions expire within 60 s after a sleep past their expiry time

* mcp: cards of image and video actions are text while media are off

* mcp: /forward answers that files and media are off in the session group

* mcp: docs say an observer's standing approvals count again as admin

* mcp: serve passes the 0.2 tests unchanged

* mcp: serve answers /give with the list of commands, as 0.2

* mcp: maxTimer is private to messages.ts again, as 0.2

* mcp: docs state what text cards and serve's kept expired actions do

* mcp: the e2e test checks the bot receives the image with its file

* mcp: Claude names the group preference that refuses a post

* mcp: spec drops the reply file approvals that decision 87 removed

* mcp: docs say a refused outcome card leaves a performed action done

* mcp: a refused outcome card of a done action says it was performed

* mcp: a refused terminal prompt says the feature is not allowed for User

* mcp: test the cards refused for a preset server's SimpleX link

* mcp: docs name the text that reply returns for a refused file

* mcp: refused cards name the outcome; failure logs end with one period

* mcp: test the notice of a card edit refused after an expiry

* mcp: serve logs a failure with the period of 0.2

* mcp: reset-owners replaces the Main group at once, without an approval

* mcp: the plugin install links the marketplace on master

* mcp: docs state which Main group texts Claude keeps

* mcp: the plugin leaves serve agents named token and lock as they are

* mcp: rename the plugin's daemon to the service

* mcp: remove // and /!; a message starting with ! is a prompt

* mcp: docs say one-line / messages are the group's commands

* mcp: spec drops // and /!, which decision 117 removed

* mcp: remove the plugin's link and reset-owners skills

* mcp: test an admin's multi-line // and /! text reaches Claude as sent

* mcp: docs say the PreToolUse hook runs plugin/allow.js

* mcp: publish the plugin with its production dependencies bundled

* mcp, docs: the package bundles its dependencies; nothing installs them

* mcp: spec of the bundled dependencies and the package without a lockfile

* mcp: test the packed plugin has no link, which Claude Code refuses

* mcp, docs: plugin-only README; serve and shared settings in REFERENCE

* mcp, docs: shared settings name channels and process IDs precisely

* mcp: the description shows the model from the first answer

* mcp, docs: the Stop hook reads the model of its answer

* mcp, docs: README names a roadmap of what comes next

* mcp, docs: README and REFERENCE in short sentences

* mcp, docs: plain sentences in TESTING, spec and plugin texts

* mcp: the marketplace description names its one plugin

* mcp, docs: README shows a session group; serve images move to REFERENCE

* mcp: simplex-chat 7.1.3 and @simplex-chat/types 7.1.3, core 7.1.3.0

* mcp, docs: the package is a 4 MB download

* mcp: an older turn request no longer replaces a newer model or effort

* mcp: a held title's model keeps the start time of its hook

* mcp: User posts only prompts a person typed, not Claude Code's own

* mcp: User posts a typed prompt behind a slow hook or a new transcript

* mcp, docs: shorter Safety section in README

* mcp, docs: README says how to use the plugin without the channel

* plan: decisions 121 and 122 are decided by judgement on 2026-11-12

---------

Co-authored-by: shum <github.shum@liber.li>
2026-11-12 18:52:05 +00:00

8.0 KiB

Library and package releases

Releases

Release Location Version Published on
libsimplex simplex-chat-libs release core-<version> version of simplex-chat.cabal push to master or stable with a new core version
Node.js add-on simplex-chat-libs release nodejs-addon-<7 characters of the commit> push to master or stable with unreleased add-on sources
@simplex-chat/types npm version of packages/simplex-chat-client/types/typescript/package.json library release with an unpublished types version
simplex-chat npm version of packages/simplex-chat-nodejs/package.json push to master or stable with an unpublished version
@simplex-chat/mcp npm version of packages/simplex-chat-mcp/package.json push to master or stable with an unpublished version, when the versions it pins for simplex-chat and @simplex-chat/types are on npm
simplex-chat PyPI __version__ of packages/simplex-chat-python/src/simplex_chat/_version.py push to master or stable with an unpublished version

Add-on sources:

  • packages/simplex-chat-nodejs/binding.gyp
  • packages/simplex-chat-nodejs/cpp/
  • node-addon-api version in devDependencies of packages/simplex-chat-nodejs/package.json

Types sources, compared with the previous library release of the branch:

  • packages/simplex-chat-client/types/typescript/src/
  • packages/simplex-chat-client/types/typescript/package.json, except version and simplexChatCore, which a library release writes

Release states in simplex-chat-libs:

draft       created by maybe-release; assets uploaded by the build jobs
published   every asset present; published by the releases job

npm tag: beta for a version with a prerelease part, latest otherwise.

Releases and publications are independent of the Haskell test results.

releases.toml of simplex-chat-libs, written by build.yml:

core.<branch>.<version>     commit of the library release; branch: master or stable
npm.<package>.<version>     commit of the publication
pypi.<package>.<version>    commit of the publication

Library release

  1. On master or stable, after git pull:

    python3 scripts/ci/packages_release.py core-release <version>
    

    Checked: version higher than the highest version recorded for the branch.

    Written:

    • version of simplex-chat.cabal
    • with types changed since the previous library release of the branch: types version (bumped), simplexChatCore, line SimpleX Chat core: of the types README

    --types-version sets the types version, for the first release of an app version, e.g. --types-version 7.1.0-beta.7.1.

  2. Commit, push to the same branch.

  3. Run of build.yml:

    • maybe-release: version claimed for the commit in releases.toml, draft core-<version> created
    • build jobs: 6 library zips uploaded; macOS libraries signed with the Developer ID and notarized
    • releases: release published
    • publish: @simplex-chat/types published, when its version is unpublished
    • record: types version recorded

Failed claim, with every build job skipped:

  • version lower than the highest version recorded for the branch
  • types changed, types version published
  • types changed, simplexChatCore different from the core version

After a failed claim, a fix commit is pushed; the version is claimed by the next push.

Incomplete draft: completed by a re-run of the failed jobs in the run of the claim. The version is skipped by later pushes, as it is recorded for another commit.

Add-on release

Run of build.yml on a push to master or stable with unreleased add-on sources:

  • maybe-release: draft nodejs-addon-<7 characters of the commit> created, notes sources: <hash of the add-on sources>
  • build jobs, 5 platforms: add-on built, tested with the latest library release of the branch, uploaded
  • releases: release published

Incomplete draft: completed by a re-run or by the next push with the same add-on sources.

Package release

  1. On master or stable, after git pull:

    python3 scripts/ci/packages_release.py prepare [nodejs] [python]
    

    Both packages when none is listed.

    Checked:

    • published library release recorded for the branch
    • add-on release published with every asset (Node.js)
    • types version published on npm (Node.js)
    • Python types unchanged since the commit of the pinned library release (Python)
    • pinned releases published with the pinned SHA-256
    • every pinned asset downloaded with a matching SHA-256

    Written:

    • pins in packages/simplex-chat-nodejs/src/release.ts and _version.py: latest library release of the branch, add-on release of the current sources (Node.js), SHA-256 of every asset
    • @simplex-chat/types dependency: ^<types version> (Node.js)
    • package versions: a published version bumped when the pins or the package files changed

    --nodejs-version and --python-version set the versions, for the first release of an app version, e.g. --nodejs-version 7.1.0-beta.7.1 --python-version 7.1.0b7.

  2. Commit, push to the same branch.

  3. Run of build.yml:

    • build jobs, 5 platforms: packages tested, Node.js with the pinned add-on
    • publish: package tests of 5 platforms and pins checked, unpublished versions published with trusted publishing
    • record: published versions recorded

Versions unpublished after a failure: published by the next push to the branch.

MCP server release

  1. On master or stable, in packages/simplex-chat-mcp: version in package.json set, the pins of simplex-chat and @simplex-chat/types updated when needed, then:

    npm install --package-lock-only
    
  2. Commit, push to the same branch.

  3. Run of build.yml:

    • publish, with the pinned versions on npm: package installed by npm ci from the published packages, type-checked and unit tested, then published with trusted publishing, with the production packages of that install bundled in it (bundleDependencies) and without a lockfile
    • record: published version recorded

The package tests of 5 platforms are not required.

A version pinned in the same commit that bumps simplex-chat or @simplex-chat/types is on npm after that run: the MCP version is published by a later push to the branch, and the run shows a notice that names the pinned version.

Local publication

  1. Step 1 of the package release.

  2. Package tests in a Python virtual environment, on the local platform (linux-x86_64, linux-aarch64, macos-aarch64, macos-x86_64 or windows-x86_64):

    scripts/ci/package-tests.sh publish <platform> nodejs python
    
  3. In packages/simplex-chat-nodejs, with the npm tag of the version:

    npm publish --access public --tag beta
    
  4. In packages/simplex-chat-python:

    python -m pip install build twine
    python -m build
    twine upload dist/simplex_chat-<version>*
    
  5. Commit, push to the same branch. Locally published versions are skipped by build.yml and are not recorded in releases.toml.

Settings

  • simplex-chat-libs: release immutability enabled
  • secret NODEJS_REPO_TOKEN: contents of simplex-chat-libs, read and write
  • secrets APPLE_SIMPLEX_SIGNING_KEYCHAIN, APPLE_SIMPLEX_NOTARIZATION_APPLE_ID and APPLE_SIMPLEX_NOTARIZATION_PASSWORD: signing and notarization of the macOS libraries, shared with the desktop app build
  • trusted publisher of simplex-chat, @simplex-chat/types and @simplex-chat/mcp on npm and of simplex-chat on PyPI: workflow build.yml
  • secrets NPM_TOKEN and PYPI_API_TOKEN: used instead of trusted publishing when set
  • variables NPM_SCOPE, PYPI_PROJECT, PYPI_URL and PYPI_UPLOAD_URL: publication under other names, for test repositories

Pull requests

  • build.yml, for every pull request it runs for: add-on built and packages tested on 4 platforms (Linux aarch64 excluded); Linux x86_64 uses the library built from the pull request when the core changed, other platforms the pinned library
  • packages.yml, for package changes in a pull request without build.yml paths: add-on built and packages tested on 5 platforms