basnijholt / matty

Simple, functional Matrix chat CLI client

Repository from Github https://github.combasnijholt/mattyRepository from Github https://github.combasnijholt/matty

Matrix TUI Logo

Matty - Matrix CLI Client

A simple, functional Matrix chat client built with Python, Typer, Pydantic, Nio, and Rich. Every interaction is a single CLI command for easy automation.

PyPI Build Status CodeCov GitHub Repo stars Ruff

Features

  • Fast CLI commands for quick Matrix operations
  • Thread support - view and navigate threaded conversations
  • Reactions support - add and view emoji reactions on messages
  • Message redaction - delete messages with optional reasons
  • AI-friendly - every action is a single CLI command
  • Functional programming style (minimal classes, maximum functions)
  • Environment-based configuration
  • Multiple output formats (rich, simple, JSON)
  • Type-safe with dataclasses and type hints
  • Persistent simple ID mapping for complex Matrix IDs

Installation

uv tool install matty
# or
pipx install matty
# or
pip install matty

For development, clone the repo and install dependencies:

# Clone the repository
git clone https://github.com/basnijholt/matrix-cli
cd matrix-cli

# Install dependencies with uv
uv sync

# Optional: Install pre-commit hooks
uv run pre-commit install

Configuration

Matty uses environment variables for configuration. Create a .env file in your working directory with your Matrix credentials:

MATRIX_HOMESERVER=https://matrix.org
MATRIX_USERNAME=your_username
MATRIX_PASSWORD=your_password
MATRIX_SSL_VERIFY=true  # Set to false for test servers

Environment Variables

Variable Description Default Example
MATRIX_HOMESERVER The Matrix homeserver URL to connect to https://matrix.org https://matrix.example.com
MATRIX_USERNAME Your Matrix username (without @ or :server) None (required) alice
MATRIX_PASSWORD Your Matrix account password None (required) secretpassword
MATRIX_SSL_VERIFY Whether to verify SSL certificates true false (for test servers)

Notes:

  • The username should be provided without the @ prefix or :server suffix
  • Set MATRIX_SSL_VERIFY=false when connecting to test servers with self-signed certificates
  • Command-line options (--username, --password) override environment variables

Usage

Available Commands


 Usage: matty [OPTIONS] COMMAND [ARGS]...

 Functional Matrix CLI client


╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --install-completion            Install completion for the current shell.    │
│ --show-completion               Show completion for the current shell, to    │
│                                 copy it or customize the installation.       │
│ --help                -h        Show this message and exit.                  │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ rooms          List all joined rooms. (alias: r)                             │
│ messages       Show recent messages from a room. (alias: m)                  │
│ users          Show users in a room. (alias: u)                              │
│ send           Send a message to a room. Supports @mentions. (alias: s)      │
│ threads        List all threads in a room. (alias: t)                        │
│ thread         Show all messages in a specific thread. (alias: th)           │
│ reply          Reply to a specific message using its handle. (alias: re)     │
│ thread-start   Start a new thread from a message using its handle. (alias:   │
│                ts)                                                           │
│ thread-reply   Reply within an existing thread. (alias: tr)                  │
│ react          Add a reaction to a message using its handle. (alias: rx)     │
│ edit           Edit a message using its handle. (alias: e)                   │
│ redact         Delete/redact a message using its handle. (alias: del)        │
│ reactions      Show detailed reactions for a specific message. (alias: rxs)  │
╰──────────────────────────────────────────────────────────────────────────────╯

Rooms Command

List all joined Matrix rooms:


 Usage: matty rooms [OPTIONS]

 List all joined rooms. (alias: r)


╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --username  -u      TEXT                Matrix username (overrides           │
│                                         MATRIX_USERNAME env var)             │
│                                         [default: None]                      │
│ --password  -p      TEXT                Matrix password (overrides           │
│                                         MATRIX_PASSWORD env var)             │
│                                         [default: None]                      │
│ --format    -f      [rich|simple|json]  Output format (rich/simple/json)     │
│                                         [default: rich]                      │
│ --help      -h                          Show this message and exit.          │
╰──────────────────────────────────────────────────────────────────────────────╯

Messages Command

Get recent messages from a room:


 Usage: matty messages [OPTIONS] [ROOM]

 Show recent messages from a room. (alias: m)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room      [ROOM]  Room ID or name [default: None]                          │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --limit     -l      INTEGER             [default: 20]                        │
