> ## Documentation Index
> Fetch the complete documentation index at: https://unmute.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Unmute compiles to exactly three targets. Pipecat and LiveKit are code targets: compile writes a Python project you run. SLNG is a hosted target: compile writes a deployment body and SLNG runs the agent, so it has no `unmute dev`. Those three are the only values `provider` accepts in `targets.yaml`. Deepgram and ElevenLabs appear in these docs as model vendors, which is not the same thing as a target, and `slng` is both.
> The Go structs in `internal/spec` and `internal/ir` are the schema truth. Check a field against them, or run `unmute validate`, rather than against what you remember.

# Prebuilt tools

> The tools the runtime already has: a closed registry with one entry today.

Some tools need no code from you because both runtimes already have them. You
select one by id.

Reach for a prebuilt when the capability already exists in the runtime, so
writing your own would just duplicate it. Today that is ending the call. For
anything else, write a [webhook](/build/tools/webhook), a
[Python handler](/build/tools/python), or point at an
[MCP server](/build/tools/mcp).

On this page:

* [The block](#the-block) - two keys
* [The registry, in full](#the-registry-in-full) - two ids, and it is closed
* [What the registry decides for you](#what-the-registry-decides-for-you) - effect, parameters, description
* [Turning it on](#turning-it-on) - the same two lists
* [Advanced](#advanced) - resolving on SLNG
* [Troubleshooting](#troubleshooting) - two refusals by name

```yaml tools/end_call.yaml theme={null}
description: "End the call when the caller is finished or says goodbye."
builtin:
  id: end_call
```

That is the file `unmute init` scaffolds, so a new agent can hang up from its first
run.

## The block

<ParamField path="id" type="string" required>
  Accepts `end_call` or `send_sms` from the registry below. No id is inferred. `send_sms`
  is SLNG only.
</ParamField>

<ParamField path="instructions" type="string">
  Instruction the runtime gives the model as the prebuilt runs. For `end_call`, use it for
  a final line or action before ending. Omit to add no custom instructions to the
  prebuilt.
</ParamField>

## The registry, in full

| id         | Effect              | Default description                                                       |
| ---------- | ------------------- | ------------------------------------------------------------------------- |
| `end_call` | `ends_conversation` | End the call when the caller is finished or says goodbye.                 |
| `send_sms` | `returns_data`      | Send a text message to a phone number the caller has given and confirmed. |

Two rows. The registry is **closed**: you cannot add to it from a package, and
there is no plugin seam. Adding a prebuilt means a row in the compiler plus a
lowering for each target, which is a change to Unmute, not to your agent.

`end_call` compiles on every target. `send_sms` is a capability SLNG curates
and compiles on the `slng` target only; a code target refuses it by name. It
takes one setting from the package, the sender:

```yaml tools/send_sms.yaml theme={null}
description: Send a text message to the guest's confirmed mobile number.

builtin:
  id: send_sms

inject:
  - from_number: "+447700900123"
```

`from_number` is a literal number in international format starting with a plus
sign, and it is the only key `inject:` may carry here: SLNG requires the
sender on the attachment and lets the model supply the recipient and the body.
SLNG reads the Twilio credentials from your vault under `TWILIO_ACCOUNT_SID`
and `TWILIO_AUTH_TOKEN`, so `unmute deploy` checks both. Pair it with a
[`source: conversation` variable](/reference/variables#sources) so the number
the caller confirmed is recorded on the call.

So read this page as a list of two things that exist, not as a catalog to
browse. If what you want is neither, it is a
[webhook](/build/tools/webhook), a [Python handler](/build/tools/python), or an
[MCP server](/build/tools/mcp).

## What the registry decides for you

**The effect.** `end_call` implies `ends_conversation`, and writing anything else
fails rather than being quietly ignored:

```text theme={null}
livekit: tool "end_call" builtin "end_call" fixes effect to ends_conversation, cannot be
  "returns_data"
```

**The parameters.** A prebuilt owns its own schema, so the contract fields have
nowhere to go:

```text theme={null}
livekit: tool "end_call" builtin execution takes no input, output, handler, or url_env
```

**The description, unless you write one.** Leave `description` out and the registry
default is used.

<Accordion title="What the two targets emit for the bare file">
  From a real compile of the bare file above, on each target:

  <CodeGroup>
    ```python LiveKit theme={null}
    tools=[
        *EndCallTool(
            extra_description="End the call when the caller is finished or says goodbye."
        ).tools
    ],
    ```

    ```python Pipecat theme={null}
    async def end_call(params: FunctionCallParams):
        """End the call when the caller is finished or says goodbye."""
        await params.result_callback({"ended": True})
        await params.llm.push_frame(EndFrame())
    ```
  </CodeGroup>

  Same tool, same description, two lowerings. `unmute init` scaffolds the LiveKit
  one; the shipped examples that declare a Pipecat target get the other.
</Accordion>

Write your own `description` when the agent needs a narrower instruction, for
example telling it to confirm before hanging up. Yours is added on top of the
default rather than replacing the tool's behavior.

Use `builtin.instructions` when the model must do something at execution time:

```yaml theme={null}
builtin:
  id: end_call
  instructions: Thank the caller briefly, then end the call.
```

It does not change the tool's id, parameters, or fixed
`ends_conversation` effect.

## Turning it on

The same two lists as any other tool:

```yaml agent.yaml theme={null}
agents:
  greeter:
    instructions: instructions.md
    think: reasoning
    speak: voice
    tools:
      - end_call

tools:
  - end_call
```

## Advanced

### Resolving on SLNG

SLNG already offers `end_call` as one of its own curated capabilities, so
`unmute deploy`'s preflight check has to match your reference against it
before pushing. It matches by the tool **file's** name, `tools/end_call.yaml`,
never by the `builtin.id` you selected inside it.

That is fine as written here, because the file is named `end_call` too. It
stops being fine the moment you rename the file to describe what it does rather
than the capability it selects.

## Troubleshooting

### An id the registry does not hold

An id the registry does not hold is refused by name. Every line below is
prefixed with the target instance that refused it, so a fresh scaffold, which
has one `livekit` instance, reads like this:

```text theme={null}
livekit: tool "end_call" has unknown builtin "transfer_to_human"
```

**Fix:** pick one of the two ids in [the registry](#the-registry-in-full), or
write the capability yourself as a webhook, a Python handler, or an MCP source.

### The SLNG preflight says the organisation has no tool of that name

A file `tools/hang_up.yaml` holding `builtin: {id: end_call}` compiles and
validates, but the organisation has no tool named `hang_up`. The preflight then
reports it absent, even though the capability exists:

```text wrap theme={null}
this organisation has no tool of this name (it has `end_call`). A builtin reference is
  the tool file's own name, so either rename the file to a capability SLNG offers, or
  create the tool in the SLNG dashboard
```

**Fix:** keep a `builtin:` file's name matching its `id`.

## Where to go next

<Columns cols={2}>
  <Card title="Knowledge bases" icon="book-open" href="/build/tools/knowledge">
    Answer from a folder of your own documents.
  </Card>

  <Card title="Tools" icon="wrench" href="/build/tools/overview">
    Return to all eight execution blocks.
  </Card>
</Columns>
