> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.getdial.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server.

# Hermes Agent

> Use Dial from a Hermes agent — install the Dial skill and route inbound events into Hermes.

Dial integrates with Hermes in two parts:

1. **Driving Dial** so the agent can send texts, place calls, and check status. Pick one of two ways below — the **CLI skill** or Dial's native **MCP server**.
2. **Inbound event handling** so Dial events (inbound SMS, completed calls) reach Hermes without the agent having to poll.

## Install

There are two ways to let Hermes drive Dial. They do the same outbound job — pick one. The CLI skill teaches the agent to run the `dial` CLI; the MCP server exposes Dial's tools to Hermes natively.

### Option 1 — CLI skill (Recommended)

First, get the `dial` CLI on your PATH:

```bash title="Shell install"
curl -fsSL https://getdial.ai/install | bash
```

```text title="Agent prompt"
Follow https://getdial.ai/skills.md to install and onboard the dial CLI.
```

Then drop the Hermes-specific Dial skill into your config:

```bash
dial auth verify-otp --code <code> --agent hermes
```

`auth verify-otp` verifies your code first, then copies the Dial skill into Hermes's config directory. The agent loads it on demand and can drive the CLI — see the [CLI reference](/documentation/cli/commands) for the full surface.

To rerun the copy later (for example, after a CLI upgrade), run `dial auth verify-otp --agent hermes` again — the verification step is a no-op once you're signed in, and the skill file is overwritten in place.

### Option 2 — MCP server

Hermes is an MCP client, so it can talk to Dial's [MCP server](/integrations/tools/mcp) directly — no `dial` CLI shell-out. Register the server with the `hermes mcp add` command, or declare it under `mcp_servers` in `~/.hermes/config.yaml`. The local (stdio) transport runs `npx -y @getdial/cli mcp` and reuses your saved CLI key; the remote transport points Hermes at `https://getdial.ai/mcp` and authenticates via OAuth in the browser on first connection.

```bash title="hermes mcp add (local)"
hermes mcp add dial --command npx --args -y @getdial/cli mcp
```

```yaml title="~/.hermes/config.yaml (local stdio)"
# ~/.hermes/config.yaml
mcp_servers:
  dial:
    command: "npx"
    args: ["-y", "@getdial/cli", "mcp"]
    enabled: true
```

```yaml title="~/.hermes/config.yaml (remote, OAuth)"
# ~/.hermes/config.yaml
mcp_servers:
  dial:
    url: "https://getdial.ai/mcp"
    auth: oauth
    enabled: true
```

See the [MCP page](/integrations/tools/mcp) for the full tool list and the remote OAuth flow, and Hermes's own [MCP docs](https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp) for the `hermes mcp` CLI, tool filtering (`tools.include` / `tools.exclude`), and the complete `mcp_servers` schema.

## Inbound event handling

You have two ways to route Dial events into Hermes. Both rely on Dial's listen daemon — install it first:

```bash
dial listen install
```

The daemon is what owns the fan-out queue. See [Listen service](/documentation/cli/listen-service).

### Option 1 — Webhook

Use Hermes's built-in webhook platform. The daemon POSTs each Dial event to a Hermes subscription URL; Hermes verifies the HMAC signature, applies its `--prompt` template, and triggers an agent run.

#### 1. Enable and configure the Hermes webhook platform

Turn on the webhook platform in `~/.hermes/config.yaml`:

```yaml
platforms:
  webhook:
    enabled: true
    extra:
      host: "127.0.0.1"
      port: 8644
      secret: "generate-a-strong-secret-here"
```

Bind to `127.0.0.1` (not `0.0.0.0`) — Dial fans out only to local loopback hosts, and binding to all interfaces would expose Hermes's webhook port to the network.

Then create a subscription that Dial events will post to:

```bash
hermes webhook subscribe dial \
  --events "message.received,call.ended" \
  --prompt "Dial event {type} on {to}"
```

