* feat(matrix): add Matrix platform adapter using mautrix-go Implements a full Matrix protocol adapter so users can interact with their coding agent through any Matrix homeserver (matrix.org, self-hosted Synapse/Dendrite, etc.). Uses mautrix-go SDK for Client-Server API. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): add Matrix platform documentation Update README.md, README.zh-CN.md, INSTALL.md, CLAUDE.md and add docs/matrix.md with setup guide, config reference and FAQ. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(matrix): add unit tests and fix session key parsing 35 tests covering config validation, message handling, lifecycle, concurrency, and error paths. Race detector clean. Fixes two bugs found by tests: - stripBotMention: strip matrix.to URL before plain user ID to avoid partial replacement inside the URL path - ReconstructReplyCtx: room IDs contain colons, so colon-based SplitN corrupted them; use ":@" boundary detection instead Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): add Chinese setup guide Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(matrix): add E2EE support via mautrix cryptohelper Add Olm/Megolm encryption support using mautrix-go's built-in cryptohelper. Encrypted rooms are now fully supported for both sending and receiving messages. Key implementation details: - Crypto DB stored per device ID (~/.cc-connect/matrix-crypto-<device>.db) - Auto-recovers from stale device keys by force-uploading new keys - All outbound messages encrypted via sendRoomEvent when room has E2EE - DecryptErrorCallback logs decryption failures through slog - Cleanup client stores on failed crypto init to prevent DB panics Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): update setup guide with E2EE instructions - Recommend creating dedicated device via curl login (avoids E2EE issues) - Add E2EE section with startup log example showing device_id - Add FAQ entries for common E2EE problems and troubleshooting - Document crypto DB location and cleanup steps Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(matrix): add SAS verification and cross-signing support Enable auto-accept SAS key verification so users can verify the bot's device from Element. Bootstrap cross-signing to eliminate "encrypted by a device not verified by its owner" warning on bot messages. - Add verification helper with auto-accept/auto-confirm SAS flow - Workaround mautrix MAC verification bug for cross-user verification - Fix in-room verification transaction ID lookup from m.relates_to - Persist cross-signing seeds to disk for stable keys across restarts - Support m.login.password UIA fallback for publishing cross-signing keys - Add auto_verify and cross_signing_password config options Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): add verification and cross-signing documentation Add SAS verification and cross-signing setup instructions to both English and Chinese Matrix guides. Document new config options (auto_verify, cross_signing_password) and FAQ entries for device verification and the red exclamation mark warning. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): fix inaccurate documentation and capability table - Fix Matrix "Markdown / cards" from ✅ to ⚠️ (no CardSender) - Change "red exclamation mark" to "red question mark" per actual UI - Recommend curl with dedicated device_id for token (not Element) - Add cross-signing seeds file to E2EE reset instructions - Clarify that cross-signing may need cross_signing_password Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): reduce verbose logging in production Downgrade per-message and internal workaround logs from Info to Debug, and use structured fields for SAS verification log. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): fix formatting, rename field, and add token redaction - Run gofmt to fix struct definition and literal alignment - Rename shareSessionInChan to shareSessionInChannel for consistency with other platforms (Telegram, Discord, Slack) - Add core.RedactToken() in connectLoop error logging to prevent access token leakage in logs Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * ci: install libolm-dev for Matrix E2EE crypto The mautrix-go crypto package depends on libolm (C library) for end-to-end encryption. The CI runners don't have it pre-installed, causing golangci-lint to fail when loading the CGO package. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): use build-tagged E2EE to avoid CGO/libolm dependency Split E2EE (end-to-end encryption) code behind a `goolm` build tag so the default build compiles without CGO or libolm-dev. This fixes CI lint failures caused by the mautrix-go crypto package pulling in the CGO-based libolm backend by default. - Default build: no E2EE, no CGO, CI lint passes - Build with `-tags goolm`: full E2EE using pure-Go olm backend Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * build: enable goolm tag by default in Makefile Matrix E2EE requires the goolm build tag. Add it as a default tag in the Makefile so `make build` includes E2EE automatically. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): suppress unused field lint for cryptoHelper The cryptoHelper field is only accessed in e2ee.go (goolm build tag), so the default build's linter flags it as unused. Add //nolint:unused since this is intentional. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(matrix): add Matrix platform adapter using mautrix-go Implements a full Matrix protocol adapter so users can interact with their coding agent through any Matrix homeserver (matrix.org, self-hosted Synapse/Dendrite, etc.). Uses mautrix-go SDK for Client-Server API. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): add Matrix platform documentation Update README.md, README.zh-CN.md, INSTALL.md, CLAUDE.md and add docs/matrix.md with setup guide, config reference and FAQ. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(matrix): add unit tests and fix session key parsing 35 tests covering config validation, message handling, lifecycle, concurrency, and error paths. Race detector clean. Fixes two bugs found by tests: - stripBotMention: strip matrix.to URL before plain user ID to avoid partial replacement inside the URL path - ReconstructReplyCtx: room IDs contain colons, so colon-based SplitN corrupted them; use ":@" boundary detection instead Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): add Chinese setup guide Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(matrix): add E2EE support via mautrix cryptohelper Add Olm/Megolm encryption support using mautrix-go's built-in cryptohelper. Encrypted rooms are now fully supported for both sending and receiving messages. Key implementation details: - Crypto DB stored per device ID (~/.cc-connect/matrix-crypto-<device>.db) - Auto-recovers from stale device keys by force-uploading new keys - All outbound messages encrypted via sendRoomEvent when room has E2EE - DecryptErrorCallback logs decryption failures through slog - Cleanup client stores on failed crypto init to prevent DB panics Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): update setup guide with E2EE instructions - Recommend creating dedicated device via curl login (avoids E2EE issues) - Add E2EE section with startup log example showing device_id - Add FAQ entries for common E2EE problems and troubleshooting - Document crypto DB location and cleanup steps Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(matrix): add SAS verification and cross-signing support Enable auto-accept SAS key verification so users can verify the bot's device from Element. Bootstrap cross-signing to eliminate "encrypted by a device not verified by its owner" warning on bot messages. - Add verification helper with auto-accept/auto-confirm SAS flow - Workaround mautrix MAC verification bug for cross-user verification - Fix in-room verification transaction ID lookup from m.relates_to - Persist cross-signing seeds to disk for stable keys across restarts - Support m.login.password UIA fallback for publishing cross-signing keys - Add auto_verify and cross_signing_password config options Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): add verification and cross-signing documentation Add SAS verification and cross-signing setup instructions to both English and Chinese Matrix guides. Document new config options (auto_verify, cross_signing_password) and FAQ entries for device verification and the red exclamation mark warning. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(matrix): fix inaccurate documentation and capability table - Fix Matrix "Markdown / cards" from ✅ to ⚠️ (no CardSender) - Change "red exclamation mark" to "red question mark" per actual UI - Recommend curl with dedicated device_id for token (not Element) - Add cross-signing seeds file to E2EE reset instructions - Clarify that cross-signing may need cross_signing_password Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): reduce verbose logging in production Downgrade per-message and internal workaround logs from Info to Debug, and use structured fields for SAS verification log. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): fix formatting, rename field, and add token redaction - Run gofmt to fix struct definition and literal alignment - Rename shareSessionInChan to shareSessionInChannel for consistency with other platforms (Telegram, Discord, Slack) - Add core.RedactToken() in connectLoop error logging to prevent access token leakage in logs Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * ci: install libolm-dev for Matrix E2EE crypto The mautrix-go crypto package depends on libolm (C library) for end-to-end encryption. The CI runners don't have it pre-installed, causing golangci-lint to fail when loading the CGO package. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): use build-tagged E2EE to avoid CGO/libolm dependency Split E2EE (end-to-end encryption) code behind a `goolm` build tag so the default build compiles without CGO or libolm-dev. This fixes CI lint failures caused by the mautrix-go crypto package pulling in the CGO-based libolm backend by default. - Default build: no E2EE, no CGO, CI lint passes - Build with `-tags goolm`: full E2EE using pure-Go olm backend Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * build: enable goolm tag by default in Makefile Matrix E2EE requires the goolm build tag. Add it as a default tag in the Makefile so `make build` includes E2EE automatically. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): suppress unused field lint for cryptoHelper The cryptoHelper field is only accessed in e2ee.go (goolm build tag), so the default build's linter flags it as unused. Add //nolint:unused since this is intentional. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(matrix): resolve lint errors for CI (errcheck + staticcheck) * feat(agent): add GitHub Copilot as a first-class agent (#865) * chore: ignore web/tsconfig.tsbuildinfo (TS incremental build cache) Co-authored-by: Cursor <cursoragent@cursor.com> * feat(qqbot): add inline keyboard buttons and INTERACTION_CREATE event handling (#1131) * feat(qqbot): add support for inline keyboard buttons and interaction events - Update default intents to include INTERACTION_CREATE - Implement SendWithButtons to send messages with inline keyboard buttons - Encode permission decisions and session key in button_data for routing callbacks - Handle INTERACTION_CREATE events to process button clicks as permission responses - Create synthetic message for permission decisions and forward to engine - Add ackInteraction to acknowledge INTERACTION_CREATE events via API call - Add extensive tests for sending buttons, handling interactions, and edge cases * fix(qqbot): ignore ackInteraction error and correct test URL check - Suppress error from ackInteraction to avoid unused error variable warning - Update test to expect corrected interaction URL path "/interactions/interact-1" instead of "/v2/interactions/interact-1" * - Add sessionKey field to replyContext to embed in button_data and session routing - Refactor SendWithButtons to use sessionKey from replyContext and validate emptiness - Enhance replyContext construction with sessionKey in various message scenarios - Implement new tests for sharing session keys in channel, empty session key errors, and interaction_create event permission routing - Update config.example.toml to document new required intents for interaction support - Modify changelog with instructions on enabling INTERACTION_CREATE intent (bit 26) for QQ Bot - Permission requests now use clickable inline buttons instead of text replies, requiring enabling the INTERACTION capability in QQ Open Platform settings * test(qqbot): ignore errors and returned values in test HTTP handlers * feat: integrate Google Antigravity CLI (agy) agent * Harden antigravity session discovery and attachment handling to preserve resume correctness under contention Constraint: Keep external behavior and interfaces unchanged while improving runtime robustness Rejected: Full process-level session correlation | Requires upstream CLI contract not available here Confidence: medium Scope-risk: narrow Directive: Keep session-id detection conservative unless agy exposes explicit correlation metadata Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... Not-tested: Real concurrent agy process race on multi-session host * Fix antigravity prompt execution and shutdown safety without changing user-facing flow Constraint: Preserve existing antigravity integration surface and core event handling contracts Rejected: Introduce a custom permission event parser for agy stdout | No stable upstream protocol contract yet Confidence: medium Scope-risk: narrow Directive: If agy publishes structured permission I/O, replace y/n terminal fallback with typed request/response framing Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... Not-tested: End-to-end interactive agy permission prompt against a live CLI binary * Stabilize antigravity permission flow so Discord approvals consistently drive CLI execution Constraint: Preserve current antigravity stream/event contracts while improving permission reliability Rejected: Full structured agy protocol parser | Upstream schema is not yet stable/public Confidence: medium Scope-risk: narrow Directive: Replace regex prompt detection with typed protocol once agy exposes machine-readable permission events Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... && go build ./cmd/cc-connect Not-tested: Live Discord permission prompts across all locales/terminal themes * Prevent agy hangs and unsupported flag crashes in cross-platform antigravity runs Constraint: Keep antigravity adapter behavior compatible across Telegram/Discord while avoiding CLI-specific crashes Rejected: Keep passing -m and rely on user wrapper scripts | Breaks agy v1.0.2 directly for normal users Confidence: high Scope-risk: narrow Directive: Re-enable explicit model flag only after agy documents stable model flag support Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... && go build ./cmd/cc-connect Not-tested: Live agy v1.0.2 interactive permission prompts on Telegram with real long-running tool tasks * Fix lint-blocking errcheck findings in antigravity adapter without behavior changes Constraint: Keep runtime behavior unchanged while satisfying CI lint gates Rejected: Broader refactor around file/stream lifecycle | Unnecessary for this blocking lint failure Confidence: high Scope-risk: narrow Directive: Keep close/remove calls explicitly checked or intentionally ignored with clear intent in this package Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... Not-tested: Full GitHub Actions rerun output * Fix remaining errcheck close-handling findings from CI lint Constraint: Resolve lint blockers without behavioral changes Rejected: Broad lifecycle refactor | unnecessary for this CI-only failure class Confidence: high Scope-risk: narrow Directive: Keep file/stream close sites explicitly checked or intentionally ignored for errcheck Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... Not-tested: GitHub Actions rerun not yet executed * docs: update MiniMax banner to M3 release - Replace minimax-en.jpeg and minimax-zh.jpeg with new M3 PNG banners - Update MiniMax description in both READMEs to reflect M3 benchmarks (SWE-Bench Pro 59.0, Terminal Bench 2.1 66.0, VIBE V2 60.1, etc.) - Update tagline: "Build, Learn & Ship" / "Mini 价格 Max 性能" Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: update MiniMax model to M3 in provider presets - Switch primary model from MiniMax-M2.7 to MiniMax-M3 - Add MiniMax-M3-highspeed variant - Keep M2.7 as fallback for compatibility - Update descriptions to reflect M3 features (Sparse Attention, Multimodal) - Bump updated_at to 2026-06-03 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(core): /stop preserves AgentSessionID so next message can resume (#1196) `cmdStop` no longer clears `AgentSessionID`; the next message can `--resume` the conversation, matching the card-button Stop path and eliminating the inconsistency described in #1189. - Session-ID write-back now always follows the live forked ID Claude reports on every `--resume` (was: skip if already set); name binding still fires only on first assignment to avoid polluting `sessionNames` - Removed `clearStaleSessionID` helper and `CompareAndSetAgentSessionID` guard; replaced with unconditional `SetAgentSessionID` + `wasEmpty` name-binding gate - Updated / renamed affected tests: - TestSessionIDWriteback_TracksLiveForkedID - TestInteractiveWriteBack_TracksForkedSessionID - TestInteractiveWriteBack_NamingBindsOnlyOnFirstAssignment - TestCmdStop_PreservesAgentSessionID Closes #1189 * fix: three bug fixes — WPS ChannelKey, Telegram text_link, workspace bind path fix(wps-xiezuo): set ChannelKey on inbound messages for per-group session isolation (#1217). Without ChannelKey, messages from different WPS groups were routed to the same session. fix(telegram): forward text_link entity URLs to agent as [label](url) (#1207). Telegram passes inline hyperlinks as entities (not in the plain text), so the agent never saw the URL. enrichTextLinks() rewrites text_link spans in-place using UTF-16 offsets (Telegram's coordinate system). fix(core): splitCommandArgs() respects quoted paths in /workspace bind (#1211). strings.Fields splits on every space, truncating paths like '/workspace bind "/my project/foo"'. The new parser honours single and double quotes so space-containing paths work correctly. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(pi): correct agent directory paths (SkillDirs + GlobalMemoryFile) (#1206) * fix(pi): correct SkillDirs paths for pi agent skill discovery cc-connect's pi agent reported wrong skill directories (~/.pi/skills/ instead of ~/.pi/agent/skills/), causing SkillRegistry to never find pi skills. This meant slash commands like /caveman were not intercepted by cc-connect's command routing — they fell through to pi's print mode as raw text, and the LLM never received the skill instructions. Fix: - ~/.pi/skills/ -> ~/.pi/agent/skills/ (pi's default agent dir) - Add ~/.agents/skills/ (common shared skill dir) - Add /skills/ if env var is set * fix(pi): correct GlobalMemoryFile path pi loads global AGENTS.md from getAgentDir() which defaults to ~/.pi/agent/, not ~/.pi/. Respect if set. * chore(pi): consistent homeDir variable naming in SkillDirs * fix(pi): add SetWorkDir to enable /dir command (#1177) pi agent implemented GetWorkDir() but not SetWorkDir(), so the WorkDirSwitcher interface was incomplete and /dir always returned 'current agent does not support dynamic work directory switching'. * fix(pi): pipe prompt via stdin to avoid CLI option parsing (#1185) Reply chain headers start with "---", which pi's CLI parser interprets as an option flag, producing "Unknown option" errors. Pass the prompt via stdin instead of as a positional argument, consistent with how gemini and codex agents handle it. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> * fix(pi): read enabledModels from settings.json for /model (#1178) * fix(pi): read enabledModels from settings.json for /model AvailableModels() now reads ~/.pi/agent/settings.json enabledModels instead of returning nil. New() also falls back to defaultModel from settings when opts don't specify model. Add helpers: piSettingsDir, settingsPath, readSettings, readSettingsModels, readDefaultModel. Respects PI_CODING_AGENT_DIR. * fix(pi): check err return values in tests to pass errcheck linter * fix(pi): silence errcheck for os.Setenv/Unsetenv in defer cleanup blocks * feat(dingtalk): add reaction emoji support (#1213) * feat(dingtalk): add reaction emoji support * fix(dingtalk): satisfy emotion lint * feat(slack,tmux): per-thread session scope and per-session tmux windows (#1179) Add `session_scope` to the Slack platform ("user" | "channel" | "thread"). "thread" keys each Slack thread to its own cc-connect session, so a new top-level message starts a fresh conversation while replies in the same thread continue it. Backward compatible: when unset, behaviour is unchanged (share_session_in_channel maps to "channel"). Add `window_per_session` to the tmux agent: each cc-connect session gets its own tmux window (and its own init_command/agent instance) instead of sharing one pane. Required for real isolation when the platform splits sessions per thread; otherwise concurrent threads interleave into a single shared agent. The allocated window name doubles as the agent session ID so resumes reuse the same window. Both options default off. Includes unit tests and config.example.toml docs. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Reply to unauthorized IM senders (#1190) * feat(relay): configure group visibility (#1209) * feat(send): 支持 --at-users / --at-all 命令行参数,DingTalk @mention 通知 (#1188) * feat(send): add --at-users and --at-all support for DingTalk @mention - Add --at-users and --at-all flags to cc-connect send command - Add AtMentionSender optional interface for platforms that support @mention - Implement ReplyWithAt in DingTalk platform using text msgtype - Add CheckLinger stub for macOS compatibility * fix: update test callers for SendToSessionWithAttachments new signature * feat(send): add --at-users and --at-all support for DingTalk @mention - Add --at-users and --at-all flags to cc-connect send command - Add AtMentionSender optional interface for platforms that support @mention - Implement ReplyWithAt in DingTalk platform using text msgtype - Add CheckLinger stub for macOS compatibility - Update all test callers for new signature * fix(dingtalk): check resp.Body.Close return value for errcheck Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: wen_guoxing <wen_guoxing@itrus.com.cn> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> * feat(cron): align manual trigger command with exec (#1201) * feat: add manual cron run support * feat(cron): align manual trigger command with exec * fix(cron): guard shell manual triggers * test(cron): accept manual run output before trigger ack * test(release): align footer expectations without markdown italics * fix(core): keep full reply footer paths * test(core): normalize local dir path expectation * fix(cron): check exec response body close --------- Co-authored-by: aoko <aokodesuka@gmail.com> Co-authored-by: 张彧 <aaron@mac.tail449498.ts.net> Co-authored-by: 张彧 <aaron@Aaron-MacBook-Pro-14.local> * feat(codex): support request_user_input app-server events (#1200) Co-authored-by: Cursor <cursoragent@cursor.com> * feat(feishu): refresh rich card rendering and panel handling (#1204) Squash merge of PR #1204 (rebased onto main, minor conflicts resolved). Adds structured per-turn reply footer, cardkit-v1 streaming, status footer interface, claude context usage tracking, and rich card body improvements. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(feishu): send audio and video attachments as media (#1202) Co-authored-by: Cursor <cursoragent@cursor.com> * fix(opencode): pass --agent flag when agent config option is set (#1210) Adds optional 'agent' config option under [projects.agent.options] for opencode. When set, the value is passed as --agent to every 'opencode run' invocation, enabling plugin-defined agents (e.g. oh-my-openagent's 'Sisyphus - Ultraworker') to work correctly without falling back to the default agent. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(core): remove leftover conflict markers in engine_test.go from #1202 merge Co-authored-by: Cursor <cursoragent@cursor.com> * fix: three bug fixes for #1184, #1139, and #1176 fix(core): multiSelect AskUserQuestion on card platforms (closes #1184) - For multiSelect questions, render options as a numbered text list instead of instant-resolve buttons (buttons resolved on first click, preventing multi-selection) - Add new i18n key MsgAskQuestionNoteMulti with per-language hint to reply with comma-separated numbers (e.g. 1,3) - Single-select questions keep the existing button UX unchanged fix(config): allow cc-connect web with agent-only config (closes #1139) - Add LoadPermissive() / validatePermissive() that skip the "at least one platform" requirement - runWeb now uses LoadPermissive so the web admin UI starts even before any platforms are configured, enabling first-time setup fix(weixin): fail fast on ret=-2 when context_token cannot be refreshed (closes #1176) - When sendMessage returns ret=-2 and the stored token is the same as the current one (no inbound message has refreshed it), stop retrying immediately instead of burning 3 retries on the same stale token - Return a clear actionable error: "user must send a new message to refresh the session token" - Applied to both text (weixin.go) and media (media_outbound.go) paths Co-authored-by: Cursor <cursoragent@cursor.com> * fix(matrix): support MATRIX_CROSS_SIGNING_PASSWORD env var and document crypto DB paths - Add environment variable fallback for cross_signing_password (env var takes precedence over config file, avoiding plaintext password in config) - Document E2EE crypto data storage location (~/.cc-connect/) and file purpose (crypto DB + cross-signing seeds) in both English and Chinese setup guides - Add data directory comment in config.example.toml Addresses P3 items from PR #834 review. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: m3 <Marvae@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: 7a3lv7 <hjkl931031@gmail.com> Co-authored-by: JazzuLu <27945372+JazzuLu@users.noreply.github.com> Co-authored-by: shellus <353358601@qq.com> Co-authored-by: Han <hanzr.nju@outlook.com> Co-authored-by: Marco <48539922+MMMarcinho@users.noreply.github.com> Co-authored-by: masakasu <32926719+MASAKASUNO1@users.noreply.github.com> Co-authored-by: Rael <realraelmail@gmail.com> Co-authored-by: Yu Zhang <34849476+AaronZ345@users.noreply.github.com> Co-authored-by: wgx521 <wgx521@139.com> Co-authored-by: wen_guoxing <wen_guoxing@itrus.com.cn> Co-authored-by: aoko <aokodesuka@gmail.com> Co-authored-by: 张彧 <aaron@mac.tail449498.ts.net> Co-authored-by: 张彧 <aaron@Aaron-MacBook-Pro-14.local>
13 KiB
Matrix Setup Guide
This guide walks you through connecting cc-connect to Matrix, the open standard for decentralized communication. Once set up, you can chat with your local AI agent from any Matrix client (Element, FluffyChat, Nheko, etc.).
Prerequisites
- A Matrix account on any homeserver (public like
matrix.org, or self-hosted) - A machine that can run cc-connect (no public IP needed)
- Claude Code (or another supported agent) installed and configured
Advantage: Uses
/synclong polling — no public IP, no domain, no reverse proxy needed. Works behind NAT and firewalls.
Step 1: Create a Matrix Account
If you don't already have a Matrix account:
- Visit https://app.element.io (or your self-hosted Element instance)
- Click Create Account
- Choose a homeserver (the default
matrix.orgworks for most users) - Complete registration
You can also use any existing Matrix account — a dedicated bot account is recommended but not required.
Step 2: Get Your Access Token
You need an access token so cc-connect can authenticate as your Matrix user.
Via curl (Recommended)
Use curl to create a dedicated device with its own device ID. This ensures E2EE (end-to-end encryption) works correctly:
curl -XPOST "https://matrix.org/_matrix/client/v3/login" \
-H "Content-Type: application/json" \
-d '{"type":"m.login.password","user":"your-username","password":"your-password","device_id":"CC-CONNECT"}'
The response contains "access_token": "syt_...". Copy it for the config.
Recommended: Set
device_idtoCC-CONNECTor another recognizable name. A dedicated device ensures encryption keys are distributed correctly.
Via Element (Web/Desktop)
- Log in to Element (app.element.io)
- Open Settings (click your avatar → Settings)
- Go to Help & About → scroll to Advanced
- Click Access Token → copy the token
Note
: Tokens from Element reuse Element's device ID, which may cause E2EE issues. Creating a dedicated device via curl is recommended.
Warning
: Treat your access token like a password. Anyone with it can send messages as you. If it leaks, you can invalidate it by logging out of all sessions in Element.
Step 3: Find Your User ID (Optional)
Your user ID looks like @username:matrix.org. cc-connect can auto-detect it from the access token, but you can also specify it explicitly in config.
In Element: click your avatar — your user ID is shown at the top.
Step 4: Configure cc-connect
Add the Matrix platform to your config.toml:
[[projects]]
name = "my-project"
[projects.agent]
type = "claudecode"
[projects.agent.options]
work_dir = "/path/to/your/project"
mode = "default"
[[projects.platforms]]
type = "matrix"
[projects.platforms.options]
homeserver = "https://matrix.org"
access_token = "syt_xxx_xxx"
# ── Optional settings ────────────────────────────────────────
# user_id = "@bot:matrix.org" # auto-detected if omitted
# allow_from = "*" # "*" = all users, or "id1,id2"
# auto_join = true # auto-accept room invites (default: true)
# auto_verify = true # auto-accept SAS key verification (default: true)
# cross_signing_password = "" # bot account password for cross-signing setup (one-time)
# share_session_in_channel = false # true = all users share one session per room
# group_reply_all = false # true = respond to all messages in group rooms
# proxy = "" # HTTP/SOCKS5 proxy, e.g. "http://proxy:8080"
Common mistake:
homeservermust include the scheme (https://) and must be the same server your account is registered on.
Step 5: Start cc-connect
cc-connect
# Or specify a config file
cc-connect -config /path/to/config.toml
You should see logs like:
level=INFO msg="matrix: E2EE enabled" device_id=CC-CONNECT
level=INFO msg="matrix: connected" user=@bot:matrix.org
level=INFO msg="platform started" project=my-project platform=matrix
level=INFO msg="cc-connect is running" projects=1
If you see E2EE not available, encryption initialization failed. Encrypted rooms won't work. See the FAQ below.
Step 6: Start Chatting
6.1 Direct Message
- Open your Matrix client (Element, FluffyChat, etc.)
- Start a new DM with the bot's user ID (e.g.
@bot:matrix.org) - Send a message — cc-connect will respond
6. Group Chat
- Create or open a room
- Invite the bot's user ID to the room
- The bot will auto-join if
auto_join = true(default) - Send messages in the room
Note
: In group rooms, the bot responds when mentioned (e.g.
@bot:matrix.org) or whengroup_reply_all = trueis set.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Matrix Homeserver │
│ │
│ User Message ──→ /sync endpoint ◄── Long Polling │
│ ▲ │
└──────────────────────────┼───────────────────────────────────┘
│
│ HTTPS (no public IP needed)
▼
┌─────────────────────────────────────────────────────────────┐
│ Your Local Machine │
│ │
│ cc-connect ◄──► Claude Code CLI ◄──► Your Project Code │
│ │
└─────────────────────────────────────────────────────────────┘
Configuration Reference
| Option | Required | Default | Description |
|---|---|---|---|
homeserver |
Yes | — | Matrix homeserver URL (e.g. https://matrix.org) |
access_token |
Yes | — | Access token for authentication |
user_id |
No | auto-detected | Matrix user ID (e.g. @bot:matrix.org) |
allow_from |
No | "*" |
Comma-separated user IDs allowed to interact, or "*" for all |
auto_join |
No | true |
Automatically accept room invitations |
auto_verify |
No | true |
Auto-accept SAS key verification requests |
cross_signing_password |
No | "" |
Bot account password for cross-signing key setup (one-time, needed on first run or when keys are reset). Can also be set via MATRIX_CROSS_SIGNING_PASSWORD environment variable (takes precedence over config file) |
share_session_in_channel |
No | false |
Share a single agent session among all users in a room |
group_reply_all |
No | false |
Respond to all messages in group rooms (not just mentions) |
proxy |
No | "" |
HTTP or SOCKS5 proxy URL |
FAQ
Q: Bot doesn't respond to messages?
- Is cc-connect running and showing
matrix: connectedin logs? - Is the access token valid? Try regenerating it.
- In group rooms, is the bot mentioned or is
group_reply_all = trueset? - If logs show
E2EE not availableordecrypt failed, see E2EE questions below.
Q: How to restrict who can use the bot?
Set allow_from to a comma-separated list of Matrix user IDs:
allow_from = "@alice:matrix.org,@bob:matrix.org"
Q: Bot doesn't join rooms?
Make sure auto_join = true (this is the default). If the bot was already invited before cc-connect started, re-invite it.
Q: E2EE (End-to-End Encryption)
cc-connect supports encrypted rooms (E2EE) when built with the goolm build tag. If you see matrix: E2EE enabled at startup, encryption is working. If you see matrix: E2EE not available (build with -tags goolm to enable), rebuild with E2EE support:
Data storage: E2EE crypto data is stored under
~/.cc-connect/(created with0700permissions):
matrix-crypto-<device_id>.db— encryption key database (one per device)matrix-cross-signing-<device_id>.json— cross-signing seed (one per device)To reset E2EE (e.g. after changing device or reinstalling), delete these files and restart cc-connect:
rm ~/.cc-connect/matrix-crypto-*.db* ~/.cc-connect/matrix-cross-signing-*.json
go build -tags goolm ./cmd/cc-connect
Note
: To remove the red question mark ("encrypted by a device not verified by its owner") on bot messages, cross-signing must be set up. cc-connect does this automatically on first run, but some servers require
cross_signing_passwordin config for the initial setup. See the red question mark FAQ below.
Logs show "E2EE not available"?
Possible causes and fixes:
device ID not available from whoami— The server didn't return a device ID. Create a dedicated device via curl withdevice_id.not marked as shared, but there are keys on the server— Old crypto data conflicts with the current device. cc-connect tries to auto-recover. If it persists, delete old crypto databases and cross-signing seeds:rm ~/.cc-connect/matrix-crypto-*.db* ~/.cc-connect/matrix-cross-signing-*.jsonmismatching device ID in client and crypto store— The token's device ID doesn't match the crypto database. Delete the database and seeds:rm ~/.cc-connect/matrix-crypto-*.db* ~/.cc-connect/matrix-cross-signing-*.json
Logs show "decrypt failed: no session found"?
The sender's client didn't send the encryption key to the bot's device. This usually happens when:
- Reusing Element's access token — Element's device ID conflicts with the bot's encryption keys. Create a dedicated device via curl (see Step 2).
- Just changed the access token — The sender's client may not have discovered the bot's new device yet. Wait 1-2 minutes and send a new message.
- Corrupted crypto database — Delete and restart:
rm ~/.cc-connect/matrix-crypto-*.db* ~/.cc-connect/matrix-cross-signing-*.json
How to get a dedicated access token (recommended)?
Use the Matrix API to create a dedicated device, avoiding conflicts with Element or other apps:
# Replace homeserver URL, username, and password
curl -XPOST "https://your-homeserver.com/_matrix/client/v3/login" \
-H "Content-Type: application/json" \
-d '{
"type": "m.login.password",
"user": "your-bot-username",
"password": "your-password",
"device_id": "CC-CONNECT"
}'
The access_token in the response can be used in config. The device_id will be CC-CONNECT, easy to identify and manage.
Red question mark on bot messages ("encrypted by a device not verified by its owner")?
This means the bot's device hasn't been cross-signed. cc-connect automatically sets up cross-signing on first run, but some Matrix servers require password authentication (UIA) to publish the cross-signing keys.
If logs show no supported UIA flow for cross-signing, provide the bot account's password. You can set it in config:
cross_signing_password = "your-bot-password"
Or preferably via environment variable (avoids storing the password in the config file):
export MATRIX_CROSS_SIGNING_PASSWORD="your-bot-password"
The environment variable takes precedence over the config file value. This is a one-time operation — once cross-signing keys are published and saved, remove the password from config or unset the environment variable.
How to verify the bot's device?
cc-connect auto-accepts SAS key verification requests (when auto_verify = true, which is the default). To verify from Element:
- Open a DM with the bot
- Click the bot's avatar → Verify (or go to Settings → Security → find the bot's device)
- The bot will automatically accept and confirm the verification
- Element will show the device as verified
After verification, encrypted messages from the bot will no longer show warnings.
Q: How to use a self-hosted Matrix server?
Set homeserver to your server's URL (e.g. https://synapse.example.com). Make sure the URL is reachable from the machine running cc-connect.
Q: How to use a proxy?
proxy = "http://proxy-host:8080"
# or SOCKS5:
proxy = "socks5://proxy-host:1080"