***

title: Quick Start: Your First Agent
description: Build a working voice AI agent in under 5 minutes with a single file.
slug: /guides/quickstart
max-toc-depth: 3
---------------------

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

[development-environment]: /docs/server-sdks/guides/dev-environment

[exposing-your-agent]: /docs/server-sdks/guides/exposing-agents

[architecture]: /docs/server-sdks/guides/architecture

[agentbase]: /docs/server-sdks/guides/agent-base

### The Minimal Agent

<Tabs>
  <Tab title="Python">
    `my_first_agent.py`

    ```python
    #!/usr/bin/env python3
    ## my_first_agent.py - A simple voice AI agent
    """
    My First SignalWire Agent

    A simple voice AI agent that greets callers and has conversations.
    """

    from signalwire import AgentBase

    class MyFirstAgent(AgentBase):
        def __init__(self):
            super().__init__(name="my-first-agent")

            # Set the voice
            self.add_language("English", "en-US", "rime.spore")

            # Define the AI's personality and behavior
            self.prompt_add_section(
                "Role",
                "You are a friendly and helpful assistant. Greet the caller warmly "
                "and help them with any questions they have. Keep responses concise "
                "and conversational."
            )

            self.prompt_add_section(
                "Guidelines",
                body="Follow these rules:",
                bullets=[
                    "Be friendly and professional",
                    "Keep responses brief (1-2 sentences when possible)",
                    "If you don't know something, say so honestly",
                    "End conversations politely when the caller is done"
                ]
            )

    if __name__ == "__main__":
        agent = MyFirstAgent()
        print("Starting My First Agent...")
        print("Server running at: http://localhost:3000")
        print("Press Ctrl+C to stop")
        agent.run()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    #!/usr/bin/env npx tsx
    // my_first_agent.ts - A simple voice AI agent
    import { AgentBase } from 'signalwire-agents';

    const agent = new AgentBase({ name: 'my-first-agent' });

    agent.addLanguage({ name: 'English', code: 'en-US', voice: 'rime.spore' });

    agent.promptAddSection('Role', {
      body: 'You are a friendly and helpful assistant. Greet the caller warmly '
        + 'and help them with any questions they have. Keep responses concise '
        + 'and conversational.',
    });

    agent.promptAddSection('Guidelines', {
      body: 'Follow these rules:',
      bullets: [
        'Be friendly and professional',
        'Keep responses brief (1-2 sentences when possible)',
        'If you don\'t know something, say so honestly',
        'End conversations politely when the caller is done',
      ],
    });

    console.log('Starting My First Agent...');
    console.log('Server running at: http://localhost:3000');
    agent.run();
    ```
  </Tab>
</Tabs>

### Run the Agent

| Language   | Command                     |
| ---------- | --------------------------- |
| Python     | `python my_first_agent.py`  |
| TypeScript | `npx tsx my_first_agent.ts` |

You'll see output like:

<Frame caption="Agent startup output">
  <img class="diagram" src="https://files.buildwithfern.com/signalwire.docs.buildwithfern.com/docs/2cde7f9665e6bdc1613c9e0d841ca9f695f8c21e1caaae165165183ccbc3a27c/assets/images/sdks/diagrams/01_03_quickstart_diagram1.webp" alt="Agent startup output showing security configuration, service initialization, basic auth credentials, and server startup information." />
</Frame>

<Note>
  The SDK shows:

  * Security configuration (SSL, CORS, rate limits)
  * Service initialization details
  * Basic auth credentials (username and password)
  * Server startup information
</Note>

### Test the Agent

Open a new terminal and test with curl. Use the Basic Auth credentials shown in the agent output:

```bash
## Get the SWML document (what SignalWire receives)
## Replace the password with the one from your agent's output
curl -u signalwire:7vVZ8iMTOWL0Y7-BG6xaN3qhjmcm4Sf59nORNdlF9bs \
  http://localhost:3000/
```

<Note>
  The `-u` flag provides Basic Auth credentials in the format `username:password`. Use the exact password shown in your agent's startup output.
</Note>

You'll see JSON output like:

```json
{
  "version": "1.0.0",
  "sections": {
    "main": [
      {"answer": {}},
      {
        "ai": {
          "prompt": {
            "text": "# Role\nYou are a friendly and helpful assistant..."
          },
          "languages": [
            {"name": "English", "code": "en-US", "voice": "rime.spore"}
          ]
        }
      }
    ]
  }
}
```

### What Just Happened?

