https://github.com/batalabs/muxd
An open-source AI coding agent that lives in your terminal. Multi-provider, multi-channel, persistent sessions with git-like branching.
https://github.com/batalabs/muxd
ai-assistant anthropic cli code-generation coding-agent developer-tools fireworks-ai golang grok llm ollama openai terminal tui
Last synced: 29 days ago
JSON representation
An open-source AI coding agent that lives in your terminal. Multi-provider, multi-channel, persistent sessions with git-like branching.
- Host: GitHub
- URL: https://github.com/batalabs/muxd
- Owner: batalabs
- License: apache-2.0
- Created: 2026-02-24T00:58:37.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-05-03T22:04:34.000Z (29 days ago)
- Last Synced: 2026-05-03T22:07:37.243Z (29 days ago)
- Topics: ai-assistant, anthropic, cli, code-generation, coding-agent, developer-tools, fireworks-ai, golang, grok, llm, ollama, openai, terminal, tui
- Language: Go
- Homepage: https://muxd.sh
- Size: 15.9 MB
- Stars: 8
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Security: docs/security.md
Awesome Lists containing this project
README
muxd
An open source AI coding agent that lives in your terminal.
37 tools. Any model. Sessions that survive reboots. An agent that builds its own tools.
mux = multiplex your sessions · d = daemon
(Unix tradition)
> **Full docs at [muxd.sh](https://muxd.sh/docs)** · [Client setup](https://muxd.sh/docs/client) · [Hub setup](https://muxd.sh/docs/hub) · [Commands](https://muxd.sh/docs/commands) · [Tools](https://muxd.sh/docs/tools) · [Config](https://muxd.sh/docs/configuration)
---
## Architecture
muxd has four components. Run them all on one machine for local dev, or distribute them across servers for a team setup.
| Component | Binary | Role |
|---|---|---|
| **muxd** | `muxd` | Terminal TUI client |
| **muxd-daemon** | `muxd-daemon` | Agent server (sessions, tools, model calls) |
| **muxd-hub** | `muxd-hub` | Hub coordinator (nodes, workers, webhooks) |
| **Web UI** | served by hub | Browser dashboard for workers and nodes |
### muxd Terminal Client
The TUI you interact with. Connects to a local daemon or a remote hub. Pure client, no agent logic.
```bash
muxd # connect to local daemon
muxd --remote hub.example.com:4097 --token x # connect to remote hub
```
Flags: `--version`, `--remote `, `--token `
### muxd-daemon Agent Server
Headless server that runs sessions, executes tools, talks to model APIs. One per machine.
```bash
muxd-daemon # start on localhost:4096
MUXD_BIND=0.0.0.0 muxd-daemon # listen on all interfaces
```
Configuration is via `config.json` or environment variables:
| Env Var | What |
|---|---|
| `MUXD_MODEL` | Model name or alias (e.g. `claude-sonnet`) |
| `MUXD_PROVIDER` | Provider name (e.g. `anthropic`, `openai`) |
| `MUXD_BIND` | Network interface to bind (default: `localhost`) |
| `MUXD_HUB_URL` | Hub URL to register with |
| `MUXD_NODE_NAME` | Node name (defaults to hostname) |
### muxd-hub Hub Coordinator
Central coordinator for multiple daemons. Manages node registration, worker lifecycle, webhooks, and serves the web UI.
```bash
muxd-hub # start on localhost:4097
MUXD_HUB_BIND=0.0.0.0 muxd-hub # listen on all interfaces
```
| Env Var | What |
|---|---|
| `MUXD_HUB_BIND` | Network interface to bind |
| `MUXD_HUB_TOKEN` | Auth token (auto-generated if not set) |
| `MUXD_WEB_DIR` | Path to web UI static files (enables web dashboard) |
### Web UI Browser Dashboard
React + Vite + Tailwind dashboard for managing workers and monitoring nodes. Served by the hub when `MUXD_WEB_DIR` is set (automatic in Docker).
Pages:
- **Dashboard** — nodes, workers, sessions, cost overview
- **Workers** — create and manage autonomous agents triggered by webhooks or schedules
- **Worker Detail** — activity feed with approve/reject for human-in-the-loop
- **Nodes** — registered daemon nodes with status
```bash
# Local dev
cd web && npm run dev # starts on :5173, proxies /api to hub on :4097
# Production (built into hub)
MUXD_WEB_DIR=/var/lib/muxd/web muxd-hub
```
---
## Configuration
All three binaries share one config file at `~/.config/muxd/config.json`. Each binary only reads the fields it needs.
| File | Location | Purpose |
|---|---|---|
| `config.json` | `~/.config/muxd/` | Shared config for all binaries |
| `muxd.db` | `~/.local/share/muxd/` | Sessions, messages, branches (daemon) |
| `hub.db` | `~/.local/share/muxd/` | Nodes, workers, memory, logs (hub) |
| `server.lock` | `~/.local/share/muxd/` | Daemon PID, port, token (auto-managed) |
### Config fields by binary
**muxd** (TUI client): `model`, `provider`, `hub_url`, `hub_auth_token`
**muxd-daemon** (agent server): `model`, `provider`, API keys, `daemon_bind_address`, `hub_url`, `hub_node_token`, `hub_node_name`
**muxd-hub** (coordinator): `hub_bind_address`, `hub_auth_token`
### Setting values
Three ways to configure, in priority order:
1. **Environment variables** — override everything (e.g. `MUXD_MODEL=claude-sonnet`)
2. **`config.json`** — persisted settings, edited via `/config set ` in the TUI
3. **Defaults** — sensible defaults when nothing is set
API keys follow the same pattern: set in `config.json` via `/config set anthropic.api_key `, or use the standard env var (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc).
### Key config values
| Key | Env var | What |
|---|---|---|
| `model` | `MUXD_MODEL` | Default model (e.g. `claude-sonnet`) |
| `provider` | `MUXD_PROVIDER` | Default provider (e.g. `anthropic`) |
| `daemon_bind_address` | `MUXD_BIND` | Daemon bind interface |
| `hub_url` | `MUXD_HUB_URL` | Hub URL for daemon registration |
| `hub_node_token` | `MUXD_HUB_NODE_TOKEN` | Token for daemon to register with hub |
| `hub_node_name` | `MUXD_NODE_NAME` | Node name (defaults to hostname) |
| `hub_bind_address` | `MUXD_HUB_BIND` | Hub bind interface |
| `hub_auth_token` | `MUXD_HUB_TOKEN` | Hub auth token |
---
## What makes muxd different
Most AI coding tools treat conversations as disposable. muxd saves everything to local SQLite. Close your terminal, reboot, come back next week, and pick up exactly where you left off.
### Agent capabilities
| | |
|---|---|
| **37 built-in tools** | File I/O, bash, grep, glob, web search, HTTP, SMS, git, scheduling, document reading, parallel pipeline, LSP, and more |
| **Any model** | Claude, GPT, Gemini, Mistral, Grok, GLM, Fireworks, DeepInfra, Ollama, or any OpenAI compatible API |
| **Inline diffs** | Every file edit shows a red and green diff in the chat. See exactly what changed |
| **Read any document** | PDFs, Word, Excel, PowerPoint, HTML, CSV, JSON, XML. No plugins required |
| **Self extending tools** | The agent creates its own tools at runtime. Command templates or scripts, ephemeral or persistent |
| **Second opinion** | Ask a different model for a review. Response shown separately with a crystal ball emoji |
| **Chat modes** | Code (read/edit/run), Ask (read-only), Architect (plan only). Switch with `/mode` |
| **Repo map** | Auto-generated codebase overview injected into context for better navigation |
| **Parallel pipeline** | Run sub-agents concurrently with a live DAG showing animated spinners and per-task activity |
| **Code intelligence** | LSP integration with go-to-definition, references, hover, diagnostics, and symbol search across Go, TypeScript, Python, Rust, and C/C++ |
### Session management
| | |
|---|---|
| **Persistent sessions** | Conversations survive restarts. Resume any session by project or ID |
| **Branch and fork** | Explore alternatives without losing your thread. Like git branches for conversations |
| **Project memory** | The agent remembers your conventions and decisions across sessions |
| **Smart compression** | Tiered compaction at 60k/75k/90k tokens. Preserves key decisions while cutting costs |
### Infrastructure
| | |
|---|---|
| **Hub architecture** | Coordinate multiple daemons across machines. Connect from any TUI or mobile client |
| **Copy mode** | Press Ctrl+S to toggle mouse tracking for native text selection. Arrow keys scroll the viewport |
| **Always on daemon** | Background service that survives reboots. Auto titles, schedules tasks, runs headless |
| **Mobile app** | [iOS app](https://apps.apple.com/us/app/muxd/id6759869997) connects via QR code. Chat with your agent from anywhere |
| **Hub dispatch** | Send tasks to remote nodes. The agent can delegate work across your machines |
| **Web dashboard** | Browser-based UI for workers, nodes, and activity monitoring |
---
## Demo
---
## Install
**Windows (PowerShell)**
```powershell
irm https://raw.githubusercontent.com/batalabs/muxd/main/install.ps1 | iex
```
**macOS / Linux**
```bash
curl -fsSL https://raw.githubusercontent.com/batalabs/muxd/main/install.sh | bash
```
**From source** (requires [Go 1.25+](https://go.dev/dl/))
```bash
go install github.com/batalabs/muxd@latest
```
**Prerequisites**: git (for undo/redo) and an API key for at least one [supported provider](https://muxd.sh/docs/configuration).
---
## Quick Start Binaries
### 1 machine: daemon + TUI
Everything local. Two terminals, no hub.
```bash
# Terminal 1: start the daemon
muxd-daemon
# Terminal 2: start the TUI (auto-discovers the daemon)
muxd
```
### 1+1: hub + daemon on the same server
One server runs the hub and daemon. You connect from your laptop.
```bash
# 1. Install (as root)
curl -fsSL https://raw.githubusercontent.com/batalabs/muxd/main/install.sh | sh
# 2. Set up env vars (as your user, on minimal servers without a desktop)
export XDG_RUNTIME_DIR=/run/user/$(id -u)
export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus
# 3. Install and start the hub service
MUXD_HUB_BIND=0.0.0.0 muxd-hub -service install
muxd-hub -service start
# 4. Keep services running after SSH logout (as root)
su - -c "loginctl enable-linger $USER"
# 5. Get the QR code and token
muxd-hub -service qr
# 6. Install and start the daemon (on the same server)
muxd-daemon -service install
MUXD_HUB_URL=http://localhost:4097 MUXD_HUB_NODE_TOKEN= muxd-daemon -service start
```
```bash
# On your laptop: connect to the hub
muxd --remote :4097 --token
```
Open `http://:4097` in your browser to see the web dashboard.
### 1+2: hub and daemon on separate servers
Dedicate one server to the hub, another to the daemon. More secure: your API keys only live on the daemon server.
```bash
# Server A (hub): coordinate nodes
muxd-hub # prints token + QR code
# Server B (daemon): runs the agent
MUXD_HUB_URL=http://server-a:4097 \
MUXD_HUB_NODE_TOKEN= \
MUXD_NODE_NAME=worker-1 \
muxd-daemon
# Your laptop: connect to hub
muxd --remote server-a:4097 --token
```
### Adding more servers (1+n)
Each additional machine just runs `muxd-daemon` pointing at the hub:
```bash
# Server C, D, E... each run:
MUXD_HUB_URL=http://server-a:4097 \
MUXD_HUB_NODE_TOKEN= \
MUXD_NODE_NAME=worker-3 \
muxd-daemon
```
The hub shows all nodes in the web dashboard. Use `/nodes` in the TUI to pick which node to run sessions on.
---
## Quick Start Docker
First build the images:
```bash
git clone https://github.com/batalabs/muxd.git
cd muxd
docker compose build
```
API keys can be passed as env vars or set inside the TUI with `/config set .api_key `:
| Provider | Env var |
|---|---|
| Anthropic | `ANTHROPIC_API_KEY` |
| OpenAI | `OPENAI_API_KEY` |
| Google | `GOOGLE_API_KEY` |
| Mistral | `MISTRAL_API_KEY` |
| Grok | `XAI_API_KEY` |
| ZAI (GLM) | `ZAI_API_KEY` |
| Fireworks | `FIREWORKS_API_KEY` |
| DeepInfra | `DEEPINFRA_API_KEY` |
| Ollama | `OLLAMA_API_BASE` (default: `http://localhost:11434`) |
### 1+1: hub + daemon on one machine
```bash
# Create .env
echo "MUXD_MODEL=claude-sonnet" > .env
echo "ANTHROPIC_API_KEY=sk-ant-..." >> .env
# Start hub + daemon
docker compose up -d
# Connect from your laptop
muxd --remote localhost:4097 --token
```
Open `http://localhost:4097` in your browser to see the web dashboard.
`docker-compose.yml`:
```yaml
services:
hub:
build:
context: .
target: hub
ports: ["4097:4097"]
environment:
MUXD_HUB_BIND: "0.0.0.0"
daemon:
build:
context: .
target: daemon
environment:
MUXD_MODEL: ${MUXD_MODEL:-claude-sonnet}
MUXD_BIND: "0.0.0.0"
MUXD_HUB_URL: "http://hub:4097"
MUXD_HUB_NODE_TOKEN: ${HUB_TOKEN:-}
env_file: .env
```
### 1+2: hub and daemon on separate servers
```bash
# Server A (hub)
docker run -d -p 4097:4097 -e MUXD_HUB_BIND=0.0.0.0 muxd-hub
# Server B (daemon)
docker run -d -p 4096:4096 \
-e MUXD_MODEL=claude-sonnet \
-e MUXD_BIND=0.0.0.0 \
-e MUXD_HUB_URL=http://server-a:4097 \
-e MUXD_HUB_NODE_TOKEN= \
-e MUXD_NODE_NAME=worker-1 \
-e ANTHROPIC_API_KEY=sk-ant-... \
muxd-daemon
# Your laptop
muxd --remote server-a:4097 --token
```
### Adding more servers (1+n)
Each additional daemon server is one `docker run`:
```bash
# Server C, D, E...
docker run -d -p 4096:4096 \
-e MUXD_BIND=0.0.0.0 \
-e MUXD_HUB_URL=http://server-a:4097 \
-e MUXD_HUB_NODE_TOKEN= \
-e MUXD_NODE_NAME=worker-3 \
-e MUXD_MODEL=claude-sonnet \
-e ANTHROPIC_API_KEY=sk-ant-... \
muxd-daemon
```
Or add more `daemon` services to your `docker-compose.yml` on each server.
---
## Running as a Service
Install muxd-hub or muxd-daemon as a system service so it starts on boot and survives SSH disconnects.
### Linux (systemd)
```bash
# Install the hub as a user service
muxd-hub -service install
muxd-hub -service start
# Install the daemon as a user service
muxd-daemon -service install
muxd-daemon -service start
```
**Important**: On minimal servers (no desktop environment), set these env vars first:
```bash
export XDG_RUNTIME_DIR=/run/user/$(id -u)
export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus
```
Then keep services running after logout:
```bash
loginctl enable-linger $USER
```
Without `enable-linger`, systemd kills user services when you close your SSH session.
### Service management
```bash
muxd-hub -service status # check if running
muxd-hub -service stop # stop the service
muxd-hub -service uninstall # remove the service
muxd-hub -service qr # re-show the QR code and token
```
Same commands work for `muxd-daemon -service `.
### macOS (launchd)
```bash
muxd-hub -service install # creates ~/Library/LaunchAgents/com.muxd.hub.plist
muxd-hub -service start
muxd-hub -service status
```
### Windows (registry)
```bash
muxd-daemon -service install # adds startup registry entry
muxd-daemon -service start # launches in background
muxd-daemon -service stop # kills process via lockfile
```
---
## Contributing
```bash
git clone https://github.com/batalabs/muxd.git
cd muxd
# Build all binaries
go build -o muxd .
go build -o muxd-hub ./cmd/muxd-hub
go build -o muxd-daemon ./cmd/muxd-daemon
# Run tests
go test ./...
# Web UI
cd web && npm install && npm run dev
```
See [muxd.sh/docs/contributing](https://muxd.sh/docs/contributing) for code style and development guide.
---
## License
[Apache License 2.0](LICENSE)