High-Performance AI Agent Runtime
HotPlex transforms terminal AI tools (Claude Code, OpenCode) into production services. Built with Go using the Cli-as-a-Service paradigm, it eliminates CLI startup latency through persistent process pooling and ensures execution safety via PGID isolation and Regex WAF. The system supports WebSocket/HTTP/SSE communication with Python and TypeScript SDKs. At the application layer, HotPlex integrates with Slack and Feishu, supporting streaming output, interactive cards, and multi-bot protocols.
Quick Start · Features · Architecture · Docs · Discussions · 简体中文
- Quick Start
- Core Concepts
- Project Structure
- Features
- Architecture
- Usage Examples
- Development Guide
- Documentation
- Contributing
# One-line installation
curl -sL https://raw.githubusercontent.com/hrygo/hotplex/main/install.sh | bash
# Or build from source
make build
# Start the daemon
./hotplexd start -config configs/server.yaml
# Start with custom environment file
./hotplexd start -config configs/server.yaml -env-file .env.local| Component | Version | Notes |
|---|---|---|
| Go | 1.25+ | Runtime & SDK |
| AI CLI | Claude Code or OpenCode | Execution target |
| Docker | 24.0+ | Optional, for container deployment |
# 1. Clone and build
git clone https://github.com/hrygo/hotplex.git
cd hotplex
make build
# 2. Copy environment template
cp .env.example .env
# 3. Configure your AI CLI
# Ensure Claude Code or OpenCode is in PATH
# 4. Run the daemon
./hotplexd start -config configs/server.yamlUnderstanding these concepts is essential for effective HotPlex development.
HotPlex maintains long-lived CLI processes instead of spawning fresh instances per request. This eliminates:
- Cold start latency (typically 2-5 seconds per invocation)
- Context loss between requests
- Resource waste from repeated initialization
Request 1 → CLI Process 1 (spawned, persistent)
Request 2 → CLI Process 1 (reused, instant)
Request 3 → CLI Process 1 (reused, instant)
The Runner component handles bidirectional communication between:
- Upstream: User requests (WebSocket/HTTP/ChatApp events)
- Downstream: CLI stdin/stdout/stderr streams
// Each session has dedicated I/O channels
type Session struct {
Stdin io.Writer
Stdout io.Reader
Stderr io.Reader
Events chan *Event // Internal event bus
}Process Group ID (PGID) isolation ensures clean termination:
- CLI processes are spawned with
Setpgid: true - Termination sends signal to entire process group (
kill -PGID) - No orphaned or zombie processes
Web Application Firewall layer intercepts dangerous commands before they reach the CLI:
- Block patterns:
rm -rf /,mkfs,dd,:(){:|:&};: - Configurable via
security.danger_wafin config - Works alongside CLI's native tool restrictions (
AllowedTools)
Unified interface for multi-platform bot integration:
type ChatAdapter interface {
// Platform-specific event handling
HandleEvent(event Event) error
// Unified message format
SendMessage(msg *ChatMessage) error
}Advanced platforms implement streaming and message management:
type MessageOperations interface {
StartStream(ctx, channelID, threadTS) (messageTS, error)
AppendStream(ctx, channelID, messageTS, content) error
StopStream(ctx, channelID, messageTS) error
UpdateMessage(ctx, channelID, messageTS, msg) error
DeleteMessage(ctx, channelID, messageTS) error
}The engine layer is the brain of HotPlex, coordinating all AI interactions.
- Deterministic ID Mapping: Generates UUID v5 using platform metadata, ensuring that the corresponding Claude CLI process can be retrieved even after
hotplexdrestarts. - Health Detection: 500ms frequency
waitForReadypolling combined withprocess.Signal(0)detection ensures that sessions assigned to users are 100% available. - Cleanup Mechanism: Dynamically adjusts the cleanup interval (Timeout/4), balancing resource utilization and response speed.
HotPlex acts as a WAF for the local system.
- Multi-level Filtering: Pre-configured with over 50 dangerous command patterns, ranging from simple
rmto complexsudo bashreverse shells. - Evasion Defense: Specifically designed for LLM-generated content, it includes automatic markdown code block stripping and real-time detection of malicious control characters (e.g., null bytes).
- Protocol Translation: The core
ExecutionControllerserializes complex CLI events into standard streaming JSON for consumption by upstream platforms. - Admin API: Provides complete session audit logs (Audit Events) and export interfaces.
- "System 1" Abstraction: Providing lightweight intent recognition and safety pre-audit interfaces, supporting multiple LLM model routing.
- Resiliency: Built-in circuit breakers and automatic failover logic to ensure core capabilities remain available even if the primary model is down.
- OpenTelemetry: Deeply integrated OTEL, not only tracking request latency but also tracing every "Permission Decision" made by the AI.
- Monitoring Metrics: Exports Prometheus-compatible metrics covering session success rates, token costs, and security interception frequency.
hotplexd is not just a daemon; it is also a full-featured management tool:
status: View engine load, active session count, and memory usage in real-time.session: Provides fine-grained session control includinglist(list),kill(kill), andlogs(view logs).doctor: Automatically diagnoses the local environment, checkingclaudeCLI connectivity, permission settings, and Docker status.config: Validates and renders the current merged configuration tree, supporting both local and remote validation.cron: Schedule and manage background AI tasks with standard cron syntax and history tracking.relay: Configure cross-platform bot-to-bot relaying and binding.
hotplex/
├── [cmd/](./cmd) # CLI & Daemon entrypoints
│ └── [hotplexd/](./cmd/hotplexd) # Main daemon implementation
├── internal/ # Core implementation (private)
│ ├── engine/ # Session pool & runner
│ ├── server/ # WebSocket & HTTP gateway
│ ├── security/ # WAF & isolation
│ ├── config/ # Configuration loading
│ ├── sys/ # OS signals
│ ├── telemetry/ # OpenTelemetry
│ └── ...
├── brain/ # Native Brain orchestration
├── cache/ # Caching layer
├── [provider/](./provider) # AI provider adapters
│ ├── [claude_provider.go](./provider/claude_provider.go) # Claude Code protocol
│ ├── [opencode_provider.go](./provider/opencode_provider.go) # OpenCode protocol
│ └── ...
├── [chatapps/](./chatapps) # Platform adapters
│ ├── slack/ # Slack Bot
│ ├── feishu/ # Feishu Bot
│ └── base/ # Common interfaces
├── types/ # Public type definitions
├── event/ # Event system
├── plugins/ # Extension points
│ └── storage/ # Message persistence
├── sdks/ # Language bindings
│ ├── go/ # Go SDK (embedded)
│ ├── python/ # Python SDK
│ └── typescript/ # TypeScript SDK
├── docker/ # Container definitions
├── configs/ # Configuration examples
└── docs/ # Architecture docs
| Directory | Purpose | Public API |
|---|---|---|
types/ |
Core types & interfaces | ✅ Yes |
event/ |
Event definitions | ✅ Yes |
hotplex.go |
SDK entry point | ✅ Yes |
internal/engine/ |
Session management | ❌ Internal |
internal/server/ |
Network protocols | ❌ Internal |
provider/ |
CLI adapters |
| Feature | Description | Use Case |
|---|---|---|
| 🔄 Deterministic Sessions | Precise mapping based on UUID v5 (SHA1) to ensure cross-platform context consistency | High-frequency AI collaboration |
| 🛡️ Secure Isolation | Unix PGID and Windows Job Objects isolation to completely eliminate zombie processes | Production-grade security |
| 🛡️ Regex WAF | 6-level risk assessment system to prevent command injection, privilege escalation, and reverse shells | System hardening |
| 🌊 Streaming Delivery | 1MB-level I/O buffer + full-duplex Pipe for sub-second Token response | Real-time interactive UI |
| 💬 Multi-platform Adaptation | Native support for Slack and Feishu with |
Enterprise-level communication |
| 🛡️ Cross-platform Relay | Secure bot-to-bot message routing between different chat platforms | Multi-agent collaboration |
| ⏰ Background Cron | Native scheduling for periodic AI tasks with failure recovery and webhooks | Automation & Monitoring |
| Packaged Go SDK | Zero-overhead embedded engine for direct integration into Go business logic | Custom Agents |
| 🔌 Protocol Compatibility | Full OpenCode HTTP/SSE protocol support for seamless frontend integration | Cross-language frontend |
| 📊 Deep Telemetry | Built-in OpenTelemetry tracing for tool execution and permission decisions | Production monitoring |
| 🐳 BaaS Architecture | Docker 1+n containerization scheme with pre-installed major language environments | Rapid deployment |
HotPlex employs a decoupled layered architecture to ensure high reliability from chat platforms to the execution engine.
- Deterministic ID Mapping: Uses
UUID v5 (SHA1)to mapNamespace + Platform + UserID + ChannelIDto a persistentproviderSessionID. This ensures that as long as the user metadata remains the same, the session can be accurately recovered after a daemon restart. - Cold/Warm Start Logic: Features a 500ms polling
waitForReadymechanism combined with Job Markers for state recovery and stale session detection.
- Process Group Isolation: Utilizes PGID (Process Group ID). Upon session termination, a signal is sent to the negative PID, forcing the removal of the entire process tree and eradicating orphan processes.
- Dual-Layer WAF: Performs a 6-level risk assessment before commands reach the CLI. Includes evasion protection (blocking null bytes/control chars) and automatic markdown stripping (reducing false positives).
- OpenCode Compatibility: Real-time mapping of internal events to
reasoning,text, andtoolparts. - I/O Multiplexing: Full-duplex pipes with 1MB dynamic buffers to prevent accidental blocking during large concurrent read/write operations.
- Management Plane: Provides both direct local CLI access and a remote Admin API (port 9080) for session management, diagnostics, and metrics.
-
Provider System: Plug-in architecture supporting Claude Code's
~/.claude/projects/directory management and permission synchronization. -
ChatApp Adapter: Built-in secondary indexing for
$O(1)$ session lookup based onuser + channel.
graph TD
User([User / ChatApps]) -- WebSocket / HTTP --> Gateway[hotplexd Gateway]
Gateway -- Event Map --> Pool[Session Pool]
Pool -- ID Mapping --> Runner[Runner/Multiplexer]
Runner -- PGID Isolation --> CLI[AI CLI Process]
subgraph Security Layer
WAF[Regex WAF] .-> Runner
Auth[API Key / Admin Auth] .-> Gateway
end
subgraph Persistence
Marker[Session Marker Store] .-> Pool
Log[Session Logs] .-> Runner
end
import (
"context"
"fmt"
"time"
"github.com/hrygo/hotplex"
"github.com/hrygo/hotplex/types"
)
func main() {
// Initialize engine
engine, err := hotplex.NewEngine(hotplex.EngineOptions{
Timeout: 5 * time.Minute,
IdleTimeout: 30 * time.Minute,
})
if err != nil {
panic(err)
}
defer engine.Close()
// Execute prompt
cfg := &types.Config{
WorkDir: "/path/to/project",
SessionID: "user-session-123",
}
engine.Execute(context.Background(), cfg, "Explain this function", func(eventType string, data any) error {
switch eventType {
case "message":
if msg, ok := data.(*types.StreamMessage); ok {
fmt.Print(msg.Content) // Streaming output
}
case "error":
if errMsg, ok := data.(string); ok {
fmt.Printf("Error: %s\n", errMsg)
}
case "usage":
if stats, ok := data.(*types.UsageStats); ok {
fmt.Printf("Tokens: %d input, %d output\n", stats.InputTokens, stats.OutputTokens)
}
}
return nil
})
}# configs/base/slack.yaml
platform: slack
mode: socket
provider:
type: claude-code
default_model: sonnet
allowed_tools:
- Read
- Edit
- Glob
- Grep
- Bash
engine:
work_dir: ~/projects/hotplex
timeout: 30m
idle_timeout: 1h
security:
owner:
primary: ${HOTPLEX_SLACK_PRIMARY_OWNER}
policy: trusted
assistant:
bot_user_id: ${HOTPLEX_SLACK_BOT_USER_ID}
dm_policy: allow
group_policy: multibot// Connect
const ws = new WebSocket('ws://localhost:8080/ws/v1/agent');
// Listen for messages
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'message':
console.log(data.content);
break;
case 'error':
console.error(data.error);
break;
case 'done':
console.log('Execution complete');
break;
}
};
// Execute prompt
ws.send(JSON.stringify({
type: 'execute',
session_id: 'optional-session-id',
prompt: 'List files in current directory'
}));# 1. Create session
curl -X POST http://localhost:8080/session
# 2. Send prompt (async)
curl -X POST http://localhost:8080/session/{session_id}/message \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello, AI!"}'
# 3. Listen for events (SSE)
curl -N http://localhost:8080/global/event# Run tests
make test
# Run with race detector
make test-race
# Build binary
make build
# Run linter
make lint
# Build Docker images
make docker-build
# Start Docker stack
make docker-upTip
The version information displayed by hotplexd version is injected via LDFLAGS during build. If you run go run or go build directly without LDFLAGS, it will show the default v0.0.0-dev. Using make build is recommended for compilation.
- Implement the adapter interface in
chatapps/<platform>/:
type Adapter struct {
client *platform.Client
engine *engine.Engine
}
// Implement base.ChatAdapter interface
var _ base.ChatAdapter = (*Adapter)(nil)
func (a *Adapter) HandleEvent(event base.Event) error {
// Platform-specific event parsing
}
func (a *Adapter) SendMessage(msg *base.ChatMessage) error {
// Platform-specific message sending
}- Register in
chatapps/setup.go:
func init() {
registry.Register("platform-name", NewAdapter)
}- Add configuration in
configs/base/:
platform: platform-name
mode: socket # or http
# ... platform-specific config- Implement the Provider interface in
provider/:
// provider/custom_provider.go
type CustomProvider struct{}
func (p *CustomProvider) Execute(ctx context.Context, cfg *types.Config, prompt string, callback event.Callback) error {
// Implement provider-specific logic
}- Register the new type in
provider/factory.go.
| Guide | Description |
|---|---|
| 🚀 Deployment | Docker, production setup |
| 💬 ChatApps | Slack & Feishu integration |
| 🛠 Go SDK | SDK reference |
| 🔒 Security | WAF, isolation |
| 📊 Observability | Metrics, tracing |
| ⚙️ Configuration | Full config reference |
We welcome contributions! Please follow these steps:
# 1. Fork and clone
git clone https://github.com/hrygo/hotplex.git
# 2. Create a feature branch
git checkout -b feat/your-feature
# 3. Make changes and test
make test
make lint
# 4. Commit with conventional format
git commit -m "feat(engine): add session priority support"
# 5. Submit PR
gh pr create --fill<type>(<scope>): <description>
Types: feat, fix, refactor, docs, test, chore
Scope: engine, server, chatapps, provider, etc.
- Follow Uber Go Style Guide
- All interfaces require compile-time verification
- Run
make test-racebefore submitting
MIT License © 2024-present HotPlex Contributors