**1. You run: `python my_first_agent.py`**

Agent starts a web server on port 3000.

**2. SignalWire (or curl) sends: `GET http://localhost:3000/`**

Agent returns SWML document (JSON).

**3. SWML tells SignalWire:**

* Answer the call
* Use this AI prompt (your personality config)
* Use this voice (rime.spore)
* Use English language

**4. SignalWire's AI:**

* Converts caller's speech to text (STT)
* Sends text to AI model (GPT-4, etc.)
* Gets AI response
* Converts response to speech (TTS)

### Adding a Custom Function

Let's add a function the AI can call:

<Tabs>
  <Tab title="Python">
    ```python
    #!/usr/bin/env python3
    ## my_first_agent_with_function.py - Agent with custom function
    """
    My First SignalWire Agent - With Custom Function
    """

    from signalwire import AgentBase, FunctionResult

    class MyFirstAgent(AgentBase):
        def __init__(self):
            super().__init__(name="my-first-agent")

            # Set the voice
            self.add_language("English", "en-US", "rime.spore")

            # Define the AI's personality
            self.prompt_add_section(
                "Role",
                "You are a friendly assistant who can tell jokes. "
                "When someone asks for a joke, use your tell_joke function."
            )

            # Register the custom function
            self.define_tool(
                name="tell_joke",
                description="Tell a joke to the caller",
                parameters={"type": "object", "properties": {}},
                handler=self.tell_joke
            )

        def tell_joke(self, args, raw_data):
            """Return a joke for the AI to tell."""
            import random
            jokes = [
                "Why do programmers prefer dark mode? Because light attracts bugs!",
                "Why did the Python programmer need glasses? Because they couldn't C!",
                "What's a programmer's favorite hangout spot? Foo Bar!",
            ]
            joke = random.choice(jokes)
            return FunctionResult(f"Here's a joke: {joke}")

    if __name__ == "__main__":
        agent = MyFirstAgent()
        print("Starting My First Agent (with jokes!)...")
        print("Server running at: http://localhost:3000")
        agent.run()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    #!/usr/bin/env npx tsx
    // my_first_agent_with_function.ts - Agent with custom function
    import { AgentBase, FunctionResult } from 'signalwire-agents';

    const agent = new AgentBase({ name: 'my-first-agent' });
    agent.addLanguage({ name: 'English', code: 'en-US', voice: 'rime.spore' });

    agent.promptAddSection('Role', {
      body: 'You are a friendly assistant who can tell jokes. '
        + 'When someone asks for a joke, use your tell_joke function.',
    });

    agent.defineTool({
      name: 'tell_joke',
      description: 'Tell a joke to the caller',
      parameters: {},
      handler: () => {
        const jokes = [
          'Why do programmers prefer dark mode? Because light attracts bugs!',
          'Why did the Python programmer need glasses? Because they couldn\'t C!',
          'What\'s a programmer\'s favorite hangout spot? Foo Bar!',
        ];
        return new FunctionResult(`Here's a joke: ${jokes[Math.floor(Math.random() * jokes.length)]}`);
      },
    });

    console.log('Starting My First Agent (with jokes!)...');
    agent.run();
    ```
  </Tab>
</Tabs>

Now when a caller asks for a joke, the AI will call your `tell_joke` function!

### Using the Debug Endpoint

The agent provides a debug endpoint to inspect its configuration:

```bash
## Use the Basic Auth credentials from your agent's startup output
## (or set via SWML_BASIC_AUTH_USER and SWML_BASIC_AUTH_PASSWORD env vars)
curl -u "$SWML_BASIC_AUTH_USER:$SWML_BASIC_AUTH_PASSWORD" http://localhost:3000/debug
```

This shows detailed information about:

* Registered functions
* Prompt configuration
* Voice settings
* Authentication credentials

### Test with swaig-test CLI

The SDK includes a CLI tool for testing:

```bash
## Show the SWML document
swaig-test my_first_agent.py --dump-swml

## List available functions
swaig-test my_first_agent.py --list-tools

