README
ΒΆ
marchat
A lightweight terminal chat with real-time messaging over WebSockets, optional E2E encryption, and a flexible plugin ecosystem. Built for developers who prefer the command line.
Latest Updates
v0.9.0-beta.4 (Current)
- Admin Metrics: Fixed the Total Messages counter in the web admin panel for accurate reporting
- Encrypted Sessions: Restored plugin command support for non-admin users; server still enforces permissions
- Dependencies: Updated
github.com/charmbracelet/x/termto 0.2.2 for improved terminal handling - Docs & Release Process: Refreshed release notes and contributor acknowledgments ahead of the new beta
Recent Releases
- v0.9.0-beta.3: Added :q quit command, improved theme handling, ESC behavior tweaks, and better database backups
- v0.9.0-beta.2: Database performance improvements, documentation enhancements, dependency updates
- v0.9.0-beta.1: Enhanced notifications, custom themes, plugin ecosystem, test coverage improvements
- v0.8.0-beta.11: Encryption UI, hotkey alternatives, command encryption fix, username validation
- v0.8.0-beta.10: Plugin persistence, state management, auto-discovery, deadlock fixes
- v0.8.0-beta.9: Critical security fixes for path traversal and command injection
- v0.8.0-beta.8: Debug log management, log rotation, full plugin management, plugin hotkeys
- v0.8.0-beta.7: Real-time log capture, OS-specific log export, metrics tracking
- v0.8.0-beta.6: Profile selection bug fix, object-based returns
- v0.8.0-beta.5: Database backup fix, improved admin commands
- v0.8.0-beta.4: Interactive server setup, simplified configuration
- v0.8.0-beta.3: Environment variables only setup, container-friendly configuration
- v0.8.0-beta.2: Interactive server configuration, profile management
- v0.8.0-beta.1: Comprehensive test suite, cross-platform testing
- v0.7.0-beta.7: Advanced security hardening, session management
Full changelog on GitHub releases.