Hermes auto-generates a URL and HMAC-SHA256 secret for the subscription and persists them to `~/.hermes/webhook_subscriptions.json`. The `--prompt` template uses `{dot.notation}` to interpolate fields off the Dial event JSON — e.g. `{type}`, `{from}`, `{to}`, plus event-specific fields like `{body}` on `message.received` and `{status}` / `{duration}` on `call.ended`. See [Hermes webhook subscriptions](https://hermes-agent.nousresearch.com/docs/user-guide/skills/bundled/devops/devops-webhook-subscriptions#create-a-subscription) for the full template syntax.

#### 2. Register the subscription with Dial

Read the URL and secret straight out of the Hermes file and hand them to `dial local-target add url`:

```bash title="jq"
SUBS=~/.hermes/webhook_subscriptions.json
URL=$(jq -r '.subscriptions[] | select(.name=="dial") | .url'    "$SUBS")
SEC=$(jq -r '.subscriptions[] | select(.name=="dial") | .secret' "$SUBS")

dial local-target add url "$URL" --secret "$SEC" --signature-header "X-Hermes-Signature"
```

```bash title="One-liner"
dial local-target add url \
  "$(jq -r '.subscriptions[] | select(.name=="dial") | .url'    ~/.hermes/webhook_subscriptions.json)" \
  --secret "$(jq -r '.subscriptions[] | select(.name=="dial") | .secret' ~/.hermes/webhook_subscriptions.json)" \
  --signature-header "X-Hermes-Signature"
```

No daemon restart is required — the fan-out registry updates on the fly.

#### 3. Verify

```bash
# Send yourself an SMS to one of your Dial numbers, then check
dial listen status              # confirm the fan-out POST went out
hermes webhook test dial        # confirm Hermes accepted the last signed POST
```

To remove the wiring later, run `dial local-target remove <url>` followed by `hermes webhook remove dial`.

### Option 2 — CLI command target

Skip Hermes's webhook listener entirely and spawn a fresh Hermes agent session per Dial event using a [CLI command target](/integrations/methods/cli-command-target). The daemon runs your handler with the event JSON as the final positional argument; the handler builds a prompt and launches Hermes detached. Useful when:

* You don't want to expose Hermes's webhook port (even on loopback).
* You'd rather not maintain Hermes's per-subscription HMAC plumbing.
* A one-shot agent run per event is enough — no need for `--events` filters and prompt templates.

#### 1. Write a handler

```bash
#!/usr/bin/env bash
# /usr/local/bin/handle-dial-event-hermes
event="$1"

type=$(jq -r '.type'        <<<"$event")
from=$(jq -r '.from // ""'  <<<"$event")
body=$(jq -r '.body // ""'  <<<"$event")

prompt=$(cat <<EOF
A Dial event just arrived. Decide what to do and act on it.

  type: $type
  from: $from
  body: $body

raw event JSON:
$event
EOF
)

# Detach a fresh Hermes session and return right away.
nohup hermes -z "$prompt" </dev/null >>~/.dial/hermes.log 2>&1 &
disown
exit 0
```

`hermes -z` is Hermes's purest one-shot mode — single prompt in, final response text out on stdout, nothing else. Use `hermes chat -q "$prompt"` instead if you want tool calls in the transcript too.

#### 2. Register

```bash
chmod +x /usr/local/bin/handle-dial-event-hermes
dial local-target add cmd /usr/local/bin/handle-dial-event-hermes
```

The `nohup … & disown` pattern keeps Hermes running after the handler exits, so a multi-minute agent run never collides with the daemon's per-attempt `--timeout`. See [CLI command target](/integrations/methods/cli-command-target) for the full reference, delivery semantics, and the once-retry behavior.

## Use it

Either path works the same in use — just ask your Hermes agent in plain language:

> Send an SMS to +14155550123 with the body "running late, ETA 10 min".

The agent figures out the action and runs it. With the CLI skill it drives the `dial` CLI; with the MCP server it calls Dial's tools directly (no CLI shell-out). See [Using Dial from an agent](/documentation/get-started/using-dial-from-an-agent) for more examples.