Message catalog

Message catalog

Generated by go run ./tools/gendocs docs; do not edit this page.

action

ID Kind Class Placeholders English
action.error.unavailable error voice name: string {name}: this action is not available in this build
action.link.error.layout error voice n: int, reasons: string, action: string = link: {action} the repo breaks {n:a layout rule|# layout rules}:
action.link.error.unknown_tree error voice tree: string, action: string = link:, autolink: string = autolink, private: string = private {action} unknown tree "{tree}" (use {autolink} or {private})
action.link.status.changed status voice n: int, action: string = link: {action} {n} changed
action.link.summary help mixed Link autolink/ and private/ into $HOME. - link or - link: [autolink]
action.link.warning.in_way warning voice n: int, cmd: string = {self} link , {n} in the way (see: {cmd})
action.run.error.exit error voice command: string, code: int, action: string = run: {action} "{command}" exited with
action.run.summary help mixed Run shell commands from manifests/. - run: ./scripts/thing.sh
action.unlock.status.decrypted status voice n: int, action: string = unlock: {action} {n} decrypted
action.unlock.status.nothing status voice action: string = unlock: {action} nothing to decrypt
action.unlock.summary help mixed Decrypt private/ (asks for your passphrase once). - unlock
action.unlock.warning.conflicts warning voice self: string, n: int, unlock: string = unlock , {n} conflicts (see: {self}{unlock})

actions

ID Kind Class Placeholders English
actions.kind.builtin label voice builtin
actions.kind.custom label voice custom
actions.kind.internal label voice internal
actions.line status fact name: string, action_kind: string, summary: string {name} {action_kind}

brand

ID Kind Class Placeholders English
brand.package_description label mixed Attention-Deficit Home Discipline: a dotfiles manager that keeps your home in order and tells you what it needs from you.

cleanup

ID Kind Class Placeholders English
cleanup.choice.delete choice voice remove the backup; what is linked there now stays
cleanup.choice.keep choice voice leave it for now; homebot asks again next time
cleanup.choice.line choice fact key: string, meaning: string, tool: string (optional) {key} {meaning}
cleanup.choice.merge choice voice pick some of the backup's lines for the repo file
cleanup.choice.quit choice voice stop for now; this backup and the rest stay as they are
cleanup.choice.use choice voice copy the backup into the repo file, then remove it
cleanup.diff.backup_is_link status voice dest: path The backup is a link to {dest}.
cleanup.diff.gone label voice something that is gone
cleanup.diff.kind_mismatch status voice backup_kind: string, path: path, now_kind: string The backup is a {backup_kind}, but {path} is a {now_kind} now.
cleanup.diff.only_copy status voice path: path Nothing is at {path} now; this backup is the only copy.
cleanup.diff.same status voice Identical to what is linked there now.
cleanup.error.merge_not_repo error voice path: path {path} isn't a file in the repo, so there is nothing to merge into
cleanup.error.scratch_git error voice subcommand: string, git: string = git {git} {subcommand} in the merge scratch repo failed.
cleanup.error.use_not_repo error voice path: path {path} isn't a file in the repo, so the backup can't go there
cleanup.fzf.header prompt fact path: path, i: int, total: int {path} ({i} of {total})
red lines are only in the backup, green only in what is linked now. Esc stops.
cleanup.fzf.header_merge prompt fact picker_keys: string
merge opens lazygit.
cleanup.fzf.prompt prompt fact >
cleanup.hint.terminal hint voice Review them in a terminal:
cleanup.hint.terminal_cmd hint fact self: string {self} cleanup
cleanup.list.item status fact path: path
cleanup.picker.git hint fact y takes a block, n skips it, s splits it smaller, e edits it, q stops. What you take goes into the repo file.
cleanup.picker.lazygit hint fact Enter opens the file. Green lines are the backup's: space takes one, shift+arrows select several, d drops them. q when done.
cleanup.prompt.header prompt fact i: int, total: int, path: path [{i}/{total}]
cleanup.scratch.author commit fact homebot <homebot@localhost>
cleanup.scratch.commit commit voice the repo's version
cleanup.status.nothing_taken status voice Nothing taken from the backup.
cleanup.status.summary status voice deleted: int, used: int, kept: int Deleted {deleted}, used {used}, kept {kept}.
cleanup.status.summary_merged status voice deleted: int, used: int, kept: int, merged: int Deleted {deleted}, used {used}, kept {kept}; merged lines {merged:# time|# times}.
cleanup.success.deleted success voice path: path deleted
cleanup.success.merged success voice self: string, repo_path: path, save: string = save merged into {repo_path}; {self}{save} commits it
cleanup.success.none success voice No backups to review.
cleanup.success.used success voice self: string, repo_path: path, save: string = save copied into {repo_path} and deleted the backup; {self}{save} commits it
cleanup.word.file label voice file
cleanup.word.folder label voice folder

cli

ID Kind Class Placeholders English
cli.error.args error fact node_message: string homebot:
cli.error.args_hint hint voice command_space: string (optional), homebot: string = {self} , help: string = --help See: {homebot}{command_space}
cli.error.completion_extra error mixed argument: string, self: string Completion takes one shell, not {argument}. See: {self} completion --help
cli.error.completion_missing error mixed self: string Choose a completion shell: bash, zsh or fish. See: {self} completion --help
cli.error.completion_unknown error mixed shell: string, self: string Unknown completion shell {shell}. Choose bash, zsh or fish. See: {self} completion --help
cli.error.option.ambiguous error fact option: string Option '{option}' argument is ambiguous.
Did you forget to specify the option argument for '{option}'?
To specify an option argument starting with a dash use '{option}=-XYZ'.
cli.error.option.ambiguous_short error fact option: string, name: string Option '{option}' argument is ambiguous.
Did you forget to specify the option argument for '{option}'?
To specify an option argument starting with a dash use '–{name}=-XYZ' or '{option}-XYZ'.
cli.error.option.missing_value error fact flag: string Option '{flag} <value>' argument missing
cli.error.option.no_value error fact flag: string Option '{flag}' does not take an argument
cli.error.option.unknown error fact option: string Unknown option '{option}'. To specify a positional argument starting with a '-', place it at the end of the command after '–', as in '– ""
cli.error.prefix error fact message: string homebot:
cli.error.unknown_action error voice name: string No action named "{name}". See:
cli.error.unknown_command error voice name: string Unknown command "{name}". See:
cli.error.version_args error voice argument: string, version: string = version {version} takes no arguments, not "{argument}". See:
cli.usage.action error fact Usage: homebot action <name> [args…]. See: homebot actions
cli.usage.actions error fact Usage: homebot actions (it takes no arguments). To run one, use: homebot action <name>
cli.usage.hook error fact Usage: homebot hook pre-commit
cli.usage.keys error fact Usage: homebot keys init
cli.usage.name error fact self: string Usage: {self} name [word|–off]
cli.usage.remote error fact Usage: homebot remote [url]
cli.usage.shell error fact Usage: homebot shell zsh
cli.version status fact version: string

config

ID Kind Class Placeholders English
config.doc.ai help fact Reserved for a future release; currently ignored.
config.doc.autosave help fact Set the background save cadence and push behavior.
config.doc.autosave.commit help fact Commit automatically: off, hourly or daily.
config.doc.autosave.push help fact Push background commits when enabled.
config.doc.exports help fact Programs that write files into the home repo.
config.doc.exports.name help fact Name used to select an export.
config.doc.exports.on help fact Operating systems that run this export.
config.doc.exports.out help fact Repo-relative output path for the export.
config.doc.exports.profiles help fact Profiles allowed to run this export.
config.doc.exports.run help fact Shell command that produces the export.
config.doc.limits help fact Size limits enforced by the commit guard.
config.doc.limits.max_file_mb help fact Maximum file size in megabytes.
config.doc.name help fact Optional command name for this homebot.
config.doc.persona help fact Optional persona id, or none for a neutral voice.
config.doc.profiles help fact Choose which profile each machine unpacks.
config.doc.profiles.default help fact Profile used when a host has no entry.
config.doc.profiles.hosts help fact Map each host name to its profile.
config.doc.triage help fact Choose files the inbox offers to pack.
config.doc.triage.watch help fact Home-relative glob patterns to watch.
config.doc.update help fact Release behavior: off, notify or auto. Automatic updates use a signed build after a soak period.
config.error.autosave error voice file: path, autosave: string = autosave {file}: {autosave} must be a mapping
config.error.autosave_commit error voice file: path, commit: string = autosave.commit, choices: string = off, hourly or daily {file}: {commit} must be
config.error.autosave_push error voice file: path, push: string = autosave.push, boolean: string = true or false {file}: {push} must be
config.error.export_duplicate error voice file: path, i: int, name: string, exports_open: string = exports[, exports_close: string = ], profiles: string = profiles {file}: {exports_open}{i}{exports_close}: duplicate export name "{name}" (give each one {profiles} that don't overlap)
config.error.export_mapping error voice where: string, keys: string = name, out, run {where}: expected a mapping with
config.error.export_out_absolute error voice where: string, out: string, name: string, out_key: string = out {where}: {out_key} {out} of export "{name}" is an absolute path; give a path inside the repo, relative to it
config.error.export_out_git error voice where: string, out: string, name: string, out_key: string = out, git_dir: string = .git {where}: {out_key} {out} of export "{name}" is in {git_dir}, which belongs to git
config.error.export_out_managed error voice where: string, out: string, name: string, managed: path, out_key: string = out, manifests: string = manifests/ {where}: {out_key} {out} of export "{name}" is {managed}, which homebot keeps for itself; put exports under
config.error.export_out_managed_inside error voice where: string, out: string, name: string, managed: path, out_key: string = out, manifests: string = manifests/ {where}: {out_key} {out} of export "{name}" is inside {managed}, which homebot keeps for itself; put exports under
config.error.export_out_outside error voice where: string, out: string, name: string, out_key: string = out {where}: {out_key} {out} of export "{name}" leads outside the repo
config.error.export_out_private error voice where: string, out: string, name: string, out_key: string = out, private: string = private/ {where}: {out_key} {out} of export "{name}" is in {private}, where your secrets are
config.error.export_out_root error voice where: string, out: string, name: string, out_key: string = out {where}: {out_key} {out} of export "{name}" is the repo itself; name a file or folder inside it
config.error.export_out_symlink error voice where: string, out: string, name: string, target: path, out_key: string = out {where}: {out_key} {out} of export "{name}" goes through a symlink to {target}, which is outside the repo, the repo itself, or a path homebot keeps for itself
config.error.export_profiles error voice where: string, profiles: string = profiles {where}.{profiles}: expected a list of profile names
config.error.export_required error voice where: string, key_name: string {where}: {key_name} is required
config.error.exports error voice file: path, exports: string = exports {file}: {exports} must be a list
config.error.limits error voice file: path, limits: string = limits {file}: {limits} must be a mapping
config.error.limits_max error voice file: path, max_file: string = limits.maxFileMB {file}: {max_file} must be a positive number
config.error.link_gone error voice file: path, link: string = link, marks: string = (), autolink: string = autolink/, example: string = autolink/common/(claude)/settings.json {file}: "{link}" is gone. Wrap a folder's name in {marks} in {autolink} to keep it a real folder, e.g.
config.error.name error voice where: string, name_key: string = name, example: string = zork {where}: {name_key} must be a word, the command you call your homebot by, such as
config.error.name_syntax error voice where: string, value: string, name_key: string = name, rule: string = 2 to 32 lowercase letters, digits and hyphens, starting with a letter {where}: {name_key} "{value}" must be
config.error.not_mapping error voice file: path {file}: expected a mapping at the top level
config.error.old_name error voice path: path, config_file: string = homebot.yml homebot reads {config_file} now: rename {path} to
config.error.persona error voice where: string, key: string = persona, allowed: string = none or a lowercase id of at most 32 letters, digits and hyphens, starting with a letter {where}: {key} must be a string:
config.error.persona_syntax error voice where: string, value: string, key: string = persona, allowed: string = none or a lowercase id of at most 32 letters, digits and hyphens, starting with a letter {where}: {key} "{value}" must be
config.error.profiles error voice file: path, profiles: string = profiles {file}: {profiles} must be a mapping
config.error.profiles_default error voice file: path, default_key: string = profiles.default {file}: {default_key} must be a profile name
config.error.profiles_hosts error voice file: path, hosts_key: string = profiles.hosts {file}: {hosts_key} must map host names to profile names
config.error.string_list error voice where: string {where}: expected a string or a list of strings
config.error.triage error voice file: path, triage: string = triage {file}: {triage} must be a mapping
config.error.triage_watch error voice file: path, value: string, watch: string = triage.watch, star: string = /, dot_star: string = /. {file}: {watch} entries end in {star} or {dot_star} (got "{value}")
config.error.unknown_key error voice where: string, key_name: string, keys: string {where}: unknown key "{key_name}" (expected {keys})
config.error.unknown_key_under error voice where: string, key_name: string, parent: string, keys: string {where}: unknown key "{key_name}" under {parent} (expected {keys})
config.error.unknown_os error voice where: string, value: string, linux: string = linux, macos: string = macos {where}: unknown OS "{value}" (use {linux} or {macos})
config.error.yaml error voice file: path, parser_message: string, yaml: string = YAML {file}: invalid {yaml}:
config.warning.update warning fact value: string, file: path, line: int Unknown update value {value} at {file}:{line}; using off.

conflict

ID Kind Class Placeholders English
conflict.different error voice already exists with different content
conflict.file_vs_folder error voice is a file, but the repo has a folder here
conflict.folder_vs_file error voice is a folder, but the repo has a file here
conflict.symlink_outside error voice dest: path is a symlink to {dest}, outside this repo

context

ID Kind Class Placeholders English
context.error.no_config error voice config: string = homebot.yml, self: string, env: string = HOMEBOT_ROOT No {config} found. Run {self} inside your home repo, or set {env}.
context.error.no_home error voice env: string = HOME {env} is not set.
context.error.platform error voice platform: string, oses: string = linux and macos homebot supports {oses}, not {platform}.
context.hint.setup hint voice New here? This clones your home repo or starts one:

export

ID Kind Class Placeholders English
export.error.empty_file error voice out: path produced an empty file; kept the previous
export.error.empty_folder error voice out: path produced an empty folder; kept the previous
export.error.exit error voice code: int, stderr: string (optional) exited with {code}
export.error.kept_aside error voice error: string, path: path {error}
The previous export is kept at {path}.
export.error.no_output error fact out: path the command did not write {out}, the file given to it as {{out}}
export.error.out_is_file error voice out: path, out_key: string = out wrote a folder, but {out} is a file; kept the file. Remove it yourself, or give the export another
export.error.out_is_folder error voice out: path, out_key: string = out wrote a file, but {out} is a folder; kept the folder. Remove it yourself, or give the export another
export.error.unknown error voice names: string, known: string No export named {names} for this OS. Exports here: {known}.
export.line.failed status fact label: string, name: string, error: string {label} {name}:
export.line.ok status fact label: string, out: path {label}
export.line.skipped status fact label: string, name: string, reason: string {label} {name}:
export.reason.not_installed status voice tool: string {tool} is not installed
export.status.none status voice config: string = homebot.yml No exports configured for this OS in {config}.
export.warning.left_behind warning voice path: path The temporary folder {path} could not be removed. It is safe to delete.
export.where label mixed name: string homebot.yml export
export.word.none label voice none

format

ID Kind Class Placeholders English
format.ago.days label voice d: int {d}d ago
format.ago.hours label voice h: int {h}h ago
format.ago.just_now label voice just now
format.ago.minutes label voice m: int {m}m ago
format.command hint fact command: string
format.failure.tool_line error fact tool: string (optional), line: string {tool}:
format.size label fact value: string, unit: string {value}

fsutil

ID Kind Class Placeholders English
fsutil.error.bad_json error voice path: path, format: string = JSON {path} is not valid {format}. Fix or delete it (it is machine state, safe to delete).

git

ID Kind Class Placeholders English
git.error.failed error voice args: string, git: string = git {git} {args} failed.
git.gitconfig_aside hint fact mv ~/.gitconfig ~/.gitconfig.homebot-backup-$(date +%Y%m%d-%H%M%S)
git.identity_fix hint fact mkdir -p ~/.config/git && git config --file ~/.config/git/config user.name "Your Name" && git config --file ~/.config/git/config user.email [email protected]
git.signing_off hint fact git config --file ~/.config/git/config.local commit.gpgsign false && git config --file ~/.config/git/config.local tag.gpgsign false

guard

ID Kind Class Placeholders English
guard.all_sealed_deleted error mixed n: int This commit deletes {n:# sealed file|all # sealed files} in private/ and leaves none: private/ is missing, moved or emptied. If that is a mistake, put it back and unstage the deletions with the first command. If you mean to remove your secrets from the repo, commit with git yourself, in the home repo, with the second:
git restore --staged private
git commit --no-verify – private
guard.bullet error fact problem: string -
guard.check_failed error voice message: string Could not check the staged files:
guard.gitleaks_failed error mixed why: string gitleaks failed to run:
guard.gitleaks_failed.exit_code error voice code: int exit code
guard.headline error voice homebot refused this commit:
guard.hooks_path_overridden error voice path: string, want: path core.hooksPath is {path} after homebot set it to {want}: a worktree config or an include overrides it, so the commit guard would not run. Remove that setting.
guard.leak error mixed gitleaks_output: string gitleaks found something that looks like a secret. Move it to private/ (homebot pack --private <path>) or unstage it.
guard.no_gitleaks error mixed gitleaks is not installed, so this commit can't be checked for leaked secrets. Install it:
brew install gitleaks
guard.not_home error voice repo: path {repo} has no homebot.yml, so this commit can't be checked. Refusing.
guard.not_sealed error mixed file_path: path {file_path} is named like a sealed file but is not age-encrypted. Unstage it:
git rm --cached
guard.plaintext error mixed file_path: path {file_path} is plaintext. Only *.age files may be committed from private/. Unstage it:
git rm --cached
guard.plaintext_not_ignored error mixed file_path: path, gitignore: path {file_path} is plaintext, and {gitignore} does not ignore it, so every save stages it again. Only *.age files may be committed from private/: edit {gitignore} so it ignores the file, then unstage it:
git rm --cached
guard.private_gitlink error mixed file_path: path {file_path} is a repository (a submodule or an embedded repo). Only *.age files may be committed from private/. Unstage it:
git rm --cached
guard.private_not_folder error mixed file_path: path {file_path} is staged as a symlink or a file, not a folder: committing it would drop every sealed secret from the repo. Make private a real folder again, then unstage it:
git rm --cached
guard.script.no_runtime error mixed homebot: homebot isn't installed, so this commit can't be checked. Refusing.
guard.seal_failed error voice message: string Could not seal secrets:
guard.too_big error mixed file_path: path, size: string, limit: string {file_path} is {size} (limit {limit} MB). Unstage it and add it to .gitignore.

help

ID Kind Class Placeholders English
help.action.about help mixed self: string Runs one action with the environment a profile step gets. Everything after
the name goes to the action, so {self} action &lt;name&gt; --help reaches the
action; this page is {self} action --help.
help.action.example.1 help mixed add the vendor apt repositories
help.action.summary help voice run one action by hand
help.action.usage help fact self: string {self} action <name> [args…]
help.actions.about help mixed Lists the actions profile steps can use: the built-in ones (link, unlock,
run) and the scripts in homebot/actions/.
help.actions.summary help voice list the actions profiles can use
help.actions.usage help fact self: string {self} actions
help.cleanup.about help mixed self: string Goes through the backups {self} link --backup left
(<name>.homebot-backup-<time>) one at a time. Each shows how it differs from
what is linked there now (beside the choices, when fzf is installed), and you
pick:

delete remove the backup; what is linked there now stays
keep leave it; homebot asks again next time
use copy the backup over the repo file, then remove it
merge take some of the backup's lines into the repo file

merge opens lazygit when it is installed. The backup's lines are the green
ones: space takes the line under the cursor, shift+arrows select several, d
drops them, q finishes. Without lazygit it is git add -p: y takes a block, n
skips it, s splits it smaller, e edits it. What you took is written to the
repo file, and the same backup comes back with what is left, so you can
delete it.
help.cleanup.option.list help voice only list the backups
help.cleanup.summary help mixed go through what link --backup moved aside
help.cleanup.usage help fact self: string {self} cleanup
help.completion.about help voice Prints a completion script for bash, zsh or fish. Load it in your shell when an install does not include completion files.
help.completion.example help mixed self: string print the zsh script; load it for this session with source <({self} completion zsh)
help.completion.summary help voice print a shell completion script
help.completion.usage help fact self: string {self} completion bash|zsh|fish
help.export.about help mixed Writes what is installed (Brewfile, apt and flatpak lists, vendor apt
repositories…) into manifests/, as configured under exports in homebot.yml.
Without names it runs every export for this OS. The background helper runs
them about once a day.
help.export.example.1 help mixed after installing a package from a new apt repository
help.export.summary help mixed snapshot installed packages into manifests/
help.export.usage help fact self: string {self} export [name…]
help.group.keeping_order label voice Keeping order
help.group.moving_in label voice Moving in
help.group.secrets label voice Secrets
help.hook.about help mixed The check git runs before each commit in the repo (installed by homebot
setup). It refuses plaintext under private/ and anything gitleaks flags.
help.hook.summary help voice the commit guard
help.hook.usage help fact homebot hook pre-commit
help.inbox.about help mixed self: string Lists what needs you, most urgent first, each with the command that fixes it,
and what the background helper did since you last looked. {self} inbox is
the same command.
help.inbox.option.all help voice show every item, not only the first five
help.inbox.summary help voice what needs you (the inbox)
help.inbox.usage help fact self: string {self} [–all]
help.inventory.about help voice One screen: this machine's profile and whether it changed since the last
unpack, links, secrets, things to triage, the repo and its remote, package
exports and the background helper.
help.inventory.summary help voice what's managed and what isn't
help.inventory.usage help fact self: string {self} inventory
help.keys.about help mixed self: string Creates the age key pair that seals private/. It asks for a passphrase, then
writes private/identity.age (the key, encrypted with that passphrase) and
private/recipients.txt (the public key). Run it once ever; other machines get
the key with the repo and run {self} unlock.
help.keys.summary help voice create the key pair (asks for a passphrase)
help.keys.usage help fact self: string {self} keys init
help.link.about help mixed self: string Links everything under autolink/ (and unlocked secrets under private/) into
$HOME. It never overwrites anything: what is in the way is listed as blocked.
A file identical to the repo's copy is replaced by the link, since nothing is
lost.

–backup moves the blockers aside first, renamed <name>.homebot-backup-<time>,
and then links. {self} cleanup goes through those backups later.
help.link.option.backup help voice move what is in the way aside, then link
help.link.option.dry_run help voice show what would change, change nothing
help.link.summary help voice make every link, show what's in the way
help.link.usage help fact self: string {self} link
help.lock.about help mixed Seals the secrets in private/ that changed since they were last sealed. The
background helper does this on its own before each autosave.
help.lock.option.ours help voice for conflicts, keep this machine's version
help.lock.option.wipe help voice also delete the decrypted copies (keeps any that aren't safely sealed)
help.lock.summary help voice encrypt changed secrets
help.lock.usage help fact self: string {self} lock
help.name.about help voice Shows the name in homebot.yml and the name that works here. Give a word
to make it a command on this machine, or use --off to remove a link homebot
made. A name may need a new shell before it works.
help.name.option.off help voice remove the name and a link homebot made
help.name.summary help voice show, change or turn off your homebot's command name
help.name.usage help fact self: string {self} name [word]
help.next.about help mixed Runs the fix for the first inbox item, the command shown next to it. When the
fix is a shell command homebot shouldn't run for you, it prints it instead.
help.next.summary help voice do the first thing in the inbox
help.next.usage help fact self: string {self} next
help.overview.footer help mixed self: string Details, options and examples for any command: {self} <command> --help
help.overview.row help voice usage: string, summary: string {usage}
help.overview.title help voice homebot: Attention-Deficit Home Discipline
help.pack.about help mixed self: string Moves a file or folder from $HOME into the repo and puts a link in its place,
so it is tracked from then on. It goes to autolink/common unless --layer says
otherwise. With --private it is sealed under private/ (encrypted with age)
instead. Commit it with {self} save.
help.pack.example.1 help mixed track Zed's settings on every machine
help.pack.example.2 help mixed track it on Linux only
help.pack.example.3 help voice track a key, encrypted
help.pack.option.layer help voice the layer to put it in (default: common)
help.pack.option.private help mixed a secret: seal it under private/
help.pack.summary help mixed move something from $HOME into the repo, link it back
help.pack.usage help fact self: string {self} pack <path>…
help.page.commands_label label voice Commands:
help.page.examples_label label voice Examples:
help.page.help_option help voice this page
help.page.options_label label voice Options:
help.page.row help voice left: string, right: string {left}
help.page.usage_label label voice Usage:
help.persona.about help fact List, inspect, create, and choose the voice homebot speaks in.
help.persona.ids.about help fact Lists every voiced message id with its English text and its placeholders:
the ids a persona file can give lines for.
help.persona.ids.summary help fact list the message ids a persona can give lines for
help.persona.ids.usage help fact self: string {self} persona ids
help.persona.list.about help fact Lists the built-in personas and the files in your personas folder, one per line:
a * on the one in use, its id, name, where it comes from and its tagline.
A persona that cannot be used shows why in place of its name.
help.persona.list.summary help fact list the personas you can choose
help.persona.list.usage help fact self: string {self} persona list
help.persona.new.about help fact Writes personas/<id>.toml in your config folder and never overwrites a file.
Without --from it extends neatpik and lists every voiced message as a comment;
with --from it starts from a copy of that persona's header, language, colours
and lines.
help.persona.new.summary help fact start a persona file of your own
help.persona.new.usage help fact self: string {self} persona new <id>
help.persona.option.all_variants help fact show every valid variant in a preview
help.persona.option.event help fact preview one voiced message id
help.persona.option.from help fact copy an existing persona's header and lines when creating a new one
help.persona.preview.about help fact Shows the inbox, the shell nudge, the notification and the save results in
the persona's voice, once for a light and once for a dark terminal. --event
shows one voiced message id; --all-variants shows every valid variant.
help.persona.preview.summary help fact see a persona in light and dark terminals
help.persona.preview.usage help fact self: string {self} persona preview <id>
help.persona.show.about help fact Shows a persona's emoji, name and tagline, its three colours (accent, ok and
muted, for light and dark terminals) and a few of its lines in its own voice.
help.persona.show.summary help fact show a persona's header, colours and sample lines
help.persona.show.usage help fact self: string {self} persona show <id>
help.persona.summary help fact list and manage personas
help.persona.usage help fact self: string {self} persona [command]
help.persona.use.about help fact Writes persona: in homebot.yml, after checking that the persona exists and
loads. none turns the voice off. The shell's nudge and prompt symbol are
refreshed at once.
help.persona.use.summary help fact choose the persona for this home repo
help.persona.use.usage help fact self: string {self} persona use <id|none>
help.persona.validate.about help fact Checks a persona and every persona it extends, and prints each problem with
the file it is in. Give an id, or the path of a file you have not installed
yet. Without one it checks the persona this home repo selects.
help.persona.validate.summary help fact check a persona and the personas it extends
help.persona.validate.usage help fact self: string {self} persona validate [id|file]
help.refresh.about help voice Recomputes the inbox cache the shell prompt reads. Most commands do this on
their own when they finish.
help.refresh.summary help voice recompute the inbox the prompt shows
help.refresh.usage help fact self: string {self} refresh
help.remote.about help mixed Without a remote, offers to create a private repository with gh (GitHub) or
glab (GitLab), when one is installed and logged in, or takes a URL you paste.
Then it pushes. With a URL, makes that the remote (origin).

With a remote already set, checks that it can be reached. When an https
remote fails for lack of a login and you have an ssh key, it offers the ssh
address of the same repository.
help.remote.example.1 help voice check the remote, or set one up
help.remote.example.2 help voice use this one
help.remote.summary help voice set up where the repo is backed up
help.remote.usage help fact self: string {self} remote [url]
help.save.about help mixed Seals changed secrets, commits the changes to tracked files and package
snapshots, then pulls (rebasing local commits) and pushes. New files aren't
committed: triage decides about them first. The background helper does the
same on its own (autosave in homebot.yml).
help.save.option.message help voice the commit message (default: one listing the files)
help.save.option.no_push help voice commit and pull, but don't push
help.save.summary help voice commit, pull and push
help.save.usage help fact self: string {self} save
help.setup.about help mixed Takes you from nothing to an empty inbox, one question at a time. It checks
for git and gitleaks, clones your home repo or starts a new one in ~/.home,
installs the commit guard and the background helper (a systemd user timer on
Linux, a launchd agent on macOS), and offers to load the shell integration,
back the repo up and commit. Steps already done are skipped, so running it
again is safe. Without a terminal it asks nothing, creates no repo, and says
what is left.
help.setup.option.name help voice choose a command name for your homebot
help.setup.option.persona help voice choose the persona for this home repo
help.setup.option.remove help voice uninstall the background helper
help.setup.summary help voice set up this machine, from nothing to an empty inbox
help.setup.usage help fact self: string {self} setup
help.shell.about help mixed Prints the zsh integration: the prompt line that says when something needs
you, refreshed in the background. Load it from .zshrc:

eval "$(homebot shell zsh)"
help.shell.summary help voice print the shell integration
help.shell.usage help fact self: string {self} shell zsh
help.tidy.about help mixed Runs what the background helper runs on its timer: installs the commit guard
if it's missing, seals secrets, refreshes package exports that are due,
autosaves and syncs (when homebot.yml turns autosave on), fixes links that
are safe to fix, and refreshes the inbox.
help.tidy.option.notify help voice show a desktop notification when something needs you
help.tidy.option.quiet help voice print nothing
help.tidy.summary help voice run the background chores now
help.tidy.usage help fact self: string {self} tidy
help.triage.about help mixed Asks once about each new thing in the watched folders (~/.config/, ~/.) and
each untracked file in the repo. Each answer is saved right away:

t track it everywhere (moves it into autolink/common, links it back)
o track it on this OS only
i ignore it for good (written to decisions.yml)
s snooze it for 7 days (this machine only)
enter next
q stop
help.triage.summary help voice decide about new things: track, ignore or snooze
help.triage.usage help fact self: string {self} triage
help.unlink.about help mixed self: string Removes every link homebot made. The files stay in the repo, so the links
come back with the next {self} link, and within the hour from the background
helper ({self} tidy). To keep a file unlinked, take it out of the repo.
help.unlink.summary help mixed remove every link homebot made (files stay in the repo)
help.unlink.usage help fact self: string {self} unlink
help.unlock.about help mixed Decrypts the secrets in private/ and links them into $HOME. A secret that
changed both here and in the repo is left alone and listed as a conflict.
help.unlock.option.theirs help voice for conflicts, take the repo's version
help.unlock.summary help mixed decrypt private/ (asks for the passphrase)
help.unlock.usage help fact self: string {self} unlock
help.unpack.about help mixed Runs a profile's steps in order, without asking first: package installs
(brew, apt, flatpak…), links, secrets and run: commands. Each step is
printed as it starts. Without a name it uses this machine's profile from
homebot.yml (profiles.hosts, else profiles.default).

Preview the steps with --dry-run. A step that fails stops the run and prints
the --from that resumes after you fix it. Steps that are already done (a
package that is installed, a link that exists) do nothing the second time.
help.unpack.example.1 help voice what this machine's profile would do
help.unpack.example.2 help voice resume the server profile at step 4
help.unpack.option.dry_run help voice list the steps without running any
help.unpack.option.from help voice start at step N, skipping the ones before
help.unpack.summary help voice install and link everything a profile lists
help.unpack.usage help fact self: string {self} unpack [profile]
help.version.about help mixed self: string Prints the version of this homebot. {self} --version and {self} -v
print the same.
help.version.option_check help voice Check the latest release and show how this install can upgrade
help.version.summary help voice print the version
help.version.usage help fact self: string {self} version

helper

ID Kind Class Placeholders English
helper.description.launchd label mixed hourly launchd agent sh.homebot.tidy
helper.description.systemd label mixed hourly systemd timer homebot-tidy.timer
helper.error.launchctl error voice command: string = launchctl bootstrap {command} failed.
helper.error.no_systemd error voice No systemd user session here, so the hourly helper can't be installed.
Run this yourself, or from cron:
helper.error.systemctl error voice args: string, command: string = systemctl --user {command}{args} failed.
helper.unit.service_description label voice homebot: keep the home repo tidy and say what needs attention
helper.unit.timer_description label mixed Run homebot tidy every hour

identity

ID Kind Class Placeholders English
identity.error.config_failed error voice scope: string, setting: string, value: string, git_config: string = git config {git_config} {scope} {setting} {value} failed.
identity.hint.set_once hint voice Set it once:
identity.hint.track hint voice Track it so every machine gets it:
identity.hint.track_cmd hint fact self: string {self} pack ~/.config/git/config
identity.prompt.email prompt voice Your email:
identity.prompt.name prompt voice Your name:
identity.status.skipped hint voice Skipped. Set it later:
identity.success.saved success voice name: string, email: string, config: string saved {name} <{email}> in
identity.warning.unknown warning voice bot: string (optional) Git doesn't know who you are yet, and {bot} commits as you.
identity.where.global label voice your global git config

inbox

ID Kind Class Placeholders English
inbox.backups.detail inbox fact paths: string
inbox.backups.title inbox voice self: string, n: int, link: string = link {n:# backup|# backups} that {self}{link} moved aside: compare, then delete or keep
inbox.behind.title inbox voice n: int {n:# new commit|# new commits} on the remote
inbox.blocked.title inbox voice A commit was refused
inbox.broken.title inbox voice check: string Could not check
inbox.cache.count nudge fact n: int, urgent_mark: string (optional) {n}
inbox.diverged.title inbox voice This machine and the remote both have new commits
inbox.done.heading status voice Done for you since you last looked:
inbox.done.item status fact journal_message: string
inbox.export_failing.title inbox voice name: string Export {name} is failing
inbox.gitconfig_shadow.detail inbox voice self: string, repo_config: string = ~/.config/git/config, cleanup: string = cleanup, local_config: string = ~/.config/git/config.local Git reads it after {repo_config}, so its name, email or signing win. Move it aside; {self}{cleanup} then shows it, and anything this machine needs goes in {local_config}.
inbox.gitconfig_shadow.title inbox voice gitconfig: string = ~/.gitconfig {gitconfig} overrides the git config from the repo
inbox.header.clear success voice nothing needs you. Home is in order.
inbox.header.count inbox voice n: int {n:# thing needs|# things need} you
inbox.header.prefix inbox fact bot: string (optional), host: string {bot} Β· {host} Β·
inbox.header.urgent inbox voice n: int ({n} urgent)
inbox.helper_no_linger.detail inbox voice systemd ends your timers with your last session; with lingering on it keeps them running
inbox.helper_no_linger.title inbox voice The background helper stops when you log out
inbox.helper_path.detail inbox voice paths: string Run setup to refresh these recorded paths:
inbox.helper_path.title inbox voice An installed helper or guard points at a broken homebot path
inbox.helper_stale.title inbox voice ago: duration The background helper last ran
inbox.item.fix hint fact fix: string β†’
inbox.item.line inbox fact index: int, mark: string, title: string {index} {mark}
inbox.link_conflict.detail inbox fact paths: string
inbox.link_conflict.title inbox voice n: int {n:# file is|# files are} in the way of links
inbox.link_invalid.detail inbox fact reasons: string
inbox.link_invalid.title inbox voice n: int {n:# layout error|# layout errors} in the repo; those parts aren't linked
inbox.link_pending.title inbox voice n: int {n:# link|# links} to make or fix
inbox.mark.todo label voice β€’
inbox.mark.urgent label voice !
inbox.missing_profile.detail inbox voice Write the steps that set up this machine
inbox.missing_profile.title inbox voice profile: string Profile {profile} does not exist yet
inbox.more hint voice n: int …and {n} more:
inbox.name_blocked.title inbox voice name: string The name {name} is blocked on this machine
inbox.name_helper_path.title inbox voice name: string The helper cannot use the name {name} yet
inbox.name_no_bin.title inbox voice name: string The name {name} needs a bin directory here
inbox.name_shadowed.detail inbox voice path: path The other program is at {path}.
inbox.name_shadowed_other.title inbox voice name: string Another program shadows the name
inbox.name_shadowed_ours.title inbox voice name: string The name {name} shadows another program
inbox.never_pushed.title inbox voice Not backed up yet: nothing pushed to the remote
inbox.never_unpacked.last inbox voice other: string (last unpacked: {other})
inbox.never_unpacked.title inbox voice profile: string, last: string (optional) Profile {profile} was never unpacked here
inbox.next_hint hint voice Do the first one now:
inbox.no_gitleaks.title inbox voice tool: string = gitleaks {tool} is missing, so every commit is refused
inbox.no_guard.title inbox voice The commit guard is not installed
inbox.no_helper.detail inbox voice It seals, exports, links and reminds you every hour
inbox.no_helper.title inbox voice The background helper is not installed
inbox.no_identity.detail inbox voice self: string, save: string = save Commits by {self}{save} and the hourly autosave fail without a name and email.
inbox.no_identity.title inbox voice Git doesn't know who you are
inbox.no_keys.title inbox voice Secrets are not set up yet
inbox.no_profile.detail inbox voice default_key: string = profiles.default, hosts_key: string = profiles.hosts, config_file: string = homebot.yml Set {default_key} or {hosts_key} in
inbox.no_profile.title inbox voice host: string No profile chosen for
inbox.no_remote.title inbox voice Not backed up: the repo has no remote
inbox.no_repo.title inbox voice repo: path {repo} is not a git repository
inbox.no_signing_key.detail inbox voice self: string, unlock: string = unlock Every commit fails until it's here. Restore it ({self}{unlock}), or stop signing on this machine only:
inbox.no_signing_key.title inbox voice key_path: path Commits are signed with {key_path}, which this machine doesn't have
inbox.notify.app_name notification fact homebot
inbox.notify.body notification voice title: string, more: string {title}{more}. Run:
inbox.notify.more notification voice n: int (+{n} more)
inbox.notify.title notification voice bot: string (optional) {bot} needs you
inbox.nudge nudge voice n: int, urgent: string, bot: string (optional) {bot}: {n:# thing needs|# things need} you{urgent}, run:
inbox.nudge.mark nudge fact 🚚
inbox.nudge.urgent nudge voice n: int ({n} urgent)
inbox.persona_broken.detail inbox fact self: string, id: string Run {self} persona validate {id} to see why.
inbox.persona_broken.title inbox fact id: string Persona {id} could not be loaded
inbox.profile_changed.title inbox voice profile: string Profile {profile} changed since the last unpack
inbox.secret_conflict.title inbox voice n: int {n:# secret|# secrets} changed here and on another machine
inbox.secret_locked.title inbox voice n: int {n:# secret is|# secrets are} still locked
inbox.secret_unsealed.title inbox voice n: int {n:# secret|# secrets} not sealed yet
inbox.secret_upstream.title inbox voice n: int {n:# secret|# secrets} changed on another machine
inbox.tidy_failed.title inbox voice step_name: string, ago: duration Automatic {step_name} failed
inbox.triage.detail inbox fact keys: string
inbox.triage.title inbox voice n: int {n:# new thing|# new things} to sort: track, ignore or snooze
inbox.uncommitted.title inbox voice n: int {n:# uncommitted change|# uncommitted changes}
inbox.unpack_preview inbox voice self: string, preview: string = unpack --dry-run It runs every step without asking; to see them first: {self}
inbox.unpushed.title inbox voice n: int {n:# commit|# commits} not pushed
inbox.unreachable.title inbox voice ago: duration Last reached the remote

inventory

ID Kind Class Placeholders English
inventory.exports.failing error voice name: string {name} failing
inventory.exports.never status voice name: string {name} never
inventory.exports.none status voice none configured
inventory.exports.ok status voice name: string, ago: duration {name}
inventory.helper.installed status voice ago: duration installed Β· last ran
inventory.helper.missing warning voice self: string, setup: string = setup not installed ({self}{setup})
inventory.helper.never_ran label voice never
inventory.label.exports label voice Exports
inventory.label.helper label voice Helper
inventory.label.links label voice Links
inventory.label.profile label voice Profile
inventory.label.repo label voice Repo
inventory.label.secrets label voice Secrets
inventory.label.triage label voice Triage
inventory.links.invalid error voice n: int , {n} layout errors
inventory.links.value status voice ok: int, to_fix: int, blocked: int, locked: int {ok} ok, {to_fix} to fix, {blocked} blocked, {locked} locked
inventory.profile.changed warning voice , changed since
inventory.profile.never status voice never unpacked here
inventory.profile.none warning voice none chosen for this machine
inventory.profile.unpacked status voice ago: duration unpacked
inventory.profile.value status voice profile: string, status: string {profile} Β·
inventory.repo.detached label voice detached
inventory.repo.never_pushed warning voice self: string, remote: string = remote (never pushed: {self}{remote})
inventory.repo.no_remote warning voice self: string, remote: string = remote (no remote: {self}{remote})
inventory.repo.not_repo error voice not a git repository
inventory.repo.upstream status voice upstream: string β†’
inventory.repo.value status voice branch: string, upstream: string, ahead: int, behind: int, uncommitted: int {branch}{upstream} Β· {ahead} ahead, {behind} behind, {uncommitted} uncommitted
inventory.row status fact row_label: string, value: string {row_label}
inventory.secrets.count status voice n: int, state: string {n}
inventory.secrets.no_keys warning voice self: string, keys_init: string = keys init no keys yet ({self}{keys_init})
inventory.secrets.none status voice none yet
inventory.title status fact self: string, host: string, os: string, root: path {self} inventory Β· {host} ({os}) Β·
inventory.triage.value status voice to_sort: int, ignored: int {to_sort} to sort, {ignored} ignored

keys

ID Kind Class Placeholders English
keys.error.mismatch error voice The passphrases didn't match; nothing was saved.
keys.hint.commit hint voice identity: string = private/identity.age, recipients: string = private/recipients.txt Commit {identity} and {recipients}:
keys.hint.commit_cmd hint fact self: string {self} save
keys.hint.passphrase hint voice bot: string (optional) Leave it empty and {bot} makes up a strong one and prints it. Save it in your password manager: without it, the secrets in this repo can't be recovered.
keys.prompt.confirm prompt voice Confirm passphrase:
keys.prompt.passphrase prompt voice Enter passphrase (leave empty to autogenerate a secure one):
keys.status.autogenerated status voice passphrase: string using autogenerated passphrase ""
keys.status.creating status voice bot: string (optional) Creating your secrets key. {bot} asks for a passphrase next.
keys.status.public_key status fact public_key: string
keys.success.created success voice Keys created. The public key:

label

ID Kind Class Placeholders English
label.export.failed label voice failed
label.export.skipped label voice skipped
label.export.unchanged label voice unchanged
label.export.updated label voice updated
label.link_op.adopt label voice adopt
label.link_op.conflict label voice blocked
label.link_op.create label voice link
label.link_op.invalid label voice invalid
label.link_op.locked label voice locked
label.link_op.prune label voice remove
label.link_op.replace label voice relink
label.link_op.unfold label voice unfold

layout

ID Kind Class Placeholders English
layout.both_layers error voice providers: string provided by both {providers}; keep it in one place
layout.dot_parens error voice raw: string, dot_names: string = . and … "{raw}" names no folder: {dot_names} would link outside the folder it is in; rename it
layout.double_parens error voice raw: string, name: string, marks: string = (), open: string = (, close: string = ) "{raw}": wrap the name in one pair of {marks}, like "{open}{name}"
layout.empty_parens error voice marks: string = () "{marks}" has no name inside
layout.file_parens error voice raw: string, name: string, marks: string = () {marks} marks folders only: rename "{raw}" to ""
layout.inner_error error fact path: path, error: string {path}:
layout.inner_file_parens error voice path: path, raw: string, name: string, marks: string = () {path}: {marks} marks folders only: rename "{raw}" to ""
layout.inside_repo error voice target: path would be linked at {target}, inside the home repo; rename it
layout.must_mark error voice raw: string, every_layer: string (optional), inner: path, open: string = (, close: string = ) rename "{raw}" to "{open}{raw}{close}"{every_layer}: it holds {inner}, which must not be a link, so it can't be one either
layout.must_mark.every_layer error voice in every layer
layout.old_name error voice raw: string, new: string "{raw}" is the old layout: rename it to ""
layout.outside_folder error voice target: path would be linked at {target}, outside the folder it is in; rename it
layout.spelling error voice marked: string, where_marked: string, plain: string, where_plain: string spelled "{marked}" in {where_marked} but "{plain}" in {where_plain}; use one spelling everywhere
layout.top_dot error voice raw: string, name: string, open: string = (, close: string = ) "{raw}": top-level names get their dot from homebot; rename it to "{open}{name}"
ID Kind Class Placeholders English
link.error.backup_exists error voice target: path, backup: path Cannot move {target} aside: {backup} is already there. Try again in a second.
link.error.changed error voice path: path, command: string = {self} link {path} changed while homebot was linking it, so it was left alone. Run {command} again.
link.hint.backup hint voice backup_pattern: string = *.homebot-backup-<time> To move what is in the way aside (renamed {backup_pattern}, nothing is deleted):
link.hint.backup_cmd hint fact self: string {self} link --backup
link.hint.compare hint voice Compare and delete them when you have a minute:
link.hint.compare_cmd hint fact self: string {self} cleanup
link.op.line status fact label: string, target: path, reason: string (optional) {label} {target}
link.status.dry_run_ok status voice n: int {n} already linked
link.status.interrupted status voice self: string, link: string = link Stopped; nothing else was moved or linked. Run {self}{link} again to finish.
link.status.moved_aside status voice path: path moved aside
link.summary.base status voice n: int, ok: int {n:# change|# changes}, {ok} already linked
link.summary.blocked warning voice n: int , {n} blocked
link.summary.invalid error voice n: int , {n:# layout error|# layout errors} in the repo
link.summary.locked status voice self: string, n: int, unlock: string = unlock , {n} locked ({self}{unlock})

lock

ID Kind Class Placeholders English
lock.status.nothing status voice Nothing to seal.
lock.status.wiped status voice sealed: int, n: int Sealed {sealed}, removed {n:# plaintext file|# plaintext files}.
lock.success.sealed success voice paths: string sealed
lock.warning.kept warning voice name: path, private: string = private/ kept {private}{name} (not safely sealed; resolve it first)

manifest

ID Kind Class Placeholders English
manifest.error.action_name error voice where: string, name: string {where}: "{name}" is not a valid action name
manifest.error.args error voice where: string {where}: arguments must be a value or a list of values
manifest.error.description error voice file: path, key: string = description {file}: {key} must be text
manifest.error.include error voice file: path, key: string = include {file}: {key} must be a profile name or a list of them
manifest.error.loop error voice chain: string Profiles include each other in a loop:
manifest.error.name error voice where: string, key: string = name {where}: {key} must be text
manifest.error.no_profile error voice name: string, dir: path No profile named "{name}" in {dir}.
manifest.error.no_profile.available error voice name: string, dir: path, names: string No profile named "{name}" in {dir}. Available:
manifest.error.not_mapping error voice file: path, steps: string = "steps:" {file}: expected a mapping with
manifest.error.old_extension error voice path: path, name: string, ext: string = .yml Profiles end in {ext} now: rename {path} to {name}
manifest.error.on error voice where: string, key: string = "on", oses: string = linux, macos {where}: {key} must be {oses}, or a list of them
manifest.error.on_os error voice where: string, value: string, key: string = "on", oses: string = linux or macos {where}: unknown OS "{value}" in {key} (use {oses})
manifest.error.one_action error voice where: string, names: string {where}: each step needs exactly one action, found
manifest.error.one_action.none error voice where: string {where}: each step needs exactly one action, found none
manifest.error.step_shape error voice where: string, shape: string = "- action: arguments" {where}: expected
manifest.error.steps error voice file: path, key: string = steps {file}: {key} must be a list
manifest.error.unknown_key error voice file: path, key_name: string, keys: string {file}: unknown key "{key_name}" (expected {keys})
manifest.error.unknown_variable error voice where: string, braced_key: string, vars: string {where}: unknown variable {braced_key} (available: {vars})
manifest.error.yaml error voice file: path, parser_message: string, yaml: string = YAML {file}: invalid {yaml}:
manifest.where.step label voice file: string, n: int {file} step

name

ID Kind Class Placeholders English
name.error.refused error voice name: string, reason: string, path: path Cannot use {name}: {reason} ({path})
name.error.refused_no_path error voice name: string, reason: string Cannot use {name}:
name.hint.path hint voice name: string Add ~/.local/bin to your PATH to type {name}; homebot works now.
name.journal.adopted status voice adopted this machine's name link
name.journal.made status voice made this machine's name link
name.journal.removed status voice removed this machine's name link
name.journal.repointed status voice re-pointed this machine's name link
name.reason.foreign error voice a foreign file already has that name; it was left untouched
name.reason.in_repo error voice the home repo already places that name in ~/.local/bin
name.reason.no_homebot error voice there is no stable homebot binary to link to
name.reason.on_path error voice a program with that name is on PATH
name.reason.reserved error voice homebot uses it as a command
name.reason.shell error voice the shell uses that word
name.reason.synced_bin error voice another tool manages ~/.local/bin
name.reason.syntax error voice use 2 to 32 lowercase letters, digits and hyphens, starting with a letter
name.reason.temp_blocked error voice the temporary link is occupied; your current link was kept
name.reason.tool error voice homebot runs a program by that name
name.status.configured status voice name: string Configured name:
name.status.effective status voice name: string Effective name here:
name.status.off success voice Name turned off; homebot works as before.
name.status.old_stops warning voice name: string The old name {name} stops working; no forwarding link is left.
name.status.set success voice name: string Name set to {name}.
name.warning.in_work_tree warning voice Your ~/.local/bin is inside a git work tree; another tool could commit this link.
name.why.bad_record status voice path: path The machine's name record at {path} cannot be read.
name.why.config_off status voice The machine still has a name link, but homebot.yml has no name.
name.why.link_broken status voice path: path The recorded link at {path} is missing or points elsewhere.
name.why.no_record status voice This machine has not recorded that name yet.
name.why.not_on_path status voice The name's link is not on this process's PATH.
name.why.recorded_other status voice recorded: string, configured: string This machine still uses {recorded}; run homebot name {configured} to finish the change.
name.why.shadowed status voice path: path Another program at {path} comes before the name's link on PATH.

next

ID Kind Class Placeholders English
next.hint.no_fix hint voice No automatic fix for this one; the detail above says what to change.
next.hint.run_yourself hint voice Run this yourself:
next.item.detail inbox fact detail: string
next.item.title inbox fact title: string
next.status.running status fact fix: string β†’
next.success.nothing success voice Nothing needs you.

pack

ID Kind Class Placeholders English
pack.error.already_in_repo error voice repo_path: path {repo_path} is already in the repo. Pack the new things inside it instead.
pack.error.inside_managed error voice path: path, dir: path {path} is inside {dir}, which is already managed. It is in the repo already.
pack.error.is_repo error voice path: path {path} is (or contains) the home repo itself.
pack.error.layer_not_linked error voice layer: string, os: string, layers: string The {layer} layer is not linked on {os}, so a file packed there could not be linked back (use {layers}).
pack.error.link_failed error voice path: path Moved {path} into the repo but could not link it back. Link it with:
pack.error.managed error voice path: path {path} is already managed.
pack.error.missing error voice path: path {path} does not exist.
pack.error.nested_repo error voice path: path, git_dir: string = .git {path} is a git repository of its own: the home repo would hold only a pointer to it, and its files would never reach the remote. Remove its {git_dir}, or leave it out of the home.
pack.error.no_args error voice What should be packed? e.g.
pack.error.no_keys error voice Create keys before packing secrets:
pack.error.outside_home error voice path: path Only things inside your home folder can be packed (got {path}).
pack.error.parens error voice name: string, marks: string = () "{name}" is wrapped in {marks}, which the repo uses to mark folders that must not be links, so it can't be tracked.
pack.error.plain_parent error voice repo_path: path, name: string, open: string = (, close: string = ) {repo_path} is a plain folder, so it can't hold a new folder that must stay real. Rename it to {open}{name}{close} in every layer first.
pack.error.private_reserved error voice path: path, private: string = private/, readme: string = README.md, gitignore: string = .gitignore, gitkeep: string = .gitkeep, recipients: string = recipients.txt, age_glob: string = *.age, git_dir: string = .git {path} can't go into {private}: git would stage it as plaintext there. {readme}, {gitignore}, {gitkeep} and {recipients} files, {age_glob} files and {git_dir} folders are the repo's own; rename or remove it first.
pack.error.source_not_removed error voice path: path, repo_path: path, reason: string Copied {path} into the repo as {repo_path}, but could not remove the original: {reason}
Remove it, then link the copy with:
pack.error.symlink error voice path: path {path} is a symlink. Pack the real file it points to instead.
pack.error.top_level error voice exceptions: string, name: string, home_prefix: string = ~/ Only dotfiles and {exceptions} can be tracked at the top of your home folder (got {home_prefix}{name}).
pack.error.unknown_layer error voice layer: string, layers: string Unknown layer "{layer}" (use {layers}).
pack.error.unreadable error voice path: path Can't read {path}, so homebot can't check it for a git repository of its own. Nothing was moved; make it readable, or leave it out of the home.
pack.hint.commit hint voice Commit it with:
pack.hint.commit_cmd hint fact self: string {self} save
pack.status.moved status voice from: path, to: path moved {from} β†’
pack.success.packed success voice from: path, to: path packed {from} β†’
pack.success.sealed_suffix success voice n: int (sealed {n})

persona

ID Kind Class Placeholders English
persona.diag.v0 error fact detail: string Unsafe text:
persona.diag.v1 error fact detail: string Invalid TOML:
persona.diag.v11 error fact detail: string Unknown message:
persona.diag.v12 error fact detail: string Message cannot be voiced:
persona.diag.v13 error fact detail: string Empty line variants:
persona.diag.v14 error fact detail: string Invalid line syntax:
persona.diag.v15 error fact detail: string Missing placeholder:
persona.diag.v16 error fact detail: string Unknown placeholder:
persona.diag.v17 error fact detail: string Invalid plural selector:
persona.diag.v18 error fact detail: string Hidden count:
persona.diag.v19 error fact detail: string Whitespace changed:
persona.diag.v2 error fact detail: string Unknown field:
persona.diag.v20 error fact detail: string Message prefix changed:
persona.diag.v21 error fact detail: string Punctuation changed:
persona.diag.v22 error fact detail: string Append boundary changed:
persona.diag.v23 error fact detail: string Adjacent placeholders separated:
persona.diag.v24 error fact detail: string Line breaks changed:
persona.diag.v26 error fact detail: string Line too long:
persona.diag.v28 error fact detail: string Invalid persona file:
persona.diag.v3 error fact detail: string Invalid schema:
persona.diag.v4 error fact detail: string Invalid id:
persona.diag.v5 error fact detail: string Invalid name:
persona.diag.v6 error fact detail: string Invalid emoji:
persona.diag.v7 error fact detail: string Invalid tagline:
persona.diag.v9 error fact detail: string Invalid header:
persona.diag.v9_cycle error fact detail: string Extends cycle: {detail} is already earlier in the chain
persona.diag.v9_depth error fact detail: string Extends chain too long: {detail} would be a fifth file (four at most)
persona.diag.w1 warning fact detail: string Low colour contrast:
persona.diag.w2 warning fact detail: string Emoji width may vary:
persona.diag.w4 warning fact detail: string Duplicate line variant:
persona.diag.w5 warning fact detail: string Long line variant:
persona.diag.w6 warning fact detail: string Non-English language:
persona.diag.w7 warning fact detail: string Possible new fact:
persona.error.event error fact id: string No voiced message id:
persona.error.exists error fact path: path Persona file already exists:
persona.error.id error fact id: string Invalid persona id:
persona.error.not_found error fact id: string, self: string No persona named {id}. See {self} persona list.
persona.error.reserved error fact self: string none is reserved for the neutral voice, so it has no persona file. To switch the voice off, run {self} persona use none.
persona.error.unusable error fact id: string Persona {id} is unusable.
persona.error.usage error fact self: string Use {self} persona list, show, use, new, validate, preview, or ids.
persona.hint.pack hint fact self: string, path: path Keep it in the home repo: {self} pack
persona.label.broken label fact mark: string, id: string, reason: string {mark} {id} [unusable]
persona.label.color label fact token: string, light: string, dark: string {token}: light {light}, dark
persona.label.color_unset label fact token: string {token}: terminal default
persona.label.color_unset_side label fact terminal default
persona.label.diagnostic label fact level: string, detail: string {level}:
persona.label.header label fact emoji: string, name: string, tagline: string {emoji} {name} β€”
persona.label.header_untagged label fact emoji: string, name: string {emoji}
persona.label.ids label fact id: string, kind: string, english: string, slots: string {id} [{kind}]: {english}
persona.label.row label fact mark: string, id: string, name: string, source: string, tagline: string {mark} {id} {name} [{source}]
persona.label.theme label fact theme: string {theme} theme
persona.label.variant label fact id: string, n: int, line: string {id} [{n}]:
persona.status.none status fact Neutral voice selected.
persona.status.valid status fact id: string Persona {id} is valid.
persona.success.created success voice path: path Created persona file:
persona.success.greeting success voice bot: string (optional) {bot} is ready.
persona.success.selected success voice id: string {id} is selected.
persona.warning.env warning fact HOMEBOT_PERSONA overrides persona: in homebot.yml for this process.
persona.warning.unusable warning fact id: string, self: string Persona {id} could not be loaded; using Neatpik. Run {self} persona validate {id}.

remote

ID Kind Class Placeholders English
remote.choice.forge choice mixed forge_key: string, forge: string, cli: string {forge_key} create a private {forge} repository (with {cli})
remote.choice.later choice mixed enter not now
remote.choice.url choice mixed u use the URL of a repository you already have
remote.error.bad_name error voice name: string, rule: string = letters, digits, ".", "-" and "_" only "{name}" won't do:
remote.error.create error voice cli: string, name: string {cli} couldn't create {name}.
remote.error.no_address error voice cli: string, name: string {cli} created {name} but didn't say its address. Add it with:
remote.error.set_url error voice url: string Couldn't set the remote to {url}.
remote.error.unreachable error voice Can't reach the remote.
remote.error.unreachable_login error voice https: string = https Can't reach the remote: git has no login for {https} here.
remote.error.unreachable_ssh error voice Can't reach it over ssh either.
remote.heading.none status voice Nothing is backed up yet: the repo has no remote.
remote.hint.create_cmd hint fact self: string {self} remote
remote.hint.create_in_terminal hint voice forges: string Run this in a terminal to create a private {forges} repository for it:
remote.hint.existing hint voice Use a repository you already have:
remote.hint.first_save hint voice Nothing committed yet. This commits and pushes:
remote.hint.have_key hint voice You have an ssh key, so the same repository can be reached over ssh:
remote.hint.https hint voice cli: string, ssh_dir: string = ~/.ssh, https: string = https There's no ssh key in {ssh_dir}, so the remote uses {https}. To let git use {cli}'s login:
remote.hint.https_cmd hint fact cli: string {cli} auth setup-git
remote.hint.log_in hint voice Log git in:
remote.hint.log_in_or_ssh hint voice ssh_dir: string = ~/.ssh Log git in to that host, or add an ssh key to {ssh_dir} and switch to the ssh address:
remote.hint.login hint voice cli: string, forge: string, auth_login: string = auth login {cli} is installed but not logged in. To offer {forge} too: {cli}
remote.hint.or_existing hint voice Or use a repository you already have:
remote.hint.or_ssh hint voice ssh_dir: string = ~/.ssh Or add an ssh key to {ssh_dir} and switch to the ssh address:
remote.hint.pick hint voice pick one of the letters above
remote.hint.rename hint voice names: string, bot: string (optional), origin: string = origin This repo has a remote named {names}, but {bot} pushes to the one named {origin}. Rename it:
remote.hint.rename_cmd hint fact repo: path, name: string git -C {repo} remote rename {name} origin
remote.hint.save_cmd hint fact self: string {self} save
remote.hint.ssh_cmd hint fact self: string, ssh_url: string {self} remote
remote.hint.to_switch hint voice To switch:
remote.hint.url_cmd hint fact self: string {self} remote <url>
remote.login.gh hint fact gh auth setup-git
remote.login.glab hint fact glab auth login
remote.prompt.choice prompt fact >
remote.prompt.name prompt voice forge: string, suggested: string Name for the new private {forge} repository [{suggested}]:
remote.prompt.switch prompt voice choice: string = [Y/n] Switch to it?
remote.prompt.url prompt voice URL:
remote.repo_description label voice Dotfiles, kept by homebot
remote.status.git_said status fact line: string git:
remote.status.kept_https status voice https: string = https Kept {https}. To switch later:
remote.status.not_now status voice Not now. When you're ready:
remote.status.ssh_url status fact ssh_url: string
remote.status.up_to_date status voice Already backed up: the remote has every commit.
remote.status.url status fact url: string
remote.success.created success voice name: string, forge: string created {name}, a private {forge} repository
remote.success.pushed success voice pushed the repo is backed up
remote.success.reachable success voice url: string reachable
remote.success.remote success voice url: string remote
remote.warning.waiting warning voice The remote has new commits. Commit or discard the changes here, then:

save

ID Kind Class Placeholders English
save.commit.autosave commit mixed host: string chore(autosave): sync
save.commit.body commit mixed n: int, host: string, os: string, files: string {n} file(s) changed on {host} ({os}):

save.commit.body_item commit fact file_path: path -
save.commit.body_more commit voice n: int - …and {n} more
save.commit.manual commit mixed host: string chore(home): save changes from
save.error.diverged error voice repo_abs: path, git_prefix: string = git -C , rebase: string = pull --rebase This machine and the remote changed the same files. Resolve it by hand:
{git_prefix}{repo_abs}
save.error.fast_forward error voice Could not fast-forward to the remote.
save.error.git_add error voice git_add: string = git add {git_add} failed.
save.error.push error voice Push failed.
save.error.rebase_stuck error voice repo_abs: path, continue_cmd: string = git rebase --continue, git_prefix: string = git -C , abort: string = rebase --abort This machine and the remote changed the same files, and git could not undo its rebase: {repo_abs} is still in the middle of one. Resolve the conflicts and run {continue_cmd}, or give up on it with:
{git_prefix}{repo_abs}
save.error.refused error voice reason: string Commit refused:
save.error.refused_no_reason label voice git gave no reason
save.status.nothing status voice Nothing new to commit.
save.success.committed success voice n: int committed {n:# file|# files}
save.success.pulled success voice n: int pulled {n:# commit|# commits}
save.success.pushed success voice n: int pushed {n:# commit|# commits}
save.success.sealed success voice n: int sealed {n:# secret|# secrets}
save.warning.unreachable warning voice Couldn't reach the remote, so nothing was pushed. To see why:
save.warning.unreachable_cmd hint fact self: string {self} remote
save.warning.waiting warning voice The remote has new commits. Commit or discard the changes here, then save again.

script

ID Kind Class Placeholders English
script.apt.all_installed status fact n: int, list: path apt: all {n} packages from {list} are installed
script.apt.error.no_apt error fact apt-get not found: this action is for Debian/Ubuntu systems
script.apt.error.no_list error fact list: path package list not found: manifests/
script.apt.installing status fact n: int, total: int, list: path apt: installing {n} of {total} packages from
script.apt.summary help mixed Install apt packages listed one per line (# comments allowed). - apt: linux/apt.txt
script.apt.unavailable warning fact n: int, packages: string apt: skipped {n} that no repository here offers:
script.apt_repos.added success fact name: path apt-repos: added
script.apt_repos.error.no_folder error fact dir: path apt-repos: folder not found: manifests/
script.apt_repos.present status fact n: int, dir: path apt-repos: {n} already set up in
script.apt_repos.skip_key warning fact name: path, missing: string, dir: path apt-repos: skipped {name}: its key {missing} is not in {dir}/keyrings
script.apt_repos.skip_release warning fact name: path, origin: string, here: string apt-repos: skipped {name}: it is for {origin} and this machine runs
script.apt_repos.summary help mixed Add third-party apt repositories and their signing keys. - apt-repos: linux/apt-repos
script.apt_repos.usage error fact usage: - apt-repos: <folder>
script.apt_repos.usage_export error fact usage: apt-repos --export DIR
script.brew.error.no_brew error fact brew is not installed: see https://brew.sh
script.brew.error.no_brewfile error fact list: path Brewfile not found: manifests/
script.brew.summary help mixed Install everything in one or more Brewfiles. - brew: "{{os}}/Brewfile"
script.flatpak.error.no_flatpak error fact flatpak is not installed
script.flatpak.error.no_list error fact list: path app list not found: manifests/
script.flatpak.summary help mixed Install Flatpak apps from Flathub, one app ID per line. - flatpak: linux/flatpak.txt
script.fonts.error.no_folder error fact name: string font folder not found: furniture/fonts/
script.fonts.error.os error fact os_env: string fonts: unsupported OS
script.fonts.installed status fact name: string, count: int fonts: {name} ({count} files)
script.fonts.summary help mixed Install font folders from furniture/fonts. - fonts: [JetBrainsMono, FiraCode]

secrets

ID Kind Class Placeholders English
secrets.error.cancelled error voice Stopped at the passphrase prompt; nothing changed.
secrets.error.decrypt error voice name: path, private: string = private/, age: string = .age Could not decrypt {private}{name}{age}.
secrets.error.empty_recipients error voice recipients: string = private/recipients.txt {recipients} has no public key in it. Restore it from the repo's history.
secrets.error.encrypt error voice name: path, private: string = private/ Could not encrypt {private}{name}.
secrets.error.encrypt_key error voice Encrypting the new key failed; nothing was saved.
secrets.error.identity_unreadable error voice identity: string = private/identity.age {identity} is not a passphrase-encrypted age key. Restore it from the repo's history.
secrets.error.keys_exist error voice identity: string = private/identity.age, recipients: string = private/recipients.txt Keys already exist ({identity}, {recipients}). Delete both first to start over.
secrets.error.no_identity error voice identity: string = private/identity.age No {identity} yet. Create keys first:
secrets.error.no_recipients error voice recipients: string = private/recipients.txt No {recipients} yet. Create keys first:
secrets.error.no_terminal error voice There is no terminal to ask for the passphrase on. Run this in a terminal.
secrets.error.passphrase error voice identity: string = private/identity.age Could not decrypt {identity} (wrong passphrase?)
secrets.error.reserved error voice path: path Refusing to write over {path}: it is not a secret.
secrets.error.save_gitignore error voice path: path, private: string = private/ Writing {path} failed, so nothing was set up: without it, git would take the plaintext secrets in {private}.
secrets.error.save_key error voice path: path Saving the new key to {path} failed; nothing was saved.
secrets.error.unsupported_ssh_key error voice line: int, key_type: string, recipients: string = private/recipients.txt, ed25519: string = ssh-ed25519, rsa: string = ssh-rsa, bits: string = 2048 bits Line {line} of {recipients} holds a key age cannot encrypt to ({key_type}). Use an {ed25519} key, or an {rsa} key of at least {bits}; homebot never seals to fewer keys than the file lists.

setup

ID Kind Class Placeholders English
setup.choice.clone choice mixed c clone your home repo
setup.choice.new choice mixed path: path n start a new one in
setup.error.clone_auth_gh error voice url: string, setup: string = {self} setup, command: string = gh auth login git couldn't sign in to GitHub to clone {url}. Sign in with the GitHub CLI, which sets git up to use that login, then run {setup} again:
setup.error.clone_auth_key error voice url: string, host: string, setup: string = {self} setup git couldn't sign in to {host} to clone {url}. Add an ssh key to your account there, then run {setup} again.
setup.error.clone_failed error voice url: string, setup: string = {self} setup Couldn't clone {url}. Check the address and that you can reach it, then run {setup} again.
setup.error.git_too_old error voice found: string, minimum: string, command: string = {self} setup Your git is {found}, and homebot needs {minimum} or newer: its commit guard relies on a git command that older versions lack, so every save would be refused. Update git, then run {command} again.
setup.error.git_too_old_brew error voice found: string, minimum: string, setup: string = {self} setup, command: string = brew install git Your git is {found}, and homebot needs {minimum} or newer: its commit guard relies on a git command that older versions lack, so every save would be refused. Install a newer one with Homebrew, then run {setup} again:
setup.error.home_taken error voice path: path, config: string = homebot.yml, env: string = HOMEBOT_ROOT, setup: string = {self} setup, command: string {path} is there but holds no {config}, so it isn't a home repo and setup won't touch it. Move it aside, or set {env} to another folder, then run {setup} again:
setup.error.install_failed error voice command: string, tools: string, setup: string = {self} setup {command} failed. Install {tools} yourself, then run {setup} again.
setup.error.name_syntax error voice name: string, flag: string = --name, rule: string = 2 to 32 lowercase letters, digits and hyphens, starting with a letter {flag} {name} must be
setup.error.no_terminal error voice setup: string = {self} setup, clone: string = git clone <url>, path: path No home repo yet, and setup starts or clones one only in a terminal. Run it in one:
{setup}
Or clone yours by hand:
{clone}
setup.error.not_a_home_repo error voice url: string, config: string = homebot.yml, path: path, setup: string = {self} setup {url} has no {config}, so it isn't a home repo. It is in {path} now: move it aside, then run {setup} again.
setup.error.persona_syntax error voice persona: string, flag: string = --persona, rule: string = start with a lowercase letter and contain only lowercase letters, digits and hyphens (at most 32 characters) {flag} {persona} must
setup.error.remove_flags error voice remove_flag: string = --remove, name_flag: string = --name, persona_flag: string = --persona {remove_flag} cannot be combined with {name_flag} or
setup.error.root_relative error voice env: string = HOMEBOT_ROOT, value: string, setup: string = {self} setup {env} is "{value}", which is not a full path, so homebot would find the repo only from this folder. Set it to a full path, or unset it, then run {setup} again.
setup.error.tools_missing error voice tools: string, setup: string = {self} setup, command: string Missing: {tools}. The commit guard needs it to check every commit. Install it, then run {setup} again:
setup.error.xdg_relative error voice name: string, value: string, command: string = {self} setup {name} is "{value}", which is not a full path, so the background helper can't use it. Set it to a full path, or unset it, then run {command} again.
setup.hint.keys hint voice Secrets aren't set up yet. To keep passwords and tokens in the repo, encrypted, create the keys:
setup.hint.keys_cmd hint fact self: string {self} keys init
setup.hint.name_path hint voice file: path, name: string, bin: string = ~/.local/bin, path_env: string = PATH Add {bin} to your {path_env} in {file} to type {name}; homebot works now.
setup.hint.run_later hint fact self: string, flags: string {self} setup
setup.hint.setup_cmd hint fact self: string {self} setup
setup.hint.triage_cmd hint fact self: string {self} triage
setup.hint.unpack_cmd hint fact self: string {self} unpack
setup.hint.xdg hint voice self: string, xdg_glob: string = XDG_*, config_env: string = XDG_CONFIG_HOME, data_env: string = XDG_DATA_HOME, state_env: string = XDG_STATE_HOME, cache_env: string = XDG_CACHE_HOME, setup: string = setup The helper keeps the {xdg_glob} folders it was set up with. After changing {config_env}, {data_env}, {state_env} or {cache_env}, run {self}{setup} again.
setup.hint.zshrc hint voice zshrc: string = .zshrc Add this to your {zshrc} so new terminals tell you when something needs you:
setup.hint.zshrc_cmd hint fact eval "$(homebot shell zsh)"
setup.prompt.backup prompt voice n: int, yn: string = [Y/n] {n:# file is|# files are} in the way of links. Move them aside (nothing is deleted) and link?
setup.prompt.change_name prompt voice repo: string, flag: string, choice: string = [y/N] This repo calls it {repo} on every machine. Change the shared name to {flag}?
setup.prompt.install_tools prompt voice tools: string, command: string, yn: string = [Y/n] Missing: {tools}. Install now with {command}?
setup.prompt.keys prompt voice yn: string = [Y/n] Keep passwords and tokens in the repo, encrypted? This creates your keys.
setup.prompt.name prompt voice example: string = zork, enter: string = Enter Give your homebot a command name? For example {example} ({enter} keeps homebot):
setup.prompt.name_path prompt voice file: path, bin: string = ~/.local/bin, path_env: string = PATH, choice: string = [Y/n] Put {bin} on your {path_env} in {file} so the name works?
setup.prompt.save prompt voice yn: string = [Y/n] Commit and push now?
setup.prompt.save_local prompt voice yn: string = [Y/n] Commit now?
setup.prompt.triage prompt voice n: int, yn: string = [Y/n] {n:# thing|# things} in your home could be tracked. Sort them now, one key each?
setup.prompt.unpack prompt voice n: int, yn: string = [Y/n] Run {n:this step|these # steps}?
setup.prompt.url prompt voice example: string = owner/repo URL of your home repo, or {example} on GitHub:
setup.prompt.zshrc prompt voice file: path, yn: string = [Y/n] Add it to {file} now?
setup.status.changed_here status voice Changed on this machine:
setup.status.cloning status voice url: string, path: path Cloning {url} into {path}…
setup.status.guard_present status voice Commit guard already installed.
setup.status.name_blocked status voice name: string no name link for {name} was made here
setup.status.name_link status voice name: string, bin: string = ~/.local/bin/, binary: string = homebot name link: {bin}{name} points to
setup.status.name_uncommitted status voice config: string = homebot.yml The new name is in {config} but stays uncommitted with your other work; your next save carries it.
setup.status.no_repo status voice No home repo yet.
setup.status.open_shell status voice name: string From now on, type {name}. Open a new terminal first; on some Linux systems, log out and back in.
setup.status.path_added status voice file: path, bin: string = ~/.local/bin Added {bin} to {file}.
setup.status.path_line status voice path_env: string = PATH added the {path_env} startup line
setup.status.persona status voice persona: string Persona in this repo:
setup.status.removed status voice Background helper removed.
setup.status.repo_name status voice name: string This repo calls your homebot {name}.
setup.status.repo_name_wins status voice repo: string, flag: string, name_flag: string = --name This repo calls it {repo}; {name_flag} {flag} was ignored without a terminal.
setup.status.zsh_only status voice shell: string, zsh: string = zsh Your shell is {shell}. The startup line and the prompt count are {zsh}-only for now.
setup.status.zshrc_in_repo status voice path: string That file links into your home repo, so {path} changed there.
setup.status.zshrc_linked status voice file: path, target: path {file} is a link to {target}, and setup writes only through a link to a file in your home repo. Add the line there yourself.
setup.success.created success voice path: path, profile: string = base created {path}, a new home repo with a {profile} profile
setup.success.guard success voice hook_key: string = core.hooksPath installed commit guard ({hook_key})
setup.success.helper success voice helper: string installed
setup.success.zshrc success voice file: path added the startup line to
setup.warning.clone_failed warning voice url: string Couldn't clone {url}.
setup.warning.name_blocked warning voice name: string, reason: string {name} cannot be used as a command here: {reason} Homebot will keep working.
setup.warning.name_invalid warning voice name: string, rule: string = 2 to 32 lowercase letters, digits and hyphens, starting with a letter {name} must be {rule}. Try another name.
setup.warning.no_profile warning voice host: string, config: string = homebot.yml, hosts: string = profiles.hosts, default: string = profiles.default No profile for this machine ({host}) yet, so nothing was unpacked. Name one in {config} under {hosts} or {default}, then:
setup.warning.no_repo warning voice root: path {root} is not a git repo yet; skipped the commit guard.
setup.warning.path_link warning voice file: path, target: path, bin: string = ~/.local/bin, path_env: string = PATH Cannot safely edit {file} (link target: {target}). Add {bin} to your {path_env} yourself.

shell

ID Kind Class Placeholders English
shell.comment.spaceship help mixed # Spaceship prompt section. Enable it by adding "homebot" to SPACESHIP_PROMPT_ORDER.
shell.env.count nudge fact count: string HOMEBOT_COUNT=
shell.nudge nudge fact nudge_cache: string
shell.spaceship.section nudge fact prefix: string (optional), symbol: string, count: string, suffix: string {prefix}{symbol}{count}
shell.starship.format nudge fact [🚚 $env_value ]($style)

tidy

ID Kind Class Placeholders English
tidy.did.committed status voice n: int committed {n:# file|# files}
tidy.did.exported status voice outs: string refreshed
tidy.did.guard status voice installed the commit guard
tidy.did.linked status voice n: int fixed {n:# link|# links}
tidy.did.name_off status voice removed this machine's name link
tidy.did.named status voice kept this machine's name link in sync
tidy.did.pulled status voice n: int pulled {n:# commit|# commits}
tidy.did.pushed status voice n: int pushed {n:# commit|# commits}
tidy.did.sealed status voice n: int sealed {n:# secret|# secrets}
tidy.error.autosave_no_guard error voice skipped, because the commit guard could not be installed this run (see the guard step)
tidy.error.lock error voice path: string, reason: string, env: string = XDG_STATE_HOME Could not lock {path}: {reason}. tidy takes a file lock so two runs never overlap, and the filesystem holding the state directory does not support it. Point {env} at a local disk.
tidy.journal.failed error voice step_name: string, message: string {step_name} failed:
tidy.line.done success fact did: string done
tidy.line.failed error fact step_name: string, message: string failed {step_name}:
tidy.status.inbox_count status voice n: int {n:# thing|# things} in the inbox.
tidy.status.locked status voice Another tidy is running.
tidy.status.nothing status voice Nothing to tidy.

triage

ID Kind Class Placeholders English
triage.decisions.header label mixed # Written by homebot triage; editing by hand is fine.
# Paths (globs allowed) that homebot will never offer to track again.
triage.describe.file label fact size: string
triage.describe.folder label voice size: string folder,
triage.describe.folder_big label voice size: string folder, {size}: big, probably app data
triage.describe.gone label voice gone
triage.describe.over label voice size: string over
triage.error.git_add error voice key: path, git_add: string = git add {git_add} {key} failed.
triage.error.ignore_list error voice file: path, ignore: string = ignore {file}: {ignore} must be a list of paths
triage.error.line_break error voice key: string, gitignore: string = .gitignore {key} has a line break in its name, which a {gitignore} line can't hold. Nothing was written; rename it, or snooze it.
triage.error.old_file error voice path: path, decisions: string = decisions.yml homebot reads {decisions} now: rename {path} to
triage.hint.header_suffix hint voice quit: string = q Each answer is saved right away; {quit} stops.
triage.hint.pick hint voice pick one of the letters above
triage.menu.home choice mixed os: string t track everywhere o track on {os} only i ignore forever
s snooze 7 days enter next q quit
triage.menu.repo choice mixed t track (git add) i ignore (.gitignore) s snooze 7 days
enter next q quit
triage.prompt.input prompt fact >
triage.prompt.item prompt fact i: int, total: int, key: path, description: string [{i}/{total}] {key} ({description})
triage.status.header status voice n: int {n} things to decide.
triage.status.result status fact message: string
triage.success.gitignored success voice key: path, gitignore: string = .gitignore added /{key} to
triage.success.ignored success voice key: path will never ask about {key} again
triage.success.none success voice Nothing to sort. Everything has a decision.
triage.success.packed success voice key: path, repo_path: path packed {key} into
triage.success.snoozed success voice key: path, duration: string = 7 days snoozed {key} for
triage.success.staged success voice key: path staged
ID Kind Class Placeholders English
unlink.hint.cmd hint fact self: string {self} link
unlink.hint.helper hint voice self: string, link: string = link The background helper links them again within the hour, as {self}{link} would. To keep a file unlinked, take it out of the repo.
unlink.status.removed status voice n: int Removed {n:# link|# links}. To put them back:

unlock

ID Kind Class Placeholders English
unlock.error.conflict error voice name: path, private: string = private/ conflict {private}{name}: changed here and in the repo
unlock.hint.ours hint voice Keep this machine's versions:
unlock.hint.ours_cmd hint fact self: string {self} lock --ours
unlock.hint.theirs hint voice Or take the repo's:
unlock.hint.theirs_cmd hint fact self: string {self} unlock --theirs
unlock.prompt.passphrase prompt voice Enter passphrase:
unlock.status.linked status voice n: int linked {n:# secret|# secrets}
unlock.success.unlocked success voice n: int unlocked {n:# secret|# secrets}
unlock.success.verified_suffix success voice n: int , verified

unpack

ID Kind Class Placeholders English
unpack.error.from_nan error voice from_flag: string = --from {from_flag} takes a step number
unpack.error.from_range error voice n: int, from_flag: string = --from, first_step: string = 1 {from_flag} must be between {first_step} and
unpack.error.no_action error voice i: int, action: string Step {i}: no action named "{action}". See:
unpack.error.no_profile error voice example: string = {self} unpack workstation, default_key: string = profiles.default, config_file: string = homebot.yml Which profile? Pass one ({example}) or set {default_key} in {config_file}.
unpack.error.step_exit error voice i: int, step: string, code: int Step {i} ({step}) exited with {code}.
unpack.error.step_failed error voice i: int, message: string Step {i} failed:
unpack.hint.resume hint voice Fix it, then resume:
unpack.hint.resume_cmd hint fact self: string, profile: string, i: int {self} unpack {profile} --from
unpack.status.header status voice profile: string, host: string, os: string, n: int Unpacking {profile} on {host} ({os}): {n} steps
unpack.status.header_dry_run status voice profile: string, host: string, os: string, n: int Would unpack {profile} on {host} ({os}): {n} steps
unpack.status.step status fact i: int, total: int, step: string [{i}/{total}]
unpack.status.step_skipped status fact i: int, total: int, step: string [{i}/{total}] {step} (skipped)
unpack.success.done success voice profile: string Unpacked {profile}.

update

ID Kind Class Placeholders English
update.error.check error voice reason: string Could not check the latest release:
update.item.available inbox voice version: string Version {version} is available.
update.item.broken inbox voice version: string The Homebrew install is broken after trying version {version}; reinstall it.
update.item.cosign inbox mixed version: string, minimum: string, self: string Version {version} needs cosign {minimum} or newer for an automatic signature check. Install it, then rerun {self} setup if its PATH changed.
update.item.failed inbox voice version: string, error: string The upgrade to version {version} failed:
update.item.manual inbox voice version: string Version {version} needs a manual upgrade for this install method.
update.item.root inbox voice version: string Version {version} needs a package upgrade with root privileges.
update.item.tap_lag inbox mixed version: string Homebrew has not offered version {version} after 72 hours.
update.item.timeout inbox voice version: string The upgrade to version {version} timed out.
update.item.title inbox voice A homebot update needs attention
update.item.verify inbox voice version: string Verification of version {version} failed. Nothing was installed; report this failure.
update.journal.updated status voice version: string updated homebot to
update.notify.broken warning voice command: string homebot needs reinstalling:
update.notify.success status voice version: string homebot updated to
update.notify.title status voice homebot update
update.version.auto_cosign status mixed minimum: string, self: string Automatic updates need cosign {minimum} or newer; install it and rerun {self} setup if its PATH changed.
update.version.auto_failed status voice version: string, error: string, when: string The last automatic update to {version} failed ({error}); the helper tries again after {when}.
update.version.auto_manual status voice Automatic updates are unavailable for this install method.
update.version.auto_ready status voice Automatic update is eligible on the next helper run.
update.version.auto_ready_after status voice when: string Automatic update is eligible on the first helper run after {when}.
update.version.auto_retry status voice when: string The last automatic attempt left this version in place; the helper tries again after {when}.
update.version.auto_soak status voice when: string Automatic update waits until {when}.
update.version.auto_unseen status mixed Automatic update waits for the helper to see this release and start its 48-hour soak.
update.version.command status voice command: string Upgrade:
update.version.current status voice version: string Current:
update.version.development status voice Development build; this build does not update itself.
update.version.latest status voice version: string Latest:
update.version.method status voice method: string Install method:
update.version.source status voice Built from source; this build does not update itself.
update.version.up_to_date status voice This build is up to date.