---
title: "Reusable instructions"
description: "Write an organization-wide rule once and attach it to any agent; it is appended to the agent's system prompt under its own heading."
---

Reusable instructions are named blocks of markdown that belong to your
organization rather than to one agent: rules like email normalization,
symbol read-back, or retry limits that every agent should follow. Attach an
instruction to an agent with the `reusable_instruction_ids` field on
[Agents](/api-reference/agents). At call start ThunderPhone appends each
attached instruction to the end of that agent's prompt as a section headed
`## <name>`, in the order the instructions were created. Editing an
instruction changes every agent it is attached to from their next call;
deleting one detaches it everywhere and leaves each agent's own prompt
untouched.

Unlike [knowledge](/api-reference/knowledge-bases), instructions are not
looked up through a tool during the call. They are part of the system prompt
on every call the agent handles: inbound and outbound phone calls, web widget
sessions, [realtime sessions](/api-reference/realtime) that name an agent, and
test calls from the agent builder. Because they are prompt text, they count
toward the agent's [prompt-size surcharge](/guides/pricing#prompt-size): the
first 5,000 estimated prompt tokens of the combined prompt are included, and
each further block of 10,000 tokens adds a per-minute charge.

In the dashboard, manage instructions on the **Instructions** page and attach
them from the **Reusable instructions** section of the agent builder
(**Attach instructions**), then deploy the agent. The rest of this page covers
the same flow over the API.

<Note>
  All **write** operations on this page require the `admin` role (or
  an `sk_live_` key, which carries full access). Reads are available
  to every member.
</Note>

## Endpoints

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/v1/reusable-instructions` | List the organization's instructions, newest first |
| `POST` | `/v1/reusable-instructions` | Create an instruction |
| `GET` | `/v1/reusable-instructions/{instruction_id}` | Retrieve one instruction |
| `PATCH` | `/v1/reusable-instructions/{instruction_id}` | Rename or edit an instruction |
| `DELETE` | `/v1/reusable-instructions/{instruction_id}` | Delete an instruction and detach it from every agent |

## Instruction object

```json
{
  "id": "0f4d6e2a-3b1c-4c8e-9a7d-2f5e6b8c9d10",
  "name": "Email normalization",
  "content": "When a caller gives an email address, read it back letter by letter and say \"at\" for @ and \"dot\" for periods before moving on.",
  "agent_count": 3,
  "created_at": "2026-09-21T18:24:10.113Z",
  "updated_at": "2026-09-21T18:24:10.113Z"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `id` | uuid | Stable identifier; use it in `reusable_instruction_ids` on an agent |
| `name` | string | Required, at most 255 characters. Becomes the section heading (`## <name>`) when appended to a prompt, so keep it short and descriptive |
| `content` | string | Required markdown body. Appended under the heading with surrounding whitespace trimmed and no other changes; per-call `{{variables}}` inside it render exactly as they do in the agent's own prompt |
| `agent_count` | integer | Agents with the instruction attached in their **deployed** configuration. Agents that have only staged the attachment in a draft are not counted |
| `created_at`, `updated_at` | timestamp | ISO 8601 UTC |

## Create an instruction

```bash
curl -X POST https://api.thunderphone.com/v1/reusable-instructions \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Retry limits",
    "content": "Ask for a piece of information at most twice. If it is still unclear, offer a callback instead of asking a third time."
  }'
```

Returns the [instruction object](#instruction-object) with `201 Created`.
Both `name` and `content` must be non-blank; a blank value returns `400` with
the field named. `PATCH` accepts either field on its own. Requests for an
instruction id that belongs to another organization return `404`.

## Attach to an agent

Attachment is an agent draft field, so it follows the same stage-then-deploy
flow as every other agent setting:

```bash
curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"reusable_instruction_ids": ["0f4d6e2a-3b1c-4c8e-9a7d-2f5e6b8c9d10"]}'

curl -X POST https://api.thunderphone.com/v1/agents/12/deploy \
  -H "Authorization: Bearer sk_live_..."
```

The list replaces the agent's complete attachment set; send `[]` to detach
everything, or omit the field (or send `null`) to leave it unchanged. Every id
must belong to your organization, otherwise the `PATCH` returns `400`. Test
calls from the agent builder use the staged set; production calls use the
deployed set. The agent response embeds the attached rows as
`reusable_instructions` and the staged ids as `draft_reusable_instruction_ids`.
`POST /v1/agents` accepts the same `reusable_instruction_ids` field and
attaches immediately, since a new agent has no draft.

Deleting an instruction detaches it from every deployed agent immediately.
If an agent has a staged `reusable_instruction_ids` list that still names the
deleted id, its next deploy fails with `400` on `reusable_instruction_ids` and
asks you to update or discard the draft, rather than silently deploying a
smaller set than you reviewed. Version history records which instruction ids
an agent had attached at each deploy, not their text: editing an instruction
is not a new agent version, and the new text is used from the next call.

## Test an instruction

Attach the instruction in the agent builder (or with the `PATCH` above) and
place a test call from the builder; test calls use the staged attachment set,
so you do not need to deploy first. The section is appended after the agent's
own prompt, so ask the agent about something the instruction covers and check
the behavior. The composed prompt is not returned by the API: the agent's
`prompt` field stays exactly what you wrote, and the attached instructions are
listed separately as `reusable_instructions`.
