> For a complete index of all SignalWire documentation pages, fetch https://signalwire.com/docs/llms.txt

# Built-in Skills

> The SDK includes ready-to-use skills for common tasks like datetime, math, web search, and more.

### Available Skills

| Skill                   | Description                                        | Requirements                     |
| ----------------------- | -------------------------------------------------- | -------------------------------- |
| `datetime`              | Date/time information                              | pytz                             |
| `math`                  | Mathematical calculations                          | (none)                           |
| `web_search`            | Web search via Google API                          | API key                          |
| `wikipedia_search`      | Wikipedia lookups                                  | (none)                           |
| `weather_api`           | Weather information                                | API key                          |
| `joke`                  | Tell jokes                                         | (none)                           |
| `play_background_file`  | Play audio files                                   | (none)                           |
| `swml_transfer`         | Transfer to SWML endpoint                          | (none)                           |
| `datasphere`            | DataSphere document search                         | API credentials                  |
| `native_vector_search`  | Local vector search                                | search extras                    |
| `mcp_gateway`           | MCP server integration                             | MCP Gateway service              |
| `google_maps`           | Address validation & routing                       | Google Maps API key              |
| `info_gatherer`         | Structured question collection                     | (none)                           |
| `claude_skills`         | Load SKILL.md files as tools                       | PyYAML                           |
| `api_ninjas_trivia`     | Trivia questions from API Ninjas                   | API key                          |
| `ask_claude`            | Anthropic Claude reasoning / sub-queries           | `ANTHROPIC_API_KEY`              |
| `custom_skills`         | Register one-off SWAIG tools from config           | (none)                           |
| `datasphere_serverless` | DataSphere search via DataMap (no server callback) | API credentials                  |
| `spider`                | Web scraping & crawling                            | `cheerio` (TS) / `lxml` (Python) |

### datetime

Get current date and time information with timezone support. This is one of the most commonly used skills -- callers often ask "what time is it?" or need scheduling help.

**Functions:**

* `get_current_time` - Get current time in a timezone
* `get_current_date` - Get today's date

**Requirements:** `pytz` package (usually installed automatically)

**Parameters:**

This skill takes no configuration parameters. Timezone is specified per call via the `timezone` argument on `get_current_time`; UTC is the default when omitted.

**Output format:**

* Time: "The current time in America/New\_York is 2:30 PM"
* Date: "Today's date is November 25, 2024"

**Common use cases:**

* "What time is it?" / "What time is it in Tokyo?"
* "What's today's date?"
* Scheduling and appointment contexts
* Time zone conversions

**Limitations:**

* Requires valid timezone names (e.g., "America/New\_York", not "EST")
* Doesn't do time math or calculate durations
* Doesn't handle historical dates

| Language   | Adding datetime                          |
| ---------- | ---------------------------------------- |
| Python     | `self.add_skill("datetime")`             |
| TypeScript | `await agent.addSkillByName('datetime')` |

```python
from signalwire import AgentBase

class TimeAgent(AgentBase):
    def __init__(self):
        super().__init__(name="time-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("datetime")

        self.prompt_add_section(
            "Role",
            "You help users with date and time information."
        )
```

### math

Perform mathematical calculations safely. The skill uses a secure expression evaluator that supports common operations without executing arbitrary code.

**Functions:**

* `calculate` - Evaluate mathematical expressions

**Requirements:** None

**Parameters:**

This skill takes no configuration parameters. The registered tool is always named `calculate`.

**Supported operations:**

* Basic: `+`, `-`, `*`, `/`, `**` (power), `%` (modulo)
* Functions: `sqrt`, `sin`, `cos`, `tan`, `log`, `abs`, `round`
* Constants: `pi`, `e`
* Parentheses for grouping

**Common use cases:**

* "What's 15 percent of 230?"
* "Calculate 45 times 67"
* "What's the square root of 256?"
* Price calculations, tip calculations

**Limitations:**

* Limited to supported functions (no arbitrary Python)
* Large numbers may lose precision
* Can't solve equations or do symbolic math

