# Bland CLI

The command-line interface for [Bland AI](https://bland.ai). Build, test, and deploy conversational AI agents from your terminal.

## Install

Run it with `npx` — no install step, always the published version:

```bash
npx -y bland-cli --help
```

This is the right way to run the CLI from an agent, a CI job, or any sandbox
whose policy blocks or auto-reviews global installs: `npx -y` needs no write
access outside the npm cache, and `-y` skips the "Ok to proceed?" prompt that
would otherwise hang a non-interactive session.

Prefer a permanent `bland` on your PATH? Install it globally:

```bash
npm install -g bland-cli
```

Every command below works either way — `bland <cmd>` or `npx -y bland-cli <cmd>`.

Requires Node.js 18+.

## Quick Start

### 1. Authenticate

No API key yet? Authenticate with a device code — no dashboard trip, no localhost, works from a headless box:

```bash
bland auth login --device
# same thing, shorter: bland signup
```

The CLI prints a link and a short code. Open the link (it also tries to open your browser automatically), approve it, and the CLI saves your org's API key for you.

Already have a key?

```bash
bland auth login --key YOUR_API_KEY
```

Or set the environment variable:

```bash
export BLAND_API_KEY=your_key_here
```

### 2. Check your account

```bash
bland auth whoami
```

### 3. Make a call

```bash
bland call send +15551234567 --task "Ask if they're interested in a demo" --voice nat --wait
```

### 4. Build a pathway

```bash
# Scaffold a new project
bland pathway init ./my-pathway --name "Customer Support"

# Edit the YAML file in your editor
# Then push it to Bland
bland pathway push ./my-pathway

# Test it interactively
bland pathway chat <pathway_id> --verbose
```

## Dev Terminal

An interactive AI-powered development REPL for building phone agents. Powered by Claude — streams responses, executes tools, edits pathways, and pushes to production without leaving your terminal. Launches into a dedicated dark terminal environment.

```bash
bland dev                      # Launch the dev terminal
  -m, --model <model>          #   Claude model (default: claude-opus-4-6)
  -t, --max-tokens <n>         #   Max output tokens per response
  -k, --key <key>              #   Claude API key
  --no-banner                  #   Skip ASCII banner
```

### Slash Commands

| Command | Description |
|---------|-------------|
| `/help` | Show available commands |
| `/status` | Show session status |
| `/model` | List models or switch (`/model claude-sonnet-4-6`) |
| `/tokens` | View or set max output tokens (`/tokens 64000` or `/tokens max`) |
| `/key` | Update Claude API key |
| `/clear` | Clear conversation history |
| `/exit` | Exit |

### Available Models

| Model | Max Output | Context |
|-------|-----------|---------|
| `claude-opus-4-6` | 128k | 1M |
| `claude-sonnet-4-6` | 64k | 1M |
| `claude-haiku-4-5-20251001` | 64k | 200k |
| `claude-opus-4-20250514` | 32k | 200k |
| `claude-sonnet-4-20250514` | 64k | 200k |

The dev terminal has access to all MCP tools plus local pathway operations (read, write, diff, push, pull). Type `/` then Tab to autocomplete commands, or just type naturally.

## Commands

### Authentication

```bash
bland auth login               # Log in with API key (interactive prompt)
bland auth login --key sk-...  # Log in non-interactively
bland auth login --device      # Log in via device code — no API key needed
  --client-name <name>          #   Label shown to the approver (e.g. your bot's name)
  --profile <name>              #   Profile to save under (default: "default")
  --base-url <url>              #   Custom API base URL
  --no-open                     #   Don't try to auto-open the verification link
  --json                        #   Output result as JSON (never includes the API key)
bland signup                   # Alias for `bland auth login --device`
bland auth logout              # Clear credentials
bland auth whoami              # Show account info and balance
bland auth switch              # Switch between profiles
bland auth profiles            # List all saved profiles
```

The CLI stores profiles in `~/.config/bland-cli/config.json`. You can have multiple profiles for different orgs or environments.

On a headless box (no browser, no TTY on stdin), running `bland auth login` with no `--key` automatically falls back to the device flow, since there's nowhere to type a key interactively. Print the verification link and code for whoever owns the bot to approve — the CLI polls until they do, then saves the API key locally. It's never printed, including with `--json`.

### Calls

```bash
bland call send <number>       # Make an outbound call
  --task <prompt>               #   What the AI should do
  --pathway <id>                #   Use a pathway instead of a task
  --voice <voice>               #   Voice selection (nat, josh, etc.)
  --from <number>               #   Caller ID
  --first-sentence <text>       #   Opening line
  --model <base|turbo>          #   Model selection
  --max-duration <mins>         #   Max call length
  --wait                        #   Wait and stream live transcript
  --record                      #   Enable recording
  --transfer <number>           #   Transfer number
  --request-data <json>         #   Variables to inject
  --webhook <url>               #   Post-call webhook

bland call list                # List recent calls
  --limit <n>                   #   Max results (default 20)
  --status <s>                  #   Filter: completed, active, failed
  --from <date>                 #   Start date
  --to <date>                   #   End date
  --inbound                     #   Only inbound calls
  --batch <id>                  #   Filter by batch

bland call get <call_id>       # Full call details + transcript
bland call stop <call_id>      # End an active call
bland call events <call_id>    # View call events
bland call recording <call_id> # Get recording URL
  --download                    #   Save to local file
bland call analyze <call_id>   # Run post-call analysis
```

### Pathways

The pathway workflow lets you define conversational flows as YAML files and sync them with the Bland API.

#### YAML Format

```yaml
name: "Customer Support"
description: "Handles inbound support calls"
version: draft

global:
  voice: nat
  model: base

nodes:
  greeting:
    type: default
    prompt: |
      Greet the customer warmly. Ask how you can help them today.
    tag: { name: "intake", color: "#60A5FA" }     # visual grouping in dashboard
    dialogue_examples:                             # few-shot prompt examples
      - user: "yo"
        agent: "Hey, thanks for calling. What's up?"
      - user: "Hi I have a problem"
        agent: "Sorry to hear that. What's going on?"
    edges:
      - target: identify_issue
        label: "Customer describes their problem"
      - target: transfer_human
        label: "Customer asks for a human"

  identify_issue:
    type: default
    prompt: |
      Listen to the customer's issue and categorize it.
    tag: { name: "triage", color: "#F59E0B" }
    extract_variables:
      - name: issue_type
        type: string
        description: "billing, technical, or general"
    extract_var_settings:
      ignore_previous: false                       # consider full history
      use_audio: false
    pathway_examples:                              # few-shots for routing
      - user: "I was overcharged"
        target: billing_help
      - user: "My internet is down"
        target: tech_help
    edges:
      - target: billing_help
        label: "Issue is about billing"
      - target: tech_help
        label: "Issue is technical"

  billing_help:
    type: default
    prompt: "Help with billing questions."
    edges:
      - target: goodbye

  tech_help:
    type: default
    prompt: "Help with technical issues."
    edges:
      - target: goodbye

  transfer_human:
    type: transfer
    number: "+15551234567"

  goodbye:
    type: end_call
    prompt: "Thank the customer and end the call."
```

#### Pathway Commands

```bash
# Project setup
bland pathway init [dir]       # Scaffold a new pathway project
  --name <name>                 #   Pathway name

# Sync with Bland
bland pathway pull <id> [dir]  # Download pathway as YAML
bland pathway push [dir]       # Upload YAML to Bland
  --create                      #   Create new if no ID linked
bland pathway diff [dir]       # Compare local vs remote
bland pathway validate [dir]   # Validate YAML locally
bland pathway watch [dir]      # Auto-push on file changes

# CRUD
bland pathway list             # List all pathways
bland pathway get <id>         # Show pathway details
bland pathway create [name]    # Create a new pathway
  --from-file <path>            #   Create from YAML file
bland pathway delete <id>      # Delete a pathway
bland pathway duplicate <id>   # Duplicate a pathway

# Interactive testing
bland pathway chat <id>        # Chat with a pathway in your terminal
  --start-node <name>           #   Start at a specific node
  --variables <json>            #   Inject variables (or @file.json)
  --verbose                     #   Show node transitions and variables

# Scripted chat (Claude Code / CI — non-interactive)
bland pathway chat <id> \
  --message "I need to book a checkup" \
  --json                       # one-shot, prints structured response, exits

bland pathway chat <id> \
  --script ./turns.txt \
  --json                       # multi-turn from file, prints transcript with current_node per turn

bland pathway chat <id> \
  --chat-id <existing>         #   resume an existing chat session
  --message "and another thing"

# Automated testing
bland pathway test <id>        # Run YAML test cases
  --file <test.yaml>            #   Test case file
  --parallel <n>                #   Concurrent test runs
bland pathway simulate <id>    # Run AI simulation
  --scenario <text>             #   Scenario description
  --count <n>                   #   Number of simulations

# Node-level testing
bland pathway node test <pid> <nid>  # Test a single node
  --permutations <n>                  #   Number of variations

# Versioning
bland pathway versions <id>    # List versions
bland pathway promote <id>     # Promote draft to production

# Code nodes
bland pathway code test <pid> <nid>  # Test a custom code node
  --input <json>                      #   Test input data

# AI generation
bland pathway generate         # Generate pathway from description
  --description <text>

# Editing
bland pathway edit <id>        # Edit a node prompt in $EDITOR

# Folders
bland pathway folder list
bland pathway folder create <name>
```

#### Test Cases Format

```yaml
pathway: "Customer Support"
tests:
  - name: billing_inquiry
    scenario: "Customer calls about a wrong charge on their bill."
    expected_path: [greeting, identify_issue, billing_help, goodbye]
    expected_variables:
      issue_type: "billing"

  - name: transfer_request
    scenario: "Customer immediately asks to speak to a human."
    expected_path: [greeting, transfer_human]
```

### Personas

```bash
bland persona list             # List all personas
bland persona get <id>         # Show persona details
bland persona create           # Create interactively
bland persona update <id>      # Update persona
bland persona delete <id>      # Delete persona
bland persona promote <id>     # Promote draft to production
bland persona reset-draft <id> # Reset draft to production
bland persona gaps <id>        # View knowledge gaps
```

### Phone Numbers

```bash
bland number list              # List owned numbers
bland number buy               # Purchase a new number
  --area-code <code>            #   Preferred area code
  --country <code>              #   Country code (default: US)
  --count <n>                   #   Buy multiple
bland number release <number>  # Release a number
bland number update <number>   # Update number config
  --pathway <id>                #   Set inbound pathway
  --persona <id>                #   Set persona
  --webhook <url>               #   Set webhook
  --prompt <text>               #   Set prompt
  --voice <voice>               #   Set voice
bland number configure <number>  # Interactive configuration
```

### Voices

```bash
bland voice list               # List available voices
  --language <code>             #   Filter by language
  --custom                      #   Show only custom voices
bland voice speak <text>       # Generate TTS audio
  --voice <voice>               #   Voice to use (default: nat)
  -o, --output <file>           #   Save to file
```

### Tools

```bash
bland tool list                # List all tools
bland tool get <id>            # Show tool details
bland tool create              # Create interactively
bland tool update <id>         # Update tool
bland tool delete <id>         # Delete tool
bland tool test <id>           # Test with sample input
  --input <json>                #   Test input data
  --verbose                     #   Show full request/response
bland tool types               # List tool types
```

### Knowledge Bases

```bash
bland knowledge list           # List knowledge bases (alias: bland kb list)
bland knowledge create <name>  # Create knowledge base
bland knowledge scrape <name>  # Scrape URLs into KB
  --urls <url1,url2>            #   Comma-separated URLs
  --file <urls.txt>             #   File with URLs (one per line)
bland knowledge delete <id>    # Delete knowledge base
bland knowledge status <id>    # Check processing status
```

### Testing: Scenarios & Agent-to-Agent

**`bland scenario`** — reusable, assertable regression tests for pathways/personas. New in 0.3.0.

```bash
# Seed from built-in templates (Angry Caller, Happy Path, etc.)
bland scenario templates                                         # list templates
bland scenario clone <template_id> --pathway-id <pathway_id>     # clone onto your pathway

# Create from scratch
bland scenario create --name 'Interruption recovery' \
  --pathway-id <id> \
  --tester-prompt 'You are a caller who interrupts mid-sentence...' \
  --assertions '[{"type":"LLM_JUDGE","config":{"prompt":"Did the agent recover gracefully?"}}]'

# Turn a real call into a regression test
bland scenario generate --call-id <call_id> --pathway-id <id>

# Run
bland scenario run <scenario_id>                                 # one scenario
bland scenario batch-run --scenario-ids '["id1","id2"]'          # many in parallel (CI)
bland scenario flake --scenario-ids '[...]' --iterations 10      # flakiness detection

# Debug a failure
bland scenario run-get <run_id>                                  # transcript + assertions
bland scenario analyze <run_id>                                  # AI root-cause + fix suggestions

# Analytics
bland scenario analytics <pathway_id>                            # basic: pass rate
bland scenario analytics <pathway_id> --enhanced                 # node failure heatmap, weakest link

# Tornado — iterative auto-fix (modifies your pathway!)
bland scenario tornado start --pathway-id <id> --scenario-ids '[failing...]'
bland scenario tornado status <tornado_id>
bland scenario tornado cancel <tornado_id>
```

**`bland simulate`** — ad-hoc agent-to-agent: spin up 1–5 AI caller profiles in parallel.

```bash
bland simulate --pathway-id <id> \
  --profile 'Rushed Exec::book an appt ASAP' \
  --profile 'Confused Elder::ask the same question 3 times'
# Returns simulation_id + per-profile call_ids — inspect via `bland call get <call_id>`
```

Run `bland guide get testing` or `bland guide get scenarios` for the full testing decision tree.

### Batch Campaigns

```bash
bland batch create             # Create batch campaign
  --file <contacts.csv>         #   Contacts CSV file
  --pathway <id>                #   Pathway to use
  --from <number>               #   From number
bland batch list               # List batches
bland batch get <id>           # Batch details + stats
bland batch stop <id>          # Stop a running batch
```

### SMS

```bash
bland sms send <number>        # Send SMS
  --from <number>               #   From number
  --message <text>              #   Message text
  --pathway <id>                #   Use pathway for conversation
bland sms conversations        # List SMS conversations
bland sms get <id>             # Get conversation thread
```

### Other Commands

```bash
# Web agents
bland agent list | get | create | update | delete

# Guard rails
bland guard list | create | delete

# Monitoring
bland alarm list | create | delete

# Secrets
bland secret list | set | delete

# Releases
bland release list | create | promote

# Widgets
bland widget list | create | delete

# Evaluations
bland eval run | list | get

# Audio
bland audio generate <text> --voice <voice> -o <file>
bland audio analyze <file>

# SIP
bland sip discover <host>

# Local development
bland listen                   # Forward webhooks to localhost
  --forward-to <url>           #   Your local server URL
  --port <n>                   #   Listen port (default: 4242)
  --events <types>             #   Filter event types
```

## Profiles

The CLI supports multiple profiles for managing different API keys or organizations.

```bash
# Add a second profile
bland auth login --key sk-staging-xxx

# Switch between profiles
bland auth switch

# List profiles
bland auth profiles
```

Profiles are stored at `~/.config/bland-cli/config.json`. You can also override the API key per-command with `BLAND_API_KEY`:

```bash
BLAND_API_KEY=sk-staging-xxx bland pathway list
```

## Pathway Workflow

The typical development cycle for pathways:

```
1. bland pathway init ./my-bot       # Scaffold project
2. Edit bland-pathway.yaml            # Write your flow
3. bland pathway validate             # Check for errors
4. bland pathway push --create        # Upload to Bland
5. bland pathway chat <id> --verbose  # Test interactively
6. bland pathway test <id>            # Run automated tests
7. bland pathway promote <id>         # Ship to production
8. bland pathway watch                # Auto-push on save
```

## MCP Server

The CLI includes an MCP (Model Context Protocol) server that lets AI coding tools like Claude Code and Cursor interact with your Bland account.

```bash
# Start the MCP server
bland mcp

# Or with SSE transport
bland mcp --transport sse --port 3100
```

### Claude Code Setup

Add to your Claude Code config:

```json
{
  "mcpServers": {
    "bland": {
      "command": "npx",
      "args": ["-y", "bland-cli", "mcp"]
    }
  }
}
```

`npx -y` keeps the server working without a global install — the `-y` matters,
since without it npx prompts to install and the MCP client just sees a hang.

### Available MCP Tools

82 tools across all resource types:

#### Guides
| Tool | What it does |
|------|-------------|
| `bland_guide_list` | List all available guides (start here) |
| `bland_guide_get` | Read a specific guide by slug |

#### Calls
| Tool | What it does |
|------|-------------|
| `bland_call_send` | Make a phone call |
| `bland_call_list` | List recent calls |
| `bland_call_get` | Get call details and transcript |

#### Pathways
| Tool | What it does |
|------|-------------|
| `bland_pathway_list` | List pathways |
| `bland_pathway_get` | Get pathway details |
| `bland_pathway_create` | Create a pathway from nodes/edges |
| `bland_pathway_chat` | Chat with a pathway |
| `bland_pathway_node_test` | Test a single node |
| `bland_pathway_simulate` | Persona-based simulation (resumable) |
| `bland_pathway_simulation_get` | Get simulation status |
| `bland_pathway_simulation_continue` | Continue a paused simulation |

#### Testing Scenarios (new in 0.3.0)
| Tool | What it does |
|------|-------------|
| `bland_scenario_list` / `_get` / `_create` / `_update` / `_delete` | Scenario CRUD |
| `bland_scenario_generate` | AI-generate a scenario from a historical call |
| `bland_scenario_run` / `_runs_list` / `_run_get` | Run a scenario, inspect past runs |
| `bland_scenario_run_analyze` | AI root-cause analysis of a failed run |
| `bland_scenario_batch_run` / `_batch_get` | Run many scenarios in parallel (CI-style) |
| `bland_scenario_simulation_create` / `_simulation_get` | Flakiness detection (run N× each) |
| `bland_scenario_analytics` / `_analytics_enhanced` | Pass rate, node heatmap, weakest link |
| `bland_scenario_templates_list` / `_template_clone` | Seed from built-in templates |
| `bland_scenario_tornado_*` | Iterative auto-fix loop (4 tools) |
| `bland_simulate_calls` | Ad-hoc agent-to-agent: 1–5 AI callers in parallel |

#### Personas
| Tool | What it does |
|------|-------------|
| `bland_persona_list` | List personas |
| `bland_persona_get` | Get persona details |
| `bland_persona_create` | Create a new persona |
| `bland_persona_update` | Update persona config |
| `bland_persona_delete` | Delete a persona |
| `bland_persona_versions_list` | List persona versions |
| `bland_persona_draft_get` | Get draft version |
| `bland_persona_production_get` | Get production version |
| `bland_persona_promote` | Promote draft to production |
| `bland_persona_reset_draft` | Reset draft to production |
| `bland_persona_inbound_attach` | Attach phone numbers |
| `bland_persona_inbound_detach` | Detach phone numbers |
| `bland_persona_memory_update` | Update persona memory |
| `bland_persona_gaps_list` | List knowledge gaps |
| `bland_persona_gap_resolve` | Resolve a knowledge gap |

#### Knowledge Bases
| Tool | What it does |
|------|-------------|
| `bland_knowledge_list` | List knowledge bases |
| `bland_knowledge_get` | Get KB details |
| `bland_knowledge_create_text` | Create KB from text |
| `bland_knowledge_create_web` | Create KB by scraping URLs |
| `bland_knowledge_update` | Update KB name/description |
| `bland_knowledge_delete` | Delete a KB |
| `bland_knowledge_query` | Query KB with RAG |
| `bland_knowledge_chat` | Multi-turn chat with KB |
| `bland_knowledge_crawl` | Discover sitemap URLs |
| `bland_knowledge_content_get` | Get KB content |
| `bland_knowledge_content_update` | Update KB text content |
| `bland_knowledge_versions_list` | List KB versions |
| `bland_knowledge_version_restore` | Restore a KB version |
| `bland_knowledge_replace_urls` | Replace web-scrape URLs |
| `bland_knowledge_gaps_list` | List knowledge gaps |
| `bland_knowledge_gap_resolve` | Resolve a gap |
| `bland_knowledge_analytics` | Get KB analytics |

#### Other
| Tool | What it does |
|------|-------------|
| `bland_number_list` | List phone numbers |
| `bland_number_buy` | Buy a phone number |
| `bland_voice_list` | List Bland's curated voices (the recommended set) |
| `bland_tool_test` | Test a custom tool |
| `bland_audio_generate` | Generate TTS audio |

## For LLMs

The CLI ships with a built-in guide system designed to give LLMs (Claude, Cursor, GPT, etc.) the context they need to build good pathways — not just call the API, but actually understand how phone conversations work.

### How it works

When an LLM connects via MCP, it receives:

1. **`instructions`** — a condensed overview of the Bland platform, pathway architecture, common mistakes, and recommended workflow. This loads automatically on connect.
2. **`bland_guide_list` / `bland_guide_get`** — tools to pull long-form guides on demand for deeper context.

The guides are also available to humans via the CLI:

```bash
bland guide                  # List all guides
bland guide phone-tone       # Writing natural phone prompts
bland guide pathways         # Node/edge architecture and execution model
bland guide tools            # Webhook and custom tools on nodes
bland guide testing          # Chat, simulate, node tests
bland guide variables        # Extracting and using caller data
```

### What the guides cover

| Guide | What it teaches |
|-------|----------------|
| `phone-tone` | How to write prompts that sound like a real person on the phone — not a chatbot. Covers back-channeling, brevity, empathy, and topic transitions. |
| `pathways` | How the conversation graph works: nodes, edges, global nodes, variables, the global prompt, and the execution model. |
| `tools` | Attaching webhook and custom tools to nodes for real-time data (check availability, look up orders). Covers `speech`, `behavior`, and `response_data`. |
| `testing` | The full testing workflow: `pathway chat` for interactive testing, `simulate` for end-to-end AI personas, `node-test` for stress-testing individual nodes. |
| `variables` | Extracting structured data from natural conversation with `extract_variables`, using `{{curly_braces}}` in prompts, and `spelling_precision` for names/emails. |

### Why this matters

LLMs building pathways make predictable mistakes:
- Writing edge labels as boolean conditions (`if intent == "booking"`) instead of natural language (`Caller wants to book an appointment`)
- Making prompts too verbose and chat-like instead of concise and phone-natural
- Forgetting global nodes for edge cases callers will absolutely hit
- Not setting a global prompt for tone, so every node sounds different
- Building without testing — the guides teach `pathway chat --verbose` first, real calls second

The guide system fixes this by giving the LLM opinionated, Bland-specific knowledge before it starts writing. It's the difference between an LLM that can call the API and one that actually builds good phone agents.

### Default phone tone

When you scaffold a new pathway with `bland pathway init`, the global prompt comes pre-loaded with phone-tone instructions:

```yaml
global:
  prompt: |
    Sound natural and midwestern. Everything you say is spoken aloud on a phone call.
    Play this game silently for every reply: what is the most accurate response,
    then how can I reduce it to the fewest words without sounding rude?
    Never recontextualize — no 'just to confirm', 'you said', 'got it'.
    Use 'gotcha', 'yup', 'cool'.
    Back-channel freely: 'mhmm', 'uh huh', 'right'.
    Acknowledge emotions in stride.
    Topic transitions are natural breaks — slightly more formal.
    Within a topic, keep it tight.
    After collecting one field, move immediately: 'And last?' not
    'Could you also provide your last name?'
```

This sets the baseline voice for every node. LLMs using the MCP tools will also receive this guidance through the `phone-tone` guide.

## Local Webhook Development

Forward Bland webhooks to your local dev server without ngrok:

```bash
# Terminal 1: your app
node server.js

# Terminal 2: bland webhook forwarder
bland listen --forward-to http://localhost:3000/webhook
```

The CLI creates a webhook endpoint and forwards incoming events to your local URL, logging each event with timestamps and response codes.

## JSON Output

Every list and get command supports `--json` for piping to `jq` or scripts:

```bash
# Get all pathway IDs
bland pathway list --json | jq '.[].id'

# Get a call transcript as JSON
bland call get <id> --json | jq '.transcripts'

# Count active numbers
bland number list --json | jq 'length'
```

## Environment Variables

| Variable | Purpose |
|----------|---------|
| `BLAND_API_KEY` | API key (overrides stored profile) |
| `BLAND_BASE_URL` | API base URL (default: `https://api.bland.ai`) |

## Project Files

When you run `bland pathway init`, it creates:

```
my-pathway/
  bland-pathway.yaml   # Pathway definition
  tests/
    test-cases.yaml    # Test cases
  .blandrc             # Project config (pathway ID, file paths)
```

The `.blandrc` file links your local project to a remote pathway:

```yaml
pathway_id: pw_abc123
pathway_file: bland-pathway.yaml
test_file: tests/test-cases.yaml
```

## License

MIT
