Build a Custom Skill¶
A Skill is how you extend the capabilities of an OLAV Agent. When the built-in tools don't meet your needs, you can write your own skill — a set of Python functions that teach the Agent new operations.
Feature Claims
| ID | Claim | Status |
|---|---|---|
| C-L2-04 | olav skill install <path> installs a Skill from a local directory |
✅ v0.10.0 |
| C-L2-25 | olav skill install <git-url> installs from a Git repository |
✅ v0.10.0 |
| C-L2-06 | olav skill install --merge-into appends tools to an existing workspace |
✅ ⚠️ v0.10.0 |
| C-L2-37 | requires_packages declaration automatically creates an isolated venv for dependencies |
✅ v0.10.0 |
When Do You Need a Custom Skill?¶
- You have internal APIs (ticketing system, CMDB, monitoring platform) that you want OLAV to query
- You want to package common operations tasks (bulk configuration, health check scripts)
- You have specific data-processing logic that needs automation
Minimal Skill Structure¶
A skill requires only two files:
my-skill/
├── MANIFEST.yaml ← Metadata: name, version, route keywords
└── tools.py ← Tool functions: Python functions the Agent can call
MANIFEST.yaml — Tell OLAV What This Skill Is¶
kind: Agent
name: my-skill
version: "0.1.0"
description: "Tools for querying the ticketing system"
route_keywords: # When a user's question contains these keywords, auto-route to this skill
- ticket
- jira
- issue
- 工单
route_keywords is important — OLAV's semantic router uses these keywords to decide which Agent/Skill to dispatch a question to.
tools.py — Define the Tools the Agent Can Call¶
from langchain_core.tools import tool
@tool
def get_open_tickets(team: str) -> list[dict]:
"""Query all open tickets for a given team.
Args:
team: Team name, e.g. "platform" or "network"
"""
import requests
resp = requests.get(
"https://jira.internal/api/search",
params={"jql": f"assignee in membersOf('{team}') AND status != Closed"},
headers={"Authorization": "Bearer YOUR_TOKEN"}
)
return resp.json()["issues"]
@tool
def get_ticket_detail(ticket_id: str) -> dict:
"""Get detailed information for a single ticket.
Args:
ticket_id: Ticket ID, e.g. "OPS-1234"
"""
import requests
resp = requests.get(
f"https://jira.internal/api/issue/{ticket_id}",
headers={"Authorization": "Bearer YOUR_TOKEN"}
)
return resp.json()
Tool function docstrings are critical
The LLM uses the function's docstring to decide when to call a tool and how to pass parameters. Writing clear descriptions and parameter explanations significantly improves Agent accuracy.
Installing a Skill¶
Install from a Local Directory¶
Output:
Verify:
Install from a Git Repository¶
The repository root must contain a MANIFEST.yaml or workspace.yaml.
Append to an Existing Skill¶
If you want to add new tools to an existing Agent instead of creating a new one:
This appends the tools.py from extra-tools/ into the my-skill workspace.
Using a Skill¶
Once installed, just ask in natural language:
OLAV automatically routes questions to your skill based on route_keywords.
Declaring Python Dependencies¶
If your skill needs additional Python packages, declare them in MANIFEST.yaml:
When OLAV installs the skill, it automatically creates an isolated virtual environment (.venv/), installs the declared packages, and does not affect the main environment.
Uninstalling a Skill¶
Simply delete the workspace directory:
Advanced: Skill Development Tips¶
- Use clear function names:
get_open_ticketsis better thanquery_data— the LLM can more accurately understand when to call it - Write thorough docstrings: Include a description, parameter explanations, and return value format
- Cover common phrasings in route_keywords: Users might say "ticket", "issue", or "工单" — cover them all
- Handle errors gracefully: Return meaningful error messages instead of letting the Agent face raw 500 errors
- Start small: Begin with 1-2 tool functions, verify they work, then expand