```python
from signalwire import AgentBase

class CalculatorAgent(AgentBase):
    def __init__(self):
        super().__init__(name="calculator")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("math")

        self.prompt_add_section(
            "Role",
            "You are a calculator that helps with math."
        )
```

### web\_search

Search the web using Google Custom Search API. Results are filtered for quality and summarized for voice delivery.

**Functions:**

* `web_search` - Search the web and return summarized results

**Requirements:**

* Google Custom Search API key (from Google Cloud Console)
* Search Engine ID (from Programmable Search Engine)

**Setup:**

1. Create a project in Google Cloud Console
2. Enable the Custom Search JSON API
3. Create an API key
4. Create a Programmable Search Engine at [https://programmablesearchengine.google.com/](https://programmablesearchengine.google.com/)
5. Get the Search Engine ID

**Parameters:**

| Parameter            | Type    | Description                                                | Default       |
| -------------------- | ------- | ---------------------------------------------------------- | ------------- |
| `api_key`            | string  | Google API key (falls back to `GOOGLE_SEARCH_API_KEY`)     | Required      |
| `search_engine_id`   | string  | Search engine ID (falls back to `GOOGLE_SEARCH_ENGINE_ID`) | Required      |
| `tool_name`          | string  | Custom function name (set per instance)                    | "web\_search" |
| `num_results`        | integer | Results to return                                          | 3             |
| `delay`              | number  | Seconds between requests                                   | 0.5           |
| `max_content_length` | integer | Max characters of scraped page content                     | 32768         |
| `oversample_factor`  | number  | Fetch extra results then re-rank                           | 2.5           |
| `min_quality_score`  | number  | Quality threshold (0-1)                                    | 0.3           |
| `no_results_message` | string  | Message returned when nothing matches                      | default       |
| `safe_search`        | string  | `"off"`, `"medium"`, or `"high"`                           | "medium"      |

**Multi-instance support:** Yes - add multiple instances with unique `tool_name` values (e.g. `search_news`, `search_docs`).

```python
from signalwire import AgentBase

class SearchAgent(AgentBase):
    def __init__(self):
        super().__init__(name="search-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("web_search", {
            "api_key": "YOUR_GOOGLE_API_KEY",
            "search_engine_id": "YOUR_SEARCH_ENGINE_ID",
            "num_results": 3
        })

        self.prompt_add_section(
            "Role",
            "You search the web to answer questions."
        )
```

### wikipedia\_search

Search Wikipedia for information. A free, no-API-key alternative to web search for factual queries.

**Functions:**

* `search_wikipedia` - Search and retrieve Wikipedia article summaries

**Requirements:** None (uses public Wikipedia API)

**Parameters:**

| Parameter            | Type    | Description                           | Default          |
| -------------------- | ------- | ------------------------------------- | ---------------- |
| `num_results`        | integer | Max articles returned (1-5)           | 1                |
| `no_results_message` | string  | Message returned when nothing matches | default template |

```python
from signalwire import AgentBase

class WikiAgent(AgentBase):
    def __init__(self):
        super().__init__(name="wiki-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("wikipedia_search", {
            "num_results": 3  # Return up to three articles
        })

        self.prompt_add_section(
            "Role",
            "You look up information on Wikipedia to answer factual questions."
        )
```

### weather\_api

Get current weather information for locations worldwide. Commonly used for small talk, travel planning, and location-aware services.

**Functions:**

* `get_weather` - Get current weather conditions for a location

**Requirements:** WeatherAPI.com API key (free tier available)

**Setup:**

1. Sign up at [https://www.weatherapi.com/](https://www.weatherapi.com/)
2. Get your API key from the dashboard
3. Free tier allows 1 million calls/month

**Parameters:**

| Parameter   | Type   | Description                                                            | Default        |
| ----------- | ------ | ---------------------------------------------------------------------- | -------------- |
| `api_key`   | string | WeatherAPI.com API key (falls back to `WEATHER_API_KEY`)               | Required       |
| `tool_name` | string | Custom function name                                                   | "get\_weather" |
| `units`     | string | `"metric"`, `"imperial"`, `"standard"`, `"celsius"`, or `"fahrenheit"` | "fahrenheit"   |

```python
from signalwire import AgentBase

class WeatherAgent(AgentBase):
    def __init__(self):
        super().__init__(name="weather-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("weather_api", {
            "api_key": "YOUR_WEATHER_API_KEY"
        })

        self.prompt_add_section(
            "Role",
            "You provide weather information for any location."
        )
```

### joke

Tell jokes to lighten the mood or entertain callers. Uses a curated joke database for clean, family-friendly humor.

**Functions:**

* `tell_joke` - Get a random joke

**Requirements:** None

**Parameters:**

| Parameter   | Type   | Description          | Default      |
| ----------- | ------ | -------------------- | ------------ |
| `tool_name` | string | Custom function name | "tell\_joke" |

```python
from signalwire import AgentBase

class FunAgent(AgentBase):
    def __init__(self):
        super().__init__(name="fun-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("joke")

        self.prompt_add_section(
            "Role",
            "You are a fun assistant that tells jokes when asked."
        )
```

### play\_background\_file

Play audio files in the background during calls. Audio plays while conversation continues, useful for hold music, ambient sound, or audio cues.

**Functions:**

* `play_background_file` - Start playing audio file
* `stop_background_file` - Stop currently playing audio

**Requirements:** None (audio file must be accessible via URL)

**Parameters:**

This skill supports two configuration styles:

* **Catalog mode** — preload named files via `files`, caller selects by `key`:

| Parameter   | Type   | Description                                        | Default                  |
| ----------- | ------ | -------------------------------------------------- | ------------------------ |
| `tool_name` | string | Custom play function name                          | "play\_background\_file" |
| `files`     | array  | List of `{ key, description, url, wait? }` entries | Required                 |

* **Free-form mode** — caller supplies a URL at call time (gated by `allowed_domains`):

| Parameter          | Type   | Description                                  | Default  |
| ------------------ | ------ | -------------------------------------------- | -------- |
| `default_file_url` | string | URL played when no argument is provided      | Required |
| `allowed_domains`  | array  | Whitelisted domains for caller-supplied URLs | Required |

**Supported formats:** MP3, WAV, OGG

```python
from signalwire import AgentBase

class MusicAgent(AgentBase):
    def __init__(self):
        super().__init__(name="music-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("play_background_file", {
            "files": [
                {
                    "key": "hold_music",
                    "description": "Looping hold music",
                    "url": "https://example.com/hold-music.mp3",
                }
            ]
        })
```

### swml\_transfer

Transfer calls to another SWML endpoint.

**Functions:**

* `transfer_call` (default name) - Transfer based on matched pattern

**Requirements:** None

**Parameters:**

| Parameter               | Type    | Description                                                                                  | Default                       |
| ----------------------- | ------- | -------------------------------------------------------------------------------------------- | ----------------------------- |
| `transfers`             | object  | Pattern → `{ url \| address, message?, return_message?, post_process?, final?, from_addr? }` | Required (or use `patterns`)  |
| `patterns`              | array   | Alternative shape: list of pattern entries                                                   | Required (or use `transfers`) |
| `allow_arbitrary`       | boolean | Accept caller-supplied URL instead of matching a pattern                                     | false                         |
| `tool_name`             | string  | Custom function name                                                                         | "transfer\_call"              |
| `description`           | string  | Tool description                                                                             | default                       |
| `parameter_name`        | string  | Argument name the LLM supplies                                                               | "transfer\_type"              |
| `parameter_description` | string  | Argument description                                                                         | default                       |
| `default_message`       | string  | Message when no pattern matches                                                              | default                       |
| `default_post_process`  | boolean | Default for transferred calls returning to the agent                                         | false                         |
| `required_fields`       | object  | Extra per-pattern required fields                                                            | `{}`                          |

```python
from signalwire import AgentBase

class TransferAgent(AgentBase):
    def __init__(self):
        super().__init__(name="transfer-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("swml_transfer", {
            "transfers": {
                "specialist": {
                    "url": "https://your-server.com/other-agent",
                    "message": "Transferring you to a specialist."
                }
            }
        })
```

### datasphere

Search SignalWire DataSphere documents.

**Functions:**

* `search_knowledge` (default name) - Search uploaded documents

**Requirements:** DataSphere API credentials

**Parameters:**

| Parameter            | Type    | Description                                        | Default             |
| -------------------- | ------- | -------------------------------------------------- | ------------------- |
| `space_name`         | string  | DataSphere space name                              | Required            |
| `project_id`         | string  | Project ID (falls back to `SIGNALWIRE_PROJECT_ID`) | Required            |
| `token`              | string  | API token (falls back to `SIGNALWIRE_TOKEN`)       | Required            |
| `document_id`        | string  | Document ID to search within                       | Required            |
| `tool_name`          | string  | Custom function name                               | "search\_knowledge" |
| `count`              | integer | Results to return (1-10)                           | 1                   |
| `distance`           | number  | Distance threshold (0-10)                          | 3.0                 |
| `tags`               | array   | Filter by document tags                            | —                   |
| `language`           | string  | Language filter                                    | —                   |
| `pos_to_expand`      | array   | POS tags to expand (`NOUN`, `VERB`, `ADJ`, `ADV`)  | —                   |
| `max_synonyms`       | integer | Synonym expansion limit (1-10)                     | —                   |
| `no_results_message` | string  | Message when nothing matches                       | default             |

```python
from signalwire import AgentBase

class KnowledgeAgent(AgentBase):
    def __init__(self):
        super().__init__(name="knowledge-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("datasphere", {
            "space_name": "your-space",
            "project_id": "YOUR_PROJECT_ID",
            "token": "YOUR_API_TOKEN",
            "document_id": "your-document-id"
        })
```

### native\_vector\_search

Local vector search using .swsearch index files.

**Functions:**

* Dynamic name (default `search_knowledge`) - Search a local vector index

**Requirements:** Search extras installed (`pip install "signalwire-sdk[search]"`)

**Parameters:**

| Parameter              | Type    | Description                                           | Default                            |
| ---------------------- | ------- | ----------------------------------------------------- | ---------------------------------- |
| `tool_name`            | string  | Custom function name                                  | "search\_knowledge"                |
| `index_file`           | string  | SQLite `.swsearch` path (SQLite backend)              | —                                  |
| `backend`              | string  | `"sqlite"` or `"pgvector"`                            | "sqlite"                           |
| `connection_string`    | string  | PostgreSQL URL (pgvector backend)                     | —                                  |
| `collection_name`      | string  | Table/collection name (pgvector backend)              | —                                  |
| `build_index`          | boolean | Rebuild index on startup                              | false                              |
| `source_dir`           | string  | Source directory when building                        | —                                  |
| `remote_url`           | string  | Remote search-server URL (alternative to local index) | —                                  |
| `index_name`           | string  | Named index on remote server                          | "default"                          |
| `count`                | integer | Results to return (1-20)                              | 5                                  |
| `similarity_threshold` | number  | Minimum score (0.0-1.0)                               | 0.0                                |
| `tags`                 | array   | Filter results by tag                                 | `[]`                               |
| `global_tags`          | array   | Always-applied tag filter                             | `[]`                               |
| `file_types`           | array   | File extensions to index                              | `["md","txt","pdf","docx","html"]` |
| `exclude_patterns`     | array   | Glob patterns to skip                                 | defaults                           |
| `no_results_message`   | string  | Message when nothing matches                          | default template                   |
| `response_prefix`      | string  | Prepended to result text                              | —                                  |
| `response_postfix`     | string  | Appended to result text                               | —                                  |
| `max_content_length`   | integer | Max result chars                                      | 32768                              |
| `description`          | string  | Tool description override                             | —                                  |

```python
from signalwire import AgentBase

class LocalSearchAgent(AgentBase):
    def __init__(self):
        super().__init__(name="local-search")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("native_vector_search", {
            "index_file": "/path/to/knowledge.swsearch",
            "tool_name": "search_docs"
        })
```

### mcp\_gateway

Connect to MCP (Model Context Protocol) servers via the MCP Gateway service. This skill dynamically creates SWAIG functions from MCP tools, enabling your agent to use any MCP-compatible tool.

**Functions:** Dynamically created based on connected MCP services

**Requirements:**

* MCP Gateway service running
* Gateway URL and authentication credentials

**Parameters:**

| Parameter         | Type    | Description                     | Default  |
| ----------------- | ------- | ------------------------------- | -------- |
| `gateway_url`     | string  | MCP Gateway service URL         | Required |
| `auth_user`       | string  | Basic auth username             | None     |
| `auth_password`   | string  | Basic auth password             | None     |
| `auth_token`      | string  | Bearer token (alternative auth) | None     |
| `services`        | array   | Services and tools to enable    | All      |
| `session_timeout` | integer | Session timeout (seconds)       | 300      |
| `tool_prefix`     | string  | Prefix for function names       | "mcp\_"  |
| `retry_attempts`  | integer | Connection retries              | 3        |
| `request_timeout` | integer | Request timeout (seconds)       | 30       |
| `verify_ssl`      | boolean | Verify SSL certificates         | true     |

**How it works:**

1. Skill connects to gateway and discovers available tools
2. Each MCP tool becomes a SWAIG function (e.g., `mcp_todo_add_todo`)
3. Sessions persist per call\_id, enabling stateful tools
4. Session automatically closes when call ends

```python
from signalwire import AgentBase

class MCPAgent(AgentBase):
    def __init__(self):
        super().__init__(name="mcp-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("mcp_gateway", {
            "gateway_url": "http://localhost:8080",
            "auth_user": "admin",
            "auth_password": "secure-password",
            "services": [
                {"name": "todo", "tools": "*"},
                {"name": "calculator", "tools": ["add", "multiply"]}
            ]
        })

        self.prompt_add_section(
            "Role",
            "You help users manage tasks and perform calculations."
        )
```

### google\_maps

Validate addresses and compute driving routes using Google Maps. Supports geocoding, spoken number normalization (e.g., "seven one four" becomes "714"), and location-biased search.

**Functions:**

* `lookup_address` - Validate and geocode a street address or business name
* `compute_route` - Compute driving distance and estimated travel time between two points

**Requirements:** Google Maps API key with Geocoding and Routes APIs enabled

**Parameters:**

| Parameter                   | Type   | Description                                               | Default                      |
| --------------------------- | ------ | --------------------------------------------------------- | ---------------------------- |
| `api_key`                   | string | Google Maps API key (falls back to `GOOGLE_MAPS_API_KEY`) | Required                     |
| `lookup_tool_name`          | string | Address lookup function name                              | "lookup\_address"            |
| `route_tool_name`           | string | Route computation function name                           | "compute\_route"             |
| `geocode_tool_name`         | string | Reverse-geocoding function name                           | "geocode\_address"           |
| `route_by_coords_tool_name` | string | Coord-based route function name                           | "compute\_route\_by\_coords" |
| `default_mode`              | string | `"driving"`, `"walking"`, `"bicycling"`, or `"transit"`   | "driving"                    |

```python
from signalwire import AgentBase

class DeliveryAgent(AgentBase):
    def __init__(self):
        super().__init__(name="delivery-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("google_maps", {
            "api_key": "YOUR_GOOGLE_MAPS_API_KEY"
        })

        self.prompt_add_section(
            "Role",
            "You help customers verify delivery addresses and estimate delivery times."
        )
```

### info\_gatherer

Gather answers to a configurable list of questions. This is the skill version of the InfoGathererAgent prefab, designed to be embedded within larger agents.

**Functions:**

* `start_questions` - Begin the question sequence
* `submit_answer` - Submit an answer and get the next question

**Requirements:** None

**Parameters:**

| Parameter            | Type   | Description                                                                          | Default          |
| -------------------- | ------ | ------------------------------------------------------------------------------------ | ---------------- |
| `questions`          | list   | List of question dictionaries (`key_name`, `question_text`, `confirm`, `prompt_add`) | Required         |
| `prefix`             | string | Prefix for tool names and namespace (enables multi-instance)                         | None             |
| `completion_message` | string | Message read after the last question                                                 | default template |

**Multi-instance support:** Yes - use the `prefix` parameter to run multiple question sets on a single agent. With `prefix="intake"`, tools become `intake_start_questions` and `intake_submit_answer`, and state is stored under `skill:intake` in global\_data.

```python
from signalwire import AgentBase

class MultiFormAgent(AgentBase):
    def __init__(self):
        super().__init__(name="multi-form")
        self.add_language("English", "en-US", "rime.spore")

        # First question set
        self.add_skill("info_gatherer", {
            "prefix": "contact",
            "questions": [
                {"key_name": "name", "question_text": "What is your name?"},
                {"key_name": "email", "question_text": "What is your email?", "confirm": True}
            ]
        })

        # Second question set
        self.add_skill("info_gatherer", {
            "prefix": "feedback",
            "questions": [
                {"key_name": "rating", "question_text": "How would you rate our service?"},
                {"key_name": "comments", "question_text": "Any additional comments?"}
            ]
        })
```

### claude\_skills

Load Claude Code-style SKILL.md files as agent tools. Each SKILL.md file in the configured directory becomes a SWAIG function, with YAML frontmatter parsed for metadata (name, description, parameters).

**Functions:** Dynamically created from SKILL.md files (prefixed with `claude_` by default)

**Requirements:** PyYAML package

**Parameters:**

| Parameter                   | Type    | Description                                  | Default          |
| --------------------------- | ------- | -------------------------------------------- | ---------------- |
| `skills_path`               | string  | Path to directory containing SKILL.md files  | Required         |
| `include`                   | array   | Glob patterns of SKILL.md files to load      | `["*"]`          |
| `exclude`                   | array   | Glob patterns to skip                        | `[]`             |
| `tool_prefix`               | string  | Prefix for generated function names          | "claude\_"       |
| `prompt_title`              | string  | Section title added to agent prompt          | "Claude Skills"  |
| `prompt_intro`              | string  | Prose introducing the loaded skills          | default template |
| `skill_descriptions`        | object  | Override descriptions, keyed by skill name   | `{}`             |
| `response_prefix`           | string  | Prepended to each skill response             | —                |
| `response_postfix`          | string  | Appended to each skill response              | —                |
| `allow_shell_injection`     | boolean | Permit shell metacharacters in arguments     | false            |
| `allow_script_execution`    | boolean | Permit running scripts referenced by a skill | false            |
| `ignore_invocation_control` | boolean | Bypass per-skill invocation gating           | false            |
| `shell_timeout`             | integer | Shell command timeout (seconds)              | 30               |

```python
from signalwire import AgentBase

class ClaudeSkillsAgent(AgentBase):
    def __init__(self):
        super().__init__(name="claude-skills-agent")
        self.add_language("English", "en-US", "rime.spore")

        self.add_skill("claude_skills", {
            "skills_path": "/path/to/skills/directory",
            "tool_prefix": "skill_"
        })
```

### Skills Summary Table

| Skill                   | Functions | API Required | Multi-Instance |
| ----------------------- | --------- | ------------ | -------------- |
| `datetime`              | 2         | No           | No             |
| `math`                  | 1         | No           | No             |
| `web_search`            | 1         | Yes          | Yes            |
| `wikipedia_search`      | 1         | No           | No             |
| `weather_api`           | 1         | Yes          | No             |
| `joke`                  | 1         | No           | No             |
| `play_background_file`  | 2         | No           | No             |
| `swml_transfer`         | 1         | No           | Yes            |
| `datasphere`            | 1         | Yes          | Yes            |
| `native_vector_search`  | 1         | No           | Yes            |
| `mcp_gateway`           | Dynamic   | No\*         | Yes            |
| `google_maps`           | 2         | Yes          | No             |
| `info_gatherer`         | 2         | No           | Yes            |
| `claude_skills`         | Dynamic   | No           | Yes            |
| `api_ninjas_trivia`     | 1         | Yes          | Yes            |
| `ask_claude`            | 1         | Yes          | No             |
| `custom_skills`         | Dynamic   | No           | No             |
| `datasphere_serverless` | 1         | Yes          | Yes            |
| `spider`                | 1         | No           | Yes            |

\* Requires MCP Gateway service, not external API