---
title: "How Skills Work"
source: "https://docs.vertesiahq.com/agent-runner/skills-model"
markdown: "https://docs.vertesiahq.com/llms/agent-runner/skills-model.md"
---

# How Skills Work

Agents with fifty tools available from turn one don't behave well. They forget the rules, misuse the wrong tool, hallucinate arguments. **Skills** are the mechanism that fixes this: a skill is a bundle of *instructions* + a *tool set* that the agent must explicitly opt into.

This page explains the skill model: what a skill is, how agents invoke skills, and how skills differ from plain tools.

## The shape

Every system skill is a `SystemSkillDefinition`:

```ts
interface SystemSkillDefinition {
    name: string;                                 // e.g. "web_search"
    title: string;                                // "Web Search"
    description: string;                          // shown in the skill catalog
    instructions: string | ((ctx) => string);     // unlocked on call
    tools: string[];                              // unlocked on call
    related_tools?: string[];                     // complementary, shown in catalog
    input_schema?: ToolDefinition['input_schema'];
}
```

Each skill is surfaced to agents as a tool named `learn_` — so `web_search` becomes `learn_web_search`. The tool's description is `[Skill] `; its input schema is either a generic `{ context: string }` or whatever the skill declares.

## Two phases: unlock, then act

Without a skill, an agent sees only its declared tools plus any `learn_*` entries. Domain tools — `web_search_serper`, `fetch_document`, `create_or_update_object_type` — aren't available yet. When the agent calls a `learn_*`:

1. The skill's `tools` list is **unlocked** for the remainder of the conversation. They become callable on subsequent turns.
2. The skill's `instructions` (markdown, often several paragraphs) are returned as the tool result.
3. The agent reads the instructions, then proceeds with the newly-available tools.

The forced read matters. Instructions are where the platform encodes "when to use provider A vs B", "which parameter is required", "common pitfalls". Without the unlock, an agent can't stumble into calling a misconfigured tool — it has to ask for the skill first and reads the rules on the way in.

This is why you'll often see agent prompts say things like *"if you need to search the web, call `learn_web_search` first"*. It's not a politeness; it's the only path that opens the tools.

## Static vs dynamic instructions

Instructions can be a string literal or a function of `SkillContext`:

```ts
interface SkillContext {
    project?: Project;
    enabledTools: string[];
}
```

Dynamic instructions let a skill adapt to the project — for example, `web_search` can inspect `project.configuration.web_search_providers` and only describe Serper's behavior if Serper is actually configured. The unlocked `tools` list is also typically filtered so the agent doesn't see tools that would fail at runtime.

## `related_tools`

A skill's `tools` are the ones **unlocked by calling it**. `related_tools` are tools that complement it but stay hidden — typically rare or heavy tools the skill itself points at conditionally. They show up in the skill catalog (`list_tools`) so an agent can see what's available without unlocking everything at once.

## System skills live in `packages/workflows/src/skills/sys/`

Browse the directory for concrete examples. A few worth reading:

- **`web-search.ts`** — classic multi-provider skill. Describes three search providers and three fetch providers, returns a comparison table, unlocks all six tools.
- **`process-definitions.ts`** — the grammar + authoring rules for process definitions. Unlocks `list_tools`, `list_interactions`, `validate_process_definition`, `create_process_definition`, etc. Used by the Studio Assistant for process authoring.
- **`document-search.ts`** — guidance on using `search_documents` in Search Mode vs DSL Mode.
- **`artifact-operations.ts`** — reading and writing agent-run artifacts.

Registration happens in `packages/workflows/src/skills/sys/index.ts`.

## How to declare which skills an agent gets

Skills are tools with a `+` prefix convention, same as any other tool:

```ts
agent_runner_options: {
    is_agent: true,
    tool_names: [
        "+learn_web_search",
        "+learn_document_management",
        "+fetch_document",     // unlocked already, no learn step
    ],
},
```

- `+learn_X` **adds** the skill's learn entry to the default tool set.
- `learn_X` (no prefix) **replaces** the default set with an explicit list.
- `-learn_X` removes a skill the defaults would otherwise include.

For process agent nodes, declare skills the same way in `node.tools`:

```json
"extract_terms": {
    "type": "agent",
    "tools": ["+learn_document_management", "+fetch_document"],
    ...
}
```

## The skill catalog

The `list_tools` builtin returns every tool *and* every skill (annotated as `is_system_skill: true`) that's available in the current project. An agent can call `list_tools` with a grep filter to discover capabilities before unlocking anything. This is how the Studio Assistant browses its own toolkit at runtime.

## Custom skills

Custom skills follow the same shape but are authored outside `packages/workflows/src/skills/sys/`. They're typically written as a `SkillDefinition` in the `tools-sdk` pattern (a markdown file with frontmatter plus an `instructions` block). The `toSystemSkill()` helper in `skills/types.ts` converts that shape into the runtime `SystemSkillDefinition`. See the tools-sdk docs for the authoring path.

## When to reach for a skill vs just a tool

Make it a tool when:

- The tool is always safe to call without context.
- One-liner usage; no preambles needed.
- It's a primitive the rest of the system composes freely (e.g. `get_current_time`).

Make it a skill when:

- There's non-trivial guidance — "use A for X, B for Y", pitfalls, required param combinations.
- The feature set is broad enough that loading everything at once bloats the tool list and hurts model quality.
- You want to enforce a particular ordering ("read the rules before building").

## When skills misfire

Two common failure modes:

1. **Agent never calls the skill.** Usually the prompt didn't mention the skill or didn't explain the forcing function. Fix in the system prompt: state that certain capabilities require `learn_*` first.
2. **Agent calls the skill repeatedly.** Once unlocked, a skill stays unlocked for the conversation — there's no need to re-call. If the agent loops, check that the instructions don't imply re-reading on every use.

## See also

- [Studio Assistant](/studio/assistant) — the always-on assistant that is itself skill-driven.
- [Authoring Processes](/processes/authoring) — the Studio Assistant's skill-first iteration loop for process authoring.
- [Agent Runner — Skills](/agent-runner/skills) — how to list, configure, and invoke skills on an agent run.
- [Agent Runner — Built-in Tools](/agent-runner/tools) — the broader tool catalog skills unlock.