diff --git a/fern/docs.yml b/fern/docs.yml
index c7ba1c4ea..713427228 100644
--- a/fern/docs.yml
+++ b/fern/docs.yml
@@ -344,6 +344,8 @@ navigation:
path: gpt-live/design.mdx
- page: Build with tools
path: gpt-live/tools.mdx
+ - page: Reasoner skills
+ path: gpt-live/skills.mdx
- page: Migrate to GPT-Live
path: gpt-live/migrate.mdx
- page: Test and improve
diff --git a/fern/gpt-live/configuration.mdx b/fern/gpt-live/configuration.mdx
index 73a60d33e..d7cfa6cba 100644
--- a/fern/gpt-live/configuration.mdx
+++ b/fern/gpt-live/configuration.mdx
@@ -1,13 +1,13 @@
---
title: GPT-Live settings and compatibility
subtitle: Supported features, fields, voices, hooks, call connections, and live controls
-description: Reference for GPT-Live in Vapi. Feature compatibility, speaker and reasoner fields, personality packs, voices with previews, greetings, idle-message hooks, call connections, and live call control.
+description: Reference for GPT-Live in Vapi. Feature compatibility, speaker and reasoner fields, reasoner skills, personality packs, voices with previews, greetings, idle-message hooks, call connections, and live call control.
slug: gpt-live/configuration
---
This page is the reference for GPT-Live's settings and supported features. For how to use them in a conversation, start with [Design conversations](/gpt-live/design).
-**Jump to:** [Compatibility](#compatibility) · [Model settings](#model-settings) · [Personality](#personality-and-language) · [Voices](#voices) · [Greetings](#greetings-and-duration) · [Idle messages](#idle-messages) · [Calls](#connect-a-call) · [Live control](#live-call-control)
+**Jump to:** [Compatibility](#compatibility) · [Model settings](#model-settings) · [Skills](#reasoner-skills) · [Personality](#personality-and-language) · [Voices](#voices) · [Greetings](#greetings-and-duration) · [Idle messages](#idle-messages) · [Calls](#connect-a-call) · [Live control](#live-call-control)
## Compatibility
@@ -56,6 +56,7 @@ Give tools unique names. Classic tool messages, such as request-start messages,
| Feature | Support |
| --- | --- |
| Squads and assistant handoffs | Not supported. See [Migrate to GPT-Live](/gpt-live/migrate#from-a-squad) |
+| Reasoner skills | Supported. See [Reasoner skills](/gpt-live/skills) |
| Knowledge bases | Not available to the reasoner. Use a retrieval tool |
| Exact or prerecorded speech | Not supported. All speech, including greetings and idle check-ins, is generated |
| Audio URL greetings, generated first-message mode | Not supported |
@@ -95,17 +96,35 @@ These fields belong to the assistant object. See [Create Assistant](/api-referen
| `model.reasoner.model` | `gpt-5.6-sol`, `gpt-5.6-terra`, or `gpt-5.6-luna`. Defaults to `gpt-5.6-terra` |
| `model.reasoner.reasoningEffort` | `none`, `low`, `medium`, `high`, `xhigh`, or `max`. Defaults to `low`. Higher effort can increase response time |
| `model.reasoner.instructions` | Reasoner prompt. Omit to use Vapi's default |
-| `model.tools` | Inline tool definitions available to the reasoner |
-| `model.toolIds` | IDs of saved tools |
+| `model.reasoner.skills` | Array of skills. See [Reasoner skills](#reasoner-skills) |
+| `model.tools` | Inline base tool definitions, available whether or not a skill is loaded |
+| `model.toolIds` | IDs of saved base tools |
| `voice.provider` | `openai` |
| `voice.voiceId` | One of the [22 supported voices](#voices) |
## Prompt defaults and overrides
- Explicit speaker instructions take precedence over `model.systemPrompt` and system messages in `model.messages`. If you omit the speaker instructions, Vapi uses that classic configuration.
-- Omitting reasoner instructions uses Vapi's default reasoner prompt. Custom instructions replace that prompt entirely. Vapi doesn't append behavioral instructions to a custom prompt.
+- Omitting reasoner instructions uses Vapi's default reasoner prompt. Custom instructions replace that prompt entirely. When skills are configured, Vapi adds skill-loading guidance and the content of loaded skills.
- An explicit empty string stays empty. Updating one prompt doesn't update the other.
- Personality packs append guidance to the speaker prompt.
+- The speaker also receives the names and descriptions of any reasoner skills.
+
+## Reasoner skills
+
+Set `model.reasoner.skills` to an array of skills. See [Reasoner skills](/gpt-live/skills) for how to design them.
+
+| Field | Behavior | Limit |
+| --- | --- | --- |
+| `name` | Unique within the assistant. Start with a lowercase letter; use lowercase letters, digits, hyphens, or underscores. The speaker and reasoner both see it | 64 characters |
+| `description` | Tells the reasoner, and the speaker, when the skill applies | 1,024 characters |
+| `content` | The full procedure. Only the reasoner sees it, once the skill is loaded | 32,000 characters |
+| `tools` | Optional inline tool definitions, available only while the skill is loaded | 20 tools |
+| `toolIds` | Optional IDs of saved tools, available only while the skill is loaded | 20 tools |
+
+An assistant can have up to 20 skills.
+
+Skills are stored with the assistant. Tools in `model.tools` and `model.toolIds` stay available whether or not a skill is loaded. Each delegation starts from the catalog and loads the skills it needs, and the reasoner can unload a skill when it finishes that work or changes tasks. A saved tool ID that doesn't exist can stop calls from starting.
## Personality and language
diff --git a/fern/gpt-live/design.mdx b/fern/gpt-live/design.mdx
index e4aed8419..189d5fdd8 100644
--- a/fern/gpt-live/design.mdx
+++ b/fern/gpt-live/design.mdx
@@ -70,7 +70,7 @@ The speaker and reasoner see different things. You need this to predict how the
| --- | --- | --- |
| Live audio | Hears the caller and speaks continuously | Doesn't hear audio. Works from the conversation transcript |
| Conversation | Is part of it | Receives the transcript available when the request starts |
-| Instructions | Speaker prompt, plus any personality packs | Reasoner prompt. The speaker prompt isn't copied over |
+| Instructions | Speaker prompt, plus any personality packs | Reasoner prompt and any loaded skills. The speaker prompt isn't copied over |
| Tools | None. It asks the reasoner | Your tools. It can use its earlier work and tool results from the call |
Two consequences shape the rest of this page.
@@ -290,11 +290,13 @@ A detour can help the caller make the next decision:
If the answer is already known, as with an appointment's length in the [example prompt](#example-split-a-scheduling-prompt), the speaker can give it directly. If it needs a lookup, delegate it. Either way, return to the unfinished task with the caller's earlier details intact.
+When an assistant covers several kinds of work, such as scheduling and service questions, [reasoner skills](/gpt-live/skills) let you keep each procedure and its tools separate behind the same conversation.
+
### Start with one assistant
-GPT-Live keeps one voice for the whole call. Start with a clear task and the tools it needs. Put its procedure in the reasoner prompt and its delegation triggers in the speaker prompt. Expand the assistant's responsibilities after it handles that task well.
+GPT-Live keeps one voice for the whole call. Needs that used to lead to a squad of assistants, like separate intake, scheduling, and information roles, can often be covered by one assistant with clear delegation triggers and a few skills. The caller hears one continuous conversation instead of handoffs.
-Existing squads and assistant handoffs aren't supported with GPT-Live. See [Migrate to GPT-Live](/gpt-live/migrate) for moving a single assistant and the limits for squads.
+Existing squads and assistant handoffs aren't supported with GPT-Live. See [Migrate to GPT-Live](/gpt-live/migrate#from-a-squad) for how to map a squad's responsibilities onto one assistant.
## Names, numbers, and dates
diff --git a/fern/gpt-live/migrate.mdx b/fern/gpt-live/migrate.mdx
index 07bf26ea5..ca560d706 100644
--- a/fern/gpt-live/migrate.mdx
+++ b/fern/gpt-live/migrate.mdx
@@ -1,11 +1,13 @@
---
title: Migrate to GPT-Live
-subtitle: Move an existing assistant, compare it with the original, and keep a way back
-description: Migrate a Vapi assistant to GPT-Live. Check fit, convert a copy, split prompts between the speaker and reasoner, compare results, and roll back safely.
+subtitle: Move an existing assistant or squad, compare it with the original, and keep a way back
+description: Migrate a Vapi assistant or squad to GPT-Live. Check fit, convert a copy, split prompts between the speaker and reasoner, map squad members to reasoner skills, compare results, and roll back safely.
slug: gpt-live/migrate
---
-Move a copy of your assistant first, compare it with the original, and switch traffic after it meets the same goals. This guide covers a single assistant. If you use a squad, see [From a squad](#from-a-squad) for the current limits.
+This page has two complete paths. Follow [From a single assistant](#from-a-single-assistant) if you're moving one assistant, or [From a squad](#from-a-squad) if you're combining a squad into one GPT-Live assistant. Each path repeats what it needs, so you can follow one without reading the other.
+
+Both start from the same preparation.
## Before you start
@@ -14,7 +16,7 @@ Move a copy of your assistant first, compare it with the original, and switch tr
Some features don't carry over. If your assistant depends on one of these, plan how to replace it before you begin:
- **Voices** must be one of the [OpenAI voices GPT-Live supports](/gpt-live/configuration#voices). Other voice providers and custom or cloned voices aren't available.
-- **Squads and assistant handoffs** aren't supported. There is no direct squad conversion; see [the current limits](#from-a-squad).
+- **Squads and assistant handoffs** aren't supported. A squad becomes one assistant, as described [below](#from-a-squad).
- **Model and voice fallbacks** must be removed. GPT-Live can't be a fallback model either.
- **Exact or prerecorded speech** isn't available. GPT-Live generates all of its speech, including the greeting.
- **Keypad input** from callers isn't supported.
@@ -29,7 +31,7 @@ Pick a handful of calls that represent what the assistant has to get right: a st
### Keep the original running
-Leave your phone numbers on the original assistant until the GPT-Live version has passed the same calls. Work on a copy, test it on its own, and switch traffic when you're ready.
+Leave your phone numbers on the original assistant or squad until the GPT-Live version has passed the same calls. Work on a copy, test it on its own, and switch traffic when you're ready.
## From a single assistant
@@ -145,6 +147,8 @@ Three things changed besides the split:
- **Waiting is designed.** In the classic flow, the assistant read times out after a lookup and then asked for the name. The speaker now asks for the name while the lookup runs.
- **Results are for speaking.** The reasoner returns short facts that the speaker can use directly.
+If the reasoner prompt grows to cover several distinct procedures, group them into [reasoner skills](/gpt-live/skills).
+
### 4. Map the settings
| Classic setting | With GPT-Live |
@@ -207,6 +211,104 @@ If you need to take a converted assistant back to Classic, select **Revert to Cl
## From a squad
-GPT-Live doesn't support squads or assistant handoffs. **Switch to GPT Live** converts one assistant; it doesn't convert a squad or preserve its routing and handoff behavior.
+A squad splits a conversation across assistants and hands the caller between them. GPT-Live keeps one voice for the whole call, and its reasoner can switch between procedures without a handoff. Migrating a squad means mapping what each member was responsible for onto one assistant. **Switch to GPT Live** converts a single assistant. It doesn't convert a squad, so this path is done by hand.
+
+### How the pieces map
+
+Take a squad with a front-desk assistant that greets callers and routes them, a scheduling assistant, and a service-information assistant:
+
+| In the squad | In one GPT-Live assistant |
+| --- | --- |
+| Front-desk greeting, intake, and routing | Shared speaker behavior, assistant-wide reasoner rules, and delegation triggers |
+| Scheduling assistant | A `schedule-appointment` skill with its procedure and booking tools |
+| Service-information assistant | An `answer-service-questions` skill with its guidance and retrieval tool |
+| Handoff conditions | Skill descriptions and the speaker's delegation triggers |
+| Values passed between assistants | What the caller said is in the shared conversation. Values an earlier assistant or tool produced come from your services |
+| Protected actions | Checks in your services: prerequisites, confirmation, duplicate handling |
+| Transfer to a person | A `transferCall` tool, kept as a base tool |
+
+### 1. Map each member's responsibility
+
+For each assistant in the squad, write down what it's responsible for and why it was separate. Common reasons are a long procedure, a different set of tools, or a different tone.
+
+Then decide where each responsibility goes:
+
+- A procedure with its own rules and tools becomes a **skill**.
+- Rules every part of the call follows, like "never report an action a tool didn't confirm", go in the **reasoner prompt**.
+- Conversation guidance, like tone and pacing, goes in the **speaker prompt**.
+
+You don't need one skill per old assistant. A front-desk assistant that only greeted and routed usually doesn't need a skill at all: its job becomes the speaker's greeting and delegation triggers. Two specialists with closely related work may be clearer as one skill.
+
+### 2. Keep one voice and shared conversation rules
+
+Write one speaker prompt for the whole call. Take the greeting and tone from the assistant callers heard first, and add anything the specialists did differently that callers relied on, such as a slower pace for explaining policies.
+
+Remove handoff announcements like "Let me transfer you to our scheduling team." The caller stays with the same assistant, so they aren't needed. One of the goals of the migration is that the caller no longer repeats details at each handoff. Check that on real calls: it depends on your prompts and on the reasoner using the earlier conversation.
+
+A handoff was also a point where the conversation paused. Now the speaker can keep going while the reasoner works. When the caller moves from a question to booking, the speaker can start the lookup and ask for the name in the same breath:
+
+> **Caller:** Thanks. Can I book a consultation downtown on Friday?
+>
+> **Assistant:** Sure, I'll check Friday downtown. Who should I put it under?
+
+Give the speaker the same waiting guidance as a single assistant: ask what the next step needs, answer what it already knows, and acknowledge a blocked wait once instead of filling it. See [Redesign the waits](#5-redesign-the-waits) above.
+
+### 3. Build the skills
+
+Each specialist's procedure becomes a skill's `content`, and its tools become the skill's tools. A minimal version for the scheduling and service-information specialists:
+
+```json title="model.reasoner (excerpt)"
+{
+ "instructions": "Work from the latest request in the conversation transcript. Load the skill that fits the request. Return short, plain facts the assistant can say. Never report an action a tool did not confirm. Call endCall when the caller asks to end the call.",
+ "skills": [
+ {
+ "name": "schedule-appointment",
+ "description": "Check open times, book a time, or cancel or move a booking made on this call.",
+ "content": "Call lookupAvailability when you have the service, location, and date. A caller choosing a time isn't agreement to book. Call bookAppointment only for a time from the latest lookup, and only when the transcript shows the assistant read back the day, time, location, and name and the caller then clearly said yes. Otherwise, return those details for the assistant to read back and confirm. To move a booking, look up the new time and confirm it with the caller first, then cancel the existing booking with cancelAppointment and book the new time. If the new booking fails after the cancellation, say so.",
+ "toolIds": ["LOOKUP_TOOL_ID", "BOOK_TOOL_ID", "CANCEL_TOOL_ID"]
+ },
+ {
+ "name": "answer-service-questions",
+ "description": "Answer questions about services, how long they take, what to bring, locations, hours, and the change policy.",
+ "content": "Use getServiceInfo and answer only from its result. If the caller was in the middle of booking, say so in your result so the assistant can return to it."
+ }
+ ]
+}
+```
+
+The `toolIds` are the IDs of the saved tools the scheduling assistant used. Tools that several skills need, or that must always be available, go in the assistant's base tools instead. Here `getServiceInfo`, `endCall`, and any transfer to a person are base tools. See [Reasoner skills](/gpt-live/skills#example-scheduling-and-service-questions) for the full procedure and tool placement.
+
+### 4. Turn handoff conditions into descriptions and triggers
+
+In the squad, handoff conditions decided which assistant took over. Now they do two jobs:
+
+- **Skill descriptions** tell the reasoner which procedure a request needs. Write them in terms of the caller's request, and make sure two skills don't claim the same requests.
+- **Delegation triggers** in the speaker prompt tell the speaker when to send work to the reasoner at all.
+
+A condition like "hand off to scheduling when the caller wants to book, move, or cancel" becomes the scheduling skill's description and a line in the speaker's triggers.
+
+The speaker also sees skill names and descriptions, so keep them short and suitable for the caller to hear about.
+
+### 5. Plan for what doesn't carry over
+
+- **Different voices or models per member.** One assistant has one voice and one reasoner model. Skills don't change either.
+- **Separate context per member.** In one assistant, the whole call's conversation is shared, and skills don't isolate it. If a member was separate to keep information apart, enforce that in your services or keep that flow outside this assistant.
+- **Handoff tools.** Remove them, since handoffs aren't supported.
+- **Values passed at handoff.** Inventory each one before removing it. Details the caller said are in the shared conversation. Values an earlier assistant or tool produced, such as an account ID or a lookup result, may not be. Make those available from your services, for example through a tool the reasoner can call, and keep authoritative state there.
+- **Member-specific hooks or settings.** Combine them into the one assistant's configuration, and check each against [Settings and compatibility](/gpt-live/configuration#compatibility).
+
+### 6. Test the switches between procedures
+
+The old handoff boundaries are the places to test most carefully, because that's where the combined assistant switches between procedures. Test:
+
+- **A switch** from scheduling to a service question and back, without repeating details.
+- **A return** to an unfinished booking after the detour.
+- **A correction** during a lookup.
+- **An already-completed action.** After a booking, return to the topic and check the assistant doesn't book again.
+- **A failure** from a tool, and the recovery.
+
+For each, check the call's messages for the skill loads and tool calls, your service's state for the outcome, and the recording for how it sounded. The reasoner uses the conversation and earlier results to continue, which works well when results are clear about status. Skills don't track workflow state for you, so your services must still reject duplicates and out-of-order actions.
+
+### 7. Roll out and keep the squad
-Keep your existing squad if your call flow depends on those capabilities. The single-assistant steps above aren't a replacement for a squad migration.
+Move traffic to the new assistant when it passes your saved calls. Keep the original squad and its configuration unchanged as your fallback. Revert to Classic works on converted single assistants and doesn't recreate a squad, so the squad itself is your way back.
diff --git a/fern/gpt-live/overview.mdx b/fern/gpt-live/overview.mdx
index ac83e500b..760cf8ac0 100644
--- a/fern/gpt-live/overview.mdx
+++ b/fern/gpt-live/overview.mdx
@@ -10,7 +10,7 @@ GPT-Live is an OpenAI voice model that listens to the caller's audio and generat
In Vapi, a GPT-Live assistant pairs that voice model with a second model that does the task work, so the conversation can carry on while your tools run.
-**Private beta.** GPT-Live must be enabled for your Vapi organization. See [Access](#access). If you already have a Vapi assistant, see [Migrate to GPT-Live](/gpt-live/migrate).
+**Private beta.** GPT-Live must be enabled for your Vapi organization. See [Access](#access). If you already have a Vapi assistant or squad, see [Migrate to GPT-Live](/gpt-live/migrate).
## How it works
@@ -41,7 +41,7 @@ For you, more of the design lives in the two prompts:
- **Plan for generated speech.** All speech, including the greeting, is generated, so exact wording isn't guaranteed.
- **Keep saying and doing separate.** The assistant saying something happened is different from your service confirming it.
-[Design conversations](/gpt-live/design) works through these decisions with an appointment-booking example.
+[Design conversations](/gpt-live/design) works through these decisions with an appointment-booking example. As an assistant takes on more kinds of work, [reasoner skills](/gpt-live/skills) let you organize each procedure and its tools behind the same conversation.
## In this guide
@@ -52,8 +52,8 @@ For you, more of the design lives in the two prompts:
Shape a conversation that reaches the caller's goal while work runs alongside it.
-
- Move an existing assistant, compare it with the original, and keep a way back.
+
+ Move an existing assistant or squad, compare it with the original, and keep a way back.
See what's supported before you build or migrate.
@@ -66,7 +66,7 @@ Vapi connects GPT-Live to your phone numbers and tools, and provides call record
- Browser, Twilio, Vapi SIP, and WebSocket calls.
- Function, API request, and MCP tools, plus built-in end-call, transfer, and DTMF tools.
-- Speaker and reasoner prompts, personality packs, and 22 voices.
+- Speaker and reasoner prompts, reasoner skills, personality packs, and 22 voices.
- Idle-message hooks and HTTP live call control.
- Transcripts, recordings, structured outputs, scorecards, Boards, Monitoring, and Voice Simulations.
@@ -76,7 +76,7 @@ Before you commit, check whether your assistant depends on something GPT-Live do
| --- | --- |
| Exact or prerecorded speech | Not available. All speech is generated |
| A voice from another provider, or a custom voice | Not available. Choose from 22 OpenAI voices |
-| A squad with handoffs | Not supported. GPT-Live runs as a single assistant |
+| A squad with handoffs | Not supported. Use one assistant, often with skills |
| Knowledge bases or the Query tool | Not available. Use a retrieval tool |
| Warm transfers, or transfers on browser calls | Not supported. Blind transfers work on Twilio and Vapi SIP |
| Caller keypad input | Not supported |
diff --git a/fern/gpt-live/quickstart.mdx b/fern/gpt-live/quickstart.mdx
index 432bb32d9..5800049bc 100644
--- a/fern/gpt-live/quickstart.mdx
+++ b/fern/gpt-live/quickstart.mdx
@@ -146,4 +146,4 @@ See [the troubleshooting guide](/gpt-live/testing#said-goodbye-but-the-call-didn
- **[Design conversations](/gpt-live/design):** how to shape a conversation that reaches the caller's goal while work runs in the background.
- **[Build with tools](/gpt-live/tools):** connect your service so the assistant can look things up and take actions.
-- **[Migrate to GPT-Live](/gpt-live/migrate):** move an existing assistant.
+- **[Migrate to GPT-Live](/gpt-live/migrate):** move an existing assistant or squad.
diff --git a/fern/gpt-live/skills.mdx b/fern/gpt-live/skills.mdx
new file mode 100644
index 000000000..1c91da9b3
--- /dev/null
+++ b/fern/gpt-live/skills.mdx
@@ -0,0 +1,144 @@
+---
+title: Reasoner skills
+subtitle: Organize specialist procedures and tools behind one continuing conversation
+description: Use reasoner skills in GPT-Live to group a procedure with its tools, so the reasoner loads the right instructions for each task while the caller hears one assistant.
+slug: gpt-live/skills
+---
+
+As an assistant takes on more kinds of work, its reasoner prompt fills with procedures that only apply some of the time. Scheduling needs rules about dates, confirmation, and changes. Answering service questions needs different guidance. Keeping all of it in one prompt makes each procedure harder to find, and gives the reasoner every tool on every request.
+
+A **reasoner skill** groups one procedure with the tools it needs. The reasoner sees a short catalog of skills and loads the ones a request calls for. The caller still hears the same assistant throughout: skills change what the reasoner works with, not who the caller is talking to.
+
+The examples on this page use an appointment assistant that checks open times, books and cancels appointments, and answers questions about the business.
+
+## When a skill helps
+
+Keep a procedure in the main reasoner prompt when it's short or applies to most requests. Move it into a skill when it's a coherent piece of work with its own rules, and often its own tools.
+
+For the appointment assistant:
+
+- **Shared rules** apply to every request: work from the latest request, return short plain facts, never report an action a tool didn't confirm. These stay in the reasoner prompt.
+- **Scheduling** has a multi-step procedure and three tools of its own: one to look up times and two that change bookings. That's a good skill.
+- **Service questions** have their own guidance, such as what to say about the change policy. That can be a second skill.
+
+Group by responsibility. A skill per conversational step ("ask for the date", "ask for the name") splits one procedure into pieces that always load together. A skill that tries to cover everything is just the main prompt again.
+
+## How skills work during a call
+
+When the speaker delegates, the reasoner starts with:
+
+- the reasoner prompt,
+- the catalog of skill names and descriptions,
+- the **base tools**, which are the assistant's own tools and are always available.
+
+If the request fits a skill, the reasoner loads it. That adds the skill's full instructions and its tools. The reasoner then follows the procedure and calls the tools. Loading a skill doesn't take any action on its own. It only makes the procedure and tools available.
+
+Several skills can be active in the same delegation. The reasoner can unload a skill when it finishes that work or changes tasks; unloading removes its instructions and exclusive tools from the active set. Each new delegation starts again from the catalog and loads whatever it needs. The reasoner can still use the call's earlier conversation and tool results, so it can see what's already been done.
+
+Loading a skill is an extra reasoning step before the skill's tools can be used. Keep the catalog small and the descriptions distinct, so the reasoner picks the right skill the first time. Measure the effect on your calls rather than assuming skills make them faster or slower.
+
+The speaker also sees the skill names and descriptions, which helps it recognize when to delegate. Write descriptions in terms of the caller's need, keep them short, and leave out anything the caller shouldn't hear. Callers don't need to hear skill names, and the speaker prompt can say so.
+
+## Example: scheduling and service questions
+
+The appointment assistant has two skills. The scheduling skill's procedure, written as plain instructions:
+
+```text title="schedule-appointment"
+Get today's date from getServiceInfo if you don't know it, and resolve
+relative dates against it.
+
+Call lookupAvailability when you have the service, location, and date. If a
+detail is missing, return a short question for the assistant to ask. The
+lookup returns every open time for that day and location, so filter by a
+time-of-day preference without another lookup. A different service, location,
+or date needs a new lookup.
+
+A caller choosing a time is a selection, not agreement to book. Call
+bookAppointment only when the assistant has read back the day, time,
+location, and name and the caller has clearly said yes. Otherwise, return
+those details for the assistant to read back and confirm.
+
+To move a booking, look up the new time and confirm it with the caller first.
+Then cancel the existing booking with cancelAppointment and book the new time.
+If the new booking fails after the cancellation, say that the original booking
+was cancelled and the new time wasn't booked.
+```
+
+The service-questions skill is shorter: use `getServiceInfo`, answer only from its result, give the specific fact the caller asked for, and note if a booking was in progress so the assistant can return to it. It has no tools of its own, but it still earns its place: it holds guidance that only matters for that kind of request.
+
+The tools are placed like this:
+
+- `lookupAvailability`, `bookAppointment`, and `cancelAppointment` belong to the scheduling skill, because they only make sense within that procedure.
+- `getServiceInfo` is a base tool, because both skills use it.
+- `endCall` is a base tool, so ending the call never depends on loading a skill.
+
+In the assistant's configuration, skills live in `model.reasoner.skills`. Each skill has a `name`, a `description`, and its procedure as `content`. Attach saved tools by their IDs in `toolIds`, or include inline definitions in `tools`. See [Settings and compatibility](/gpt-live/configuration#reasoner-skills) for the field details and limits.
+
+## Write descriptions the reasoner can select
+
+The description is how the reasoner, and the speaker, decide a skill is relevant. Describe the caller's need and the work the skill covers:
+
+| Description | Why it works or doesn't |
+| --- | --- |
+| "Check open times, book a time, or cancel or move a booking made on this call." | Names the requests it handles in the caller's terms |
+| "Scheduling." | Too vague to separate from anything else that mentions a date |
+| "Use this skill for everything related to appointments and customers." | Overlaps with every other skill, so selection becomes a guess |
+| "Calls lookupAvailability then bookAppointment." | Describes the mechanics, not when the skill applies |
+
+If two skills could both fit a request, make their descriptions say where one ends and the other begins, or merge them.
+
+## Base tools and skill tools
+
+A tool's placement decides when the reasoner can use it:
+
+- **Base tools**, in `model.tools` or `model.toolIds`, are available on every request.
+- **Skill tools**, in a skill's `tools` or `toolIds`, are available only while that skill is loaded.
+
+Put a tool under a skill when it only makes sense within that procedure, as with the booking tools. Keep it in the base list when several procedures need it, or when the assistant must be able to use it at any time. `endCall`, and a transfer to a person, are usually base tools, so ending or handing off a call never depends on loading the right skill first. That's a design choice, not a rule. Don't move every action into the base list by default.
+
+## What skills don't do
+
+Skills organize instructions and tools for the reasoner. Some things stay the same:
+
+- **One assistant.** A skill doesn't create another assistant, hand the call off, or change the voice or model.
+- **No workflow engine.** Loading a skill doesn't track which steps are done, enforce their order, or remember task state between requests. The reasoner works from the conversation and earlier tool results.
+- **No enforcement.** Skills don't prevent duplicate actions, check approvals, or keep one skill's information separate from another's. Your service enforces the rules that matter, as described in [Actions that change state](/gpt-live/tools#actions-that-change-state).
+- **One copy per assistant.** Skills are saved with the assistant. Copying an assistant copies its skills, and there's no shared skill library to update across assistants.
+
+## Create and edit skills
+
+**In the dashboard**, open a GPT-Live assistant and add skills in its reasoner settings. For each skill, enter the name, description, and content, and select saved tools to attach.
+
+**Through the API**, set `model.reasoner.skills` when you create or update the assistant. Inline tool definitions in a skill's `tools` are available through the API and assistant JSON.
+
+**From Markdown**, you can import an existing skill with `name` and `description` in its frontmatter and the procedure in its body. Other frontmatter fields are ignored, and tools aren't imported. Attach them to the skill after importing.
+
+**With Composer**, ask in plain language. Composer can read, create, rename, edit, and remove skills, and attach saved tools, through the assistant's normal draft and publish flow. For example:
+
+> In my booking assistant, update the schedule-appointment skill so a move checks the new time and gets the caller's agreement before cancelling the old booking. Don't change the other skills or the speaker prompt. Save it as a draft.
+
+Then open the draft, read the changed skill, test it, and publish.
+
+Every saved tool a skill references must exist. A missing tool reference stops calls from starting, even if the skill is rarely used. Give tools unique names across the base list and all skills. Size limits are in [Settings and compatibility](/gpt-live/configuration#reasoner-skills).
+
+## Test a detour and return
+
+Skills matter most when a call moves between them. Test a caller who asks a service question in the middle of booking, then carries on, and a caller who comes back to a booking that's already been made.
+
+For each, check three things together:
+
+- **The call's messages** show which skills loaded and which tools ran. The scheduling skill should load for the lookup and booking, and the service-questions skill, or `getServiceInfo`, for the question.
+- **Your service's records** show one booking, for the time the caller confirmed, and no second booking when the caller returns to the topic.
+- **The recording** shows the assistant answered the question and returned to the booking without asking for details again.
+
+### When skills misbehave
+
+| Symptom | Possible causes | What to check |
+| --- | --- | --- |
+| The wrong skill loads | Overlapping or vague descriptions | Compare the descriptions with the request. Make each one name the requests it covers |
+| A skill loads but no action follows | The content doesn't say when to call its tools, or a required detail is missing | Look at what the reasoner returned after the load, and whether it asked for a detail |
+| A tool is unavailable | The tool belongs to a skill that wasn't loaded | Check which skills loaded. Move the tool to the base list if it's needed at any time |
+| Calls don't start after adding a skill | A saved tool ID in the skill may not exist, among other configuration errors | Check each tool ID in the skill, then the call's error details |
+| Work is repeated after a detour | The earlier result didn't read as current, or the service accepted a duplicate | Check that results include booking status and IDs, and that your service rejects duplicates |
+
+Field details are in [Settings and compatibility](/gpt-live/configuration#reasoner-skills). To move a squad onto one assistant with skills, see [Migrate to GPT-Live](/gpt-live/migrate#from-a-squad).
diff --git a/fern/gpt-live/testing.mdx b/fern/gpt-live/testing.mdx
index 6d2dbbb65..cbca438ce 100644
--- a/fern/gpt-live/testing.mdx
+++ b/fern/gpt-live/testing.mdx
@@ -13,7 +13,7 @@ A GPT-Live call can go wrong in two separate ways. The conversation can be poor
| --- | --- |
| **Recording** | What the caller heard, and when: pace, overlap, interruptions, how waits sounded |
| **Transcript** | What was said. Transcripts can contain recognition mistakes, so check key details against the recording |
-| **Call messages** | Tool calls with their arguments and results, including `endCall` |
+| **Call messages** | Tool calls with their arguments and results, including `endCall` and any skill loads |
| **Your service's state** | What actually happened: bookings made, changed, or not made |
| **Ended reason** | How the call ended |
| **Costs** | The call's cost breakdown, including billable voice time |
@@ -117,6 +117,7 @@ When the task takes too long, try these, one at a time, and check that the outco
| Slow tools | Speed up your handler. Check the service log for the time each call takes |
| Reasoning time | Try a lower `model.reasoner.reasoningEffort`, such as `none`. The default is `low` |
| Model choice | Compare `gpt-5.6-luna`, `gpt-5.6-terra`, and `gpt-5.6-sol` on your scenarios |
+| Skill loading | Each skill load adds a reasoning step. Keep the catalog small and descriptions distinct |
Lower effort or a smaller model can miss steps that a larger one handles. The right setting is the fastest one that still passes your scenarios.
@@ -157,14 +158,14 @@ The call's `costs` include the model cost with its billable voice time in `secon
- **GPT-Live isn't offered for your organization.** It must be enabled for your organization. See [Access](/gpt-live/overview#access).
- **You use your own OpenAI API key.** The key needs access to GPT-Live and to the reasoner model you selected.
- **The assistant is rejected when you save it.** See [A voice or tool is rejected when saving](#a-voice-or-tool-is-rejected-when-saving).
-- **Calls stopped starting after you added a saved tool.** Check that every saved tool ID the assistant references still exists.
+- **Calls stopped starting after you added a skill or saved tool.** Check that every saved tool ID the assistant or its skills reference still exists.
### The assistant said it would act, but nothing happened
Follow the request through the call, in order:
1. **Was there a tool call?** Check the call's messages at that point. If there's none, the speaker may not have delegated, or the reasoner may have returned a question instead of acting. Add a concrete trigger for that request to the speaker's delegation policy, and make answering the reasoner's questions a trigger too.
-2. **Did the right tool run?** If a tool is missing, check that it's attached and that the reasoner prompt says when to use it.
+2. **Did the right tool run?** If a tool is missing, check that it's attached, and, if it's in a skill, that the skill's description covers the request.
3. **What did the tool return?** An error in the result means the action failed. The reasoner prompt should report failures plainly.
4. **What does your service show?** Its state is the answer to whether the action happened.
@@ -190,6 +191,10 @@ The reasoner works from the transcript. Compare the tool arguments with the reco
A correction arrived while earlier work was running. Check that the speaker prompt says to delegate the updated request and not to present old results, and that your results include the request details, such as the date, so a stale one is recognizable.
+### The wrong skill loaded, or a tool was unavailable
+
+See [When skills misbehave](/gpt-live/skills#when-skills-misbehave).
+
### Waits feel awkward
Listen to the recording. Repeated "still checking" messages, invented progress, or unrelated questions point to the speaker's guidance for [while work is running](/gpt-live/design#while-work-is-running). Long silences with no acknowledgment point the other way. Adjust one line at a time.
diff --git a/fern/gpt-live/tools.mdx b/fern/gpt-live/tools.mdx
index ec5d5f07e..b4a1572ac 100644
--- a/fern/gpt-live/tools.mdx
+++ b/fern/gpt-live/tools.mdx
@@ -142,3 +142,5 @@ At the start of a call, Vapi connects to the MCP server and makes its tools avai
## Check the outcome, not just the conversation
When you test a tool, look at three things together: what the assistant said, the tool calls and results in the call's messages, and your service's own records. The assistant saying a booking is done doesn't prove it happened. [Test and improve](/gpt-live/testing#scenarios-to-run) has a set of scenarios to run, including corrections, failures, and slow tools.
+
+When an assistant handles several kinds of work, [reasoner skills](/gpt-live/skills) group each procedure with its tools.