# Matrix Skill Agentic Skills for Matrix, distributed as a Claude Code plugin. Three skills ship in this repo: | Skill | Purpose | API surface | |-------|---------|-------------| | [**matrix-communication**](skills/matrix-communication/) | Send / read / edit / react in chat rooms on behalf of a regular user, with full E2EE support, and follow a room live through a daemon | Matrix Client-Server API | | [**matrix-administration**](skills/matrix-administration/) | Operate a Synapse homeserver — snapshot rooms, rate room health, render a Graphviz map, force-join, promote, harden, deactivate, search history | Synapse Admin API | | [**matrix-announcement**](skills/matrix-announcement/) | Compose scannable, structured Matrix announcements — release notes, digests, heads-ups, postmortems. HTML subset, type-tag system, glyph rules, and HTML-card-to-PNG templates. | Content guidance only — pairs with `matrix-communication` | The three skills are independent — you can install the plugin and use any combination. `matrix-communication` and `matrix-administration` share `~/.config/matrix/config.json`. `matrix-announcement` has no runtime; it's reference material the agent reads while composing messages. **What is an Agentic Skill?** Platform-agnostic instructions and tools that AI coding agents can use. This skill is packaged as a Claude Code plugin but follows the open [Agentic Skills specification](https://github.com/anthropics/agentic-skills). ## matrix-communication — Features **Follow a room while you work.** `matrix-watchd.py` holds the E2EE store, syncs, decrypts, and appends every event of a watched room to a per-room JSONL log. `matrix-watch.py` follows that log without opening the store, so any number of readers run at once — an agent can stay current with a room, post its status and answer, without a second process ever touching the encryption state. - **Send messages** to any joined Matrix room - **Rich formatting** — bold, italic, code, strikethrough, spoilers, lists, blockquotes - **Real mentions** — `--mention '@user:server'` sets `m.mentions`, which is what notifies a client, and renders that name in your text as a pill; a plain `@name` without `--mention` does neither - **Smart link shortening** — Jira, GitHub, GitLab URLs become readable links - **Room links** — `#room:server` becomes a clickable room link - **Code blocks** — syntax-highlighted multi-line code - **Emotes** — `/me` style action messages (`--emote`) - **Thread replies** — keep discussions organized (`--thread`) - **Reactions** — add emoji reactions to messages - **Edit and redact** — modify or delete messages you sent - **Visual effects** — confetti, fireworks, snowfall (Element clients) - **List rooms** to find the right destination - **Read messages** — both unencrypted and E2EE decryption - **Bot prefix** — optional 🤖 prefix for automated messages - **Device verification** — SAS emoji verification for E2EE - **One writer per store** — every path that opens the E2EE store takes an exclusive lock, so two processes cannot corrupt it ## Installation ### Marketplace (Recommended) Add the [Netresearch marketplace](https://github.com/netresearch/claude-code-marketplace) once, then browse and install skills: ```bash # Claude Code /plugin marketplace add netresearch/claude-code-marketplace /plugin install matrix-communication@netresearch-claude-code-marketplace ``` ### Without a marketplace Since Claude Code 2.1.157 a plugin directory under your personal skills directory loads on its own, including the commands this repo ships: ```bash mkdir -p ~/.claude/skills git clone https://github.com/netresearch/matrix-skill.git \ ~/.claude/skills/matrix-communication ``` It loads as `matrix-communication@skills-dir` on the next session. Update with `git -C ~/.claude/skills/matrix-communication pull` and start a new session; remove it by deleting the directory. This route has no `claude plugin update`. ### npx ([skills.sh](https://skills.sh)) Install with any [Agent Skills](https://agentskills.io)-compatible agent: ```bash npx skills add https://github.com/netresearch/matrix-skill --skill matrix-communication ``` > **Limitation:** `npx skills` installs `SKILL.md`-based skills only. This repo also ships `commands`, which it does not install — use the marketplace or the skills directory for those. ### Download Release Download the [latest release](https://github.com/netresearch/matrix-skill/releases/latest) and extract to your agent's skills directory. ### Git Clone ```bash git clone https://github.com/netresearch/matrix-skill.git ``` ### Composer (PHP Projects) ```bash composer require netresearch/matrix-skill ``` Requires [netresearch/composer-agent-skill-plugin](https://github.com/netresearch/composer-agent-skill-plugin). ### npm (Node Projects) ```bash npm install --save-dev \ @netresearch/agent-skill-coordinator \ github:netresearch/matrix-skill ``` Requires [@netresearch/agent-skill-coordinator](https://github.com/netresearch/node-agent-skill-coordinator), which discovers the skill in `node_modules` and registers it in `AGENTS.md` via a `postinstall` hook. For pnpm, also allowlist the coordinator's postinstall: ```json { "pnpm": { "onlyBuiltDependencies": ["@netresearch/agent-skill-coordinator"] } } ``` ## Prerequisites **For E2EE support** (most Matrix rooms), install libolm: ```bash sudo apt install libolm-dev # Debian/Ubuntu sudo dnf install libolm-devel # Fedora brew install libolm # macOS ``` ## Usage Paths are shortened to `$C` below: ```bash C=skills/matrix-communication/scripts ``` The `*-e2ee.py` scripts are the ones to use. Most Matrix rooms are encrypted, and the non-E2EE variants cannot read or write in them. Prepend `set +H` to any command whose arguments contain `!`, or bash history expansion eats it. ### Send a Message ```bash set +H && uv run $C/matrix-send-e2ee.py "#myroom:matrix.org" "Deployment complete" set +H && uv run $C/matrix-send-e2ee.py "!abc123:matrix.org" "**Build passed** for abc123" # Notify someone. --mention is what actually reaches them. set +H && uv run $C/matrix-send-e2ee.py "#dev:matrix.org" \ "alex, schaust du drauf?" --mention '@alex:matrix.org' ``` ### Follow a Room ```bash # Add rooms to watch_rooms in ~/.config/matrix/config.json, then: uv run $C/matrix-watchd.py --start uv run $C/matrix-watchd.py --status # One line per event on stdout, for a human or an agent's monitor uv run $C/matrix-watch.py "#myroom:matrix.org" # What arrived since this reader last looked, then exit uv run $C/matrix-watch.py "#myroom:matrix.org" --once ``` While the daemon runs it owns the store; send, react, redact and edit route through it automatically. With no daemon they open the store themselves. Nothing changes at the call site either way. ### List Joined Rooms ```bash uv run $C/matrix-rooms.py uv run $C/matrix-rooms.py --search ops ``` ### Read Messages ```bash uv run $C/matrix-read-e2ee.py "#myroom:matrix.org" --limit 10 uv run $C/matrix-read-e2ee.py "#myroom:matrix.org" --limit 50 --json ``` ### Resolve Room Alias ```bash uv run $C/matrix-resolve.py "#myroom:matrix.org" ``` ### Check the Setup ```bash python3 $C/matrix-doctor.py # verifies every credential against the homeserver ``` ## E2EE Support `matrix-e2ee-setup.py` creates a dedicated "Matrix Skill E2EE" device that runs alongside your Element client. It logs in once with your password, which is used and not stored. | Script | Purpose | |--------|---------| | `matrix-send-e2ee.py` | Send encrypted messages | | `matrix-read-e2ee.py` | Read and decrypt messages | | `matrix-edit-e2ee.py` | Edit a message you sent | | `matrix-download-e2ee.py` | Download and decrypt attachments | | `matrix-e2ee-setup.py` | Create or remove the agent's device | | `matrix-e2ee-verify.py` | SAS emoji verification | | `matrix-fetch-keys.py` | Request missing room keys from your other devices | | `matrix-key-backup.py` | Restore room keys from the server-side backup | | `matrix-watchd.py` | The daemon that owns the store and follows rooms | First run takes ~2–5 s for the initial key sync; later runs are faster. ### Never reuse a running client's access token Not from Element, Element X, FluffyChat or a browser session. A token carries a `device_id`, and E2EE state is per device: two clients on one device cannot read each other's messages, and the one that breaks is the client you use — it starts showing `[Unable to decrypt]` for its own messages. Nothing fails at the moment you paste it. Earlier versions of this documentation offered that as a fallback "if password-based setup isn't possible". That advice was wrong and is retracted. No password means no E2EE, and that is the answer. ### Verification ```bash C=skills/matrix-communication/scripts # You start it, aimed at one of your own devices uv run $C/matrix-e2ee-verify.py --list # find the device id uv run $C/matrix-e2ee-verify.py --request DEVICE --timeout 300 # Or Element starts it and this side waits — needs --listen uv run $C/matrix-e2ee-verify.py --listen --timeout 300 ``` Without `--request` **and** without `--listen` the script picks a device itself, which is rarely the one you are sitting in front of. Use Element Desktop or Element Android. Element X has an incompatible verification flow. ### The matrix-nio pin The scripts pin `matrix-nio[e2e]<0.26`. 0.26 sends the SAS commitment in a format Element rejects, so no verification completes ([matrix-nio#570](https://github.com/matrix-nio/matrix-nio/issues/570)), and the two releases write incompatible store formats — opening one with the other fails as `BAD_ACCOUNT_KEY`, which names a key that is not the problem. Moving the pin is a migration, not a version bump. The store cannot be converted: ```bash uv run $C/matrix-e2ee-setup.py --logout && uv run $C/matrix-e2ee-setup.py uv run $C/matrix-key-backup.py --import-keys uv run $C/matrix-e2ee-verify.py --request DEVICE ``` ## matrix-administration — Features Synapse homeserver administration via the [Synapse Admin API](https://element-hq.github.io/synapse/latest/usage/administration/admin_api/index.html). **Stdlib-only Python** (no E2EE deps required). Works against any Synapse 1.x server. - Paginated room snapshot (`synapse-fetch-rooms.py` → `rooms.json`) - Health rating with EN+DE phrasing — public, unencrypted, orphaned-from-spaces - Colour-coded Graphviz SVG of the entire room/space tree - Force-join, promote-admin, link-room-to-space - One-shot hardening pipeline: add to space + restrict joins + enable encryption + restore power levels - **Destructive** user deactivation with optional GDPR `--erase` - Inspection: list user's admin/membership rooms, replay join/leave timelines, search unencrypted history, find biggest rooms by DB size Quick start: ```bash # Snapshot all rooms (the admin token comes from ~/.config/matrix/config.json) python3 skills/matrix-administration/scripts/synapse-fetch-rooms.py # Rate them in German, treating !home:example.com as our home space python3 skills/matrix-administration/scripts/synapse-rate-rooms.py \ --language de --space '!home:example.com' # Render a Graphviz SVG (requires the `dot` binary) python3 skills/matrix-administration/scripts/synapse-graph.py --space '!home:example.com' ``` Full reference and safety guide live in [`skills/matrix-administration/`](skills/matrix-administration/). ## matrix-announcement — Features Content-design guidance for any agent-authored Matrix room post longer than a single line — release notes, version bumps, weekly digests, breaking-change heads-ups, postmortems, RFCs, multi-skill pipeline summaries. - **Five rules** — one headline, `formatted_body` always, lists beat paragraphs, code in `
`, layout-heavy → render to PNG
- **Type-tag system** — `Release` / `Patch` / `Heads-up` / `Digest` / `Postmortem` / `RFC` / `New skill`. Pick one; never stack.
- **Glyph rules** — one prefix glyph max, no rockets (🚀), no party emoji (🎉), no multi-emoji ladders
- **`m.text` vs `m.notice`** — `m.notice` for unattended automation (bots can't auto-reply, prevents loops)
- **Three rendered HTML card templates** — `release-card.html` (1200×630), `weekly-digest.html` (1200×1500), `comparison.html` (1200×900) — render headlessly with Chromium and post as `m.image`
- **Seven `formatted_body` skeletons** — drop-in templates for each type tag
- **Visual gallery** at `skills/matrix-announcement/references/gallery.html` — preview every rule, all five worked examples, and the three card templates side-by-side

```bash
# Open the live preview gallery
xdg-open skills/matrix-announcement/references/gallery.html

