Progressive Skills¶
For: people packaging a repeatable job. After this page you can write a skill with its own model, tools, gates and instructions.
Skills let you package domain-specific instructions, preferred model defaults, enabled built-in tools, and custom @tool Python functions into a self-contained unit.
Tether searches for skills in:
./skills/(workspace skills)~/.tether/skills/(user-global skills)
Skill Structure¶
A skill can be either a single Markdown file (skills/<name>.md) or a directory (skills/<name>/SKILL.md) with an optional companion skills/<name>/tools.py:
SKILL.md¶
---
name: analyst
description: Financial ratio and margin analysis
model: ollama/qwen3.5:9b
tools: [web, mem, calc-margin]
---
You are a quantitative financial analyst.
1. Use `calc-margin` to verify gross and operating margins.
2. Pin verified metrics with `mem pin` before synthesizing your report.
Companion tools.py¶
Any @tool-decorated function in skills/<name>/tools.py is loaded with the skill, and is registered into the session's multiplexer only if its name is also listed in the skill's tools: (see below):
from tether import tool
@tool(name="calc-margin", description="Compute profit margin percentage")
def calc_margin(revenue: float, cost: float) -> str:
"""Calculate profit margin percentage from revenue and cost."""
return f"{((revenue - cost) / revenue) * 100:.2f}%"
Small models rarely quote arguments, so extra unquoted words join into the last str parameter (yt-search arquitetura em camadas with def yt_search(query: str, limit: int = 3) gives query="arquitetura em camadas"; set limit with --limit 2). A *args: str parameter receives the words as separate positional arguments.
Using a Skill¶
Example: course builder¶
The course-builder example has three skills, each with its own model, tools and gate:
---
name: searcher
description: Picks one real YouTube video for every topic of the plan
model: ollama/qwen3.5:9b
tools: [yt-todo, yt-candidates, yt-save]
verify:
- 'python3 checks.py videos'
---
| Skill | tools: |
verify: |
|---|---|---|
planner |
edit |
python3 checks.py plan |
searcher |
yt-todo, yt-candidates, yt-save (from its tools.py) |
python3 checks.py videos |
writer |
edit, course-source, course-build (from its tools.py) |
python3 checks.py course |
tools.py and the tools: list¶
Defining a tool in tools.py is not enough: name it in the skill tools: as well, or the model gets unknown command (#24). A skill's own custom tools are opt-in like built-in ones, so list them in tools:. Loading a skill whose tools.py defines an unlisted @tool emits a UserWarning naming it (costs no prompt tokens). See Python SDK and Custom Tools.
Let the model decide, let code enforce hard requirements¶
The planner's goal states what the course must cover; the model designs the modules, topics and their order. Code checks only what is a hard requirement: checks.py plan demands 1 to 3 modules and at least one topic per module, nothing about content. Gates that police taste make small models loop.