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.
- Real-time log capture: Admin panels now display live server logs from memory buffer
- OS-specific log export: Logs export to appropriate directories (Windows/macOS/Linux/Android)
- Metrics tracking: Connection and disconnect counters now display accurate totals
- Structured logging: Converted hub and server events to use structured loggers
- Live updates: Admin panel logs grow in real-time as events occur
- 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.
- 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
:store
and:plugin
commands - 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
- Bell Notifications - Audio alerts with
:bell
and:bell-mention
- Themes - System (default), patriot, retro, modern
- Docker Support - Containerized deployment with security features
- Health Monitoring -
/health
and/health/simple
endpoints with system metrics - Structured Logging - JSON logs with component separation and user tracking
- Cross-Platform - Runs on Linux, macOS, Windows, and Android/Termux
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 |
---|---|
![]() |
![]() |
openssl rand -hex 32
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
# 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
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
Binary Installation:
# Linux (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.8.0-beta.3/marchat-v0.8.0-beta.3-linux-amd64.zip
unzip marchat-v0.8.0-beta.3-linux-amd64.zip && chmod +x marchat-*
# macOS (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.8.0-beta.3/marchat-v0.8.0-beta.3-darwin-amd64.zip
unzip marchat-v0.8.0-beta.3-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.8.0-beta.2
docker run -d -p 8080:8080 \
-e MARCHAT_ADMIN_KEY=$(openssl rand -hex 32) \
-e MARCHAT_USERS=admin1,admin2 \
codecodesxyz/marchat:v0.8.0-beta.2
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.23+ (download)
- Linux clipboard support:
sudo apt install xclip
(Ubuntu/Debian) orsudo yum install xclip
(RHEL/CentOS)
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 (1MB default) |
Additional variables: MARCHAT_LOG_LEVEL
, MARCHAT_CONFIG_DIR
, MARCHAT_BAN_HISTORY_GAPS
, MARCHAT_PLUGIN_REGISTRY_URL
, MARCHAT_MAX_FILE_MB
Interactive Setup: Use --interactive
flag for guided server configuration when environment variables are missing.
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 | - |
- Clear DB - Wipe all messages
- Backup DB - Create database backup
- Show Stats - Display database statistics
Command | Description |
---|---|
:theme <name> |
Switch theme (system/patriot/retro/modern) |
:time |
Toggle 12/24-hour format |
:clear |
Clear chat buffer |
:sendfile [path] |
Send file (or open picker without path) |
:savefile <name> |
Save received file |
:code |
Open code composer with syntax highlighting |
:bell |
Toggle message notifications |
:bell-mention |
Toggle mention-only notifications |
:store |
Browse plugin store |
:plugin install/list/uninstall |
Manage plugins |
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.)
Key | Action |
---|---|
Ctrl+H |
Toggle help overlay |
Enter |
Send message |
Esc |
Quit |
↑/↓ |
Scroll history |
PgUp/PgDn |
Page through history |
Ctrl+C/V/X/A |
Copy/Paste/Cut/Select all |
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) |
Key | Action |
---|---|
Ctrl+A |
Open 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)
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-Key
auth - 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
- Public deployments: Server accessible from internet
- Production environments: Enhanced security required
- Corporate networks: Security policy compliance
- HTTPS reverse proxies: Behind nginx, traefik, etc.
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-verify
only for development. Production should use valid CA-signed certificates.
Global encryption for secure group chat using shared keys across all clients.
- 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_KEY
for key distribution - Auto-Generation: Creates new key if none provided
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
🔐 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
- 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
Extend functionality with remote plugins from configured registry.
# 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"
:store # Browse available plugins
:plugin install echo # Install plugin
:plugin list # List installed
:plugin uninstall echo # Remove plugin
- Echo: Simple echo plugin for testing
See PLUGIN_ECOSYSTEM.md for development guide.
Temporary Kicks (24 hours):
:kick <username>
orCtrl+K
for temporary discipline- Auto-allowed after 24 hours, or override early with
:allow
- Ideal for cooling-off periods
Permanent Bans (indefinite):
:ban <username>
orCtrl+B
for serious violations- Remains until manual
:unban
orCtrl+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).
./marchat-client
Guides through server URL, username, admin privileges, E2E encryption, theme selection, and profile saving.
# Auto-connect to recent profile
./marchat-client --auto
# Select from saved profiles
./marchat-client --quick-start
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:
i
orv
- View profile detailsr
- Rename profiled
- Delete profile
# 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
-
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_KEY
securely - Use strong keystore passphrases
- Never share keystores between users
- Rotate keys periodically for sensitive deployments
- Store
Issue | Solution |
---|---|
Connection failed | Verify ws:// or wss:// protocol in URL |
Admin commands not working | Check --admin flag and correct --admin-key |
Admin commands encrypted | Hotkey alternatives work when E2E enabled (e.g., Ctrl+Shift+A ) |
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 |
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
Foundational test suite covering core functionality, cryptography, and plugins.
go test ./... # Run all tests
go test -cover ./... # With coverage
go test ./server -v # Specific package
go test ./... -timeout 10s # With timeout (CI recommended)
- Linux/macOS:
./test.sh
- Windows:
.\test.ps1
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 |
55.2% | 1816 LOC | Medium |
plugin/store |
46.8% | 559 LOC | Medium |
cmd/license |
42.2% | 160 LOC | Medium |
server |
35.4% | 5391 LOC | Medium |
client |
27.8% | 3679 LOC | Medium |
plugin/host |
22.3% | 486 LOC | Low |
plugin/manager |
12.4% | 464 LOC | Low |
cmd/server |
5.6% | 403 LOC | Low |
Overall: 37.1% - See TESTING.md for detailed information.
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 ./...
- 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
- Report bugs
- Ask questions
- Commercial support: [email protected]
Thanks to Self-Host Weekly, mtkblogs.com, and Terminal Trove for featuring marchat!
See CONTRIBUTORS.md for full contributor list.
License: MIT License