# Render a release card to PNG
chromium --headless=new --hide-scrollbars --window-size=1200,630 \
  --screenshot=card.png \
  "file://$(pwd)/skills/matrix-announcement/references/templates/release-card.html"
```

Full reference lives in [`skills/matrix-announcement/`](skills/matrix-announcement/).

## Structure

```
matrix-skill/
├── .claude-plugin/
│   └── plugin.json              # Plugin manifest (lists all three skills)
├── skills/
│   ├── matrix-communication/    # Client-Server API, E2EE chat
│   │   ├── SKILL.md
│   │   ├── scripts/
│   │   │   ├── _lib/                    # stdlib-only shared helpers
│   │   │   ├── matrix-create-room.py    # Create a room
│   │   │   ├── matrix-doctor.py         # Health check (python3, not uv run)
│   │   │   ├── matrix-download-e2ee.py  # Download attachments (E2EE)
│   │   │   ├── matrix-e2ee-setup.py     # Create or remove the agent device
│   │   │   ├── matrix-e2ee-verify.py    # SAS emoji verification
│   │   │   ├── matrix-edit-e2ee.py      # Edit (E2EE) — USE THIS
│   │   │   ├── matrix-edit.py           # Edit (non-E2EE fallback)
│   │   │   ├── matrix-fetch-keys.py     # Request missing room keys
│   │   │   ├── matrix-invite.py         # Invite a user
│   │   │   ├── matrix-key-backup.py     # Restore keys from server backup
│   │   │   ├── matrix-power-level.py    # Read or set power levels
│   │   │   ├── matrix-react.py          # React to messages
│   │   │   ├── matrix-read-e2ee.py      # Read (E2EE) — USE THIS
│   │   │   ├── matrix-read.py           # Read (non-E2EE fallback)
│   │   │   ├── matrix-redact.py         # Delete messages
│   │   │   ├── matrix-resolve.py        # Resolve aliases
│   │   │   ├── matrix-rooms.py          # List rooms
│   │   │   ├── matrix-send-e2ee.py      # Send (E2EE) — USE THIS
│   │   │   ├── matrix-send.py           # Send (non-E2EE fallback)
│   │   │   ├── matrix-watch.py          # Follow a room's event log
│   │   │   └── matrix-watchd.py         # Daemon: owns the store, follows rooms
│   │   └── references/
│   ├── matrix-administration/  # Synapse Admin API, server ops
│   │   ├── SKILL.md
│   │   ├── scripts/
│   │   │   ├── _lib/                    # stdlib-only shared helpers
│   │   │   ├── synapse-fetch-rooms.py
│   │   │   ├── synapse-rate-rooms.py
│   │   │   ├── synapse-graph.py
│   │   │   ├── synapse-biggest-rooms.py
│   │   │   ├── synapse-join-room.py
│   │   │   ├── synapse-make-admin.py
│   │   │   ├── synapse-add-to-space.py
│   │   │   ├── synapse-migrate-room.py
│   │   │   ├── synapse-deactivate-user.py
│   │   │   ├── synapse-user-admin-rooms.py
│   │   │   ├── synapse-user-rooms.py
│   │   │   ├── synapse-room-member-flow.py
│   │   │   └── synapse-search.py
│   │   └── references/
│   │       ├── synapse-admin-api.md
│   │       ├── room-health-checks.md
│   │       ├── room-graph-pipeline.md
│   │       └── safety-guide.md
│   └── matrix-announcement/    # Content guidance (no scripts)
│       ├── SKILL.md
│       ├── README.md
│       ├── evals/evals.json
│       └── references/
│           ├── html-subset.md
│           ├── structure.md
│           ├── glyphs.md
│           ├── image-cards.md
│           ├── threading.md
│           ├── anti-patterns.md
│           ├── text-templates.md
│           ├── gallery.html              # visual preview of all rules + examples
│           └── templates/
│               ├── release-card.html     # 1200×630
│               ├── weekly-digest.html    # 1200×1500
│               └── comparison.html       # 1200×900
├── docs/
│   ├── ARCHITECTURE.md          # system design and distribution
│   ├── specs/                   # design documents (OKF)
│   └── exec-plans/              # implementation plans
├── LICENSE-MIT           # Code license (MIT)
├── LICENSE-CC-BY-SA-4.0  # Content license (CC-BY-SA-4.0)
└── README.md
```

## License

This project uses split licensing:

- **Code** (scripts, workflows, configs): [MIT](LICENSE-MIT)
- **Content** (skill definitions, documentation, references): [CC-BY-SA-4.0](LICENSE-CC-BY-SA-4.0)

See the individual license files for full terms.
## Author

Netresearch DTT GmbH - https://www.netresearch.de