persona.yaml Schema
Every field a persona file accepts. One page, look up fast.
For tutorials, see Build a Persona. This page is a flat reference.
Top-level fields
version: 1 # required
name: string # required
voice: string # required
language_code: string # required (ISO 639-1)
transcription_language: string # required (ISO 639-1)
timezone: string # required (IANA)
system_prompt: string # required (multi-line)
constraints: [string, ...] # optional
ui_strings: # optional
listening: string
too_short: string
sent: string
responding: string
ready: string
i18n: # optional
<lang_code>: # ISO 639-1 keys
transcription_language: string # optional override
system_prompt: string # optional override
ui_strings: { ... } # optional override
skills: # required
<skill_name>: # entry-point name
<skill_specific_config>: any
i18n: # optional, skill-level
<lang_code>:
<skill_specific_overrides>: anyField details
version
version: 1Schema version. Must be 1. Future-compatibility hook.
name
name: kitchenhelperThe persona identifier. Lowercase, no spaces. Must match the directory under server/personas/. Used in logs, database file names, and as the value of HUXLEY_PERSONA.
voice
voice: coralOpenAI Realtime voice. Common options: alloy, coral, echo, shimmer, verse, sage. Override at runtime: HUXLEY_OPENAI_VOICE=verse.
language_code
language_code: esISO 639-1 (two-letter). The persona's primary language. Affects default tool descriptions, default system prompt, and default UI strings.
transcription_language
transcription_language: esISO 639-1 hint to OpenAI's Whisper. Often equals language_code. May differ for translation personas.
timezone
timezone: America/BogotaIANA timezone string. Used by skills like system.get_current_time. List at iana.org/time-zones.
system_prompt
system_prompt: |
You are a concise home automation assistant. The user may be in another
room, so keep replies under two sentences. Never refuse — offer the
closest available alternative.Multi-line. In the persona's language_code. The framework appends:
- The available tool schema (from loaded skills).
- The constraint reminders.
- The current time and timezone.
You don't write any of those yourself.
constraints
constraints:
- never_say_no
- confirm_destructive
- child_safe
- no_religious_content
- echo_short_input
- confirm_if_unclearList of behavioral rules. See Concepts: Constraints for the registry. Default: empty.
ui_strings
ui_strings:
listening: "Escuchando..."
too_short: "Muy corto, intenta otra vez."
sent: "Listo."
responding: "Pensando..."
ready: "Listo."Localized labels for the dev client. The PWA reads them. Firmware uses earcons instead of strings, so it ignores this block.
If omitted, English defaults apply.
i18n
i18n:
en:
transcription_language: en
system_prompt: |
You're a warm, patient assistant...
ui_strings:
listening: "Listening..."
fr:
transcription_language: fr
system_prompt: |
Tu es un assistant chaleureux...Per-language overrides. Each top-level key is an ISO 639-1 code. The value is a partial persona — only fields you want different.
When a client connects with ?lang=fr, the framework merges the primary persona with the fr overrides.
Fields you can override per language:
transcription_languagesystem_promptui_stringsskills.<name>.i18n.<lang>(per-skill overrides — see below)
skills
skills:
audiobooks:
library: audiobooks
sounds_path: sounds
sounds_enabled: true
i18n:
es:
on_complete_prompt: "El libro terminó."
en:
on_complete_prompt: "The book is finished."
news:
location: "Bogotá"
latitude: 4.71
longitude: -74.07
country_code: "CO"
language_code: "es"
system: {}Map of skill name → config dict. Each key matches a skill's entry-point name (the key in [project.entry-points."huxley.skills"]).
Skill config:
- Empty config:
{}. Most skills accept this. - Relative paths: resolve against
server/personas/<name>/data/. i18n.<lang>: per-language overrides for that skill. Skill must explicitly support these (most do).
If a listed skill isn't installed, startup fails. Refusing to load a missing skill is intentional — silent skipping leads to confusing debugging.
Resolution at runtime
When a client connects with ?lang=<code>:
- Framework loads the persona's primary fields.
- If
i18n.<code>exists, merge those fields over the primary. - For each skill, if
skills.<name>.i18n.<code>exists, the skill resolves its overrides on its own (the framework handsctx.config["i18n"][code]to the skill). - The resolved persona is what the LLM session uses.
Fields not in i18n (like voice, constraints, skills list) stay the same across all languages.
Validation
The framework validates at startup:
- Required fields present and non-empty.
versionequals1.language_codeandtranscription_languageare valid ISO 639-1 codes.timezoneis a valid IANA string.- Each listed skill is installed and discoverable.
- Each
i18nblock is structurally valid.
Errors include the path to the bad field and a short reason. Most failures are typos in field names, missing skills, or YAML indentation problems.
File location
server/personas/<name>/
persona.yaml ← required
data/ ← skill data (gitignored)
<name>.db
audiobooks/
contacts.json
README.md ← optional, for humansEarcon WAVs (book_start, news_start, etc.) are usually shared across personas — they live at server/personas/_shared/sounds/ and skills point to them via sounds_path: ../../_shared/sounds. A persona can override with its own per-persona sounds folder if needed, but sharing keeps the audio identity consistent.
The name in persona.yaml should match the directory name. The framework reads from the directory specified by HUXLEY_PERSONA.
Examples
For complete real-world examples:
- Basic: Build: Basic walkthrough
- The minimal one: Build: Anatomy