This document provides a comprehensive overview of the marchat system architecture, including component relationships, data flow, and design patterns.
Marchat is a self-hosted, terminal-based chat application built in Go with a client-server architecture. The system emphasizes security through end-to-end encryption, extensibility through a plugin system, and usability through multiple interface options.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client TUI │◄──►│ WebSocket │◄──►│ Server Hub │
│ │ │ Communication │ │ │
│ • Chat Interface│ │ • JSON Messages │ │ • Message Hub │
│ • File Transfer │ │ • E2E Encryption│ │ • User Mgmt │
│ • Admin Panel │ │ • Real-time │ │ • Plugin Host │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Configuration │ │ Shared Types │ │ Database Layer │
│ • Profiles │ │ • Message Types │ │ • SQL Backends │
│ • Encryption │ │ • Crypto Utils │ │ • Postgres/MySQL│
│ • Themes │ │ • Protocols │ │ • Dialect State │
└─────────────────┘ └─────────────────┘ └─────────────────┘
The client is a standalone terminal user interface built with the Bubble Tea framework. It's a complete application that can be built and run independently. The code is split across several files:
main.go: Core model, state, Update loop, and command handlerscli_output.go: Lipgloss helpers for pre-TUI stdout (connection, E2E status, profile flow messages)hotkeys.go: Key binding definitions and methodsrender.go: Message rendering and UI display logic (optional per-line metadata: message id and encrypted flag)websocket.go: WebSocket connection management, send/receive, and E2E encryption helpersexthook/: Optional, experimental subprocess hooks for local automation (stdin JSON per event); see CLIENT_HOOKS.mdcommands.go: Help text generation and command-related utilitiesnotification_manager.go: Desktop/bell notification system
model: Main application state manager handling WebSocket communication, message rendering, and user interactionsConfigUIModel: Interactive configuration interface for server connection settingsProfileSelectionModel: Multi-profile management system for different server configurations (colored URL and[Admin]/[E2E]/[Recent]tags in the list)SensitiveDataModel: Secure credential input for admin keys and encryption passphrases (inactive fields use dim styling)codeSnippetModel: Code block rendering with syntax highlighting and selection capabilitiesfilePickerModel: Interactive file selection interface with filtering and previewNotificationManager: Notification system supporting bell sounds and desktop notifications
- Real-time chat with message history and user list
- Message editing, deletion, pinning, and reactions
- Direct messages between users
- Channel-based messaging (join/leave channels)
- Typing indicators (throttled, with timeout)
- Message search (server-side)
- Chat history export to file
- File sharing with configurable size limits (default 1MB), with optional E2E encryption
- Theme system supporting built-in and custom themes
- Administrative commands for user management
- End-to-end encryption with global key support (text and file transfers)
- Code snippet rendering with syntax highlighting
- Clipboard integration for text operations
- URL detection and external opening
- Tab completion for @mentions
- Connection status indicator
- Unread message count
- Multi-line input via Alt+Enter / Ctrl+J
- Diagnostics:
-doctorand-doctor-jsonfor environment, paths, and config checks (internal/doctor)
The server is a standalone HTTP/WebSocket server application that provides real-time communication with plugin support and administrative interfaces. The ASCII banner is followed by lipgloss-styled status lines (WebSocket URL, admins, version, TLS state, tips, and optional admin-panel key hints) on stdout before the process settles into serving. Before serving, startup checks require at least one admin, a non-empty admin key, and a valid listen port; admin names are trimmed, lowercased, deduplicated case-insensitively, and must not be empty after trim.
Hub: Central message routing system managing client connections, message broadcasting, channel management, and user state; tracks reserved usernames so handshake cannot double-book the same name before a client is registered. All sends toclient.senduse non-blockingselect/defaultto prevent deadlocks when a client's write buffer is full; stalled clients are dropped or the message is logged and skipped. Text messages fan out to plugins in a separate goroutine so plugin IPC never blocks the hub’s broadcast loop.Client: Individual WebSocket connection handler with read/write pumps and command processing. ThewritePumpgoroutine is started before history replay on connect so the send channel always has a consumer.AdminPanel: Terminal-based administrative interface for server managementWebAdminServer: Web-based administrative interface with session authenticationHealthChecker: System health monitoring with metrics collectionPluginCommandHandler: Plugin command routing and execution system
- Real-time message broadcasting to connected clients (channel-aware)
- Channel management: clients join/leave channels, messages routed per-channel
- Direct message routing between specific users
- Message editing, deletion, pinning, and search
- Typing indicator and read receipt broadcasting
- Reaction broadcasting
- User management including ban, kick, and allow operations (ban/kick state is committed under
banMutex, then the lock is released before the actual disconnect to avoid holding the mutex across a channel send) - Plugin command execution and management
- Database backup and maintenance operations (SQLite
VACUUM INTOuses proper string quoting so backup paths containing'remain safe) - System metrics collection and health monitoring
- Web-based admin panel with CSRF protection
- Health check endpoints for monitoring systems
- WebSocket message rate limiting
- Diagnostics:
-doctorand-doctor-jsonwithout binding ports (internal/doctor)
The server package contains the core server logic and components that are used by the server application.
- WebSocket Handlers: Connection management and message routing; failed handshakes close with RFC 6455 close frames (registered status code + UTF-8 reason, not a raw text payload (see
PROTOCOL.md) - Database Layer: Pluggable SQL backends (SQLite/PostgreSQL/MySQL) with dialect-aware schema and query helpers
- Admin Interfaces: Both TUI and web-based administrative panels
- Plugin Integration: Plugin command handling and execution
- Health Monitoring: System metrics and health check endpoints
Common types and utilities used across client and server components.
Message: Standard chat message structure with encryption support, message IDs, recipient, channel, edited flag, and reaction metadataMessageType: Type discriminator (text,file,admin_command,edit,delete,typing,reaction,dm,search,pin,read_receipt,join_channel,leave_channel,list_channels)ReactionMeta: Emoji, target message ID, and removal flagEncryptedMessage: End-to-end encrypted message format (AEAD payload + metadata)Handshake: WebSocket connection authentication structureSessionKey: 32-byte ChaCha20-Poly1305 key material for global E2E (fingerprint inKeyIDfor logs)FileMeta: File transfer metadata including name, size, and data
Chat end-to-end encryption uses a global symmetric key shared by all clients (via MARCHAT_GLOBAL_E2E_KEY or manual distribution), not per-user key exchange on the wire.
- ChaCha20-Poly1305: Authenticated encryption for message and file confidentiality and integrity
- Global E2E: One 32-byte key per deployment; the client normally stores it in the passphrase-protected keystore (
EncryptMessage/DecryptMessageinshared, orchestrated byclient/crypto/keystore.go). IfMARCHAT_GLOBAL_E2E_KEYis set, the client uses that key in memory for the process; it does not rewritekeystore.dat(see README.md → E2E Encryption). - Keystore file: Wrapped with AES-GCM; passphrase stretched with PBKDF2 (SHA-256, 100k iterations). Current files embed a random salt in the file header so unlocking does not depend on the absolute path. Legacy files used the keystore path as PBKDF2 salt and are migrated to the embedded-salt format on first successful load (
client/crypto/keystore.go). - File transfer: Raw byte encryption/decryption via
EncryptRaw/DecryptRawin the keystore using the same global key - Key distribution UX: Auto-generated global keys are stored in the encrypted keystore; the client does not print the raw key to stdout (see README.md / SECURITY.md).
Extensible architecture allowing custom functionality through external plugins.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Plugin SDK │ │ Plugin Host │ │ Plugin Manager │
│ │ │ │ │ │
│ • Core Interface│◄──►│ • Subprocess │◄──►│ • Installation │
│ • Communication │ │ • Lifecycle │ │ • Store │
│ • Base Classes │ │ • JSON Protocol │ │ • Commands │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Plugin Store │ │ License System │ │ Command Handler │
│ │ │ │ │ │
│ • TUI Interface │ │ • Validation │ │ • Chat Commands │
│ • Registry │ │ • Generation │ │ • Integration │
│ • Installation │ │ • Caching │ │ • Routing │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- SDK (
plugin/sdk/): Core plugin interface definitions, base implementations, and optional stdio helpers (RunStdio,HandlePluginRequest) - Host (
plugin/host/): Subprocess management and JSON-based communication; chat fan-out uses a bounded per-plugin queue and a dedicated writer goroutine so a slow or stuck plugin cannot block the server hub (overflow drops are logged). After the subprocess exits, stop waits for the stdout/stderr JSON reader goroutines before clearing pipes and the per-instance decoder so enable/disable cycles cannot race with a reader that was scheduled late (-raceclean). - Manager (
plugin/manager/): Plugin installation, store integration, and command execution - Store (
plugin/store/): Terminal-based plugin browsing and installation interface - License (
plugin/license/): Cryptographic license validation for official plugins (cached licenses re-verified on read)
Plugins communicate with the host through JSON messages over stdin/stdout:
- Request Format:
{"type": "message|command|init|shutdown", "command": "name", "data": {}} - Response Format:
{"type": "message|log", "success": true, "data": {}, "error": "message"} - Message Types: Initialization, message processing, command execution, graceful shutdown
Flexible configuration management supporting multiple sources and interactive setup.
The Go package at repository path config/ loads server settings from the process environment and from a .env file inside the server configuration directory. If .env exists, it is applied with godotenv.Overload: each KEY=value in the file overwrites that key in the process environment at startup (so the file is authoritative for keys it defines; keys set only in the environment and omitted from .env are unchanged). When go.mod is present in the process working directory, that directory defaults to ./config in the repo (alongside the server’s .env and SQLite database). Otherwise it follows MARCHAT_CONFIG_DIR or the XDG-style user config path (see server main and config package). This ./config folder is not where the TUI client stores config.json or profiles. See README.md (Configuration → Server config/.env vs process environment) and deploy/CADDY-REVERSE-PROXY.md (Breaking changes) for precedence details.
The client stores config.json, profiles.json, keystore, themes, and debug logs under the per-user application data directory (e.g. %APPDATA%\marchat on Windows, ~/.config/marchat on Linux), or under MARCHAT_CONFIG_DIR when set. This applies both when developing from a clone and when using release binaries. Path helpers in client/config share the same resolution: ResolveClientConfigDir(), GetConfigPath(), and the primary keystore path (GetKeystorePath) honor MARCHAT_CONFIG_DIR first. For the keystore file, GetKeystorePath prefers that directory, then an existing keystore.dat under the standard user marchat folder (when the override has no keystore yet), and only then a legacy ./keystore.dat in the process working directory, so a stray repo-local file does not override the real profile keystore.
- Process environment: Inherited
MARCHAT_*and other variables before.envis read .envin server config directory: Merged withgodotenv.Overload; file entries override the same variable names already in the environment- Interactive TUI: User-friendly setup for initial configuration when required settings are missing
- Profile System (client): Multiple server connection profiles in the client config directory
- Server Configuration: Port, TLS certificates, admin authentication
- Database Settings:
MARCHAT_DB_PATHselects backend and connection details (SQLite path or Postgres/MySQL DSN) - Plugin Configuration: Registry URL and installation directories
- Security Settings: Admin keys, encryption keys, and authentication
- File Transfer: Size limits and allowed file types
- Logging: Log levels and output destinations
Shared package invoked by marchat-client and marchat-server when passed -doctor (human-readable report) or -doctor-json (JSON on stdout). It summarizes Go/OS, resolved config directories, known MARCHAT_* variables with secrets masked, role-specific checks (client: profiles, clipboard, TTY, and optional experimental client hook env vars plus executable path validation when receive/send paths are set; server: .env, validation, detected DB dialect, DB connection-string format validation, DB/TLS ping checks), and optionally compares the embedded version to the latest GitHub release. For server doctor, the MARCHAT_* listing is captured after LoadConfigWithoutValidation applies godotenv.Overload on config/.env, matching effective runtime env; client doctor still reflects only the client process environment. Server doctor omits client-only hook keys from the environment section entirely, even when they are set in the process (for example the same shell session used to start the client). The text report is colorized when stdout is a terminal and NO_COLOR is unset (otherwise plain); -doctor-json is always unstyled JSON. Set MARCHAT_DOCTOR_NO_NETWORK=1 to skip the release check (e.g. air-gapped environments).
Additional command-line utilities for system management and plugin licensing.
cmd/server/main.go: Main server application with interactive configurationcmd/license/main.go: Plugin license management and validation tool
Both marchat-client and marchat-server embed diagnostics via internal/doctor (-doctor, -doctor-json); there is no separate doctor binary in release archives.
- License Generation: Create signed licenses for official plugins
- License Validation: Verify plugin license authenticity
- Key Management: Generate Ed25519 key pairs for signing
- Cache Management: Offline license validation support; cached licenses are re-signature-checked (and
plugin_namemust match the cache key) on read
Client: Input → Encrypt → WebSocket Send
Server: WebSocket Receive → Hub → Plugin Processing → SQL Backend
Server: SQL Backend → Hub → WebSocket Broadcast
Client: WebSocket Receive → Decrypt → Display
- The server chooses a backend at runtime using
MARCHAT_DB_PATH:- SQLite path (default local setup)
- PostgreSQL DSN (
postgres:///postgresql://) - MySQL DSN (
mysql:/mysql://)
- Schema creation and upsert/insert-ignore SQL are dialect-aware.
- Placeholder rebinding keeps shared query callsites portable across backends.
- SQLite-specific optimizations (for example WAL mode) are applied only when the selected backend is SQLite.
- Durable state includes:
- message history
- reactions
- read receipts
- last channel per user
The WebSocket communication uses JSON messages with the following structure:
- Handshake: Initial authentication with username and admin credentials
- Messages: Chat messages with optional encryption, message IDs, and channel/recipient metadata
- Extended Types: Edit, delete, typing, reaction, DM, search, pin, read receipt, join/leave/list channels
- Commands: Administrative and plugin commands
- System Messages: Connection status and user list updates
See PROTOCOL.md for the full message format specification.
- Key setup: Operator shares a 32-byte key (e.g.
openssl rand -base64 32asMARCHAT_GLOBAL_E2E_KEY) or the first client generates one and operators copy it to peers - Local storage: Client holds the key in
keystore.datprotected by--keystore-passphrase(embedded-salt file format; see README.md). OptionallyMARCHAT_GLOBAL_E2E_KEYsupplies the key in memory for that run without updating the file. - Message encryption: Inner JSON payload is sealed with ChaCha20-Poly1305; nonce ‖ ciphertext is base64-encoded into
contentwithencrypted: true(see PROTOCOL.md) - Transport: Standard WebSocket JSON; server does not decrypt
- Storage: Server persists opaque ciphertext in the database
- Edits: For
type: edit, the reference client sends the replacement body ciphertext when E2E is enabled; the server updatescontentand persistsis_encryptedfrom the wireencryptedfield so reconnects and message metadata stay correct
DDL below uses the SQLite dialect for readability. PostgreSQL and MySQL variants differ in type names (BIGSERIAL/BIGINT AUTO_INCREMENT for IDs, VARCHAR(191) for indexed text on MySQL, LONGTEXT/LONGBLOB for large fields) and are generated by CreateSchema in server/handlers.go.
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER DEFAULT 0,
sender TEXT,
content TEXT,
created_at DATETIME,
is_encrypted BOOLEAN DEFAULT 0,
encrypted_data BLOB,
nonce BLOB,
recipient TEXT,
edited BOOLEAN DEFAULT 0,
deleted BOOLEAN DEFAULT 0,
pinned BOOLEAN DEFAULT 0
);Edits update content and edited; is_encrypted follows the encrypted field on the edit message so ciphertext is not downgraded to plain text in the database after an edit.
CREATE TABLE user_message_state (
username TEXT PRIMARY KEY,
last_message_id INTEGER NOT NULL DEFAULT 0,
last_seen DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);CREATE TABLE ban_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
banned_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
unbanned_at DATETIME,
banned_by TEXT NOT NULL
);CREATE TABLE message_reactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER NOT NULL,
username TEXT NOT NULL,
emoji TEXT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE(message_id, username, emoji)
);CREATE TABLE user_channels (
username TEXT NOT NULL,
channel TEXT NOT NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (username)
);CREATE TABLE read_receipts (
username TEXT NOT NULL,
message_id INTEGER NOT NULL,
read_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (username, message_id)
);- Backend Selection:
MARCHAT_DB_PATHchooses SQLite/PostgreSQL/MySQL at runtime - WAL Mode (SQLite only): Write-Ahead Logging for better concurrency and crash recovery when SQLite is selected
- SQLite Database Files:
marchat.db(main),marchat.db-wal(write-ahead log),marchat.db-shm(shared memory) - Message ID Tracking: Sequential message IDs for user state management
- Encryption Support: Binary storage for encrypted message data
- Performance Indexes: Optimized queries for message retrieval and user state
- Message Cap: Automatic cleanup maintaining 1000 most recent messages
- Ban History: Comprehensive tracking of user moderation actions
- Performance Tuning: Backend-aware optimizations (SQLite pragmas when SQLite is selected)
The TUI-based admin panel provides real-time server management:
- System Monitoring: Live metrics including connections, memory usage, and message rates
- User Management: Ban, kick, and allow operations with history tracking
- Plugin Management: Install, enable, disable, and uninstall plugins
- Database Operations: Backup, restore, and maintenance functions
- System Controls: Force garbage collection and metrics reset
Implementation notes (server/admin_panel.go):
- Resize and layout: Window size updates apply width and height through a single layout path so the help bar, user table, and plugin table stay in sync; content width is derived consistently for bordered panels.
- Tabs: Tab labels render at natural width with spacing instead of fixed equal-width cells, which reads better on narrow terminals.
- Logs tab: Log lines are ordered oldest-first so the newest entries appear at the bottom; when output exceeds the visible area, the view initially anchors to the bottom of the buffer.
- Headings: Section titles and info lines avoid embedding trailing newlines inside styled strings (newlines are written separately) so System and Metrics panels stay left-aligned.
The web-based interface (admin_web.html, embedded via go:embed) provides the same functionality through a browser with a sidebar-navigation layout:
- Sidebar Navigation: Fixed sidebar with icon+label nav items (Overview, Users, System, Logs, Plugins, Metrics) and a Sign out button; collapses on mobile with a hamburger toggle and overlay
- Session Authentication: Secure login with admin key validation (1-hour HMAC-signed sessions)
- CSRF Protection: Cross-site request forgery prevention on all state-changing POST endpoints
- Confirmation Modals: Destructive actions (Clear Database, Ban, Kick, Uninstall, Reset Metrics) require user confirmation before executing
- Real-time Updates: Live data refresh every 5 seconds without page reloads; manual refresh via top-bar icon button
- RESTful API: Programmatic access to administrative functions (session cookie auth)
- Responsive Design: Sidebar collapses on screens below 800px; stat grids, metric cards, and config tables adapt to available width
- Status Badges: Pill-style badges with dot indicators for online/offline/banned/kicked states and TLS enabled/disabled
- Toast Notifications: Slide-up feedback messages for action results (success/error/info)
- Admin Key: Shared secret for administrative access
- Session Management: Secure session tokens with expiration
- CSRF Protection: Token-based request validation
- Rate Limiting: Protection against brute force attacks
- End-to-end (chat): Client-side ChaCha20-Poly1305 with a shared global symmetric key; the server never holds the plaintext key
- Keystore: PBKDF2 (passphrase + per-file salt) protects
keystore.dat(AES-GCM payload). Embedded salt makes the file portable across path changes;MARCHAT_GLOBAL_E2E_KEYoverrides the in-memory key without updating the file. - Authenticated encryption: ChaCha20-Poly1305 for chat and file payloads at the application layer
- Plugin Names: Regex-based validation preventing path traversal
- Username Validation: Case-insensitive matching with length limits
- File Upload: Type and size validation with safe path handling
- Command Parsing: Structured command validation and sanitization
- Goroutine-based: Concurrent handling of WebSocket connections
- Go Channel Communication: Non-blocking message passing between components
- Chat Channels: Server-side channel management with per-channel broadcast routing
- Connection Pooling: Efficient database connection management
- Plugin Isolation: Separate processes prevent plugin crashes from affecting server
- Message Limits: Automatic cleanup of old messages
- Connection Tracking: Efficient client state management
- Plugin Lifecycle: Proper cleanup of plugin subprocesses
- Garbage Collection: Configurable GC with monitoring
- WAL Mode (SQLite only): Write-Ahead Logging enabled for improved concurrency and performance
- Indexed Queries: Performance indexes on frequently queried columns
- Batch Operations: Efficient bulk message operations
- Connection Reuse: Persistent database connections
- Query Optimization: Prepared statements for common operations
- Performance Tuning: SQLite-specific pragmas are applied only on SQLite; Postgres/MySQL use driver/backend defaults
- Backup Considerations: SQLite WAL mode creates additional files; backups may miss recent uncommitted data if taken while server is running
- Package-based: Clear separation of concerns across packages
- Interface-driven: Dependency injection through interfaces
- Model-View-Update: Bubble Tea pattern for TUI components
- Command Pattern: Structured handling of administrative actions
- Graceful Degradation: System continues operating despite component failures
- Plugin Isolation: Plugin failures don't affect core functionality
- Comprehensive Logging: Structured logging with component identification
- User Feedback: Clear error messages and status indicators
- Unit Tests: Component-level testing with mock dependencies
- Integration Tests: End-to-end testing of client-server communication
- Plugin Testing: Isolated testing of plugin functionality
- Performance Testing: Load testing for concurrent connections
marchat produces two main executables:
marchat-client: Built fromclient/main.go- the terminal chat clientmarchat-server: Built fromcmd/server/main.go- the WebSocket server
- Cross-Platform Builds: GitHub Actions (
.github/workflows/release.yml) produces zips for linux-amd64, linux-arm64, windows-amd64, darwin-amd64, and darwin-arm64 - Termux (Android aarch64): Use the linux-arm64 release zip (static
GOOS=linuxbinary); there is no separateandroid-*artifact - CGO: Release CI sets
CGO_ENABLED=0on thebuildjob for static binaries and the pure Go SQLite stack, consistent withDockerfile,build-release.ps1, andscripts/build-linux.sh - Release versioning: A
resolve-versionjob runs first and exports the tag (published release) or workflow input (workflow_dispatch); matrix jobs cannot expose outputs, so Docker image tags, release notes, andgo build -ldflagsall consumeneeds.resolve-version.outputs.version - GitHub release assets: For
release: published(notworkflow_dispatch),upload-assetsrunsgh release uploadfor the artifact zips and thedockerjob appends the Docker Hub section withgh release edit, so publishing does not depend onsoftprops/action-gh-release(stillnode20in itsaction.yml, which triggers deprecation annotations if forced onto Node 24) - Release Scripts:
build-release.ps1and related helpers for local release-style builds - Docker Support: Containerized deployment with health checks
- Environment Variables: Primary configuration method for containers
- Interactive Setup: User-friendly initial configuration through TUI
- Profile Management: Multiple server connection profiles on the client
- Backward Compatibility: Support for deprecated command-line flags
- Diagnostics:
-doctor/-doctor-jsonon each binary for env/config verification (seeinternal/doctor)
- Docker: Official Docker images for easy deployment
- Environment-based: Configuration through environment variables
- Volume Mounting: Persistent data and configuration storage
- Health Checks: Built-in health monitoring for orchestration
- Operating Systems: Linux, macOS, Windows, and Android/Termux (Termux: linux/arm64 release asset)
- Architecture Support: AMD64 and ARM64 in official release zips
- Terminal Compatibility: Works with most terminal emulators
- File System: Handles different path separators and permissions
- SDK: Comprehensive plugin development kit
- Documentation: Detailed plugin development guides
- Examples: Reference implementations for common patterns
- Registry: Centralized plugin distribution and discovery
- JSON Configuration: Declarative theme definition
- Color Schemes: Comprehensive color palette support
- Component Styling: Granular control over UI elements
- Dynamic Loading: Runtime theme switching
- List / cycle order: Built-in themes in a fixed sequence; custom themes sorted lexicographically by JSON key for
:themesand Ctrl+T (see THEMES.md)
- WebSocket Protocol: Standardized communication layer enabling any frontend
- JSON IPC: Structured messages for easy parsing and integration
- Encryption Support: ChaCha20-Poly1305 (global symmetric E2E) for messaging and optional file encryption
- Frontend Flexibility: Architecture supports multiple frontend technologies
- Web, desktop, or mobile clients can implement real-time chat, file transfer, and admin commands
- Protocol Independence: Frontends are decoupled from server implementation
- Custom Commands: Plugin-based command extensions
- Webhooks: External system integration
- Metrics Export: Custom monitoring and alerting
- Backup Systems: Custom backup and restore procedures