A Terminal UI for Matrix chat - simple and AI-friendly
Project description
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.
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 can store Matrix access-token credentials in your user config directory:
matty auth sso https://matrix.example.com
If the homeserver advertises multiple SSO providers, list their provider IDs and labels:
matty auth providers https://matrix.example.com
Then pass the provider ID, name, or brand explicitly. Matty resolves labels like github
to the canonical provider ID before opening the browser:
matty auth sso https://matrix.example.com --idp-id github
Existing Matrix access token:
matty auth token https://matrix.example.com @alice:example.com "$MATRIX_ACCESS_TOKEN" --device-id DEVICEID
Password auth, when enabled by the homeserver:
matty auth password https://matrix.example.com @alice:example.com
Credentials are stored in the config file reported by:
matty config-path
Remove stored credentials:
matty auth logout
Environment variables are still supported and override stored credentials.
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_USER_ID |
Full Matrix user ID for access-token auth | None | @alice:example.com |
MATRIX_DEVICE_ID |
Matrix device ID for access-token auth | None | DEVICEID |
MATRIX_ACCESS_TOKEN |
Matrix access token | None | syt_... |
MATRIX_SSL_VERIFY |
Whether to verify SSL certificates | true |
false (for test servers) |
Notes:
MATRIX_USERNAMEshould be provided without the@prefix or:serversuffix- Set
MATRIX_SSL_VERIFY=falsewhen 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. │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Setup ────────────────────────────────────────────────────────────────────────────────╮
│ config-path Print the path to the Matty credential config file. │
│ auth Manage Matrix authentication credentials. │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Browse ───────────────────────────────────────────────────────────────────────────────╮
│ rooms List all joined rooms. (alias: r) │
│ messages Show recent messages from a room. (alias: m) │
│ users Show users in a room. (alias: u) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Messaging ────────────────────────────────────────────────────────────────────────────╮
│ send Send a message to a room. Supports @mentions. (alias: s) │
│ reply Reply to a specific message using its handle. (alias: re) │
│ edit Edit a message using its handle. (alias: e) │
│ redact Delete/redact a message using its handle. (alias: del) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Threads ──────────────────────────────────────────────────────────────────────────────╮
│ threads List all threads in a room. (alias: t) │
│ thread Show all messages in a specific thread. (alias: th) │
│ thread-start Start a new thread from a message using its handle. (alias: ts) │
│ thread-reply Reply within an existing thread. (alias: tr) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Reactions ────────────────────────────────────────────────────────────────────────────╮
│ react Add a reaction to a message using its handle. (alias: rx) │
│ reactions Show detailed reactions for a specific message. (alias: rxs) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Interface ────────────────────────────────────────────────────────────────────────────╮
│ tui Launch interactive TUI chat interface. │
╰────────────────────────────────────────────────────────────────────────────────────────╯
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) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env │
│ var) │
│ --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 │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --limit -l INTEGER [default: 20] │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env │
│ var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env │
│ var) │
│ --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 │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env │
│ var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env │
│ var) │
│ --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 │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --limit -l INTEGER Number of messages to check [default: 50] │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env │
│ var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env │
│ var) │
│ --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 │
│ thread_id [THREAD_ID] Thread ID (t1, t2, etc.) or full Matrix ID │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --limit -l INTEGER Number of messages to fetch [default: 50] │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env │
│ var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env │
│ var) │
│ --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 │
│ message [MESSAGE] Message to send (use @username for mentions) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --stdin Read message from stdin │
│ --file -f PATH Read message from file │
│ --no-mentions Don't parse @mentions in messages │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env var) │
│ --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 │
│ handle [HANDLE] Message handle (m1, m2, etc.) to reply to │
│ message [MESSAGE] Reply message │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --no-mentions Don't parse @mentions in messages │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env var) │
│ --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 │
│ handle [HANDLE] Message handle (m1, m2, etc.) to start thread from │
│ message [MESSAGE] First message in the thread │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --no-mentions Don't parse @mentions in messages │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env var) │
│ --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 │
│ thread_id [THREAD_ID] Thread ID (t1, t2, etc.) or full Matrix ID │
│ message [MESSAGE] Reply message │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --no-mentions Don't parse @mentions in messages │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env var) │
│ --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 │
│ handle [HANDLE] Message handle (m1, m2, etc.) to react to │
│ emoji [EMOJI] Emoji reaction (e.g., 👍, ❤️, 😄) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env var) │
│ --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 │
│ handle [HANDLE] Message handle (m1, m2, etc.) to show reactions for │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env │
│ var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env │
│ var) │
│ --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 │
│ handle [HANDLE] Message handle (m1, m2, etc.) to redact/delete │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────╮
│ --reason -r TEXT Reason for redaction │
│ --username -u TEXT Matrix username (overrides MATRIX_USERNAME env var) │
│ --password -p TEXT Matrix password (overrides MATRIX_PASSWORD env var) │
│ --help -h Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────╯
Command Aliases
For faster typing, all commands have short aliases:
matty r→matty rooms- List all roomsmatty m→matty messages- Show messages from a roommatty u→matty users- Show users in a roommatty s→matty send- Send a messagematty t→matty threads- List threadsmatty th→matty thread- Show thread messagesmatty re→matty reply- Reply to a messagematty ts→matty thread-start- Start a threadmatty tr→matty thread-reply- Reply in a threadmatty rx→matty react- Add a reaction to a messagematty del→matty redact- Delete/redact a messagematty rxs→matty 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:
- Rich (default) - Beautiful terminal UI with tables and colors
- Simple - Plain text output, perfect for scripts
- 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
matty/
├── matty/ # Package source
│ ├── __init__.py # Compatibility exports for the historical module API
│ ├── __main__.py # `python -m matty` entry point
│ ├── cli.py # Main CLI application (functional style)
│ ├── tui.py # Interactive TUI application
│ └── matty_tui.tcss # TUI stylesheet
├── 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file matty-0.11.1.tar.gz.
File metadata
- Download URL: matty-0.11.1.tar.gz
- Upload date:
- Size: 39.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f4b1dcafeec62cfecc7329df89757fe03367eae41933dd9871ea27cbd22fb12
|
|
| MD5 |
fc4e020d424045eeebaf93f26386bd7b
|
|
| BLAKE2b-256 |
3fc63e1d5735883810bb59bcebe61ffba8b5b3167ea1249d27b458e2d7a88eb4
|
Provenance
The following attestation bundles were made for matty-0.11.1.tar.gz:
Publisher:
release.yml on basnijholt/matty
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
matty-0.11.1.tar.gz -
Subject digest:
7f4b1dcafeec62cfecc7329df89757fe03367eae41933dd9871ea27cbd22fb12 - Sigstore transparency entry: 1442759661
- Sigstore integration time:
-
Permalink:
basnijholt/matty@672647f85d144e01943fc4f073cdbcff2e0c9e6c -
Branch / Tag:
refs/tags/v0.11.1 - Owner: https://github.com/basnijholt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@672647f85d144e01943fc4f073cdbcff2e0c9e6c -
Trigger Event:
release
-
Statement type:
File details
Details for the file matty-0.11.1-py3-none-any.whl.
File metadata
- Download URL: matty-0.11.1-py3-none-any.whl
- Upload date:
- Size: 35.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0aac2c1aea9438648d35ae95fe7e6edb2dd75bb9d5bf1d89cc9dfcbff35a37f
|
|
| MD5 |
f313b92d75ee45dd73ab5579adffd8e8
|
|
| BLAKE2b-256 |
357b52f859eba009ef9de716c874668e51c62e78d10c735e9c1e81df9b2967ed
|
Provenance
The following attestation bundles were made for matty-0.11.1-py3-none-any.whl:
Publisher:
release.yml on basnijholt/matty
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
matty-0.11.1-py3-none-any.whl -
Subject digest:
b0aac2c1aea9438648d35ae95fe7e6edb2dd75bb9d5bf1d89cc9dfcbff35a37f - Sigstore transparency entry: 1442759793
- Sigstore integration time:
-
Permalink:
basnijholt/matty@672647f85d144e01943fc4f073cdbcff2e0c9e6c -
Branch / Tag:
refs/tags/v0.11.1 - Owner: https://github.com/basnijholt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@672647f85d144e01943fc4f073cdbcff2e0c9e6c -
Trigger Event:
release
-
Statement type: