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

# OpenClaw

This guide shows how to integrate the AgentDuet SDK with [OpenClaw](https://docs.openclaw.ai/) so an after-hours phone agent can take a voicemail and notify Slack through OpenClaw’s message CLI.

Sample: **after-hours voicemail → OpenClaw → Slack**.

- **Business hours:** pre-answer `connect()`, then `close()` — caller rings the human line; OpenClaw is idle
- **After hours:** AI answers, takes a message, saves it locally, and notifies Slack through OpenClaw

The sample runs `openclaw message send` after Gemini calls `leave_voicemail`.

## What this integration provides

- AgentDuet answers (or pass-through connects) inbound calls
- Gemini Live runs the after-hours voicemail dialogue
- OpenClaw delivers Slack with the same CLI you already use in chat (`message send`)

## How the pieces fit

```mermaid
flowchart LR
  Caller[Caller] --> AgentDuet[AgentDuet]
  AgentDuet --> Gemini[Gemini Live]
  Gemini --> Tool[leave_voicemail]
  Tool --> OpenClaw[openclaw message send]
  OpenClaw --> Slack[Slack]
```

| Layer | Owns |
|---|---|
| **AgentDuet** | Connector, inbound calls, PCM, `connect` / `answer` / `disconnect` |
| **Gemini Live** | Speech-to-speech dialogue + tool calls |
| **OpenClaw** | Slack channel delivery (`message send`) |
| **Your app** | Business hours, prompts, voicemail store, CLI invoke |

## Prerequisites

- Python **3.12+**
- AgentDuet API key and connector UUID from [agentduet.com](https://agentduet.com)
- [Gemini API key](https://aistudio.google.com/apikey)
- OpenClaw running locally, with Slack connected (see below)

## Set up OpenClaw

Install and onboard OpenClaw from their docs:

- [Install OpenClaw](https://docs.openclaw.ai/install/)
- [Getting started](https://docs.openclaw.ai/start/getting-started)
- [Connect Slack](https://docs.openclaw.ai/channels/slack)

When that is done:

1. `openclaw` on `PATH` on the machine that runs this sample
2. Gateway running (`openclaw gateway status`)
3. Slack connected, bot invited to the notify channel
4. A working send (same shell as `python main.py`):

```bash
openclaw message send --channel slack \
  --target channel:C0123456789 \
  --message "AgentDuet OpenClaw smoke test"
```

`channel:C0123456789` is OpenClaw’s Slack target format: the prefix `channel:` plus the Slack channel ID (IDs start with `C`). In Slack, open the channel → **View channel details** → copy the ID at the bottom, or copy the channel link and take the `C…` segment. `#channel-name` also works if OpenClaw can resolve the name. See [message CLI](https://docs.openclaw.ai/cli/message).

If this command fails, fix OpenClaw before starting AgentDuet.

## Step 1: Clone the sample

```bash
git clone https://github.com/AgentDuet/agentduet-samples.git
cd agentduet-samples/integrations/openclaw/after-hours-voicemail
```

Layout:

```
after-hours-voicemail/
├── main.py            # SessionManager + Gemini + OpenClaw notify
├── requirements.txt
└── .env.example
```

## Step 2: Install dependencies

```bash
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

The sample pins [`agentduet==1.0.0`](https://pypi.org/project/agentduet/1.0.0/).

## Step 3: Configure `.env`

```bash
cp .env.example .env
```

```bash
AGENTDUET_API_KEY=your-connector-api-key
AGENTDUET_CONNECTOR_UUID=your-connector-uuid
GEMINI_API_KEY=your-gemini-api-key
OPENCLAW_SLACK_TARGET=channel:C0123456789
FORCE_AFTER_HOURS=1
```

`FORCE_AFTER_HOURS=1` makes every inbound call use the after-hours path (Riley + Slack), even if the wall clock is inside weekday 09:00–17:00 UTC. Omit it when you want real business-hours pass-through to the human line.

Optional:

```bash
# OPENCLAW_BIN=/usr/local/bin/openclaw
# OPENCLAW_DRY_RUN=1
# BUSINESS_TZ=UTC
# BUSINESS_HOURS_START=9
# BUSINESS_HOURS_END=17
# BUSINESS_DAYS=0,1,2,3,4
```

## Step 4: Run

```bash
python main.py
```

Call your AgentDuet number. Leave a short message. Confirm Slack receives an *After-hours voicemail* post delivered by OpenClaw.

| Ask / do | Expect |
|---|---|
| Call after hours (or with `FORCE_AFTER_HOURS=1`) | Riley greets; office closed |
| Leave name + reason | `leave_voicemail` → JSONL + OpenClaw Slack post |
| Say goodbye | `end_call` → disconnect |
| Call during business hours (no force flag) | `connect` → human line; agent `close`s |

## How AgentDuet and OpenClaw connect

1. Gemini Live calls the local `leave_voicemail` tool from `main.py`.
2. The handler appends `voicemails/messages.jsonl`, then runs:

   ```bash
   openclaw message send --channel slack --target "$OPENCLAW_SLACK_TARGET" --message "..."
   ```

3. Slack delivery uses OpenClaw’s configured Slack bot.

## Related

- [Sample on GitHub](https://github.com/AgentDuet/agentduet-samples/tree/main/integrations/openclaw/after-hours-voicemail)
- [Gemini Live](/integrations/gemini-live)
- [Call Commands](/concepts/call-commands)
- [OpenClaw install](https://docs.openclaw.ai/install/)
- [OpenClaw Slack](https://docs.openclaw.ai/channels/slack)
- [OpenClaw message CLI](https://docs.openclaw.ai/cli/message)