Persona files

Persona files

Built-in personas ship with homebot. Your files go in $XDG_CONFIG_HOME/homebot/personas/<id>.toml (normally ~/.config/homebot/personas/<id>.toml). A local file with a built-in ID overrides that built-in. IDs are 1–32 ASCII characters: a lowercase letter followed by lowercase letters, digits or hyphens. none is reserved for turning the voice off. Run homebot persona ids for the current list of messages a persona may reword.

schema = 1
id = "tester" # optional; must match tester.toml
name = "Tester"
emoji = "🧪"
tagline = "A careful eye on the details"
extends = "neatpik" # optional; omitted means the embedded Neatpik
lang = "en" # optional

[colors]
accent = { light = "#31466B", dark = "#AFC4E9" }
ok = { light = "#245D38", dark = "#9DE0AF" }
muted = { light = 240, dark = 248 }

[lines]
"inbox.header.count" = ["{n:# thing needs|# things need} you."]

schema = 1, a name and one emoji are required. id is optional but, when present, must match the filename. The name is 1–32 characters. The tagline is one line of at most 100 characters and cannot contain $ or a backtick. lang is a BCP 47 language tag; English is the default. Colours may be #RRGGBB or ANSI indices 0–255. Each light/dark token omitted here is inherited from the parent. extends = "none" stops traversal of explicit parents; embedded Neatpik still supplies missing colours and lines, followed by the catalog’s English for messages with no persona line. Explicit parent chains may have at most four files, the persona included (the embedded Neatpik does not count), and cannot cycle. An explicit extends = "neatpik" uses a local neatpik.toml if you have one; omitting extends always uses the embedded copy. For each message ID, the first file in that chain with usable lines supplies all its variants.

File safety and checks

User files must be regular files of at most 256 KiB. A symlink is accepted only when it points to a regular file. Pipes, devices, sockets and folders are refused; reading cannot block the background helper on a pipe. Unknown TOML keys, invalid syntax, a bad header, an invalid ID or an invalid parent make the persona unusable. An invalid line variant is dropped; usable variants remain, and an ID with none falls through to its parent. homebot persona validate <id> checks the file itself, including warnings, and that its extends target exists; it exits with an error for invalid lines. It does not load the parent chain, so problems further up (a parent’s header, too many levels, a cycle) show only in homebot persona show <id> or preview <id>, which load the whole chain. validate <file.toml> reads a file directly. homebot persona use <id> refuses a file with any error, even a single bad line variant that would otherwise just be dropped.

Line IDs must be in homebot persona ids and marked for voice. A variant must parse, preserve required and fixed placeholders, plural counts, leading/trailing whitespace, punctuation that protects an appended command, and the original number of line breaks. The validator rejects control and format characters, including terminal escapes and bidi controls. In a line, it allows only the same newlines as the English; the emoji field alone may contain the joiner and variation marks needed for one emoji. It warns about low colour contrast, uncertain emoji width, duplicate or long variants, non-English language tags and possible added facts. A variant beyond the hard length limit is rejected. Run homebot persona preview <id> to see the voice in both themes, or add --event <message-id> and --all-variants to inspect individual lines.

Selection and rotation

HOMEBOT_PERSONA (when nonempty) wins over persona: in homebot.yml; the default is Neatpik. none selects the neutral voice. A missing or unusable choice falls back to the embedded Neatpik, even if a broken local neatpik.toml shadows the built-in. A configured failure raises persona_broken in the inbox; a failing environment override warns once on a terminal. The neutral English is used when a message has no usable variant.

For each message ID, homebot picks one variant per process and tries not to repeat the previous process’s choice. Previous picks are stored per machine in $XDG_CACHE_HOME/homebot/voice.json; a cache read or write failure only changes the pick. The main nudge line uses a stable pick keyed on the inbox items; notifications and the nudge’s urgent suffix always use the same variant for a persona. Neither changes wording on every refresh. This state stays outside the home repo.