Skip to content

4. Write a skill

A library gives the agent capability. A skill gives it procedure. It is a Markdown playbook for one task, stored on your organization, that the agent pulls into the conversation when the task comes up.

Skills solve the problem that appears once an agent has a few libraries: it can do the work, but it does it differently every time. A skill pins down the order of the steps, the checks that matter, and the code that is known to work.

Skills reach the agent through tags rather than direct attachment.

  1. Each skill carries tags such as billing or onboarding.
  2. Each agent carries Skill tags on its Security tab.
  3. Every published skill sharing at least one tag with the agent is listed in the agent’s prompt under # Available skills, as a name and a description.
  4. When one matches the request, the agent calls load_skill with the exact name and gets the full body back as an observation. When nothing obvious matches, it calls search_skills with a description of the task first.

Only the name and description sit in the prompt, so a large skill library costs almost nothing per turn. The body arrives only when it is needed.

Publishing or retagging a skill changes what an agent can do without editing the agent. That is the point of the indirection: your support team can improve the refund playbook while nobody touches the agent configuration.

Open Skills in the console and select New Skill.

Name is what the agent passes to load_skill, so keep it short and unambiguous. refund-flow works; Refunds (v2, updated) does not.

Description is the only thing the agent reads before deciding to load the skill. Write it as a trigger condition, not a summary. When a customer asks to cancel or refund an order is useful. Refund documentation is not.

Tags are comma separated. They are how agents find the skill, so use the words that describe the domain, not the department that owns it.

Body is the playbook, in Markdown. Give it a “when to use” section and then numbered steps, with the code the agent should adapt:

# Refund flow
## When to use
The customer asks to cancel an order, reverse a charge, or get money back.
## Before you start
Refunds over 5000 in minor units need a human. Do not attempt those; explain the
approval step and stop.
## Steps
1. Find the order. Never trust an order id the user typed without checking it
belongs to their organization.
```js
import { getOrder } from "urai:lib/acme/acme-api";
const order = await getOrder(meta.vars.organization_id, orderId);
await urai.complete(order);
```
2. Check the order is refundable: `status` is `paid` and `refunded_at` is null.
If it is already refunded, tell the user the date and stop.
3. Issue the refund, then confirm the amount from the response rather than from
the request.
```js
import { refundOrder } from "urai:lib/acme/acme-api";
const result = await refundOrder(meta.vars.organization_id, orderId);
await urai.complete({ refunded: result.amount, reference: result.id });
```
4. Reply with the amount, the reference, and the expected settlement time of
five to ten business days.
## Failure cases
- `409` means a refund is already in flight. Tell the user to wait, do not retry.
- `403` means the order belongs to another organization. Treat it as not found.

Write the body for a model that is competent but has no context. Concrete values, real function names from your libraries, and explicit stopping points. Skip the encouragement and the background; every line that is not actionable is a line the agent has to read past.

The editor keeps a local draft as you type, so a closed tab does not lose work.

New skills start as candidate. Candidates are invisible to agents. On the Skills list, select the publish action to move one to published, which is the only status agents can load. Archived takes a skill out of circulation without deleting it.

Use the candidate state as a review step. A skill that tells the agent to call the wrong endpoint is worse than no skill, because the agent will follow it confidently.

Open the agent, go to the Security tab, and fill in Skill tags with a comma separated list:

billing, refunds, onboarding

Matching is any-overlap, so an agent tagged billing, refunds catalogs every published skill carrying either tag. Keep the list narrow. An agent that can see forty skills spends its first step choosing between them.

You do not have to mention skills in the system instructions. The runtime already tells the agent to load a matching skill before writing a script. Adding a line such as “follow the refund-flow skill exactly, including the approval limit” helps when a procedure is strict.

The fastest way to get good skills is to let the agent solve something the hard way once, then capture it.

On any agent-mode thread, admins see an Extract skill action in the thread header. It reads the conversation, distils what the agent actually did into a playbook, and saves it as a candidate skill. Extraction runs in the background and can take a while; a notification with an edit link arrives when it lands.

Edit the result before publishing. Extraction captures the steps but keeps whatever detours the agent took, so trim the dead ends, fix the tags, and sharpen the description.

Ask the agent something the skill covers. In the thread you should see a load_skill call with your skill’s name before any code, and the steps that follow should match the playbook. If the skill is never loaded, the description does not read like a trigger, or the tags do not overlap the agent’s.

Next: design the widget.