Features
- Terminal UI - Beautiful TUI built with Bubble Tea
- Real-time Chat - Fast WebSocket messaging with SQLite backend (PostgreSQL/MySQL planned)
- Plugin System - Remote registry with text commands and Alt+key hotkeys
- E2E Encryption - X25519/ChaCha20-Poly1305 with global encryption
- File Sharing - Send files up to 1MB (configurable) with interactive picker
- Admin Controls - User management, bans, kick system with ban history gaps
- Smart Notifications - Bell + desktop notifications with quiet hours and focus mode (guide)
- Themes - Built-in themes + custom themes via JSON (guide)
- Docker Support - Containerized deployment with security features
- Health Monitoring -
/healthand/health/simpleendpoints with system metrics - Structured Logging - JSON logs with component separation and user tracking
- Cross-Platform - Runs on Linux, macOS, Windows, and Android/Termux
Overview
marchat started as a fun weekend project for father-son coding sessions and has evolved into a lightweight, self-hosted terminal chat application designed specifically for developers who love the command line. Currently runs with SQLite, with PostgreSQL and MySQL support planned for greater scalability.
Key Benefits:
- Self-hosted: No external services required
- Cross-platform: Linux, macOS, Windows, and Android/Termux
- Secure: Optional E2E encryption with X25519/ChaCha20-Poly1305
- Extensible: Plugin ecosystem for custom functionality
- Lightweight: Minimal resource usage, perfect for servers
| Cross-Platform | Theme Switching |
|---|---|
![]() |
![]() |
Quick Start
1. Generate Admin Key
openssl rand -hex 32
2. Start Server
Option A: Environment Variables (Recommended)
export MARCHAT_ADMIN_KEY="your-generated-key"
export MARCHAT_USERS="admin1,admin2"
./marchat-server
# With admin panel
./marchat-server --admin-panel
# With web panel
./marchat-server --web-panel
Option B: Interactive Setup
./marchat-server --interactive
3. Connect Client
# Admin connection
./marchat-client --username admin1 --admin --admin-key your-key --server ws://localhost:8080/ws
# Regular user
./marchat-client --username user1 --server ws://localhost:8080/ws
# Or use interactive mode
./marchat-client
Database Schema
Key tables for message tracking and moderation:
- messages: Core message storage with
message_id - user_message_state: Per-user message history state
- ban_history: Ban/unban event tracking for history gaps
Installation
Binary Installation:
# Linux (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.9.0-beta.4/marchat-v0.9.0-beta.4-linux-amd64.zip
unzip marchat-v0.9.0-beta.4-linux-amd64.zip && chmod +x marchat-*
# macOS (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.9.0-beta.4/marchat-v0.9.0-beta.4-darwin-amd64.zip
unzip marchat-v0.9.0-beta.4-darwin-amd64.zip && chmod +x marchat-*
# Windows - PowerShell
iwr -useb https://raw.githubusercontent.com/Cod-e-Codes/marchat/main/install.ps1 | iex
Docker:
docker pull codecodesxyz/marchat:v0.9.0-beta.4
docker run -d -p 8080:8080 \
-e MARCHAT_ADMIN_KEY=$(openssl rand -hex 32) \
-e MARCHAT_USERS=admin1,admin2 \
codecodesxyz/marchat:v0.9.0-beta.4
From Source:
git clone https://github.com/Cod-e-Codes/marchat.git && cd marchat
go mod tidy
go build -o marchat-server ./cmd/server
go build -o marchat-client ./client
Prerequisites for source build:
- Go 1.24+ (download)
- Linux clipboard support:
sudo apt install xclip(Ubuntu/Debian) orsudo yum install xclip(RHEL/CentOS)
Configuration
Essential Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
MARCHAT_ADMIN_KEY |
Yes | - | Admin authentication key |
MARCHAT_USERS |
Yes | - | Comma-separated admin usernames |
MARCHAT_PORT |
No | 8080 |
Server port |
MARCHAT_DB_PATH |
No | ./config/marchat.db |
Database file path |
MARCHAT_TLS_CERT_FILE |
No | - | TLS certificate (enables wss://) |
MARCHAT_TLS_KEY_FILE |
No | - | TLS private key |
MARCHAT_GLOBAL_E2E_KEY |
No | - | Base64 32-byte global encryption key |
MARCHAT_MAX_FILE_BYTES |
No | 1048576 |
Max file size in bytes (1MB default) |
MARCHAT_MAX_FILE_MB |
No | 1 |
Max file size in MB (alternative to bytes) |
MARCHAT_ALLOWED_USERS |
No | - | Username allowlist (comma-separated) |
Additional variables: MARCHAT_LOG_LEVEL, MARCHAT_CONFIG_DIR, MARCHAT_BAN_HISTORY_GAPS, MARCHAT_PLUGIN_REGISTRY_URL
File Size Configuration: Use either MARCHAT_MAX_FILE_BYTES (exact bytes) or MARCHAT_MAX_FILE_MB (megabytes). If both are set, MARCHAT_MAX_FILE_BYTES takes priority.
Interactive Setup: Use --interactive flag for guided server configuration when environment variables are missing.
Admin Commands
User Management
| Command | Description | Hotkey |
|---|---|---|
:ban <user> |
Permanent ban | Ctrl+B (with user selected) |
:kick <user> |
24h temporary ban | Ctrl+K (with user selected) |
:unban <user> |
Remove permanent ban | Ctrl+Shift+B |
:allow <user> |
Override kick early | Ctrl+Shift+A |
:forcedisconnect <user> |
Force disconnect user | Ctrl+F (with user selected) |
:cleanup |
Clean stale connections | - |
Database Operations (:cleardb or Ctrl+D menu)
- Clear DB - Wipe all messages
- Backup DB - Create database backup
- Show Stats - Display database statistics
User Commands
| Command | Description | Hotkey |
|---|---|---|
:theme <name> |
Switch theme (built-in or custom) | Ctrl+T (cycles) |
:themes |
List all available themes | - |
:time |
Toggle 12/24-hour format | Alt+T |
:clear |
Clear chat buffer | Ctrl+L |
:q |
Quit application (vim-style) | - |
:sendfile [path] |
Send file (or open picker without path) | Alt+F |
:savefile <name> |
Save received file | - |
:code |
Open code composer with syntax highlighting | Alt+C |
:notify-mode <mode> |
Set notification mode (none/bell/desktop/both) | Alt+N (toggle desktop) |
:bell |
Toggle bell notifications | - |
:bell-mention |
Toggle mention-only notifications | - |
:focus [duration] |
Enable focus mode (mute notifications) | - |
:quiet <start> <end> |
Set quiet hours (e.g., :quiet 22 8) |
- |
Note: Hotkeys work in both encrypted and unencrypted sessions since they're handled client-side.
Notifications: See NOTIFICATIONS.md for full notification system documentation including desktop notifications, quiet hours, and focus mode.
Plugin Commands (Admin Only)
Text commands and hotkeys for plugin management. See Plugin Management hotkeys for keyboard shortcuts.
| Command | Description | Hotkey |
|---|---|---|
:store |
Browse plugin store | Alt+S |
:plugin list or :list |
List installed plugins | Alt+P |
:plugin install <name> or :install <name> |
Install plugin | Alt+I |
:plugin uninstall <name> or :uninstall <name> |
Uninstall plugin | Alt+U |
:plugin enable <name> or :enable <name> |
Enable plugin | Alt+E |
:plugin disable <name> or :disable <name> |
Disable plugin | Alt+D |
:refresh |
Refresh plugin list from registry | Alt+R |
Note: Both text commands and hotkeys work in E2E encrypted sessions (sent as admin messages that bypass encryption).
File Sharing
Direct send:
:sendfile /path/to/file.txt
Interactive picker:
:sendfile
Navigate with arrow keys, Enter to select/open folders, ".. (Parent Directory)" to go up.
Supported types: Text, code, images, documents, archives (.txt, .md, .json, .go, .py, .js, .png, .jpg, .pdf, .zip, etc.)
Keyboard Shortcuts
General
| Key | Action |
|---|---|
Ctrl+H |
Toggle help overlay |
Enter |
Send message |
Esc |
Close menus / dialogs |
:q |
Quit application (vim-style) |
β/β |
Scroll chat |
PgUp/PgDn |
Page through chat |
Ctrl+C/V/X/A |
Copy/Paste/Cut/Select all |
User Features
| Key | Action |
|---|---|
Alt+F |
Send file (file picker) |
Alt+C |
Create code snippet |
Ctrl+T |
Cycle themes |
Alt+T |
Toggle 12/24h time |
Alt+N |
Toggle desktop notifications |
Ctrl+L |
Clear chat history |
Admin Interface (Client)
| Key | Action |
|---|---|
Ctrl+U |
Select/cycle user |
Ctrl+D |
Database operations menu |
Ctrl+K |
Kick selected user |
Ctrl+B |
Ban selected user |
Ctrl+F |
Force disconnect selected user |
Ctrl+Shift+B |
Unban user (prompts for username) |
Ctrl+Shift+A |
Allow user (prompts for username) |
Plugin Management (Admin)
| Key | Action |
|---|---|
Alt+P |
List installed plugins |
Alt+S |
View plugin store |
Alt+R |
Refresh plugin list |
Alt+I |
Install plugin (prompts for name) |
Alt+U |
Uninstall plugin (prompts for name) |
Alt+E |
Enable plugin (prompts for name) |
Alt+D |
Disable plugin (prompts for name) |
Server
| Key | Action |
|---|---|
Ctrl+A |
Open terminal admin panel |
Admin Panels
Terminal Admin Panel
Enable with --admin-panel flag, then press Ctrl+A to access:
- Real-time server statistics (users, messages, performance)
- User management interface
- Plugin configuration
- Database operations
- Requires terminal environment (auto-disabled in systemd/non-terminal)
Web Admin Panel
Enable with --web-panel flag, access at http://localhost:8080/admin:
- Secure session-based login (1-hour expiration)
- Live dashboard with metrics visualization
- RESTful API endpoints with
X-Admin-Keyauth - CSRF protection on all state-changing operations
- HttpOnly cookies with SameSite protection
API Example:
curl -H "Cookie: admin_session=YOUR_SESSION" http://localhost:8080/admin/api/overview
TLS Support
When to Use TLS
- Public deployments: Server accessible from internet
- Production environments: Enhanced security required
- Corporate networks: Security policy compliance
- HTTPS reverse proxies: Behind nginx, traefik, etc.
Configuration Examples
With TLS (production):
# Generate self-signed cert (testing only)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
export MARCHAT_ADMIN_KEY="your-key"
export MARCHAT_USERS="admin1,admin2"
export MARCHAT_TLS_CERT_FILE="./cert.pem"
export MARCHAT_TLS_KEY_FILE="./key.pem"
./marchat-server # Shows wss:// in banner
Without TLS (development):
export MARCHAT_ADMIN_KEY="your-key"
export MARCHAT_USERS="admin1,admin2"
./marchat-server # Shows ws:// in banner
Client with TLS:
# With verification (production)
./marchat-client --server wss://localhost:8080/ws
# Skip verification (dev/self-signed only)
./marchat-client --skip-tls-verify --server wss://localhost:8080/ws
Warning: Use
--skip-tls-verifyonly for development. Production should use valid CA-signed certificates.
E2E Encryption
Global encryption for secure group chat using shared keys across all clients.
How It Works
- Shared Key Model: All clients use same global encryption key for public channels
- Simplified Management: No complex per-user key exchange
- X25519/ChaCha20-Poly1305: Industry-standard encryption algorithms
- Environment Variable:
MARCHAT_GLOBAL_E2E_KEYfor key distribution - Auto-Generation: Creates new key if none provided
Setup Options
Option 1: Shared Key (Recommended)
# Generate 32-byte key
openssl rand -base64 32
# Set on all clients
export MARCHAT_GLOBAL_E2E_KEY="your-generated-key"
# Connect with E2E
./marchat-client --e2e --keystore-passphrase your-pass --username alice --server ws://localhost:8080/ws
Option 2: Auto-Generate
# Client generates and displays new key
./marchat-client --e2e --keystore-passphrase your-pass --username alice --server ws://localhost:8080/ws
# Output shows:
# π Generated new global E2E key (ID: RsLi9ON0...)
# π‘ Set MARCHAT_GLOBAL_E2E_KEY=fF+HkmGArkPNsdb+... to share this key
Expected Output
π Using global E2E key from environment variable
π Global chat encryption: ENABLED (Key ID: RsLi9ON0...)
β
Encryption validation passed
π E2E encryption enabled with keystore: config/keystore.dat
Security Features
- Forward Secrecy: Unique session keys per conversation
- Server Privacy: Server cannot read encrypted messages
- Local Keystore: Encrypted with passphrase protection
- Validation: Automatic encryption/decryption testing on startup
Plugin System
Extend functionality with remote plugins from configured registry.
Configuration
# Default GitHub registry
export MARCHAT_PLUGIN_REGISTRY_URL="https://raw.githubusercontent.com/Cod-e-Codes/marchat-plugins/main/registry.json"
# Custom registry
export MARCHAT_PLUGIN_REGISTRY_URL="https://my-registry.com/plugins.json"
Commands
Text commands:
:store # Browse available plugins
:plugin install echo # Install plugin
:plugin list # List installed
:plugin uninstall echo # Remove plugin
:enable echo # Enable installed plugin
:disable echo # Disable plugin
:refresh # Refresh plugin registry
Keyboard shortcuts (Admin only):
Alt+P- List installed pluginsAlt+S- View plugin storeAlt+R- Refresh plugin listAlt+I- Install plugin (prompts for name)Alt+U- Uninstall plugin (prompts for name)Alt+E- Enable plugin (prompts for name)Alt+D- Disable plugin (prompts for name)
Note: Plugin management commands and custom plugin commands (e.g.,
:echo) work in E2E encrypted sessions. See Plugin Commands for full reference.
Available Plugins
- echo (v2.0.1): Simple echo plugin for testing (provides
:echocommand) - weather (v1.0.0): Get weather information and forecasts using wttr.in (
:weather [location],:forecast [location]) - githooks (v1.0.0): Git repository management with status, log, branch, and diff commands (
:git-status,:git-log,:git-branch,:git-diff,:git-watchadmin-only)
See PLUGIN_ECOSYSTEM.md for development guide.
Moderation System
Temporary Kicks (24 hours):
:kick <username>orCtrl+Kfor temporary discipline- Auto-allowed after 24 hours, or override early with
:allow - Ideal for cooling-off periods
Permanent Bans (indefinite):
:ban <username>orCtrl+Bfor serious violations- Remains until manual
:unbanorCtrl+Shift+B - Ideal for persistent troublemakers
Ban History Gaps:
Prevents banned users from seeing messages sent during ban periods. Enable with MARCHAT_BAN_HISTORY_GAPS=true (default).
Client Configuration
Interactive Mode (Default)
./marchat-client
Guides through server URL, username, admin privileges, E2E encryption, theme selection, and profile saving.
Quick Start Options
# Auto-connect to recent profile
./marchat-client --auto
# Select from saved profiles
./marchat-client --quick-start
Profile Management
Profiles stored in platform-appropriate locations:
- Windows:
%APPDATA%\marchat\profiles.json - macOS:
~/Library/Application Support/marchat/profiles.json - Linux:
~/.config/marchat/profiles.json
During profile selection:
iorv- View profile detailsr- Rename profiled- Delete profile
Traditional Flags
# Basic connection
./marchat-client --server ws://localhost:8080/ws --username alice
# Admin connection
./marchat-client --server ws://localhost:8080/ws --username admin --admin --admin-key your-key
# E2E encrypted
./marchat-client --server ws://localhost:8080/ws --username alice --e2e --keystore-passphrase your-pass
# Non-interactive (requires all flags)
./marchat-client --non-interactive --server ws://localhost:8080/ws --username alice
Security Best Practices
-
Generate Secure Keys
# Admin key (64 hex characters) openssl rand -hex 32 # Global E2E key (base64-encoded 32 bytes) openssl rand -base64 32 -
Secure File Permissions
chmod 600 ./config/marchat.db # Database chmod 600 ./config/keystore.dat # Keystore chmod 700 ./config # Config directory -
Production Deployment
- Use TLS (
wss://) with valid CA-signed certificates - Deploy behind reverse proxy (nginx/traefik)
- Restrict server access to trusted networks
- Use Docker secrets for sensitive environment variables
- Enable rate limiting and brute force protection
- Monitor security logs regularly
- Use TLS (
-
E2E Encryption
- Store
MARCHAT_GLOBAL_E2E_KEYsecurely - Use strong keystore passphrases
- Never share keystores between users
- Rotate keys periodically for sensitive deployments
- Store
-
Username Allowlist (Optional)
# Restrict to specific users for private servers export MARCHAT_ALLOWED_USERS="alice,bob,charlie"- Usernames validated (letters, numbers,
_,-,.only) - Max 32 characters, cannot start with
:or. - Case-insensitive matching
- Protects against log injection and command injection
- Usernames validated (letters, numbers,
Troubleshooting
| Issue | Solution |
|---|---|
| Connection failed | Verify ws:// or wss:// protocol in URL |
| Admin commands not working | Check --admin flag and correct --admin-key |
| Clipboard issues (Linux) | Install xclip: sudo apt install xclip |
| Port in use | Change port: export MARCHAT_PORT=8081 |
| Database migration fails | Check file permissions, backup before source build |
| Message history missing | Expected after updates - user states reset for ban/unban improvements |
| Ban history gaps not working | Ensure MARCHAT_BAN_HISTORY_GAPS=true (default) and ban_history table exists |
| TLS certificate errors | Use --skip-tls-verify for dev with self-signed certs |
| Plugin installation fails | Verify MARCHAT_PLUGIN_REGISTRY_URL is accessible and valid JSON |
| E2E encryption errors | Ensure --e2e flag and keystore passphrase provided, check debug logs |
| Global E2E key errors | Verify key is valid base64-encoded 32-byte key: openssl rand -base64 32 |
| Blank encrypted messages | Fixed in v0.3.0-beta.5+ - ensure latest version |
| Username already taken | Use admin :forcedisconnect <user> or wait 5min for auto-cleanup |
| Stale connections | Server auto-cleans every 5min, or admin use :cleanup |
| Client frozen at startup | Fixed in latest - --quick-start uses proper UI |
Stale Connection Management
Automatic: Server detects and removes stale connections every 5 minutes using WebSocket ping.
Manual (Admin):
:cleanup # Clean all stale connections
:forcedisconnect username # Force disconnect specific user
Common scenarios:
- Client crash/Ctrl+C: Auto-cleaned within 5 minutes
- Network interruption: Removed on next cleanup cycle
- Immediate reconnect: Admin uses
:forcedisconnect
Testing
Foundational test suite covering core functionality, cryptography, and plugins.
Running Tests
go test ./... # Run all tests
go test -cover ./... # With coverage
go test ./server -v # Specific package
go test ./... -timeout 10s # With timeout (CI recommended)
Test Scripts
- Linux/macOS:
./test.sh - Windows:
.\test.ps1
Coverage Summary
| Package | Coverage | Size | Status |
|---|---|---|---|
plugin/license |
83.1% | 229 LOC | High |
shared |
82.4% | 283 LOC | High |
config |
78.6% | 304 LOC | High |
client/crypto |
76.5% | 289 LOC | High |
client/config |
54.5% | 1816 LOC | Medium |
plugin/store |
46.8% | 559 LOC | Medium |
cmd/license |
42.2% | 160 LOC | Medium |
server |
32.6% | 5500+ LOC | Medium |
client |
26.2% | 3700+ LOC | Medium |
plugin/host |
23.7% | 486 LOC | Low |
plugin/manager |
22.5% | 464 LOC | Low |
cmd/server |
5.3% | 403 LOC | Low |
Overall: 35.3% - See TESTING.md for detailed information.
Contributing
We welcome contributions! See CONTRIBUTING.md for:
- Development setup instructions
- Code style guidelines and conventions
- Pull request process and requirements
- Testing expectations
Quick Start:
git clone https://github.com/Cod-e-Codes/marchat.git
cd marchat
go mod tidy
go test ./...
Documentation
- NOTIFICATIONS.md - Notification system guide (desktop, quiet hours, focus mode)
- THEMES.md - Custom theme creation guide
- PLUGIN_ECOSYSTEM.md - Plugin development guide
- ROADMAP.md - Planned features and enhancements
- TESTING.md - Comprehensive testing guide
- CONTRIBUTING.md - Contribution guidelines
- SECURITY.md - Security policy and reporting
- CONTRIBUTORS.md - Full contributor list
Getting Help
- Report bugs
- Ask questions
- Commercial support: cod.e.codes.dev@gmail.com
Appreciation
Thanks to Self-Host Weekly, mtkblogs.com, and Terminal Trove for featuring marchat!
See CONTRIBUTORS.md for full contributor list.
License: MIT License

