Add a Skill
Install a skill, configure it, see it work.
A skill is a Python package. Installing one means: add it to your dependencies, list it in your persona, restart the server. That's the whole loop.
The first-party skills
Huxley ships with seven skills. You don't install them separately — they're part of the workspace and uv sync brings them in:
| Skill | Provides |
|---|---|
huxley-skill-audiobooks | Library search, playback, bookmarks, resume |
huxley-skill-news | Weather (Open-Meteo) + headlines (Google News RSS) |
huxley-skill-radio | HTTP/Icecast streaming via ffmpeg |
huxley-skill-system | Volume, current time |
huxley-skill-telegram | Voice calls + text messages via MTProto |
huxley-skill-timers | One-shot reminders, persistent across restart |
huxley-skill-search | Web search |
To use one in a persona, list it under skills::
skills:
audiobooks:
library: audiobooks # relative to data/
sounds_path: sounds
sounds_enabled: true
news:
location: "Bogotá"
latitude: 4.71
longitude: -74.07
country_code: "CO"
language_code: "es"
system: {}
timers: {}Each skill defines what config keys it accepts. Read the skill's README, or see the Cookbook for examples.
Installing a third-party skill
Third-party skills come from PyPI, GitHub, or any other Python package source. Install with uv add from the workspace root:
uv add huxley-skill-spotify # from PyPI
uv add git+https://github.com/foo/huxley-skill-bar.git # from gituv add updates pyproject.toml and uv.lock. The skill becomes available to all personas in this workspace.
To use it, list it in persona.yaml:
skills:
spotify:
library_path: spotify/Then restart the server. Huxley discovers skills at startup via Python entry points — the new skill registers itself automatically when it's pip-installed.
Secrets: Per-skill secret interpolation (${ENV_VAR} in persona.yaml) is on the roadmap but not yet shipped. For now, well-written skills read secrets via os.environ inside their code rather than accepting them as plain config. Check each skill's README to see how it handles credentials.
What does a skill's config look like?
That depends on the skill. There's no schema enforced by the framework — a skill takes whatever config dict the persona gives it.
Conventions you'll see across well-written skills:
- Paths are relative to
data/.library: audiobooksresolves toserver/personas/<name>/data/audiobooks/. - Per-language overrides go in
i18n.audiobooks: library: audiobooks i18n: en: on_complete_prompt: "The book is finished. Tell the user warmly." es: on_complete_prompt: "El libro terminó. Anúncialo con calidez."
Removing a skill
Remove it from the persona:
skills:
audiobooks:
...
# delete the lines for the skill you no longer wantRestart. The skill stops loading. Its data on disk (the SQLite rows it owns) stays — you can add it back later and resume.
To remove the package entirely:
uv remove huxley-skill-fooMake sure no remaining persona references it; otherwise startup fails.
Conflicts and collisions
Each loaded skill must have a unique name. If two skills both call themselves news, the framework refuses to start. This is intentional — silent shadowing would be a debugging nightmare.
Tool names must also be unique across loaded skills. Two skills both exposing a play() tool will fail. Conventionally, skills prefix tools with their domain: play_book, play_radio, play_song.
Where to find skills
There's no central registry yet. Today, skills live:
- In the Huxley monorepo (the seven first-party ones).
- In Mario's personal Huxley extensions repo (eventually).
- On PyPI under names starting with
huxley-skill-.
If you write one and want it indexed, file an issue on the Huxley repo — we'll link it.
A real example
Here's a persona that loads four skills, each with its own configuration:
version: 1
name: example
voice: coral
language_code: es
transcription_language: es
timezone: America/Bogota
system_prompt: |
Eres un asistente cálido. Responde corto. Nunca digas que no — ofrece
alternativas.
constraints:
- never_say_no
skills:
audiobooks:
library: audiobooks
sounds_path: sounds
sounds_enabled: true
i18n:
es:
on_complete_prompt: "El libro terminó. Anúncialo con calidez."
news:
location: "Bogotá"
latitude: 4.71
longitude: -74.07
country_code: "CO"
language_code: "es"
interests: [politica, local]
max_items: 8
sounds_path: sounds
start_sound: news_start
timers: {}
system: {}Run it:
HUXLEY_PERSONA=example uv run huxleyYou now have an agent that plays audiobooks, reads news, sets timers, and tells the time — in Spanish, with a warm voice, never refusing requests.