---
description: "The daemon executes Agent Runs. Register one or more runtimes to scale execution capacity."
---

# Daemon Installation

The daemon executes Agent Runs. Register one or more runtimes to scale execution capacity.

![Runtime Management](/documentation/blume-assets/content/docs/img/screenshots/08-runtimes.png)

## Quick Start (Docker)

```bash
# 1. Get a registration token
# In Agent Orchestrator: Runtimes → Register Runtime → copy token

# 2. Run the daemon
docker run -d \
  --name agenthub-daemon \
  -e AGENTHUB_SERVER_URL=http://your-ao-server:8082 \
  -e AGENTHUB_TOKEN=<your-token> \
  -e AGENTHUB_RUNTIME_NAME="My Runtime" \
  -v agenthub-workspaces:/root/agenthub_workspaces \
  simplifierag/miri:daemon
```

## Quick Start (Local / Bare Metal)

```bash
# 1. Install dependencies
# Python 3.11+, git, opencode (auto-installed by daemon)

# 2. Get registration token from AO UI
export AGENTHUB_SERVER_URL=http://your-ao-server:8082
export AGENTHUB_TOKEN=<your-token>
export AGENTHUB_RUNTIME_NAME="Local Runtime"

# 3. Run
python3 agenthub_daemon.py start --foreground
```

## Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `AGENTHUB_SERVER_URL` | Yes | — | Backend URL (e.g., `http://localhost:8082`) |
| `AGENTHUB_TOKEN` | Yes | — | Registration token from AO |
| `AGENTHUB_RUNTIME_NAME` | No | `Docker Runtime` | Display name in AO |
| `AGENTHUB_WORKSPACE_ID` | No | — | Bind to specific workspace |
| `AGENTHUB_OPENCODE_PATH` | No | `opencode` | Path to opencode binary |
| `AGENTHUB_OPENCODE_MODEL` | No | — | Default model for runs |
| `AGENTHUB_MAX_CONCURRENT` | No | `3` | Max parallel runs |
| `AGENTHUB_POLL_INTERVAL` | No | `5000` | Backend poll interval (ms) |
| `AGENTHUB_IDLE_WATCHDOG` | No | `1800000` | Idle timeout (ms) |
| `AGENTHUB_RECONNECT_DELAY` | No | `5000` | Backend reconnect delay (ms) |
| `AGENTHUB_LOG_MAX_BYTES` | No | `10485760` | Log rotation size |
| `AGENTHUB_LOG_BACKUP_COUNT` | No | `5` | Rotated log files to keep |
| `AGENTHUB_STATE_DIR` | No | `<workspaces dir>/.daemon-state` | Where the daemon keeps its saved runtime credentials |
| `AGENTHUB_DRAIN_SECONDS` | No | `60` | How long a stopping daemon waits for running work |
| `AGENTHUB_WUD_URL` | No | — | Watchtower Update Daemon URL |

## Docker Compose (Production)

```yaml
# docker-compose.daemon.prod.yaml
services:
  daemon:
    image: simplifierag/miri:daemon
    environment:
      AGENTHUB_SERVER_URL: https://your-ao.com
      AGENTHUB_TOKEN: ${AGENTHUB_TOKEN}
      AGENTHUB_RUNTIME_NAME: "Production Runtime"
    volumes:
      - daemon-workspaces:/root/agenthub_workspaces
    restart: unless-stopped

volumes:
  daemon-workspaces:
```

Run: `docker compose -f docker-compose.daemon.prod.yaml --env-file .env.daemon.prod up -d`

## Systemd Service (Linux)

```bash
# Install (as root)
curl -fsSL https://raw.githubusercontent.com/simplifierag/sf-agent-os/main/daemon/install.sh | bash -s -- \
  --server https://your-ao.com \
  --token <token> \
  --name "Production Runtime"

# Manage
systemctl status agenthub-daemon
systemctl restart agenthub-daemon
journalctl -u agenthub-daemon -f
```

## opencode Integration

The daemon requires **opencode** for executing runs. It handles installation automatically:

- **Docker image** — Pre-installed at `/root/.opencode/bin/opencode`
- **Local** — Auto-installs on first run (`curl ... | bash`)
- **Version** — Pinned to compatible version in `daemon/Dockerfile`

