# DialValet CLI

Give an AI agent a phone (verified caller ID). This CLI is the front door: install, sign in, verify a U.S. number, add prepaid credit, and place one explicit user-requested call.

Install: `npm install --global @dialvalet/cli`  
Quickstart (≤5 min): https://dialvalet.com/docs/QUICKSTART.md  
Docs: https://dialvalet.com/docs/CLI.md  
API/MCP contract: https://dialvalet.com/docs/API.md  
Agent map: https://dialvalet.com/llms.txt

Requires Node.js 20+. U.S. numbers only. `--json` writes machine-readable JSON.
Live `wait`, `answer --follow`, and `steer --follow` commands emit newline-delimited
JSON events. Usage errors exit 2; API/network errors exit 1.

## If you are an agent

1. Always pass `--json`.
2. If the JSON includes `cli_update`, stop and run `cli_update.command`, then retry the same command. Do not keep going on an outdated CLI.
3. Pause after every SMS. Ask the account holder for the code. Never guess, intercept, or invent an OTP. The dashboard asks for 5 digits; the API accepts 4–10 digits.
3. Do not print the API key. It is saved locally. Only use `--print-key` if the user explicitly asked.
4. Place a call only after a direct instruction for that specific destination and objective. Always include `--confirm`.
5. A checkout URL is not a payment. A call ID is not proof the destination answered. Watch the live transcript with `calls wait`.
6. If `calls wait` emits `type: "input_required"`, the process exits successfully so you can decide. Answer the plain-text question with the supplied `answer_command`; `--follow` resumes watching.
7. You may correct the live agent with `calls steer`. Use `--interrupt` only when current speech must be stopped; already-heard speech cannot be retracted.
8. Caller-ID verification proves the user controls that number. It is not consent from the person being called.
9. DialValet does not inject a fixed opening disclosure. Put any identity, AI/artificial-voice, purpose, callback-number, recording, or opt-out notice required for that call in the objective or context.
10. Add `--allow-transfer` to `calls create` only when the user explicitly asked to be rung into the call if it needs them. The ring comes from +1 480-480-1077 (+14804801077). Do not add it otherwise. The live agent cannot transfer without it.
10. U.S. only. Prepaid. Not a dialer. No dedicated numbers or inbound forwarding. Private beta.

```sh
npm install --global @dialvalet/cli
dialvalet signup --phone +1XXXXXXXXXX --json
# STOP. Ask the user for the SMS code.
dialvalet auth verify --verification-id otp_... --code XXXXX --json
dialvalet status --json
# If no verified caller ID:
dialvalet identities verify --phone +1XXXXXXXXXX --json
# STOP. Ask the user for the caller-ID SMS code. This is a different code than signup.
dialvalet identities confirm --verification-id otp_... --code XXXXX --json
# If available_cents is 0:
dialvalet billing checkout --amount 5 --json
# Give the user checkout_url. After they pay:
dialvalet balance --json
# Only after an explicit user request for this call:
dialvalet calls create --to +1XXXXXXXXXX --objective "..." --confirm --json
dialvalet calls wait call_... --json
# If the watcher yields an input_required event:
dialvalet calls answer call_... guide_... --answer "Eight PM works; reserve it for two." --follow --json
# To send an unsolicited correction while the call is live:
dialvalet calls steer call_... --mode instruction --text "Correct the date to Friday." --interrupt --follow --json
```

Follow each command's `next_step` field. If `cli_update` is present, upgrade first. Reuse the same command after a network error; the CLI stores idempotency keys locally and does not save the destination or objective.

## Commands

```text
dialvalet signup --phone <US-E.164>
dialvalet auth start | auth login
dialvalet auth verify --verification-id <id> --code <digits>
dialvalet status | me | balance
dialvalet voices | voices list
dialvalet voices set <name>
dialvalet identities list
dialvalet identities verify --phone <US-E.164> [--channel sms|voice] [--label <text>]
dialvalet identities confirm --verification-id <id> --code <digits>
dialvalet billing checkout --amount <5-100> [--idempotency-key <key>]
dialvalet calls list [--limit <n>]
dialvalet calls get <call_id>
dialvalet calls wait | watch <call_id> [--timeout-seconds 90]
dialvalet calls answer <call_id> <request_id> --answer <text> [--follow]
dialvalet calls steer <call_id> [--mode instruction|context|say] --text <note> [--interrupt] [--follow]
dialvalet calls create --to <US-E.164> --objective <text> --confirm [--context <text>] [--max-duration-seconds <n>] [--voice <name>] [--allow-transfer]
dialvalet calls cancel <call_id> --confirm
dialvalet mcp config
dialvalet config show
dialvalet logout
dialvalet --version
```

`calls wait` streams the live transcript over a websocket, then keeps polling up
to 30 seconds for a structured result. When the call agent needs a consequential
decision that was not authorized by the objective, the stream emits
`input_required` and exits 0. The event contains one plain-text question and an
`answer_command` template.
`calls answer ... --follow` submits one answer idempotently and immediately resumes
the stream. Timeout without a terminal status exits 1. If a websocket is
unavailable, waiting falls back to status polling.

`calls steer` sends trusted application context into the active GPT-Live session:
`instruction` corrects behavior, `context` supplies a quiet fact, and `say` asks
the agent to speak the note. `--interrupt` clears queued Telnyx output before
sending the note. Add `--follow` to resume the transcript after the command.

`voices` lists GPT-Live voices with language and descriptions. `marin` is the product default. `voices set` saves the account default. `calls create --voice` overrides it for one call. Portuguese voices (`bossa`, `tempo`) speak Brazilian Portuguese.

## Trust and acceptable use

- Verified personal caller ID ≠ callee consent.
- No telemarketing, campaigns, bulk dialing, or call-center use.
- U.S. numbers and U.S. destinations only.
- Prepaid credit ($5–$100 checkout). No subscription, no auto-reload.
- No dedicated DialValet numbers and no inbound forwarding.
- Private beta. Do not promise recordings or international calling.

## MCP

URL: `https://mcp.dialvalet.com/mcp`. Scopes granted on a human consent screen:
`calls:read`, `calls:write`, `caller_identities:read`, `billing:read`.
`dialvalet mcp config` prints the Cursor JSON. A connected grant is not
per-call permission.

Cursor (`.cursor/mcp.json` or `~/.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "dialvalet": {
      "url": "https://mcp.dialvalet.com/mcp"
    }
  }
}
```

Claude Code and other HTTP MCP clients:

```json
{
  "mcpServers": {
    "dialvalet": {
      "type": "http",
      "url": "https://mcp.dialvalet.com/mcp"
    }
  }
}
```

```sh
claude mcp add --transport http dialvalet https://mcp.dialvalet.com/mcp
grok mcp add --transport http dialvalet https://mcp.dialvalet.com/mcp
```

## Credentials

- Saved at `~/.config/dialvalet/config.json` (mode `0600`).
- `DIALVALET_API_KEY` can supply a key from the environment.
- Custom API hosts need `--unsafe-api-base`. HTTPS is required except localhost when `DIALVALET_CLI_ALLOW_HTTP=1`.
- `logout` revokes the server key, then deletes the local key. If revocation fails, the local key is kept.
- Never put API keys, OTP codes, or payment details in logs, tickets, or prompts.

From this repository without npm: `node packages/cli/bin/dialvalet.mjs --help`.