│ --username  -u      TEXT                Matrix username (overrides           │
│                                         MATRIX_USERNAME env var)             │
│                                         [default: None]                      │
│ --password  -p      TEXT                Matrix password (overrides           │
│                                         MATRIX_PASSWORD env var)             │
│                                         [default: None]                      │
│ --format    -f      [rich|simple|json]  Output format (rich/simple/json)     │
│                                         [default: rich]                      │
│ --help      -h                          Show this message and exit.          │
╰──────────────────────────────────────────────────────────────────────────────╯

Users Command

List users in a room:


 Usage: matty users [OPTIONS] [ROOM]

 Show users in a room. (alias: u)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room      [ROOM]  Room ID or name [default: None]                          │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --username  -u      TEXT                Matrix username (overrides           │
│                                         MATRIX_USERNAME env var)             │
│                                         [default: None]                      │
│ --password  -p      TEXT                Matrix password (overrides           │
│                                         MATRIX_PASSWORD env var)             │
│                                         [default: None]                      │
│ --format    -f      [rich|simple|json]  Output format (rich/simple/json)     │
│                                         [default: rich]                      │
│ --help      -h                          Show this message and exit.          │
╰──────────────────────────────────────────────────────────────────────────────╯

Thread Commands

View and interact with threads:


 Usage: matty threads [OPTIONS] [ROOM]

 List all threads in a room. (alias: t)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room      [ROOM]  Room ID or name [default: None]                          │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --limit     -l      INTEGER             Number of messages to check          │
│                                         [default: 50]                        │
│ --username  -u      TEXT                Matrix username (overrides           │
│                                         MATRIX_USERNAME env var)             │
│                                         [default: None]                      │
│ --password  -p      TEXT                Matrix password (overrides           │
│                                         MATRIX_PASSWORD env var)             │
│                                         [default: None]                      │
│ --format    -f      [rich|simple|json]  Output format (rich/simple/json)     │
│                                         [default: rich]                      │
│ --help      -h                          Show this message and exit.          │
╰──────────────────────────────────────────────────────────────────────────────╯


 Usage: matty thread [OPTIONS] [ROOM] [THREAD_ID]

 Show all messages in a specific thread. (alias: th)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room           [ROOM]       Room ID or name [default: None]                │
│   thread_id      [THREAD_ID]  Thread ID (t1, t2, etc.) or full Matrix ID     │
│                               [default: None]                                │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --limit     -l      INTEGER             Number of messages to fetch          │
│                                         [default: 50]                        │
│ --username  -u      TEXT                Matrix username (overrides           │
│                                         MATRIX_USERNAME env var)             │
│                                         [default: None]                      │
│ --password  -p      TEXT                Matrix password (overrides           │
│                                         MATRIX_PASSWORD env var)             │
│                                         [default: None]                      │
│ --format    -f      [rich|simple|json]  Output format (rich/simple/json)     │
│                                         [default: rich]                      │
│ --help      -h                          Show this message and exit.          │
╰──────────────────────────────────────────────────────────────────────────────╯

Send Command

Send messages to rooms:


 Usage: matty send [OPTIONS] [ROOM] [MESSAGE]

 Send a message to a room. Supports @mentions. (alias: s)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room         [ROOM]     Room ID or name [default: None]                    │