### Model Configuration

Set default model per runtime:
```bash
export AGENTHUB_OPENCODE_MODEL=anthropic/claude-3-5-sonnet
```

Agents can override per-run via their execution settings.

## Registration Tokens, Restarts and Updates

- **A registration token works once and expires.** **Runtimes** → **Register Runtime** shows the token with an "Expires in …" countdown (24 hours). It is used up the first time a daemon registers with it.
- **A daemon needs no new token after that.** When it registers, it saves its runtime credentials (`credentials.json`, readable only by the daemon's user) in its state directory — by default `.daemon-state` inside the workspaces directory. A restart, a container recreate or an image update (including WUD) then resumes the same runtime from that file.
- **Keep the state directory on a volume.** The compose files keep it in the daemon's workspaces volume. If that volume is lost — or the daemon is started with another server URL, runtime name or token — it registers anew and needs a fresh token from **Register Runtime**.
- **Stopping drains running work.** On stop, the daemon takes no new Runs and waits up to `AGENTHUB_DRAIN_SECONDS` for running ones. Runs still unfinished go back to the queue immediately and are picked up again. Give your container or service a stop timeout above that value — the compose files use 90 seconds; a plain `docker stop` with the default 10 seconds would cut the wait short.

## WUD Auto-Update (Watchtower)

Enable automatic daemon updates:

```bash
# In daemon compose, add WUD sidecar:
wud:
  image: getwud/wud:latest
  environment:
    WUD_WATCHER_LOCAL_WATCHBYDEFAULT: "false"
    WUD_SERVER_ENABLED: "true"
  labels:
    - "wud.watch.daemon=true"
    - "wud.trigger.miri=true"

# In daemon:
environment:
  AGENTHUB_WUD_URL: http://wud:3000
```

**How it works:**
1. Backend sets `pendingUpdate` flag on runtime
2. Daemon heartbeat delivers flag
3. Daemon calls WUD locally → WUD pulls new image → restarts daemon
4. Also checks every 6 hours for new `:latest` digest

## Remote Backend + Local Daemon

Common pattern: AO backend in cloud, daemon on local machine:

```bash
# Local machine
export AGENTHUB_SERVER_URL=https://your-cloud-ao.com
export AGENTHUB_TOKEN=<token-from-cloud-ao>
python3 agenthub_daemon.py start
```

- Daemon polls cloud backend over HTTPS
- Git checkouts happen locally (your machine, your credentials)
- Deliveries pushed from your machine to git remote

## Multiple Runtimes

Register multiple daemons for:
- **Different environments** — Dev / Staging / Prod
- **Different hardware** — GPU for coding, CPU for analysis
- **Different networks** — On-prem behind firewall + cloud
- **Scaling** — Distribute runs across machines

All runtimes appear in **Runtimes** page with individual health/capacity.

## Troubleshooting

| Issue | Fix |
|-------|-----|
| "Connection refused" | Check `AGENTHUB_SERVER_URL` reachable from daemon |
| "Invalid token" | Regenerate token in AO → Runtimes → Register Runtime |
| "opencode not found" | Docker: use `simplifierag/miri:daemon`; Local: check PATH |
| "No models reported" | Ensure opencode version supports model discovery |
| "Workdir permission denied" | Volume mount: `-v agenthub-workspaces:/root/agenthub_workspaces` |
| "Git clone failed" | Check Git target credentials in Project Detail |

## Logs

```bash
# Docker
docker logs -f agenthub-daemon

# Local (foreground)
python3 agenthub_daemon.py start --foreground

# Systemd
journalctl -u agenthub-daemon -f
```

Log file: `~/.agenthub/daemon.log` (rotating, 10MB × 5 files by default)

## PID File

`~/.agenthub/daemon.pid` — used by `stop`/`restart`/`status` commands.

## Recent Updates

- **opencode Integration** — Auto-installs, pinned version, model configuration
- **WUD Auto-Update** — Daemon-mediated remote updates via Watchtower
- **Multiple Runtime Support** — Register many daemons, individual health tracking
- **Remote Backend** — Run daemon locally against cloud AO