matty 0.10.0
A Terminal UI for Matrix chat - simple and AI-friendly
License: MIT
Requires Python: >=3.12
Keywords: ai-friendly, chat, cli, client, matrix

<div align="center">
  <img src="logo.svg" alt="Matrix TUI Logo" width="200" height="200">

  # 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.
</div>

[![PyPI](https://img.shields.io/pypi/v/matty.svg)](https://pypi.python.org/pypi/matty)
[![Build Status](https://github.com/basnijholt/matty/actions/workflows/pytest.yml/badge.svg)](https://github.com/basnijholt/matty/actions/workflows/pytest.yml)
[![CodeCov](https://codecov.io/gh/basnijholt/matty/branch/main/graph/badge.svg)](https://codecov.io/gh/basnijholt/matty)
[![GitHub Repo stars](https://img.shields.io/github/stars/basnijholt/matty)](https://github.com/basnijholt/matty)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/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

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

For development, clone the repo and install dependencies:

```bash
# 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:

```bash
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

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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)             │
│ tui           Launch interactive TUI chat interface.                                   │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Rooms Command

List all joined Matrix rooms:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty rooms --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                    │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Messages Command

Get recent messages from a room:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty messages --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                    │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Users Command

List users in a room:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty users --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                    │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Thread Commands

View and interact with threads:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty threads --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                    │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty thread --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                    │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Send Command

Send messages to rooms:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty send --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                               │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Reply Command

Reply to messages:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty reply --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                               │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Thread Start Command

Start a thread from a message:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty thread-start --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                               │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Thread Reply Command

Reply in a thread:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty thread-reply --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                               │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### React Command

Add reactions to messages:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty react --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                                  │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Reactions Command

View reactions on a message:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty reactions --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                    │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

### Redact Command

Delete/redact messages:

<!-- CODE:BASH:START -->
<!-- echo '```' -->
<!-- matty redact --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```

 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.                                  │
╰────────────────────────────────────────────────────────────────────────────────────────╯

```

<!-- OUTPUT:END -->

## Command Aliases

For faster typing, all commands have short aliases:

- `matty r` → `matty rooms` - List all rooms
- `matty m` → `matty messages` - Show messages from a room
- `matty u` → `matty users` - Show users in a room
- `matty s` → `matty send` - Send a message
- `matty t` → `matty threads` - List threads
- `matty th` → `matty thread` - Show thread messages
- `matty re` → `matty reply` - Reply to a message
- `matty ts` → `matty thread-start` - Start a thread
- `matty tr` → `matty thread-reply` - Reply in a thread
- `matty rx` → `matty react` - Add a reaction to a message
- `matty del` → `matty redact` - Delete/redact a message
- `matty rxs` → `matty reactions` - Show reactions on a message

## Examples

### Basic Usage

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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:

```bash
# 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:
```bash
# 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

```bash
# 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