threema-openclaw
v0.1.2
Published
Threema channel plugin for OpenClaw
Maintainers
Readme
threema-openclaw
Threema channel plugin for OpenClaw with a focus on high-quality chat UX:
- Edit-in-place group replies (stream-like updates via
GROUP_EDIT_MESSAGE) - Slash-style group session creation via
/group - Media + voice memo support in both DMs and groups
Current Snapshot
This repository currently provides:
- Threema multi-device linking (
link-device) and mediator connectivity - Direct and group text send/receive
- Group reply evolution with optional partial streaming edits
- Direct and group media send/receive (image/audio)
- Voice memo reply synthesis (agent output -> outbound audio memo)
- Inbound audio transcription (voice memo -> transcript in context)
- Emoji reactions (apply/withdraw, direct + group)
- Typing indicator send/receive handling
- OpenClaw agent tools for group creation, media send, and reactions
Quick Start
1) One command install + setup (no clone)
npx --yes threema-openclaw@latest setupWhat this command does:
- Installs/enables the plugin from npm
- Starts interactive Threema linking (QR scan) if
identity.jsonis missing - Automatically creates
~/.openclaw/channels/threema/defaultif needed - Writes OpenClaw account config for
identityFileanddataDir - Runs plugin health checks
You can safely run setup again. Existing linked identity data is reused unless you relink.
How Threema ID linking works:
- During QR linking, the phone shares device identity material and your Threema ID.
- The plugin stores that in
identity.json. - Setup binds your OpenClaw account (default:
channels.threema.accounts.default) to that identity file path. - Result: that OpenClaw account uses the linked Threema ID for send/receive.
2) Verify load status
openclaw plugins doctor
openclaw plugins info threema-openclawIf your gateway is already running, restart it so the plugin loads.
Nifty Features
1) Stream-like group replies via message edits
When enabled, group replies are sent as an anchor message and then updated in-place via GROUP_EDIT_MESSAGE.
- Better group readability (one evolving message instead of many fragments)
- Optional partial streaming updates while model output is still arriving
Enable at channel level:
openclaw config set --json channels.threema.features.groupEvolvingReplies '{"enabled": true, "partialStreaming": {"enabled": true, "minIntervalMs": 120, "minCharsDelta": 1}}'Per-account override (optional):
channels.threema.accounts.<accountId>.features.groupEvolvingReplies.enabledchannels.threema.accounts.<accountId>.features.groupEvolvingReplies.partialStreaming.*
2) Slash command style group creation with /group
Send this in chat:
/group Product SyncBehavior:
- Creates a real Threema group session with the current contact
- Posts a bootstrap message in the new group
- Returns the canonical chat id (for example
threema:group:CREATOR/GROUP_ID)
3) Media and voice memos in DMs and groups
Outbound:
- Image/audio send for direct and group chats
- Voice memo replies generated from model output
- Optional
MEDIA:directive from text replies, e.g.MEDIA: /absolute/path/file.jpg
Inbound:
- Auto-download/decrypt media
- Persist files under
<dataDir>/media/inbound/<sender>/... - Optional audio transcription injected into context
4) Reactions and typing
- Emoji reactions: apply/withdraw in direct and group chats
- Legacy receipt mapping handled where needed
- Typing indicators are emitted and consumed
5) Replay and reflection safety guards
Defaults are now conservative to avoid replay-triggered reply loops:
processReflectedOutgoing.enableddefaults tofalsestartupReplayGuard.enableddefaults totrue- inbound forwarding is delayed until
ReflectionQueueDry(or warmup timeout)
Enable reflected outgoing processing only for explicit chats:
openclaw config set --json channels.threema.features.processReflectedOutgoing '{"enabled": true, "allowedChatIds": ["threema:group:ABCD1234/1234567890"]}'Tune startup replay guard:
openclaw config set --json channels.threema.features.startupReplayGuard '{"enabled": true, "requireReflectionQueueDry": true, "maxWarmupMs": 120000}'Chat Target Formats
Direct:
ABCD1234threema:ABCD1234
Group:
threema:group:<CREATOR>/<GROUP_ID>group:<CREATOR>/<GROUP_ID>threema:g-group-<creator>-<groupId>g-group-<creator>-<groupId>
OpenClaw Agent Tools
The plugin exposes:
threema_create_groupthreema_send_mediathreema_react_to_message
CLI Commands
No-clone usage:
npx --yes threema-openclaw@latest <command>From this repo (after npm install):
npm run cli -- <command>Supported commands:
setup [--data-dir <path>] [--account <id>] [--skip-link] [--non-interactive]link-device [--data-dir <path>]connect-mediator [--data-dir <path>]
--data-dir sets THREEMA_DATA_DIR for the command. setup defaults to ~/.openclaw/channels/threema/default.
Useful Runtime Toggles
Media:
THREEMA_MEDIA_AUTO_DOWNLOAD(1/0, default1)THREEMA_MEDIA_DOWNLOAD_MAX_BYTES
Transcription:
THREEMA_TRANSCRIBE_AUDIO(1/0, default1)THREEMA_TRANSCRIBE_MAX_BYTESOPENAI_API_KEY(required for OpenAI transcription)
Voice replies:
THREEMA_VOICE_REPLY_ENABLED(1/0, default1)THREEMA_VOICE_REPLY_AUTO_ON_REQUEST(1/0, default1)THREEMA_VOICE_REPLY_SEND_TEXT_ALSO(1/0, default0)THREEMA_AUDIO_FORCE_M4A(1/0, default1)
Data and Security
Your configured dataDir contains secrets and message artifacts.
Sensitive files include:
identity.json(client keys/device secrets)- media/transcript artifacts under
media/
Do not commit these files. See SECURITY.md.
Encryption and Security Model
This section is a high-level technical map. The full auditor-oriented document is
SECURITY.md.
Runtime crypto planes
- D2M reflection plane:
reflected envelopes are encrypted with a device-group-derived key (
dgrk) using XSalsa20-Poly1305 in nonce-ahead format (nonce || ciphertext). - CSP proxy/transport plane:
CSP frames are encrypted with a transport key derived during CSP handshake;
nonces are
cookie(16) || sequence_u64_le. - E2E message plane:
message bodies are encrypted per recipient using NaCl-style shared keys
(
X25519 + HSalsa20precomputation) and XSalsa20-Poly1305. - E2E metadata plane:
metadata containers are encrypted with a separate key derivation
(
salt='mm', personal3ma-csp). - Media/blob plane: media bytes are encrypted client-side with a random 32-byte blob key before upload; blob key distribution happens inside E2E-encrypted message payloads.
Primary long-term secrets
identity.jsonstores:clientKey(identity private key),deviceGroupKey(root for D2M keys),deviceCookie.
Compromise of these values can allow impersonation and/or decryption of protected traffic for linked-device flows.
Review posture
- This repository does not claim an independent cryptographic audit.
- Security claims should be interpreted with the threat model in
SECURITY.md. SECURITY.mdincludes a claim-to-code verification matrix for reviewers.
Development and Validation
Current focused checks:
npm run test:reflected-ackLive/manual flows (requires linked account + connectivity):
- Set
TEST_TARGET_IDfor recipient-targeted runs (for exampleTEST_TARGET_ID=YOURID01 npm run test-send) - Run all integration scripts in sequence:
npm run test:integration npm run connect-mediatornpm run test-sendnpm run test-send-medianpm run test-group-medianpm run test-send-to-group(requiresTEST_GROUP_CREATOR+TEST_GROUP_ID)npm run test-group-e2enpm run test-group-evolvingnpm run test-reactions
Troubleshooting
Plugin not loading
openclaw plugins doctor
openclaw plugins info threema-openclawGroup sends wait for leader/CSP
For strict CSP paths (group create/edit/media), leadership matters. If needed, temporarily close Threema on phone so this linked device can become leader.
Missing identity
Run linking again:
npx threema-openclaw link-device --data-dir "$THREEMA_DIR"Large reflection replay or slot mismatch (4115)
If logs show very large queueLen plus repeated Device slot state mismatch:
- Stop the gateway.
- Ensure this Mac uses its own linked
identity.json(do not share another device's file). - Relink this Mac and keep
identityFile/dataDirconsistent. - Start again and wait for
Reflection queue drybefore testing automation flows.
