# Matrix Communication

> Matrix chat communication. AUTOMATICALLY TRIGGER when user mentions Matrix rooms (#room:server), asks to send messages to chat, or wants to interact with Matrix. Use for sending messages to Matrix rooms on behalf of users via access token authentication.

- Skill: `majiayu000/matrix-communication` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/matrix-communication`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/matrix-communication/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/matrix-communication

---


# Matrix Communication

Send messages to Matrix chat rooms on behalf of users.

## Auto-Trigger

**AUTOMATICALLY USE THIS SKILL** when you encounter:
- **Room references**: `#room:server`, `!roomid:server`
- **Chat requests**: "send to matrix", "post in chat", "notify the team"
- **Matrix URLs**: `https://matrix.*/`, `https://element.*/`
- **Setup requests**: "configure matrix", "set up matrix skill"

## Setup Guide (for Agent)

When user asks to set up Matrix, guide them through these steps:

### Step 1: Check if already configured

```bash
cat ~/.config/matrix/config.json 2>/dev/null && echo "Config exists" || echo "Not configured"
```

### Step 2: If not configured, ask user for:

1. **User ID** - e.g., `@username:matrix.org` or `@username:company.com`
2. **Matrix password** - for E2EE device creation (not stored, used once)
3. **Bot prefix** (optional) - e.g., `🤖` to mark automated messages

### Step 3: Discover homeserver URL

Extract the domain from the user ID and discover the homeserver via `.well-known`:

```bash
# Extract domain from user ID (e.g., @user:example.com -> example.com)
MATRIX_DOMAIN="DOMAIN_FROM_USER_ID"

# Discover homeserver URL
curl -s "https://${MATRIX_DOMAIN}/.well-known/matrix/client" | python3 -c "import sys,json; print(json.load(sys.stdin)['m.homeserver']['base_url'])"
```

**Example:** For `@sebastian.mendel:netresearch.de`:
- Domain: `netresearch.de`
- Discovery URL: `https://netresearch.de/.well-known/matrix/client`
- Returns homeserver: `https://matrix.netresearch.de`

### Step 4: Create config file

```bash
mkdir -p ~/.config/matrix
cat > ~/.config/matrix/config.json << 'EOF'
{
  "homeserver": "DISCOVERED_HOMESERVER_URL",
  "user_id": "USER_PROVIDED_USER_ID",
  "bot_prefix": "🤖"
}
EOF
chmod 600 ~/.config/matrix/config.json
```

### Step 5: Set up E2EE device (recommended)

**Three ways to provide the password:**

**Option A: Environment variable (recommended for agents)**
```bash
MATRIX_PASSWORD="USER_PASSWORD" uv run skills/matrix-communication/scripts/matrix-e2ee-setup.py
```

**Option B: Interactive prompt (recommended for users)**
```bash
uv run skills/matrix-communication/scripts/matrix-e2ee-setup.py
# Script will securely prompt for password
```

**Option C: Command line argument (use with caution)**
```bash
set +H && uv run skills/matrix-communication/scripts/matrix-e2ee-setup.py "USER_PASSWORD"
```

This creates a dedicated "Matrix Skill E2EE" device. The password is used once and not stored.

**Why environment variable?** Avoids shell escaping issues with special characters (`!`, `$`, etc.). The `set +H` workaround for command line is less reliable.

### Step 6: Add access token to config

After E2EE setup, copy the access token to enable non-E2EE scripts:

```bash
# Extract access token from E2EE credentials and add to config
ACCESS_TOKEN=$(python3 -c "import json; print(json.load(open('$HOME/.local/share/matrix-skill/store/credentials.json'))['access_token'])")

# Update config with access token
python3 -c "
import json
config_path = '$HOME/.config/matrix/config.json'
with open(config_path) as f:
    config = json.load(f)
config['access_token'] = '$ACCESS_TOKEN'
with open(config_path, 'w') as f:
    json.dump(config, f, indent=2)
print('Access token added to config')
"
```

### Step 7: Verify setup

```bash
uv run skills/matrix-communication/scripts/matrix-e2ee-setup.py --status
uv run skills/matrix-communication/scripts/matrix-rooms.py
```

### Step 8: Verify device (IMPORTANT)

**⚠️ STRONGLY RECOMMENDED:** Verify the new "Matrix Skill E2EE" device to avoid security warnings.

**Why verify?**
- Other users see ⚠️ warnings when unverified devices send messages
- Some rooms may block messages from unverified devices
- Cross-signing establishes trust chain for your account
- Enables automatic room key sharing from other devices

**Agent workflow for real-time emoji display:**

The verification script writes emojis to `/tmp/matrix_verification_emojis.txt` for agent polling. This enables showing emojis to the user BEFORE they need to confirm in Element.

**Step 8a: Clear emoji file and start verification in background**

```bash
rm -f /tmp/matrix_verification_emojis.txt
uv run skills/matrix-communication/scripts/matrix-e2ee-verify.py --timeout 180 > /tmp/verify_log.txt 2>&1 &
```

**Step 8b: Poll for emojis and show to user immediately**

```bash
# Poll until emoji file appears (check every 1-2 seconds)
for i in {1..30}; do
    if [ -f /tmp/matrix_verification_emojis.txt ]; then
        cat /tmp/matrix_verification_emojis.txt
        break
    fi
    sleep 1
done
```

The emojis display like this:
```
╔══════════════════════════════════════════════════════════╗
║           🔐 VERIFICATION EMOJIS - COMPARE NOW! 🔐        ║
╠══════════════════════════════════════════════════════════╣
║       🐱    Cat                                          ║
║       🔑    Key                                          ║
║       🎸    Guitar                                       ║
║       ...   (7 emojis total)                             ║
╚══════════════════════════════════════════════════════════╝
```

**Step 8c: Tell user to confirm in Element**

Once emojis are displayed, instruct the user:
- "Compare these emojis with what Element shows"
- "Click 'They match' in Element to complete verification"

**Step 8d: Wait for verification to complete**

```bash
# Check verification result
grep -q "VERIFICATION SUCCESSFUL" /tmp/verify_log.txt && echo "✅ Verified!"
```

**Device selection:** The script automatically prioritizes:
1. Element Desktop/Mobile clients (interactive)
2. Web clients (riot/chrome/firefox)
3. Named devices
4. Backup devices (lowest priority - can't respond interactively)

Use `--request DEVICE_ID` to target a specific device.

**Notes:**
- User confirms emojis in **Element**, not in the terminal
- After verification, the script automatically fetches room keys
- The emoji file enables real-time display even with buffered command output

### Troubleshooting

**E2EE setup fails with "Invalid username or password":**

If your password contains special characters (`!`, `$`, `\`, etc.), bash may mangle them:

```bash
# WRONG - bash corrupts passwords with special characters
uv run .../matrix-e2ee-setup.py "MyPass!word"

# CORRECT - use environment variable (recommended)
MATRIX_PASSWORD="MyPass!word" uv run .../matrix-e2ee-setup.py

# CORRECT - use interactive prompt
uv run .../matrix-e2ee-setup.py
# Enter password when prompted

# ALTERNATIVE - disable history expansion
set +H && uv run .../matrix-e2ee-setup.py "MyPass!word"
```

**E2EE setup fails with libolm error:**
```bash
# Debian/Ubuntu
sudo apt install libolm-dev

# Fedora
sudo dnf install libolm-devel

# macOS
brew install libolm
```

**Non-E2EE scripts fail with "Config missing required fields: access_token":**

After E2EE setup, the access token is stored separately. Copy it to the main config:
```bash
# Get token and add to config
python3 -c "
import json
creds = json.load(open('$HOME/.local/share/matrix-skill/store/credentials.json'))
config = json.load(open('$HOME/.config/matrix/config.json'))
config['access_token'] = creds['access_token']
json.dump(config, open('$HOME/.config/matrix/config.json', 'w'), indent=2)
print('Done')
"
```

## Config Reference

**File:** `~/.config/matrix/config.json`

| Field | Required | Description |
|-------|----------|-------------|
| `homeserver` | Yes | Matrix server URL |
| `user_id` | Yes | Full Matrix user ID |
| `bot_prefix` | No | Prefix for messages (e.g., `🤖`) |
| `access_token` | No | Auto-created by E2EE setup |

## Scripts

All scripts are in the `scripts/` directory. Run with `uv run`.

### ⚠️ ALWAYS USE E2EE SCRIPTS

**Default to E2EE scripts (`*-e2ee.py`) for all operations.** Most Matrix rooms are encrypted. Only fall back to non-E2EE scripts if E2EE fails or user explicitly requests it.

| Operation | E2EE Script (preferred) | Non-E2EE Fallback |
|-----------|------------------------|-------------------|
| Send message | `matrix-send-e2ee.py` | `matrix-send.py` |
| Read messages | `matrix-read-e2ee.py` | `matrix-read.py` |
| Edit message | `matrix-edit-e2ee.py` | `matrix-edit.py` |
| React | `matrix-react.py` | (same) |
| Redact | `matrix-redact.py` | (same) |

| Script | Purpose |
|--------|---------|
| `matrix-send-e2ee.py` | **Send message (E2EE) - USE THIS** |
| `matrix-read-e2ee.py` | **Read messages (E2EE) - USE THIS** |
| `matrix-edit-e2ee.py` | **Edit message (E2EE) - USE THIS** |
| `matrix-react.py` | React to a message with emoji |
| `matrix-redact.py` | Delete/redact a message |
| `matrix-rooms.py` | List joined rooms |
| `matrix-resolve.py` | Resolve room alias to room ID |
| `matrix-e2ee-setup.py` | One-time E2EE device setup |
| `matrix-e2ee-verify.py` | Device verification (experimental) |
| `matrix-fetch-keys.py` | Request missing keys from other devices |
| `matrix-key-backup.py` | Restore keys from server backup |

## Room Identification

Scripts support multiple ways to identify rooms:

| Format | Example | Description |
|--------|---------|-------------|
| **Room name** | `agent-work` | Easiest - looked up from joined rooms |
| **Room ID** | `!sZBo...Q22E` | Direct - from `matrix-rooms.py` output |
| **Room alias** | `#room:server` | Resolved via Matrix directory |

**Best practice:** Use room names for simplicity. The script will find the matching room from your joined rooms list.

```bash
# These all work - room name is easiest
uv run skills/matrix-communication/scripts/matrix-send.py agent-work "Hello!"
uv run skills/matrix-communication/scripts/matrix-send.py '!sZBoTOreI1z0BgHY' "Hello!"
uv run skills/matrix-communication/scripts/matrix-send.py '#agent-work:server' "Hello!"
```

## Quick Reference

```bash
# Send message by room name (easiest - PREFERRED)
uv run skills/matrix-communication/scripts/matrix-send.py agent-work "Hello from Claude!"

# Send message by room ID (from matrix-rooms.py output)
uv run skills/matrix-communication/scripts/matrix-send.py '!sZBoTOreI1z0BgHY-s2ZC9MV63B1orGFigPXvYMQ22E' "Hello!"

# Send message by room alias
uv run skills/matrix-communication/scripts/matrix-send.py "#myroom:matrix.org" "Hello!"

# Send formatted message (markdown)
uv run skills/matrix-communication/scripts/matrix-send.py ops "**Deployment complete** for project X"

# List joined rooms (shows name, alias, and ID)
uv run skills/matrix-communication/scripts/matrix-rooms.py

# Find room ID by name
uv run skills/matrix-communication/scripts/matrix-rooms.py --lookup agent-work

# Search rooms
uv run skills/matrix-communication/scripts/matrix-rooms.py --search ops

# Read recent messages (unencrypted only)
uv run skills/matrix-communication/scripts/matrix-read.py myroom --limit 10

# Resolve room alias to ID
uv run skills/matrix-communication/scripts/matrix-resolve.py "#myroom:matrix.org"
```

## Message Types

### Regular Messages (m.text)
Default - use for most communication.

### Emote Messages (m.emote)
Like IRC `/me` - displays as action. Use `--emote` flag.
```bash
# Appears as: "* username is deploying to production"
uv run skills/matrix-communication/scripts/matrix-send.py "#ops:matrix.org" "is deploying to production" --emote
```
**When to use:** Status updates, actions, presence indicators.

### Thread Replies
Reply in a thread to keep discussions organized. Use `--thread` with root event ID.
```bash
# Start a thread or reply to existing thread
uv run skills/matrix-communication/scripts/matrix-send.py "#dev:matrix.org" "Update: tests passing" --thread '$rootEventId'
```
**When to use:** Ongoing updates to a topic, multi-step processes, avoiding main room clutter.

### Direct Replies
Reply to a specific message. Use `--reply` with event ID.
```bash
uv run skills/matrix-communication/scripts/matrix-send.py "#team:matrix.org" "Agreed, let's proceed" --reply '$eventId'
```

## Reactions

Add emoji reactions to messages to indicate status without new messages.

```bash
# React with checkmark (task done)
uv run skills/matrix-communication/scripts/matrix-react.py "#ops:matrix.org" '$eventId' "✅"

# Thumbs up (acknowledged)
uv run skills/matrix-communication/scripts/matrix-react.py "#dev:matrix.org" '$eventId' "👍"

# Eyes (looking into it)
uv run skills/matrix-communication/scripts/matrix-react.py "#support:matrix.org" '$eventId' "👀"
```

### Common Reaction Patterns

| Emoji | Meaning | Use Case |
|-------|---------|----------|
| ✅ | Done/Complete | Mark task as finished |
| 👍 | Acknowledged | Confirm receipt |
| 👀 | Looking into it | Started investigating |
| 🚀 | Deployed/Shipped | Indicate release |
| ⏳ | In progress | Working on it |
| ❌ | Failed/Blocked | Indicate problem |

**Workflow example:** Send "Going to reboot server" → later add ✅ reaction when complete.

## Visual Effects (Element Clients)

Include specific emoji to trigger visual effects in Element/SchildiChat:

| Emoji | Effect | Use Case |
|-------|--------|----------|
| 🎉 🎊 | Confetti | Celebrations, milestones |
| 🎆 | Fireworks | Major achievements |
| ❄️ | Snowfall | Seasonal, cool features |

```bash
# Celebrate a release
uv run skills/matrix-communication/scripts/matrix-send.py "#team:matrix.org" "🎉 Version 2.0 released!"
```

**Note:** Effects only show for Element/SchildiChat users. Other clients see the emoji normally.

## Message Formatting

All formatting is automatic - just use markdown syntax.

### Basic Formatting

| Syntax | Result | When to Use |
|--------|--------|-------------|
| `**bold**` | **bold** | Emphasis, headings, status |
| `*italic*` | *italic* | Secondary emphasis |
| `` `code` `` | `code` | Commands, file names, variables |
| `~~strike~~` | ~~strike~~ | Corrections, outdated info |
| `[text](url)` | linked text | Custom link labels |

### Matrix-Specific Features

| Syntax | Result | When to Use |
|--------|--------|-------------|
| `@user:server` | Clickable mention | Notify specific users |
| `#room:server` | Clickable room link | Reference other rooms |
| `> quote` | Blockquote | Quote previous messages |
| `\|\|spoiler\|\|` | Hidden text | Sensitive info, plot spoilers |
| ` ```lang ``` ` | Code block | Multi-line code with syntax highlighting |

### Smart Link Shortening

URLs are automatically shortened to readable links:

| URL | Displayed As |
|-----|--------------|
| `https://jira.*/browse/PROJ-123` | PROJ-123 |
| `https://github.com/owner/repo/issues/42` | owner/repo#42 |
| `https://github.com/owner/repo/pull/42` | owner/repo#42 |
| `https://gitlab.*/group/proj/-/issues/42` | group/proj#42 |

### Lists

```
- Item one
- Item two
- Item three
```

## When to Use Each Feature

**Deployment notifications:**
- Use **bold** for status: `**Deployed**`, `**Failed**`
- Use lists for changes
- Link to Jira issue URL (auto-shortened)

**Code sharing:**
- Use ` ```lang ``` ` for multi-line code
- Use `` `inline` `` for single commands

**Team communication:**
- Use `@user:server` to notify specific people
- Use `#room:server` to reference discussions in other rooms
- Use `> quote` when replying to earlier messages

**Sensitive information:**
- Use `||spoiler||` for credentials, secrets in examples

## E2EE Support

### Which script to use?

| Scenario | Script | Notes |
|----------|--------|-------|
| Unencrypted room | `matrix-send.py` | Fast, no deps |
| E2EE room with "allow unverified" | `matrix-send.py` | Works but not encrypted |
| E2EE room, proper encryption | `matrix-send-e2ee.py` | Requires libolm + setup |

### E2EE Setup (Recommended)

**Use a dedicated device** - this avoids key sync conflicts with Element:

```bash
# One-time setup: create dedicated E2EE device

# Option 1: Environment variable (recommended - handles special chars)
MATRIX_PASSWORD="YOUR_PASSWORD" uv run skills/matrix-communication/scripts/matrix-e2ee-setup.py

# Option 2: Interactive prompt (secure - password not in history)
uv run skills/matrix-communication/scripts/matrix-e2ee-setup.py

# Now send encrypted messages
uv run skills/matrix-communication/scripts/matrix-send-e2ee.py '#room:server' 'Encrypted message'

# Check setup status
uv run skills/matrix-communication/scripts/matrix-e2ee-setup.py --status
```

**Why dedicated device?**
- Clean key state, no conflicts with Element
- Proper cross-signing setup
- Avoids "signature verification failed" errors

**⚠️ Access token fallback (not recommended):**
Using `access_token` from config reuses Element's device, which causes key sync issues and verification problems. Only use if password-based setup isn't possible.

### E2EE Script Usage

```bash
# First run after setup is slow (~5-10s) - syncs keys
uv run skills/matrix-communication/scripts/matrix-send-e2ee.py '#encrypted-room:server' 'Secret message'

# Subsequent runs faster (uses cached keys)
uv run skills/matrix-communication/scripts/matrix-send-e2ee.py '#encrypted-room:server' 'Another message'
```

Storage locations:
- Device credentials: `~/.local/share/matrix-skill/store/credentials.json`
- Encryption keys: `~/.local/share/matrix-skill/store/*.db`

### Device Verification (Recommended)

Device verification marks a device as trusted and enables automatic key sharing from other devices.

```bash
# Auto-find Element device and initiate verification
uv run skills/matrix-communication/scripts/matrix-e2ee-verify.py --timeout 180

# Target specific device
uv run skills/matrix-communication/scripts/matrix-e2ee-verify.py --request DEVICE_ID --timeout 180

# With debug output
uv run skills/matrix-communication/scripts/matrix-e2ee-verify.py --debug --timeout 180
```

**Smart device selection:** The script automatically prioritizes Element clients (Desktop/Android/iOS) over backup devices that can't respond to verification.

**Real-time emoji display:** Emojis are written to `/tmp/matrix_verification_emojis.txt` so agents can poll and display them immediately while the user confirms in Element.

**Why verify?**
- Removes ⚠️ "unverified device" warnings for other users
- Enables automatic room key sharing from other devices
- Required for some security-conscious rooms

### Reading E2EE Messages

```bash
# Read recent encrypted messages
uv run skills/matrix-communication/scripts/matrix-read-e2ee.py '#room:server' --limit 10

# JSON output
uv run skills/matrix-communication/scripts/matrix-read-e2ee.py '#room:server' --json
```

**Note:** Messages sent before your device was created show as `[Unable to decrypt]` - this is normal E2EE behavior (new devices can't read old messages without key sharing).

### Fetching Missing Keys

New devices can't decrypt old messages by default. After verification, use these methods to get missing keys:

#### Method 1: Request from Other Devices (Recommended)

After device verification, other devices can forward keys automatically. This works without any passwords or recovery keys:

```bash
# Fetch keys for a specific room
uv run skills/matrix-communication/scripts/matrix-fetch-keys.py ROOM --sync-time 60

# Example: Fetch keys for IT room with extended wait
uv run skills/matrix-communication/scripts/matrix-fetch-keys.py IT --limit 200 --sync-time 120
```

This script:
1. Reads room history to find undecryptable messages
2. Requests keys from your other verified devices
3. Receives forwarded keys automatically

**Requirements:**
- Device must be verified (run verification first)
- Other verified devices must be online
- Works best with Element running on another device

#### Method 2: Restore from Server Backup

If key forwarding doesn't work (no other devices online), restore from backup using your **recovery key** or **passphrase**:

```bash
# Check backup status
uv run skills/matrix-communication/scripts/matrix-key-backup.py --status

# Restore using recovery key (looks like: EsTj qRGp YB4C ...)
uv run skills/matrix-communication/scripts/matrix-key-backup.py --recovery-key "EsTj qRGp YB4C ..."

# Restore using passphrase
uv run skills/matrix-communication/scripts/matrix-key-backup.py --passphrase "your recovery passphrase"
```

**Find your recovery key in Element:**
Settings → Security & Privacy → Secure Backup → "Show Recovery Key"

| Script | Purpose |
|--------|---------|
| `matrix-fetch-keys.py` | Request keys from other devices (no secrets needed) |
| `matrix-key-backup.py` | Restore keys from server backup (needs recovery key) |

### Limitations

- **Old messages**: Can't decrypt without key backup restoration
- **First sync**: Initial run is slow due to key exchange
- **Device trust**: Auto-trusts devices (TOFU model)
- **Setup required**: First use requires user's Matrix password (one-time only)
- **Verification**: Experimental - cross-signing/room-based verification not fully supported
- **Key backup**: Requires recovery key/passphrase (stored in Element settings)

## Common Patterns

### Deployment notification with Jira link
```bash
uv run skills/matrix-communication/scripts/matrix-send.py "#ops:matrix.org" \
  "**Deployed** to production

https://jira.example.com/browse/PROJ-123

- Version: 1.2.3
- Changes: Auth improvements"
```

### Status update with mentions
```bash
uv run skills/matrix-communication/scripts/matrix-send.py "#dev:matrix.org" \
  "**Done**: API refactoring complete

@lead:matrix.org ready for review

See #code-review:matrix.org for PR discussion"
```

### Share code snippet
```bash
uv run skills/matrix-communication/scripts/matrix-send.py "#dev:matrix.org" \
  "Fix for the auth bug:

\`\`\`python
def validate_token(token):
    return token.startswith('valid_')
\`\`\`"
```

### Quote and respond
```bash
uv run skills/matrix-communication/scripts/matrix-send.py "#team:matrix.org" \
  "> Should we deploy today?

**Yes** - all tests passing. Deploying now."
```

### Check room before sending
```bash
# List rooms to find the right one
uv run skills/matrix-communication/scripts/matrix-rooms.py | grep -i ops

# Then send
uv run skills/matrix-communication/scripts/matrix-send.py "#ops-team:matrix.org" "Message here"
```

### Server maintenance with status updates
```bash
# 1. Announce (save event ID from output)
uv run skills/matrix-communication/scripts/matrix-send.py "#ops:matrix.org" "⏳ Starting server maintenance..."
# Output: Event ID: $abc123

# 2. Update status via reaction
uv run skills/matrix-communication/scripts/matrix-react.py "#ops:matrix.org" '$abc123' "✅"

# 3. Or add thread update
uv run skills/matrix-communication/scripts/matrix-send.py "#ops:matrix.org" "Maintenance complete, all services restored" --thread '$abc123'
```

### Celebrate milestone
```bash
uv run skills/matrix-communication/scripts/matrix-send.py "#team:matrix.org" "🎉 **Milestone reached!**

We hit 1000 users today!

Thanks to everyone who contributed."
```

## Error Handling

| Error | Cause | Solution |
|-------|-------|----------|
| `M_FORBIDDEN` | Not in room or no permission | Join room first in Element |
| `M_UNKNOWN_TOKEN` | Invalid/expired token | Get new token from Element |
| `M_NOT_FOUND` | Room doesn't exist | Check room alias spelling |
| `Could not find room` | Name lookup failed | Use `matrix-rooms.py` to list available rooms |
| `Multiple matches found` | Ambiguous room name | Use more specific name or room ID from list |
| `Could not resolve room alias` | Alias doesn't exist | Try room name instead of alias |

## Bash Quoting

**Important:** Bash history expansion treats `!` specially, which can corrupt messages and passwords.

### Best Solution: Disable History Expansion

```bash
# MOST RELIABLE - disable history expansion for the command
set +H && uv run skills/matrix-communication/scripts/matrix-send.py "#room:server" "Done!"
```

### Alternative: Quote Carefully

```bash
# Single quotes - works for simple messages
uv run skills/matrix-communication/scripts/matrix-send.py "#room:server" 'Done!'

# WRONG - double quotes allow history expansion
uv run skills/matrix-communication/scripts/matrix-send.py "#room:server" "Done!"
# Results in: Done\!
```

### For Passwords with Special Characters

Use environment variable (most reliable) or interactive prompt:

```bash
# BEST - environment variable handles all special characters
MATRIX_PASSWORD="MyP@ss!word" uv run .../matrix-e2ee-setup.py

# GOOD - interactive prompt (password not in shell history)
uv run .../matrix-e2ee-setup.py
# Enter password when prompted

# ALTERNATIVE - disable history expansion for command line
set +H && uv run .../matrix-e2ee-setup.py "MyP@ss!word"
```

## Related

- [Matrix Client-Server API](https://spec.matrix.org/latest/client-server-api/)
- `references/api-reference.md` - Matrix API endpoints

