{"id":29821030,"url":"https://github.com/cod-e-codes/marchat","last_synced_at":"2026-04-06T22:02:35.585Z","repository":{"id":305177141,"uuid":"1020924685","full_name":"Cod-e-Codes/marchat","owner":"Cod-e-Codes","description":"Lightweight terminal chat with server/client binaries, real-time WebSocket messaging, optional E2E encryption, reactions, DMs, channels, plugins, file sharing, admin panel, and code snippets. Built in Go with Bubble Tea and SQLite; ideal for developers and small teams.","archived":false,"fork":false,"pushed_at":"2026-03-30T16:36:53.000Z","size":5653,"stargazers_count":126,"open_issues_count":0,"forks_count":9,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-03-30T18:24:56.040Z","etag":null,"topics":["admin-panel","bubbletea","channels","chat","code-snippets","cross-platform","direct-message","docker","encryption","file-sharing","go","golang","open-source","plugins","real-time","self-hosted","sqlite","terminal","tui","websocket"],"latest_commit_sha":null,"homepage":"https://github.com/Cod-e-Codes/marchat","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Cod-e-Codes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["Cod-e-Codes"]}},"created_at":"2025-07-16T15:48:32.000Z","updated_at":"2026-03-30T16:36:56.000Z","dependencies_parsed_at":"2025-07-18T19:42:26.459Z","dependency_job_id":"c2e7c9be-1673-4591-85f5-9f00b15de277","html_url":"https://github.com/Cod-e-Codes/marchat","commit_stats":null,"previous_names":["cod-e-codes/marchat"],"tags_count":51,"template":false,"template_full_name":null,"purl":"pkg:github/Cod-e-Codes/marchat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cod-e-Codes%2Fmarchat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cod-e-Codes%2Fmarchat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cod-e-Codes%2Fmarchat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cod-e-Codes%2Fmarchat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Cod-e-Codes","download_url":"https://codeload.github.com/Cod-e-Codes/marchat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cod-e-Codes%2Fmarchat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31314189,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["admin-panel","bubbletea","channels","chat","code-snippets","cross-platform","direct-message","docker","encryption","file-sharing","go","golang","open-source","plugins","real-time","self-hosted","sqlite","terminal","tui","websocket"],"created_at":"2025-07-28T23:39:02.458Z","updated_at":"2026-04-02T19:14:47.140Z","avatar_url":"https://github.com/Cod-e-Codes.png","language":"Go","readme":"# marchat\n\n\u003cimg src=\"assets/marchat-transparent.svg\" alt=\"marchat - terminal chat application\" width=\"200\" height=\"auto\"\u003e\n\n[![Go CI](https://github.com/Cod-e-Codes/marchat/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/Cod-e-Codes/marchat/actions/workflows/go.yml)\n[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/Cod-e-Codes/marchat?logo=go)](https://go.dev/dl/)\n[![GitHub all releases](https://img.shields.io/github/downloads/Cod-e-Codes/marchat/total?logo=github)](https://github.com/Cod-e-Codes/marchat/releases)\n[![Docker Pulls](https://img.shields.io/docker/pulls/codecodesxyz/marchat?logo=docker)](https://hub.docker.com/r/codecodesxyz/marchat)\n[![Version](https://img.shields.io/badge/version-v0.10.0--beta.3-blue)](https://github.com/Cod-e-Codes/marchat/releases/tag/v0.10.0-beta.3)\n\nA 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.\n\n**Quick start:** [QUICKSTART.md](QUICKSTART.md) for a single-page walkthrough (install → server → client → next docs).\n\n## Latest Updates\n\n### v0.10.0-beta.3 (Current)\n- **Caddy / WSS**: `docker-compose.proxy.yml`, `deploy/caddy/` (`Caddyfile`, `proxy.env.example`), cross-platform `scripts/build-linux.sh` and `scripts/connect-local-wss.sh`, full walkthrough in `deploy/CADDY-REVERSE-PROXY.md`\n- **Client**: WSS/TLS tweaks; sanitize pasted `--server` URLs; connect from flags without profile picker when server+username are set (keystore passphrase prompted for `--e2e` unless `--non-interactive`); `MARCHAT_GLOBAL_E2E_KEY` unchanged\n- **Server config**: Document `godotenv.Overload` for `config/.env` vs process env (see README / env.example)\n\n### v0.10.0-beta.2\n- **CLI diagnostics**: `marchat-client` and `marchat-server` support `-doctor` and `-doctor-json` for environment, paths, and config health\n- **Build**: `build-release.ps1` sets `CGO_ENABLED=0` for consistent cross-compilation\n- **Dependencies**: `modernc.org/sqlite` 1.47.0 → 1.48.0 (via Dependabot)\n- **Docs**: Updated LOC and test coverage figures; streamlined beta.1 feature list in README\n- **Docker**: image entrypoint fixes `/data` volume permissions and drops to non-root via `su-exec`; Unix line endings on `entrypoint.sh` for reliable Windows-built images\n\n### v0.10.0-beta.1\n- **Message Management**: Edit, delete, pin, search messages by ID\n- **Reactions**: React to messages with emoji aliases (`:react 42 +1`, `heart`, `fire`, `party`, etc.)\n- **Direct Messages**: Private DM conversations between users\n- **Channels**: Multiple chat rooms with join/leave and per-channel messaging\n- **Typing Indicators**: See when other users are typing\n- **E2E File Transfers**: End-to-end encryption extended to file sharing\n- **UX Enhancements**: Connection status indicator, @mention tab completion, unread count, multi-line input (Alt+Enter/Ctrl+J), chat history export\n- **Security**: Rate limiting, constant-time admin key comparison, plugin download timeouts, SHA-pinned CI actions\n- **Refactoring**: Client split into hotkeys/render/websocket/commands modules, config directory unified, orphaned code removed\n- **Docker**: Added docker-compose.yml for local development\n- **Plugins**: Full plugin system wiring (message forwarding, user list updates, command responses, init handshake, store UI, license enforcement)\n\n### Recent Releases\n- **v0.10.0-beta.3**: Caddy TLS proxy example, Unix helper scripts, client WSS/direct-connect UX, config `.env` precedence docs\n- **v0.10.0-beta.2**: Doctor CLI, build-release cross-compile fix, sqlite bump, doc metrics refresh, Docker image entrypoint/volume permission fixes\n- **v0.9.0-beta.6**: Rebuilt with Go 1.25.8 to address CVE-2026-25679, CVE-2026-27142, CVE-2026-27139\n- **v0.9.0-beta.5**: Automated release workflow, PBKDF2 keystore key derivation, JWT secret auto-generation, race condition fixes, Docker optimizations\n\nFull changelog on [GitHub releases](https://github.com/Cod-e-Codes/marchat/releases).\n\n![Server Demo](assets/demo-server.gif \"marchat server startup\")\n![Client Demo](assets/demo-client-1.gif \"marchat client interface\")\n\n## Features\n\n- **Terminal UI** - Beautiful TUI built with Bubble Tea\n- **Real-time Chat** - Fast WebSocket messaging with SQLite backend (PostgreSQL/MySQL planned)\n- **Message Management** - Edit, delete, pin, react to, and search messages\n- **Direct Messages** - Private DM conversations between users\n- **Channels** - Multiple chat rooms with join/leave and per-channel messaging\n- **Typing Indicators** - See when other users are typing\n- **Read Receipts** - Message read acknowledgement (broadcast-level)\n- **Plugin System** - Remote registry with text commands and Alt+key hotkeys\n- **E2E Encryption** - X25519/ChaCha20-Poly1305 with global encryption, including file transfers\n- **File Sharing** - Send files up to 1MB (configurable) with interactive picker and optional E2E encryption\n- **Admin Controls** - User management, bans, kick system with ban history gaps\n- **Smart Notifications** - Bell + desktop notifications with quiet hours and focus mode ([guide](NOTIFICATIONS.md))\n- **Themes** - Built-in themes + custom themes via JSON ([guide](THEMES.md))\n- **Docker Support** - Containerized deployment with `docker-compose.yml` for local dev; optional **TLS reverse proxy** via Caddy ([guide](deploy/CADDY-REVERSE-PROXY.md))\n- **Health Monitoring** - `/health` and `/health/simple` endpoints with system metrics\n- **Structured Logging** - JSON logs with component separation and user tracking\n- **UX Enhancements** - Connection status indicator, tab completion for @mentions, unread message count, multi-line input, chat export\n- **Cross-Platform** - Runs on Linux, macOS, Windows, and Android/Termux\n- **Diagnostics** - `marchat-client -doctor` and `marchat-server -doctor` (or `-doctor-json`) summarize environment, resolved paths, and configuration health\n\n## Overview\n\nmarchat 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.\n\n**Key Benefits:**\n- **Self-hosted**: No external services required\n- **Cross-platform**: Linux, macOS, Windows, and Android/Termux\n- **Secure**: Optional E2E encryption with X25519/ChaCha20-Poly1305\n- **Extensible**: Plugin ecosystem for custom functionality\n- **Lightweight**: Minimal resource usage, perfect for servers\n\n| Cross-Platform | Theme Switching |\n|---------------|----------------|\n| \u003cimg src=\"assets/mobile-file-transfer.jpg\" width=\"300\"/\u003e | \u003cimg src=\"assets/theme-switching.jpg\" width=\"300\"/\u003e |\n\n## Quick Start\n\n### 1. Generate Admin Key\n```bash\nopenssl rand -hex 32\n```\n\n### 2. Start Server\n\n**Option A: Environment Variables (Recommended)**\n```bash\nexport MARCHAT_ADMIN_KEY=\"your-generated-key\"\nexport MARCHAT_USERS=\"admin1,admin2\"\n./marchat-server\n\n# With admin panel\n./marchat-server --admin-panel\n\n# With web panel\n./marchat-server --web-panel\n```\n\n**Option B: Interactive setup (first run, missing required config)**\n```bash\n./marchat-server --interactive\n```\nRuns a guided wizard **only when** `MARCHAT_ADMIN_KEY` or `MARCHAT_USERS` is not set. If they are already in the environment or `config/.env`, the server starts normally and `--interactive` does nothing extra.\n\n### 3. Connect Client\n```bash\n# Admin connection\n./marchat-client --username admin1 --admin --admin-key your-key --server ws://localhost:8080/ws\n\n# Regular user\n./marchat-client --username user1 --server ws://localhost:8080/ws\n\n# Or use interactive mode\n./marchat-client\n```\n\n## Database Schema\n\nKey tables for message tracking and moderation:\n- **messages**: Core message storage with `message_id`\n- **user_message_state**: Per-user message history state\n- **ban_history**: Ban/unban event tracking for history gaps\n\n## Installation\n\n**Binary Installation:**\n```bash\n# Linux (amd64)\nwget https://github.com/Cod-e-Codes/marchat/releases/download/v0.10.0-beta.3/marchat-v0.10.0-beta.3-linux-amd64.zip\nunzip marchat-v0.10.0-beta.3-linux-amd64.zip \u0026\u0026 chmod +x marchat-*\n\n# macOS (amd64)\nwget https://github.com/Cod-e-Codes/marchat/releases/download/v0.10.0-beta.3/marchat-v0.10.0-beta.3-darwin-amd64.zip\nunzip marchat-v0.10.0-beta.3-darwin-amd64.zip \u0026\u0026 chmod +x marchat-*\n\n# Windows - PowerShell\niwr -useb https://raw.githubusercontent.com/Cod-e-Codes/marchat/main/install.ps1 | iex\n```\n\n**Docker:**\n```bash\ndocker pull codecodesxyz/marchat:v0.10.0-beta.3\ndocker run -d -p 8080:8080 \\\n  -e MARCHAT_ADMIN_KEY=$(openssl rand -hex 32) \\\n  -e MARCHAT_USERS=admin1,admin2 \\\n  codecodesxyz/marchat:v0.10.0-beta.3\n```\n\n**Docker Compose (local development):**\n\nThe sample `docker-compose.yml` only sets port and database path. You must still provide **`MARCHAT_ADMIN_KEY`** and **`MARCHAT_USERS`** (see [Essential Environment Variables](#essential-environment-variables)). Typical approach: add the two lines below under `server.environment` and keep values in a gitignored `.env` file next to the compose file (Compose substitutes `${VAR}` from that `.env` automatically):\n\n```yaml\n      - MARCHAT_ADMIN_KEY=${MARCHAT_ADMIN_KEY}\n      - MARCHAT_USERS=${MARCHAT_USERS}\n```\n\nExample `.env` (generate a strong key for anything reachable from a network):\n\n```bash\nMARCHAT_ADMIN_KEY=your-secret-here\nMARCHAT_USERS=admin1,admin2\n```\n\nThen:\n\n```bash\ndocker compose up -d\n```\n\n**TLS reverse proxy (Caddy, optional):** To terminate TLS in front of a **host-native** `marchat-server` (plain HTTP on port 8080), use `docker-compose.proxy.yml`, `deploy/caddy/Caddyfile`, and `deploy/caddy/proxy.env.example` plus optional gitignored `deploy/caddy/proxy.env` for **`MARCHAT_CADDY_EXTRA_HOSTS`** (public IP/DNS on `tls internal`). Published port **8443** maps to HTTPS/WebSocket inside the container; clients use `wss://localhost:8443/ws` (with `--skip-tls-verify` while using Caddy’s internal CA). The proxy stack must be running whenever you use that URL. Full steps, helper scripts (`scripts/build-windows.ps1` / `scripts/build-linux.sh`, `scripts/connect-local-wss.ps1` / `scripts/connect-local-wss.sh`), source changes, and breaking notes: **[deploy/CADDY-REVERSE-PROXY.md](deploy/CADDY-REVERSE-PROXY.md)**.\n\n**From Source:**\n```bash\ngit clone https://github.com/Cod-e-Codes/marchat.git \u0026\u0026 cd marchat\ngo mod tidy\ngo build -o marchat-server ./cmd/server\ngo build -o marchat-client ./client\n```\n\n**Prerequisites for source build:**\n- Go 1.25+ ([download](https://go.dev/dl/))\n- Linux clipboard support: `sudo apt install xclip` (Ubuntu/Debian) or `sudo yum install xclip` (RHEL/CentOS)\n\n## Configuration\n\n### Essential Environment Variables\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `MARCHAT_ADMIN_KEY` | Yes | - | Admin authentication key |\n| `MARCHAT_USERS` | Yes | - | Comma-separated admin usernames |\n| `MARCHAT_PORT` | No | `8080` | Server port |\n| `MARCHAT_DB_PATH` | No | `./config/marchat.db` | Database file path |\n| `MARCHAT_TLS_CERT_FILE` | No | - | TLS certificate (enables wss://) |\n| `MARCHAT_TLS_KEY_FILE` | No | - | TLS private key |\n| `MARCHAT_GLOBAL_E2E_KEY` | No | - | Base64 32-byte global encryption key |\n| `MARCHAT_MAX_FILE_BYTES` | No | `1048576` | Max file size in bytes (1MB default) |\n| `MARCHAT_MAX_FILE_MB` | No | `1` | Max file size in MB (alternative to bytes) |\n| `MARCHAT_ALLOWED_USERS` | No | - | Username allowlist (comma-separated) |\n\n**Additional variables:** `MARCHAT_LOG_LEVEL`, `MARCHAT_CONFIG_DIR`, `MARCHAT_BAN_HISTORY_GAPS`, `MARCHAT_PLUGIN_REGISTRY_URL`\n\n**Doctor / diagnostics:** Set `MARCHAT_DOCTOR_NO_NETWORK` to `1` to skip the GitHub latest-release check in `-doctor` / `-doctor-json`.\n\n**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.\n\n**Interactive Setup:** Use `--interactive` flag for guided server configuration when environment variables are missing.\n\n### Server: `config/.env` vs process environment\n\nThe server loads **`{config directory}/.env`** (for a repo clone, usually **`config/.env`**) if the file exists, using **`godotenv.Overload`**.\n\n| Situation | Effect |\n|-----------|--------|\n| A variable appears **in `.env`** | That value **replaces** the same name already in the process environment when the server starts. |\n| A variable is set **only** in the environment (not in `.env`) | It is **unchanged** by `.env` loading. |\n| No `.env` file | Configuration comes only from the environment, flags, and defaults. |\n\n**Why:** Older `godotenv.Load` behavior skipped keys already set in the environment, so a stale shell `MARCHAT_ADMIN_KEY` could override an updated `config/.env`. `Overload` makes the file authoritative for any key it defines.\n\n**Operational notes:** Restart the server after editing `.env`. If you deploy with both injected secrets and a mounted `.env`, any **overlapping** key in the file wins at startup. See **[deploy/CADDY-REVERSE-PROXY.md](deploy/CADDY-REVERSE-PROXY.md#breaking-changes)** for migration and edge cases.\n\n**Not the same as Docker Compose’s `.env`:** Compose’s file next to `docker-compose.yml` is for **substituting** `${VAR}` into YAML; the table above is about **marchat-server** reading **`config/.env`** at runtime.\n\n### Client vs server config locations\n\n| Role | Default location | Override |\n|------|------------------|----------|\n| **Server** (`.env`, SQLite DB, debug log) | In development from a repo clone: `./config` next to `go.mod`. Otherwise `MARCHAT_CONFIG_DIR` or the user config path (see [ARCHITECTURE.md](ARCHITECTURE.md)). | `MARCHAT_CONFIG_DIR`, `--config-dir` |\n| **Client** (`config.json`, `profiles.json`, keystore, `themes.json`) | Per-user app data (e.g. Windows `%APPDATA%\\marchat`, Linux/macOS `~/.config/marchat`). Same when developing from source. | `MARCHAT_CONFIG_DIR` |\n\nThe repository’s `config/` directory holds **server** runtime files and the **Go package** `github.com/Cod-e-Codes/marchat/config`; it is not the client’s profile folder.\n\n### Diagnostics (`-doctor`)\n\nRun **`./marchat-client -doctor`** or **`./marchat-server -doctor`** for a text report (paths, masked `MARCHAT_*` env, sanity checks). Use **`-doctor-json`** for machine-readable output. If both flags were passed, `-doctor-json` wins. Exits without starting the TUI or listening on a port. See [ARCHITECTURE.md](ARCHITECTURE.md) for details.\n\n## Admin Commands\n\n### User Management\n| Command | Description | Hotkey |\n|---------|-------------|--------|\n| `:ban \u003cuser\u003e` | Permanent ban | `Ctrl+B` (with user selected) |\n| `:kick \u003cuser\u003e` | 24h temporary ban | `Ctrl+K` (with user selected) |\n| `:unban \u003cuser\u003e` | Remove permanent ban | `Ctrl+Shift+B` |\n| `:allow \u003cuser\u003e` | Override kick early | `Ctrl+Shift+A` |\n| `:forcedisconnect \u003cuser\u003e` | Force disconnect user | `Ctrl+F` (with user selected) |\n| `:cleanup` | Clean stale connections | - |\n\n### Database Operations (`:cleardb` or `Ctrl+D` menu)\n- **Clear DB** - Wipe all messages\n- **Backup DB** - Create database backup\n- **Show Stats** - Display database statistics\n\n## User Commands\n\n### General\n| Command | Description | Hotkey |\n|---------|-------------|--------|\n| `:theme \u003cname\u003e` | Switch theme (built-in or custom) | `Ctrl+T` (cycles) |\n| `:themes` | List all available themes | - |\n| `:time` | Toggle 12/24-hour format | `Alt+T` |\n| `:clear` | Clear chat buffer | `Ctrl+L` |\n| `:q` | Quit application (vim-style) | - |\n| `:sendfile [path]` | Send file (or open picker without path) | `Alt+F` |\n| `:savefile \u003cname\u003e` | Save received file | - |\n| `:code` | Open code composer with syntax highlighting | `Alt+C` |\n| `:export [file]` | Export chat history to a text file | - |\n\n### Messaging\n| Command | Description |\n|---------|-------------|\n| `:edit \u003cid\u003e \u003ctext\u003e` | Edit a message by its ID |\n| `:delete \u003cid\u003e` | Delete a message by its ID |\n| `:dm [user] [msg]` | Send a DM or toggle DM mode (no args exits DM mode) |\n| `:search \u003cquery\u003e` | Search message history on the server |\n| `:react \u003cid\u003e \u003cemoji\u003e` | React to a message (supports aliases: `+1`, `heart`, `fire`, `party`, `laugh`, `eyes`, `check`, `rocket`, `think`, etc.) |\n| `:pin \u003cid\u003e` | Toggle pin on a message |\n| `:pinned` | List all pinned messages |\n\n### Channels\n| Command | Description |\n|---------|-------------|\n| `:join \u003cchannel\u003e` | Join a channel (clients start in `#general`) |\n| `:leave` | Leave current channel, return to `#general` |\n| `:channels` | List active channels with user counts |\n\n### Notifications\n| Command | Description | Hotkey |\n|---------|-------------|--------|\n| `:notify-mode \u003cmode\u003e` | Set notification mode (none/bell/desktop/both) | `Alt+N` (toggle desktop) |\n| `:bell` | Toggle bell notifications | - |\n| `:bell-mention` | Toggle mention-only notifications | - |\n| `:focus [duration]` | Enable focus mode (mute notifications) | - |\n| `:quiet \u003cstart\u003e \u003cend\u003e` | Set quiet hours (e.g., `:quiet 22 8`) | - |\n\n\u003e **Note**: Hotkeys work in both encrypted and unencrypted sessions since they're handled client-side.\n\u003e\n\u003e **Notifications**: See [NOTIFICATIONS.md](NOTIFICATIONS.md) for full notification system documentation including desktop notifications, quiet hours, and focus mode.\n\n### Plugin Commands (Admin Only)\n\nText commands and hotkeys for plugin management. See [Plugin Management hotkeys](#plugin-management-admin) for keyboard shortcuts.\n\n| Command | Description | Hotkey |\n|---------|-------------|--------|\n| `:store` | Browse plugin store | `Alt+S` |\n| `:plugin list` or `:list` | List installed plugins | `Alt+P` |\n| `:plugin install \u003cname\u003e` or `:install \u003cname\u003e` | Install plugin | `Alt+I` |\n| `:plugin uninstall \u003cname\u003e` or `:uninstall \u003cname\u003e` | Uninstall plugin | `Alt+U` |\n| `:plugin enable \u003cname\u003e` or `:enable \u003cname\u003e` | Enable plugin | `Alt+E` |\n| `:plugin disable \u003cname\u003e` or `:disable \u003cname\u003e` | Disable plugin | `Alt+D` |\n| `:refresh` | Refresh plugin list from registry | `Alt+R` |\n\n\u003e **Note**: Both text commands and hotkeys work in E2E encrypted sessions (sent as admin messages that bypass encryption).\n\n### File Sharing\n\n**Direct send:**\n```bash\n:sendfile /path/to/file.txt\n```\n\n**Interactive picker:**\n```bash\n:sendfile\n```\nNavigate with arrow keys, Enter to select/open folders, \".. (Parent Directory)\" to go up.\n\n**Supported types:** Text, code, images, documents, archives (`.txt`, `.md`, `.json`, `.go`, `.py`, `.js`, `.png`, `.jpg`, `.pdf`, `.zip`, etc.)\n\n## Keyboard Shortcuts\n\n### General\n| Key | Action |\n|-----|--------|\n| `Ctrl+H` | Toggle help overlay |\n| `Enter` | Send message |\n| `Alt+Enter` / `Ctrl+J` | Insert newline (multi-line input) |\n| `Tab` | Autocomplete @mentions |\n| `Esc` | Close menus / dialogs |\n| `:q` | Quit application (vim-style) |\n| `↑/↓` | Scroll chat |\n| `PgUp/PgDn` | Page through chat |\n| `Ctrl+C/V/X/A` | Copy/Paste/Cut/Select all |\n\n### User Features\n| Key | Action |\n|-----|--------|\n| `Alt+F` | Send file (file picker) |\n| `Alt+C` | Create code snippet |\n| `Ctrl+T` | Cycle themes |\n| `Alt+T` | Toggle 12/24h time |\n| `Alt+N` | Toggle desktop notifications |\n| `Ctrl+L` | Clear chat history |\n\n\u003e **Multi-line input**: Use `Alt+Enter` or `Ctrl+J` to insert newlines. `Shift+Enter` is not reliably supported on Windows terminals.\n\n### Admin Interface (Client)\n| Key | Action |\n|-----|--------|\n| `Ctrl+U` | Select/cycle user |\n| `Ctrl+D` | Database operations menu |\n| `Ctrl+K` | Kick selected user |\n| `Ctrl+B` | Ban selected user |\n| `Ctrl+F` | Force disconnect selected user |\n| `Ctrl+Shift+B` | Unban user (prompts for username) |\n| `Ctrl+Shift+A` | Allow user (prompts for username) |\n\n### Plugin Management (Admin)\n| Key | Action |\n|-----|--------|\n| `Alt+P` | List installed plugins |\n| `Alt+S` | View plugin store |\n| `Alt+R` | Refresh plugin list |\n| `Alt+I` | Install plugin (prompts for name) |\n| `Alt+U` | Uninstall plugin (prompts for name) |\n| `Alt+E` | Enable plugin (prompts for name) |\n| `Alt+D` | Disable plugin (prompts for name) |\n\n### Server\n| Key | Action |\n|-----|--------|\n| `Ctrl+A` | Open terminal admin panel |\n\n## Admin Panels\n\n### Terminal Admin Panel\nEnable with `--admin-panel` flag, then press `Ctrl+A` to access:\n- Real-time server statistics (users, messages, performance)\n- User management interface\n- Plugin configuration\n- Database operations\n- Requires terminal environment (auto-disabled in systemd/non-terminal)\n\n### Web Admin Panel\nEnable with `--web-panel` flag, access at `http://localhost:8080/admin`:\n- Secure session-based login (1-hour expiration)\n- Live dashboard with metrics visualization\n- RESTful API endpoints with `X-Admin-Key` auth\n- CSRF protection on all state-changing operations\n- HttpOnly cookies with SameSite protection\n\n**API Example:**\n  ```bash\ncurl -H \"Cookie: admin_session=YOUR_SESSION\" http://localhost:8080/admin/api/overview\n  ```\n\n## TLS Support\n\n### When to Use TLS\n\n- **Public deployments**: Server accessible from internet\n- **Production environments**: Enhanced security required\n- **Corporate networks**: Security policy compliance\n- **HTTPS reverse proxies**: Behind nginx, traefik, **Caddy**, etc.\n\n### Reverse proxy (Caddy)\n\nThe repo includes a **Docker Compose**-based Caddy setup for local or LAN use: **`docker-compose.proxy.yml`**, **`deploy/caddy/Caddyfile`**, **`deploy/caddy/proxy.env.example`** (and optional local **`deploy/caddy/proxy.env`**), and the walkthrough **[deploy/CADDY-REVERSE-PROXY.md](deploy/CADDY-REVERSE-PROXY.md)** (build flags, `config/.env`, firewall, `wss://` client flags, E2E, and **breaking change**: `config/.env` is applied with `godotenv.Overload` so file values override pre-set `MARCHAT_*` in the process environment).\n\n**Quick reference:**\n\n| Item | Role |\n|------|------|\n| `marchat-server` on the host | Listens on **8080** (`ws://`), reads **`config/.env`** |\n| `docker compose -f docker-compose.proxy.yml up -d` | Runs Caddy; host **8443** → container **443** |\n| Client | `wss://localhost:8443/ws` + `--skip-tls-verify` until you use a public CA cert on Caddy |\n| If 8443 is refused | Caddy is not running; start the compose stack or use `ws://127.0.0.1:8080/ws` |\n\n### Configuration Examples\n\n**With TLS (production):**\n```bash\n# Generate self-signed cert (testing only)\nopenssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes\n\nexport MARCHAT_ADMIN_KEY=\"your-key\"\nexport MARCHAT_USERS=\"admin1,admin2\"\nexport MARCHAT_TLS_CERT_FILE=\"./cert.pem\"\nexport MARCHAT_TLS_KEY_FILE=\"./key.pem\"\n./marchat-server  # Shows wss:// in banner\n```\n\n**Without TLS (development):**\n```bash\nexport MARCHAT_ADMIN_KEY=\"your-key\"\nexport MARCHAT_USERS=\"admin1,admin2\"\n./marchat-server  # Shows ws:// in banner\n```\n\n**Client with TLS:**\n```bash\n# With verification (production)\n./marchat-client --server wss://localhost:8080/ws\n\n# Skip verification (dev/self-signed only)\n./marchat-client --skip-tls-verify --server wss://localhost:8080/ws\n```\n\n\u003e **Warning**: Use `--skip-tls-verify` only for development. Production should use valid CA-signed certificates.\n\n## E2E Encryption\n\nGlobal encryption for secure group chat using shared keys across all clients.\n\n### How It Works\n- **Shared Key Model**: All clients use same global encryption key for public channels\n- **Simplified Management**: No complex per-user key exchange\n- **X25519/ChaCha20-Poly1305**: Industry-standard encryption algorithms\n- **Environment Variable**: `MARCHAT_GLOBAL_E2E_KEY` for key distribution\n- **Auto-Generation**: Creates new key if none provided\n\n### Setup Options\n\n**Option 1: Shared Key (Recommended)**\n```bash\n# Generate 32-byte key\nopenssl rand -base64 32\n\n# Set on all clients\nexport MARCHAT_GLOBAL_E2E_KEY=\"your-generated-key\"\n\n# Connect with E2E\n./marchat-client --e2e --keystore-passphrase your-pass --username alice --server ws://localhost:8080/ws\n```\n\n**Option 2: Auto-Generate**\n```bash\n# Client generates and displays new key\n./marchat-client --e2e --keystore-passphrase your-pass --username alice --server ws://localhost:8080/ws\n\n# Output shows:\n# 🔐 Generated new global E2E key (ID: RsLi9ON0...)\n# 💡 Set MARCHAT_GLOBAL_E2E_KEY=fF+HkmGArkPNsdb+... to share this key\n```\n\n### Expected Output\n```\n🔐 Using global E2E key from environment variable\n🌐 Global chat encryption: ENABLED (Key ID: RsLi9ON0...)\n✅ Encryption validation passed\n🔐 E2E encryption enabled with keystore: config/keystore.dat\n```\n\n### Security Features\n- **Forward Secrecy**: Unique session keys per conversation\n- **Server Privacy**: Server cannot read encrypted messages\n- **Local Keystore**: Encrypted with passphrase protection using PBKDF2\n- **Validation**: Automatic encryption/decryption testing on startup\n\n**Note**: Keystore encryption was upgraded from SHA256 to PBKDF2 for enhanced security. Existing keystores encrypted with the old method will need to be re-initialized.\n\n## Plugin System\n\nExtend functionality with remote plugins from configured registry.\n\n### Configuration\n```bash\n# Default GitHub registry\nexport MARCHAT_PLUGIN_REGISTRY_URL=\"https://raw.githubusercontent.com/Cod-e-Codes/marchat-plugins/main/registry.json\"\n\n# Custom registry\nexport MARCHAT_PLUGIN_REGISTRY_URL=\"https://my-registry.com/plugins.json\"\n```\n\n### Commands\n\n**Text commands:**\n```bash\n:store                    # Browse available plugins\n:plugin install echo      # Install plugin\n:plugin list              # List installed\n:plugin uninstall echo    # Remove plugin\n:enable echo              # Enable installed plugin\n:disable echo             # Disable plugin\n:refresh                  # Refresh plugin registry\n```\n\n**Keyboard shortcuts** (Admin only):\n- `Alt+P` - List installed plugins\n- `Alt+S` - View plugin store  \n- `Alt+R` - Refresh plugin list\n- `Alt+I` - Install plugin (prompts for name)\n- `Alt+U` - Uninstall plugin (prompts for name)\n- `Alt+E` - Enable plugin (prompts for name)\n- `Alt+D` - Disable plugin (prompts for name)\n\n\u003e **Note**: Plugin management commands and custom plugin commands (e.g., `:echo`) work in E2E encrypted sessions. See [Plugin Commands](#plugin-commands-admin-only) for full reference.\n\n### Available Plugins\n- **echo** (v2.0.1): Simple echo plugin for testing (provides `:echo` command)\n- **weather** (v1.0.0): Get weather information and forecasts using wttr.in (`:weather [location]`, `:forecast [location]`)\n- **githooks** (v1.0.0): Git repository management with status, log, branch, and diff commands (`:git-status`, `:git-log`, `:git-branch`, `:git-diff`, `:git-watch` admin-only)\n\nSee [PLUGIN_ECOSYSTEM.md](PLUGIN_ECOSYSTEM.md) for development guide.\n\n## Moderation System\n\n**Temporary Kicks (24 hours):**\n- `:kick \u003cusername\u003e` or `Ctrl+K` for temporary discipline\n- Auto-allowed after 24 hours, or override early with `:allow`\n- Ideal for cooling-off periods\n\n**Permanent Bans (indefinite):**\n- `:ban \u003cusername\u003e` or `Ctrl+B` for serious violations\n- Remains until manual `:unban` or `Ctrl+Shift+B`\n- Ideal for persistent troublemakers\n\n**Ban History Gaps:**\nPrevents banned users from seeing messages sent during ban periods. Enable with `MARCHAT_BAN_HISTORY_GAPS=true` (disabled by default).\n\n## Client Configuration\n\n### Interactive Mode (Default)\n```bash\n./marchat-client\n```\nGuides through server URL, username, admin privileges, E2E encryption, theme selection, and profile saving.\n\n### Quick Start Options\n```bash\n# Auto-connect to recent profile\n./marchat-client --auto\n\n# Select from saved profiles\n./marchat-client --quick-start\n```\n\n### Profile Management\nProfiles stored in platform-appropriate locations:\n- **Windows**: `%APPDATA%\\marchat\\profiles.json`\n- **macOS**: `~/Library/Application Support/marchat/profiles.json`  \n- **Linux**: `~/.config/marchat/profiles.json`\n\n**During profile selection:**\n- `i` or `v` - View profile details\n- `r` - Rename profile\n- `d` - Delete profile\n\n### Traditional Flags\n```bash\n# Basic connection\n./marchat-client --server ws://localhost:8080/ws --username alice\n\n# Admin connection\n./marchat-client --server ws://localhost:8080/ws --username admin --admin --admin-key your-key\n\n# E2E encrypted\n./marchat-client --server ws://localhost:8080/ws --username alice --e2e --keystore-passphrase your-pass\n\n# Non-interactive (requires all flags)\n./marchat-client --non-interactive --server ws://localhost:8080/ws --username alice\n```\n\n## Security Best Practices\n\n1. **Generate Secure Keys**\n   ```bash\n   # Admin key (64 hex characters)\n   openssl rand -hex 32\n   \n   # Global E2E key (base64-encoded 32 bytes)\n   openssl rand -base64 32\n   ```\n\n2. **Secure File Permissions**\n   ```bash\n   chmod 600 ./config/marchat.db    # Database\n   chmod 600 ./config/keystore.dat  # Keystore\n   chmod 700 ./config               # Config directory\n   ```\n\n3. **Production Deployment**\n   - Use TLS (`wss://`) with valid CA-signed certificates\n   - Deploy behind reverse proxy (nginx, traefik, or Caddy; see [deploy/CADDY-REVERSE-PROXY.md](deploy/CADDY-REVERSE-PROXY.md) for the bundled Caddy example)\n   - Restrict server access to trusted networks\n   - Use Docker secrets for sensitive environment variables\n   - Enable rate limiting and brute force protection\n   - Monitor security logs regularly\n\n4. **E2E Encryption**\n   - Store `MARCHAT_GLOBAL_E2E_KEY` securely\n   - Use strong keystore passphrases\n   - Never share keystores between users\n   - Rotate keys periodically for sensitive deployments\n\n5. **Username Allowlist (Optional)**\n   ```bash\n   # Restrict to specific users for private servers\n   export MARCHAT_ALLOWED_USERS=\"alice,bob,charlie\"\n   ```\n   - Usernames validated (letters, numbers, `_`, `-`, `.` only)\n   - Max 32 characters, cannot start with `:` or `.`\n   - Case-insensitive matching\n   - Protects against log injection and command injection\n\n## Troubleshooting\n\n| Issue | Solution |\n|-------|----------|\n| Wrong config folder / paths | Run `marchat-client -doctor` or `marchat-server -doctor`; see **Client vs server config locations** |\n| Connection failed | Verify `ws://` or `wss://` protocol in URL |\n| `wss://localhost:8443` reconnect loop / connection refused | Ensure Caddy is up: `docker compose -f docker-compose.proxy.yml up -d`, or use `ws://127.0.0.1:8080/ws` without the proxy ([reverse proxy guide](deploy/CADDY-REVERSE-PROXY.md)) |\n| Admin commands not working | Check `--admin` flag and correct `--admin-key` |\n| Clipboard issues (Linux) | Install xclip: `sudo apt install xclip` |\n| Port in use | Change port: `export MARCHAT_PORT=8081` |\n| Database migration fails | Check file permissions, backup before source build |\n| Message history missing | Expected after updates - user states reset for ban/unban improvements |\n| Ban history gaps not working | Ensure `MARCHAT_BAN_HISTORY_GAPS=true` (disabled by default) and `ban_history` table exists |\n| TLS certificate errors | Use `--skip-tls-verify` for dev with self-signed certs |\n| Plugin installation fails | Verify `MARCHAT_PLUGIN_REGISTRY_URL` is accessible and valid JSON |\n| E2E encryption errors | Ensure `--e2e` flag and keystore passphrase provided, check debug logs |\n| Global E2E key errors | Verify key is valid base64-encoded 32-byte key: `openssl rand -base64 32` |\n| Blank encrypted messages | Fixed in v0.3.0-beta.5+ - ensure latest version |\n| Username already taken | Use admin `:forcedisconnect \u003cuser\u003e` or wait 5min for auto-cleanup |\n| Stale connections | Server auto-cleans every 5min, or admin use `:cleanup` |\n| Client frozen at startup | Fixed in latest - `--quick-start` uses proper UI |\n| Multi-line input not working | Use `Alt+Enter` or `Ctrl+J`; `Shift+Enter` is not supported in most Windows terminals |\n\n### Stale Connection Management\n\n**Automatic:** Server detects and removes stale connections every 5 minutes using WebSocket ping.\n\n**Manual (Admin):**\n```bash\n:cleanup                    # Clean all stale connections\n:forcedisconnect username   # Force disconnect specific user\n```\n\n**Common scenarios:**\n- Client crash/Ctrl+C: Auto-cleaned within 5 minutes\n- Network interruption: Removed on next cleanup cycle\n- Immediate reconnect: Admin uses `:forcedisconnect`\n\n## Testing\n\nFoundational test suite covering core functionality, cryptography, and plugins.\n\n### Running Tests\n```bash\ngo test ./...              # Run all tests\ngo test -cover ./...       # With coverage\ngo test ./server -v        # Specific package\ngo test ./... -timeout 10s # With timeout (CI recommended)\n```\n\n### Test Scripts\n- **Linux/macOS**: `./test.sh`\n- **Windows**: `.\\test.ps1`\n\n### Coverage Summary\n| Package | Coverage | Size | Status |\n|---------|----------|------|--------|\n| `shared` | 85.9% | 348 LOC | High |\n| `plugin/license` | 83.1% | 229 LOC | High |\n| `client/crypto` | 79.5% | 354 LOC | High |\n| `config` | 73.2% | 327 LOC | High |\n| `client/config` | 54.5% | 1862 LOC | Medium |\n| `plugin/store` | 47.0% | 552 LOC | Medium |\n| `cmd/license` | 42.2% | 160 LOC | Medium |\n| `server` | 33.7% | 6558 LOC | Medium |\n| `plugin/manager` | 23.8% | 747 LOC | Low |\n| `client` | 23.3% | 5334 LOC | Low |\n| `plugin/host` | 21.1% | 617 LOC | Low |\n| `cmd/server` | 5.3% | 455 LOC | Low |\n\n**Overall: 34.1%** - See [TESTING.md](TESTING.md) for detailed information.\n\n## Contributing\n\nWe welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for:\n- Development setup instructions\n- Code style guidelines and conventions\n- Pull request process and requirements\n- Testing expectations\n\n**Quick Start:**\n```bash\ngit clone https://github.com/Cod-e-Codes/marchat.git\ncd marchat\ngo mod tidy\ngo test ./...\n```\n\n## Documentation\n\n- **[QUICKSTART.md](QUICKSTART.md)** - Short path from install to first client connection\n- **[ARCHITECTURE.md](ARCHITECTURE.md)** - Components, data flow, config paths, diagnostics\n- **[PROTOCOL.md](PROTOCOL.md)** - WebSocket message types and payloads\n- **[deploy/CADDY-REVERSE-PROXY.md](deploy/CADDY-REVERSE-PROXY.md)** - Optional TLS reverse proxy (Caddy) for local or LAN `wss://`\n- **[NOTIFICATIONS.md](NOTIFICATIONS.md)** - Notification system guide (desktop, quiet hours, focus mode)\n- **[THEMES.md](THEMES.md)** - Custom theme creation guide\n- **[PLUGIN_ECOSYSTEM.md](PLUGIN_ECOSYSTEM.md)** - Plugin development guide\n- **[ROADMAP.md](ROADMAP.md)** - Planned features and enhancements\n- **[TESTING.md](TESTING.md)** - Comprehensive testing guide\n- **[CONTRIBUTING.md](CONTRIBUTING.md)** - Contribution guidelines\n- **[SECURITY.md](SECURITY.md)** - Security policy and reporting\n- **[CONTRIBUTORS.md](CONTRIBUTORS.md)** - Full contributor list\n\n## Getting Help\n\n- [Report bugs](https://github.com/Cod-e-Codes/marchat/issues)\n- [Ask questions](https://github.com/Cod-e-Codes/marchat/discussions)\n- Commercial support: [cod.e.codes.dev@gmail.com](mailto:cod.e.codes.dev@gmail.com)\n\n## Appreciation\n\nThanks to [Self-Host Weekly](https://selfh.st/weekly/2025-07-25/), [mtkblogs.com](https://mtkblogs.com/2025/07/23/marchat-a-go-powered-terminal-chat-app-for-the-modern-user/), and [Terminal Trove](https://terminaltrove.com/) for featuring marchat!\n\nSee [CONTRIBUTORS.md](CONTRIBUTORS.md) for full contributor list.\n\n---\n\n**License**: [MIT License](LICENSE)\n","funding_links":["https://github.com/sponsors/Cod-e-Codes"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcod-e-codes%2Fmarchat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcod-e-codes%2Fmarchat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcod-e-codes%2Fmarchat/lists"}