## Test a function
swaig-test my_first_agent.py --exec tell_joke
```

### Complete Example with Multiple Features

Here's a more complete example showing common patterns -- voice, hints, prompts, and multiple tools.

<Tabs>
  <Tab title="Python">
    ```python
    #!/usr/bin/env python3
    ## complete_first_agent.py - Complete agent example with multiple features
    """
    Complete First Agent Example

    Demonstrates: voice config, AI parameters, prompt sections, custom functions, speech hints.
    """

    from signalwire import AgentBase, FunctionResult

    class CompleteFirstAgent(AgentBase):
        def __init__(self):
            super().__init__(
                name="complete-agent",
                auto_answer=True,
                record_call=False
            )

            # Voice and language
            self.add_language("English", "en-US", "rime.spore")

            # AI behavior parameters
            self.set_params({
                "end_of_speech_timeout": 500,      # Wait 500ms for speaker to finish
                "attention_timeout": 15000         # 15 second attention span
            })

            # Speech recognition hints (improves accuracy)
            self.add_hints([
                "SignalWire",
                "SWML",
                "AI agent"
            ])

            # Prompt sections
            self.prompt_add_section(
                "Identity",
                "You are Alex, a helpful AI assistant created by SignalWire."
            )

            self.prompt_add_section(
                "Capabilities",
                body="You can help callers with:",
                bullets=[
                    "Answering general questions",
                    "Telling jokes",
                    "Providing the current time",
                    "Basic conversation"
                ]
            )

            self.prompt_add_section(
                "Style",
                "Keep responses brief and friendly. Use a conversational tone."
            )

            # Register functions
            self.define_tool(
                name="get_current_time",
                description="Get the current time",
                parameters={"type": "object", "properties": {}},
                handler=self.get_current_time
            )

            self.define_tool(
                name="tell_joke",
                description="Tell a random joke",
                parameters={"type": "object", "properties": {}},
                handler=self.tell_joke
            )

        def get_current_time(self, args, raw_data):
            """Return the current time."""
            from datetime import datetime
            now = datetime.now()
            return FunctionResult(f"The current time is {now.strftime('%I:%M %p')}")

        def tell_joke(self, args, raw_data):
            """Return a random joke."""
            import random
            jokes = [
                "Why do programmers prefer dark mode? Because light attracts bugs!",
                "Why did the developer go broke? Because they used up all their cache!",
                "There are only 10 types of people: those who understand binary and those who don't.",
            ]
            return FunctionResult(random.choice(jokes))

    if __name__ == "__main__":
        agent = CompleteFirstAgent()
        print("Complete First Agent running at http://localhost:3000")
        agent.run()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    #!/usr/bin/env npx tsx
    // complete_first_agent.ts - Complete agent example with multiple features
    import { AgentBase, FunctionResult } from 'signalwire-agents';

    const agent = new AgentBase({ name: 'complete-agent', autoAnswer: true, recordCall: false });

    agent.addLanguage({ name: 'English', code: 'en-US', voice: 'rime.spore' });
    agent.setParams({ end_of_speech_timeout: 500, attention_timeout: 15000 });
    agent.addHints(['SignalWire', 'SWML', 'AI agent']);

    agent.promptAddSection('Identity', {
      body: 'You are Alex, a helpful AI assistant created by SignalWire.',
    });
    agent.promptAddSection('Capabilities', {
      body: 'You can help callers with:',
      bullets: ['Answering general questions', 'Telling jokes', 'Providing the current time', 'Basic conversation'],
    });
    agent.promptAddSection('Style', {
      body: 'Keep responses brief and friendly. Use a conversational tone.',
    });

    agent.defineTool({
      name: 'get_current_time',
      description: 'Get the current time',
      parameters: {},
      handler: () => new FunctionResult(`The current time is ${new Date().toLocaleTimeString()}`),
    });

    agent.defineTool({
      name: 'tell_joke',
      description: 'Tell a random joke',
      parameters: {},
      handler: () => {
        const jokes = [
          'Why do programmers prefer dark mode? Because light attracts bugs!',
          'Why did the developer go broke? Because they used up all their cache!',
          'There are only 10 types of people: those who understand binary and those who don\'t.',
        ];
        return new FunctionResult(jokes[Math.floor(Math.random() * jokes.length)]);
      },
    });

    console.log('Complete First Agent running at http://localhost:3000');
    agent.run();
    ```
  </Tab>
</Tabs>

### Next Steps

Your agent is running locally, but SignalWire can't reach `localhost`. You need to expose it to the internet.

**Continue to:**

1. **[Development Environment][development-environment]** - Set up a professional project structure with environment variables and testing
2. **[Exposing Your Agent][exposing-your-agent]** - Make your agent accessible via ngrok so SignalWire can reach it

**Or jump ahead to:**

* **[architecture][architecture]** - Understand SWML, SWAIG, and the request lifecycle
* **[Building Agents][agentbase]** - Learn all agent configuration options