│   message      [MESSAGE]  Message to send (use @username for mentions)       │
│                           [default: None]                                    │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --stdin                      Read message from stdin                         │
│ --file         -f      PATH  Read message from file [default: None]          │
│ --no-mentions                Don't parse @mentions in messages               │
│ --username     -u      TEXT  Matrix username (overrides MATRIX_USERNAME env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --password     -p      TEXT  Matrix password (overrides MATRIX_PASSWORD env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --help         -h            Show this message and exit.                     │
╰──────────────────────────────────────────────────────────────────────────────╯

Reply Command

Reply to messages:


 Usage: matty reply [OPTIONS] [ROOM] [HANDLE] [MESSAGE]

 Reply to a specific message using its handle. (alias: re)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room         [ROOM]     Room ID or name [default: None]                    │
│   handle       [HANDLE]   Message handle (m1, m2, etc.) to reply to          │
│                           [default: None]                                    │
│   message      [MESSAGE]  Reply message [default: None]                      │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --no-mentions                Don't parse @mentions in messages               │
│ --username     -u      TEXT  Matrix username (overrides MATRIX_USERNAME env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --password     -p      TEXT  Matrix password (overrides MATRIX_PASSWORD env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --help         -h            Show this message and exit.                     │
╰──────────────────────────────────────────────────────────────────────────────╯

Thread Start Command

Start a thread from a message:


 Usage: matty thread-start [OPTIONS] [ROOM] [HANDLE] [MESSAGE]

 Start a new thread from a message using its handle. (alias: ts)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room         [ROOM]     Room ID or name [default: None]                    │
│   handle       [HANDLE]   Message handle (m1, m2, etc.) to start thread from │
│                           [default: None]                                    │
│   message      [MESSAGE]  First message in the thread [default: None]        │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --no-mentions                Don't parse @mentions in messages               │
│ --username     -u      TEXT  Matrix username (overrides MATRIX_USERNAME env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --password     -p      TEXT  Matrix password (overrides MATRIX_PASSWORD env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --help         -h            Show this message and exit.                     │
╰──────────────────────────────────────────────────────────────────────────────╯

Thread Reply Command

Reply in a thread:


 Usage: matty thread-reply [OPTIONS] [ROOM] [THREAD_ID] [MESSAGE]

 Reply within an existing thread. (alias: tr)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room           [ROOM]       Room ID or name [default: None]                │
│   thread_id      [THREAD_ID]  Thread ID (t1, t2, etc.) or full Matrix ID     │
│                               [default: None]                                │
│   message        [MESSAGE]    Reply message [default: None]                  │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --no-mentions                Don't parse @mentions in messages               │
│ --username     -u      TEXT  Matrix username (overrides MATRIX_USERNAME env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --password     -p      TEXT  Matrix password (overrides MATRIX_PASSWORD env  │
│                              var)                                            │
│                              [default: None]                                 │
│ --help         -h            Show this message and exit.                     │
╰──────────────────────────────────────────────────────────────────────────────╯

React Command

Add reactions to messages:


 Usage: matty react [OPTIONS] [ROOM] [HANDLE] [EMOJI]

 Add a reaction to a message using its handle. (alias: rx)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room        [ROOM]    Room ID or name [default: None]                      │
│   handle      [HANDLE]  Message handle (m1, m2, etc.) to react to            │
│                         [default: None]                                      │
│   emoji       [EMOJI]   Emoji reaction (e.g., 👍, ❤️, 😄) [default: None]     │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --username  -u      TEXT  Matrix username (overrides MATRIX_USERNAME env     │
│                           var)                                               │
│                           [default: None]                                    │
│ --password  -p      TEXT  Matrix password (overrides MATRIX_PASSWORD env     │
│                           var)                                               │
│                           [default: None]                                    │
│ --help      -h            Show this message and exit.                        │
╰──────────────────────────────────────────────────────────────────────────────╯

Reactions Command

View reactions on a message:


 Usage: matty reactions [OPTIONS] [ROOM] [HANDLE]

 Show detailed reactions for a specific message. (alias: rxs)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room        [ROOM]    Room ID or name [default: None]                      │
│   handle      [HANDLE]  Message handle (m1, m2, etc.) to show reactions for  │
│                         [default: None]                                      │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --username  -u      TEXT                Matrix username (overrides           │
│                                         MATRIX_USERNAME env var)             │
│                                         [default: None]                      │
│ --password  -p      TEXT                Matrix password (overrides           │
│                                         MATRIX_PASSWORD env var)             │
│                                         [default: None]                      │
│ --format    -f      [rich|simple|json]  Output format (rich/simple/json)     │
│                                         [default: rich]                      │
│ --help      -h                          Show this message and exit.          │
╰──────────────────────────────────────────────────────────────────────────────╯

Redact Command

Delete/redact messages:


 Usage: matty redact [OPTIONS] [ROOM] [HANDLE]

 Delete/redact a message using its handle. (alias: del)


╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│   room        [ROOM]    Room ID or name [default: None]                      │
│   handle      [HANDLE]  Message handle (m1, m2, etc.) to redact/delete       │
│                         [default: None]                                      │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --reason    -r      TEXT  Reason for redaction [default: None]               │
│ --username  -u      TEXT  Matrix username (overrides MATRIX_USERNAME env     │
│                           var)                                               │
│                           [default: None]                                    │
│ --password  -p      TEXT  Matrix password (overrides MATRIX_PASSWORD env     │
│                           var)                                               │
│                           [default: None]                                    │
│ --help      -h            Show this message and exit.                        │
╰──────────────────────────────────────────────────────────────────────────────╯

Command Aliases

For faster typing, all commands have short aliases:

  • matty rmatty rooms - List all rooms
  • matty mmatty messages - Show messages from a room
  • matty umatty users - Show users in a room
  • matty smatty send - Send a message
  • matty tmatty threads - List threads
  • matty thmatty thread - Show thread messages
  • matty rematty reply - Reply to a message
  • matty tsmatty thread-start - Start a thread
  • matty trmatty thread-reply - Reply in a thread
  • matty rxmatty react - Add a reaction to a message
  • matty delmatty redact - Delete/redact a message
  • matty rxsmatty reactions - Show reactions on a message

Examples

Basic Usage

# List all rooms
matty rooms
# or use alias: matty r

# Show users in a room (with mention hints)
matty users lobby
# or: matty u lobby

# Get recent messages from a room
matty messages lobby --limit 10
# or: matty m lobby --limit 10

# Send a message to a room
matty send lobby "Hello from CLI!"
# or: matty s lobby "Hello from CLI!"

# Send a message with mentions
matty send lobby "@alice check this out!"
# or: matty s lobby "@bob @alice meeting at 3pm"

# Use different output formats
matty rooms --format json
matty rooms --format simple
# or: matty r --format json

Working with Threads

# List threads in a room
matty threads lobby

# View messages in a specific thread (using simple ID)
matty thread lobby t1

# Start a thread from a message
matty thread-start lobby m2 "Starting a thread!"

# Reply in a thread (using simple thread ID)
matty thread-reply lobby t1 "Reply in thread"

Reactions and Redaction

# Add a reaction to a message
matty react lobby m3 "👍"
# or: matty rx lobby m3 "🚀"

# View reactions on a message
matty reactions lobby m3
# or: matty rxs lobby m3 --format simple

# Delete/redact a message
matty redact lobby m5 --reason "Accidental message"
# or: matty del lobby m5

Message Handles and Replies

# Reply to a message using handle
matty reply lobby m3 "This is a reply!"

# Reply to the 5th message in a room
matty messages lobby --limit 10
matty reply lobby m5 "Replying to message 5"

Mentions

The CLI supports @mentions in messages:

# Mention a user by username
matty send lobby "@alice can you check this?"

# Multiple mentions
matty send lobby "@bob @alice meeting in 5 minutes"

# List users to see available mentions
matty users lobby  # Shows User IDs and simplified @mentions

# Mentions work in replies and threads too
matty reply lobby m3 "@alice I agree with your point"
matty thread-reply lobby t1 "@bob what do you think?"

The mention system will:

  • Automatically find the full Matrix ID for @username mentions
  • Support full Matrix IDs like @user:server.com
  • Format mentions properly so users get notified

Message Handles and Thread IDs

The CLI uses convenient handles to reference messages and threads:

  • Message handles: m1, m2, m3, etc. - Reference messages by their position
  • Thread IDs: t1, t2, t3, etc. - Reference threads with simple persistent IDs

These IDs are stored in ~/.matrix_cli_ids.json and persist across sessions.

Why Simple IDs?

Matrix uses complex IDs like:

  • Event: $Uj2XuH2a8EqJBh4g:matrix.org
  • Room: !DfQvqvwXYsFjVcfLTp:matrix.org

Our CLI simplifies these to:

  • Messages: m1, m2, m3 (temporary handles for current view)
  • Threads: t1, t2, t3 (persistent IDs across sessions)

Output Formats

The CLI supports three output formats:

  1. Rich (default) - Beautiful terminal UI with tables and colors
  2. Simple - Plain text output, perfect for scripts
  3. JSON - Machine-readable format for automation

Example:

# Pretty tables with colors
matty rooms

# Simple text output
matty rooms --format simple

# JSON for automation
matty rooms --format json | jq '.[] | .name'

Project Structure

matrix-cli/
├── matty.py         # Main CLI application (functional style)
├── test_client.py        # Connection testing utility
├── tests/                # Test suite
│   ├── __init__.py
│   ├── conftest.py       # Pytest configuration
│   └── test_matrix_cli.py # Unit tests
├── .github/              # GitHub Actions workflows
│   └── workflows/
│       ├── pytest.yml    # Test runner
│       ├── release.yml   # PyPI release
│       └── markdown-code-runner.yml # README updater
├── .env                  # Your credentials (not in git)
├── .env.example          # Example environment file
├── CLAUDE.md            # Development guidelines
├── pyproject.toml       # Project configuration
└── README.md            # This file

Development

This project follows functional programming principles:

  • Private functions (_function_name) for internal logic
  • Dataclasses over dictionaries for data structures
  • Type hints everywhere for clarity
  • No unnecessary abstractions or class hierarchies
  • Functions over classes where possible

See CLAUDE.md for detailed development guidelines.

Testing

# Run tests
uv run pytest tests/ -v

# Test with coverage
uv run pytest tests/ -v --cov=matty --cov-report=term-missing

# Test connection to Matrix server
uv run python test_client.py

# Run pre-commit checks
uv run pre-commit run --all-files

License

MIT

About

Simple, functional Matrix chat CLI client


Languages

Language:Python 96.0%Language:Shell 4.0%