Message catalog
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}) |
cleanup.fzf.header_merge |
prompt | fact | picker_keys: string | |
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. |
cli.error.option.ambiguous_short |
error | fact | option: string, name: string | Option '{option}' argument is ambiguous. |
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} |
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: |
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: |
|
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: |
guard.plaintext |
error | mixed | file_path: path | {file_path} is plaintext. Only *.age files may be committed from private/. Unstage it: |
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: |
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: |
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: |
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 |
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, |
|
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 |
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 |
|
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 |
|
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, |
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 |
|
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 |
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 |
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 |
|
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 |
|
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 |
|
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, |
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: |
|
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: |
|
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. |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
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 |
|
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 |
|
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. |
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. |
|
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}" |
link
| 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} |
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: |
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: |
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.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 |
|
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 |
triage.menu.repo |
choice | mixed | t track (git add) i ignore (.gitignore) s snooze 7 days |
|
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 |
unlink
| 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. |