Files

Every file say-hi is made of, reads, recognizes, and creates — on your machine, on a target, and in a package — with the variable that moves a path where one does. Settings are SETTINGS.md; what a session may touch on a target is argued in SECURITY.md.

Throughout, $_HI_HOME is the directory holding the tree, $_HI_ROOT is $_HI_HOME/say-hi, and $_HI_CONFIG_DIR is ${XDG_CONFIG_HOME:-$HOME/.config}/say-hi unless set.

Contents

The tree

Each file is marked with where it goes:

  • payload — hi.sh’s _HI_PAYLOAD (common/, config/, load.sh, hi.sh): comment-stripped, gzipped, and sent to every target on every connect.
  • package — scripts/install.sh’s _HI_PACKAGE_CONTENTS (the payload plus scripts/, LICENSE.md, README.md), copied to <prefix>/say-hi by a package or install.sh --prefix.
  • dev — only in a checkout.

Top level

File Goes What it is
hi.sh payload The client: parses flags, resolves the target, ships the tree, chainloads load.sh there.
load.sh payload The target half: header, session rc, shell handoff, cleanup.
README.md, LICENSE.md package The walkthrough and roadmap; the MIT license.
CLAUDE.md, .claude/settings.json dev Conventions and shared tool permissions for agent sessions in this repo.
_config.yml dev The GitHub Pages site’s Jekyll config.
.editorconfig, .vscode/settings.json, .zed/settings.json dev Editor settings; shfmt reads its style from .editorconfig.
.gitattributes, .gitignore dev LF everywhere, so Git Bash never gets a CRLF hi.sh; what stays untracked, dist/ too.
.shellcheckrc, .hadolint.yaml dev shellcheck resolves source beside the sourcing file; hadolint’s rules for tests/dockerfiles/.
.markdownlint.yaml, .prettierrc.yaml, .prettierignore, .moxide.toml dev Markdown lint and formatting, kept in agreement.
.typos.toml, lychee.toml dev The spelling check’s allowlist; both link checks’ settings.
.scorecard.yml dev OpenSSF Scorecard annotations.

common/ and config/

All payload but config/plugins. common/ is hi’s code; config/ holds the shipped defaults an overlay copy replaces.

File What it is
common/core.sh What every bash and zsh entry point sources first: toggles, settings, paths, colors, shared functions.
common/paths.sh Every path hi uses, in plain export lines bash, zsh, fish, and sh all read.
common/bash.sh hi’s bash rc: prompt, completion, plugins, the local greeting.
common/zsh.zsh The same for zsh.
common/_hi zsh’s completion for hi, autoloaded off $fpath by the rc’s own compinit.
common/config.fish The same for fish, with its own copies of what fish cannot call in bash.
common/fw_<name>.<ext> One prompt framework’s loader each, sourced by its shell’s rc; a target not handed that framework is not sent it.
common/env_prompt.sh, git_prompt.sh The (myproj) environment segment and the git segment, for bash and zsh.
common/header.sh The connect and disconnect banner, and the package check.
common/targets.sh Every name hi <target> answers to, for all three completions; standalone POSIX.
common/flags hi’s own flags, one row each: dispatch, --help, and completion all read it.
common/aliases.sh The aliases, in the subset bash, zsh, and fish all parse.
config/colors Color pins, in TOML.
config/packages What the package check looks for, in TOML, a table per group: core, useful, and deprecated run by default; base waits to be switched on. docs/packages.example is a longer list to copy.
config/plugins Every tool’s configs hi carries, in TOML: a table per plugin, with its files, its tool, its wire, its places at home, and its dialect (SETTINGS.md). Read where the payload is packed, and not sent.

scripts/

All package, never in the payload.

File What it is
scripts/install.sh hi --install: wires the local shells, links hi; also --prefix and --uninstall.
scripts/rc.sh The lines hi adds to rc files: writing, removing, and syntax-checking them.
scripts/zshrc.sh Where this machine’s zsh reads its .zshrc: under ZDOTDIR, the environment’s or the one ~/.zshenv sets, else ~. rc.sh and pack.sh source it.
scripts/configure.sh hi --configure, the one writer of settings.sh.
scripts/doctor.sh, preview.sh hi --doctor and hi --preview.
scripts/update.sh hi --update: moves the checkout to a release tag, or fast-forwards dev.
scripts/add_package.sh hi --add-package and --remove-package: adds rows to a group in ~/.config/say-hi/packages, or removes them, copying the tree’s in first.
scripts/add_tag.sh hi --add-tag: writes a # Tags: line into ~/.ssh/config.
scripts/set_color.sh hi --set-color and --unset-color: writes or removes a pin in ~/.config/say-hi/colors, copying the tree’s in first.
scripts/convert_settings.sh Rewrites an older hi’s packages, colors, plugins, and settings.sh into the current shape, keeping each as <file>.old; --install, --configure, and --update run it.
scripts/plugins.sh hi --plugins, --plugin-off, --plugin-on, --add-plugin, and --remove-plugin: lists what rides, keeps _HI_PLUGINS_OFF in settings.sh, and writes tables of ~/.config/say-hi/plugins.
scripts/pack.sh The packer hi.sh sources on a client: the overlay table and the plugins rows, the include scan, the comment strip, and the cached tars a connect sends. A session has none, and relays its tree as it stands (HI.66).
scripts/lib.sh Helpers shared by the tooling, kept out of core.sh for the payload budget.
scripts/table.sh The display the scripts draw through: column padding, the pieces a line is painted from, the boxed table the previews draw, and the section of rows hi --doctor and hi --plugins report in.
scripts/settings Every setting, a row each: docs/SETTINGS.md’s Every setting table is written from it, and hi --configure reads its menu items from it.

packaging/

All dev: the inputs a release builds from.

File What it is
packaging/nfpm/nfpm.yaml Where the staged tree lands in a .deb, .rpm, and .apk.
packaging/mkpkg.sh Stages the tree through install.sh --prefix, then runs nfpm.
packaging/mkrepo.sh Turns the packages into signed apt, dnf, and apk repositories.
packaging/srctar.sh The release source tarball.
packaging/bump.sh Sets the version and checksums in the AUR and Homebrew manifests at release time.
packaging/stamp.sh Stamps _HI_RELEASE for hi --version, the same way in every channel.
packaging/lib.sh Shared plumbing for the scripts above but stamp.sh, which is standalone.
packaging/stamp_badge.sh Stamps README’s payload badge as measured; bench runs its --check.
packaging/homebrew/say-hi.rb The tap formula template.
packaging/aur/say-hi/, aur/say-hi-git/ The versioned and the VCS AUR packages (PKGBUILD, .SRCINFO).
packaging/gpg/say-hi.asc, apk/say-hi.rsa.pub The public keys the repositories and release signatures are checked against.

docs/

dev, except docs/hi.1, the man page a package installs. The docs are indexed in README.md; docs/tapes/ holds the VHS demo tapes, their fixtures, generate.sh to render them, and demo.gif, plus USAGE.md’s examples (usage) and usage.sh to render them.

tests/

All dev; TESTING.md is the full layout.

Path What it is
tests/test_runner.sh The runner and its _HI_TESTS table of suites and groups.
tests/test_lib.sh, tests/lib/ The harness every suite sources: workdir, reporting, parallel cases, fixtures, ssh and container backends.
tests/<dir>/*_test.sh One suite per tested area, in a directory named for what it tests (common/, hi/, load/, scripts/, config/, packaging/, harness/).
tests/<dir>/<suite>/ Data files one suite reads, beside it (scripts/convert_settings/: the name:N packages and comma colors files).
tests/lint/ The lint group: shellcheck, the zsh and fish dialects, formatters and editor rcs, drift checks.
tests/bench/ Hot-path timings and the payload size budget.
tests/targets/ The e2e and backends groups: ssh, docker, podman, nomad, kube, install methods, frameworks.
tests/dockerfiles/ Every image those suites build: sshd targets, shell floors, installed-target variants, frameworks.
tests/coverage.sh, coverage_v2.sh, profile.sh kcov and bashcov coverage, and timep profiles.

.github/

All dev. workflows/ holds CI (ci.yml and the BSD and Windows runs it calls), coverage, release and publishing, the docs site, demos, and usage images, the link, tool-pin, and release-note checks, and the scanners, each header saying when it runs; actions/ the composite actions they share (shells, backends, setup-tool/tools.txt’s pinned tool roster); scripts/ the helpers they call; plus the issue and pull request templates, CODEOWNERS, dependabot.yml, allowed_signers (the keys a release tag may be signed with), package.json/package-lock.json (the pinned Markdown linters), and prettier-plugin-docs.mjs (writes each doc’s ## Contents list, the settings table, and USAGE.md’s commands as prettier formats them).

Your files

The overlay

Everything in $_HI_CONFIG_DIR that hi knows by name (hi.sh’s _HI_OVERLAY_FILES). All of it is optional and, plugins aside, rides to every target in its own small stream, and lands there in $_HI_ROOT/config/, over the defaults it replaces. extensions/, and zellij’s layouts/ and themes/, ride member by member; a member name is a letter or digit, then [A-Za-z0-9_.-], never ending .bak, .orig, .rej, or .tmp.

File Variable Replaces Read by
settings.sh _HI_SETTINGS - every shell, first; written by hi --configure
colors _HI_COLORS config/colors prompt and header colors
packages _HI_PACKAGES config/packages the header’s package check, wholesale over the tree’s
aliases.sh - - common/aliases.sh, sourced last
plugins - - hi here, for the plugins yours add or replace (SETTINGS.md)
extensions/ _HI_EXTENSIONS - every shell, after the aliases, in name order
header/ _HI_HEADER_CELLS - the header, a cell a file (INTEGRATIONS.md)
bashrc, zshrc, config.fish - - the end of hi’s rc for that shell
vim/vimrc, nvim/init.lua, helix/config.toml, helix/languages.toml, nano/nanorc, emacs/init.el - - the editor aliases and $VIMINIT
kak/kakrc, kak/colors/ - - kakoune on a target ($KAKOUNE_CONFIG_DIR)
tmux/tmux.conf - - the tmux alias (tmux -f)
screenrc - - the screen alias (screen -c)
micro/ (settings.json, bindings.json, init.lua) - - the micro alias (-config-dir)
zellij/ (config.kdl, layouts/, themes/) - - the zellij alias (--config-dir)
starship.toml, oh-my-posh.json (or .yaml, .toml), eza/theme.yml, bat/config - - starship, oh-my-posh, eza, and bat on a target
inputrc - - readline on a target ($INPUTRC)
ripgreprc, fzfrc, lazygit/config.yml - - rg, fzf, and lazygit on a target ($RIPGREP_CONFIG_PATH, $FZF_DEFAULT_OPTS_FILE, $LG_CONFIG_FILE)
p10k.zsh, oh-my-zsh.zsh-theme, oh-my-bash.theme.sh, bash-it.theme.bash, tide.vars - - powerlevel10k, oh-my-zsh, oh-my-bash, bash-it, and tide on a target
ssh_tags - - a hi run from inside a session, for the next hop’s tag colors

wiring.sh rides beside them, written by hi as the overlay is packed: the lines that point each tool at its member on a target (HI.62). It is not a member, and one in $_HI_CONFIG_DIR is not read.

A member in the Replaces column travels in the tree’s place, not beside it: the payload leaves out a default your overlay shadows, so the wire holds one colors, not two - and an editor default whose editor this machine lacks stays home too, so a client without emacs sends no emacs/init.el. aliases.sh is the exception by design - yours is sourced on top of the tree’s, so both ride. The <file>.old copies scripts/convert_settings.sh keeps are not members and stay home. Nor is a settings.<tag>.sh: a host carrying the tag is sent a settings.sh with it joined on (SETTINGS.md).

What happens to a line in one of these that reads a file no target has is SETTINGS.md’s.

Configs read from where their tool keeps them

On this machine (never on a target), hi carries the config a tool already reads rather than asking for a copy - the middle step of the one order (HI.61): the first one found in each row wins, an overlay copy wins over all of them - for the prompt programs, eza, bat, rg, fzf, lazygit, and your aliases on a target only, since at home each already reads its own - and the tree’s default, where there is one, applies when neither is there. bashrc, zshrc, and config.fish are never looked for here: they ride only as an overlay copy. A prompt program’s member rides only when that program is in the list a target is handed (INTEGRATIONS.md), and an editor’s, tmux’s, screen’s, micro’s, zellij’s, bat’s, eza’s, rg’s, fzf’s, or lazygit’s only with that tool installed here (INTEGRATIONS.md’s Which side is asked), and readline’s always; an overlay copy rides either way.

Member Looked for, in order
aliases.sh ~/.aliases, the file your bash or zsh rc sources here; sourced last on a target, so it keeps to the subset bash, zsh, and fish all parse
vim/vimrc ~/.vimrc, ~/.vim/vimrc, $XDG_CONFIG_HOME/vim/vimrc
nvim/init.lua $XDG_CONFIG_HOME/nvim/init.lua
kak/kakrc ${KAKOUNE_CONFIG_DIR:-$XDG_CONFIG_HOME/kak}/kakrc
kak/colors/ ${KAKOUNE_CONFIG_DIR:-$XDG_CONFIG_HOME/kak}/colors/, file by file
helix/config.toml $XDG_CONFIG_HOME/helix/config.toml
helix/languages.toml $XDG_CONFIG_HOME/helix/languages.toml
nano/nanorc ~/.nanorc, $XDG_CONFIG_HOME/nano/nanorc
emacs/init.el ~/.emacs.el, ~/.emacs, ~/.emacs.d/init.el, $XDG_CONFIG_HOME/emacs/init.el
tmux/tmux.conf ~/.tmux.conf, $XDG_CONFIG_HOME/tmux/tmux.conf
screenrc ${SCREENRC:-~/.screenrc}
micro/<file> ${MICRO_CONFIG_HOME:-$XDG_CONFIG_HOME/micro}/<file>, each of the three on its own
zellij/<file> ${ZELLIJ_CONFIG_DIR:-$XDG_CONFIG_HOME/zellij}/<file>: config.kdl, and each file of layouts/ and themes/, the overlay's copy of a name first
starship.toml ${STARSHIP_CONFIG:-~/.config/starship.toml}
oh-my-posh.* the last oh-my-posh init ... --config <file> in ~/.bashrc, ${ZDOTDIR:-~}/.zshrc, and fish’s config.fish, then ${POSH_CONFIG:-$POSH_THEME} over it; the member is the one its extension names, and any overlay copy puts all of them out of the running
p10k.zsh ${POWERLEVEL9K_CONFIG_FILE:-${ZDOTDIR:-~}/.p10k.zsh}
oh-my-zsh.zsh-theme the theme the last ZSH_THEME= in ${ZDOTDIR:-~}/.zshrc names, under ${ZSH_CUSTOM:-${ZSH:-~/.oh-my-zsh}/custom} and its themes/, then ${ZSH:-~/.oh-my-zsh}/themes
oh-my-bash.theme.sh the theme the last OSH_THEME= in ~/.bashrc names, under ${OSH_CUSTOM:-${OSH:-~/.oh-my-bash}/custom} and its themes/, then ${OSH:-~/.oh-my-bash}/themes
bash-it.theme.bash the theme the last BASH_IT_THEME= in ~/.bashrc names, under ${BASH_IT_CUSTOM:-${BASH_IT:-~/.bash_it}/custom}/themes, then ${BASH_IT:-~/.bash_it}/themes
tide.vars the SETUVAR tide_* lines of $XDG_CONFIG_HOME/fish/fish_variables, and nothing else from it
eza/theme.yml ${EZA_CONFIG_DIR:-$XDG_CONFIG_HOME/eza}/theme.yml
bat/config ${BAT_CONFIG_PATH:-${BAT_CONFIG_DIR:-$XDG_CONFIG_HOME/bat}/config}
ripgreprc $RIPGREP_CONFIG_PATH; rg reads no file without it
fzfrc $FZF_DEFAULT_OPTS_FILE; fzf reads no file without it
lazygit/config.yml $LG_CONFIG_FILE, $XDG_CONFIG_HOME/lazygit/config.yml, ~/Library/Application Support/lazygit/config.yml
inputrc ${INPUTRC:-~/.inputrc}
ssh_tags the # Tags: lines of ~/.ssh/config and its Includes, each with the Host or Match host line under it and nothing else

Paths hi recognizes

Read, probed, or checked, on whichever machine the shell runs; nothing here is written.

Path Variable Why
the tree, from the entry file’s own path _HI_HOME where every other tree path is derived from
~/.bashrc, ${ZDOTDIR:-~}/.zshrc, ${XDG_CONFIG_HOME:-~/.config}/fish/config.fish - the rc files install wires and doctor checks
~/.bash_profile, ~/.bash_login, ~/.profile - which one a login bash reads (macOS), and the chain a session restores
~/.ssh/config _HI_SSH_CONFIG ssh targets, their # Tags:, completion
~/.ssh/*.pub, ~/.ssh/authorized_keys _HI_SSH_DIR, _HI_SSH_AUTHORIZED_KEYS the header’s key counts
/etc/os-release _HI_LINUX_RELEASE the header’s OS line
/proc/meminfo, /proc/loadavg, /proc/cpuinfo, /proc/uptime, /sys/devices/system/cpu/cpu0/cpufreq - the header’s stats on Linux; macOS and the BSDs are asked through sysctl
/etc/debian_chroot - the prompt’s chroot label
$TERMINFO, ~/.terminfo, /etc/terminfo, /lib/terminfo, /usr/share/terminfo - whether a target knows $TERM, else xterm-256color
.tool-versions, .mise.toml, mise.toml, .mise/config.toml in $PWD and above - the mise environment segment
.git above $PWD - the git segment, read without taking the index lock
$_HI_ROOT/.git - hi --update needs a checkout
hi on $PATH - install and doctor check it runs this tree

docker, podman, nerdctl, finch, nomad, and kubectl are only ever invoked; hi reads none of their config files.

What hi creates on this machine

Install, configure, update, uninstall

Path What
~/.bashrc, ${ZDOTDIR:-~}/.zshrc, ${XDG_CONFIG_HOME:-~/.config}/fish/config.fish lines tagged # added by hi during install, in the login shell’s rc and any other that exists already (--shell chooses); ZDOTDIR is the environment’s, else the one ~/.zshenv sets; the file and its directory are created if missing; --print-rc prints the lines instead
<rc>.hi-orig a one-time backup before hi first writes a non-empty rc; never overwritten, and left by uninstall
~/.bash_profile (macOS) a line sourcing ~/.bashrc, plus ~/.profile in a file hi creates
$_HI_CONFIG_DIR/plugins the tables hi --add-plugin writes and hi --remove-plugin takes out
$_HI_CONFIG_DIR/settings.sh the settings block hi --configure writes, and the _HI_PLUGINS_OFF line hi --plugin-off keeps
~/.local/bin/hi (--link user), /usr/bin/hi (--link system) a symlink to hi.sh; $_HI_LINK; a link that is not hi’s, or a package’s, is left alone
the checkout hi --update fetches tags and checks one out; refused on a dirty tree
uninstall removes the tagged lines (and an rc hi created that is now empty), settings.sh, and hi’s links; --purge also removes $_HI_CONFIG_DIR

Caches and sockets

In the runtime directory: $XDG_RUNTIME_DIR when it exists, else ${TMPDIR:-/tmp}/hi-<uid>, created mode 700 and refused if it is a symlink or owned by someone else. A cache is written under a temporary name and moved into place.

File What
hi.targets.<kind> completion’s target list, for $_HI_TARGETS_TTL seconds
hi.payload.tree.<key> the gzipped payload, rebuilt when a tree file changes, keyed on the tree’s path and its cut list (the defaults an overlay shadows, or whose tool is not installed here, and the prompt loaders a target is not handed); off with _HI_PAYLOAD_CACHE=0
hi.overlay.<key> the overlay stream, keyed on its member list and the home paths any member was packed from
hi.settings.<key> settings.sh with a tagged target’s settings.<tag>.sh files joined on, what that target is sent; rewritten only when its content changes
hi.ssh_tags the ssh_tags member, recut when ~/.ssh/config is newer
hi.ctl.<key> the shared ssh ControlMaster socket, kept $_HI_CTL_PERSIST seconds (0 turns it off)
hi.mux.<target>.kdl the zellij layout --mux starts a session from, rewritten each time

fish also keeps __hi_color_user, __hi_color_host, and __hi_colors_key as universal variables in its own store, so a color is only resolved once per change.

Temporary files

All under $TMPDIR (mktemp -t), and removed when the command ends.

Pattern Made by
hi.log.XXXXXX every hi run
hi.stage.XXXXXX/ building the payload and overlay (the lint and strip passes)
hi.cm.XXXXXX/s a per-run ControlMaster socket, where the shared one is off
hi-probe.<pid>/ completion’s parallel backend sweep (mkdir -m 700)
hi.probes.XXXXXX/ the header’s parallel backend probes
hi.doc.err.XXXXXX hi --doctor
hi.append.XXXXXX, hi.rewrite.XXXXXX, hi.settings.XXXXXX rewriting an rc file or settings.sh in place
hi.packages.XXXXXX hi --add-package, hi --remove-package
hi.sshconfig.XXXXXX hi --add-tag
hi.colors.XXXXXX hi --set-color, hi --unset-color
hi.plugins.XXXXXX hi --plugin-off, hi --plugin-on, hi --add-plugin, hi --remove-plugin
hi.convert.XXXXXX scripts/convert_settings.sh

What a session does on a target

hi never writes to a target’s own login files, and a say-hi already installed there is ignored: the session runs the tree it shipped, even where the target’s rc files point at another one.

The session tree

One scratch directory per session under the target’s $TMPDIR, named for the user running hi:

Arm Directory
ssh ${TMPDIR:-/tmp}/<user>.hi.XXXXXX/
container, nomad alloc, pod ${TMPDIR:-/tmp}/<user>.hi.log.<pid>/, mode 700, refused if it exists

That directory is $_HI_HOME and $_HI_CLEANUP. Inside it:

Path What
say-hi/ $_HI_ROOT: the unpacked payload
say-hi/config/ $_HI_CONFIG_DIR: hi’s defaults with the unpacked overlay over them
say-hi/hi.bashrc the bootloader rc: names this tree, then sources load.sh
say-hi/.hi_fallback_rc, say-hi/.zshrc on a target without bash: the aliases-and-prompt rc $ENV or ZDOTDIR points at (the container arm keeps these, and a lone aliases.sh, at the top of the directory)
hi.rc.XXXXXX/ the session rc directory, below

The ssh arm also lands its bootloader in ${TMPDIR:-/tmp}/hi.boot.XXXXXX/, removed when the session ends. A read-only root works when $TMPDIR names a writable mount; with nowhere writable, hi says so and names --plain, which writes nothing. How the tree goes on exit is SECURITY.md’s; the container arm’s client also removes it after the attach returns.

The session rc directory

hi.rc.XXXXXX/, pointed at by $_HI_SESSION_RC. Each shell’s rc sources the target’s own rc first, then re-points _HI_HOME, _HI_ROOT, and _HI_CONFIG_DIR at the session tree, then sources hi’s:

File For
bashrc bash --rcfile: ~/.bashrc, then common/bash.sh
.zshenv ZDOTDIR points here: sources ~/.zshenv with ZDOTDIR unset, keeps where it left it, points it back
.zshrc the .zshrc in that ZDOTDIR (~/.zshrc by default), read under it, then common/zsh.zsh
fish.config fish -C: blanks fish_greeting, then common/config.fish (fish has read ~/.config/fish/config.fish already)
shrc $ENV for sh, dash, and ash: common/paths.sh and common/aliases.sh

What a target’s files are read for

Path Why
/etc/profile, then ~/.bash_profile, ~/.bash_login, or ~/.profile the login chain bash --rcfile skips, restored with _HI_REMOTE_SESSION=1 already set
~/.bashrc, ~/.zshenv, ~/.zshrc, ~/.config/fish/config.fish the target’s own shell setup, under hi’s
/etc/passwd (through getent) the login shell, when $SHELL is unset
everything in Paths hi recognizes that applies to a shell the header, prompt, and completion, the same as locally

The editors never read a target’s own rcs: the home lookup is off with _HI_REMOTE_SESSION=1, and $VIMINIT names the session’s vimrc.

Writes outside the session tree

Path When
fish’s universal variable store (~/.config/fish/fish_variables) a fish session caches its two prompt colors there, as it does locally
the runtime directory’s caches only when hi is run again from inside the session, to reach a further target

The editors are started so they leave nothing behind: neovim with XDG_STATE_HOME, XDG_DATA_HOME, and XDG_CACHE_HOME under the session tree’s nvim/, so its shada, swap, undo, log, and vim.loader cache go with the session; vim with the same three under vim/, for a vimrc that keeps its undo files there, and no viminfo (-i NONE); micro with no backups or history.

Packaged installs

Channel Tree hi Also
.deb, .rpm, .apk /usr/share/say-hi/ /usr/bin/hi → hi.sh /etc/profile.d/say-hi.sh (exports _HI_HOME), /usr/share/man/man1/hi.1.gz
install.sh --prefix <dir> $DESTDIR<dir>/say-hi/ (default /usr/share) $DESTDIR/usr/bin/hi the same profile snippet and man page; no rc files, no sudo
AUR (say-hi, say-hi-git) /usr/share/say-hi/, through install.sh --prefix /usr/bin/hi /usr/share/licenses/<package>/LICENSE.md
Homebrew #{libexec}/say-hi/ #{bin}/hi, a wrapper exporting _HI_HOME #{man1}/hi.1; no profile snippet

A package touches no user’s rc files: each user runs hi --install. Adding a repository places /etc/apt/keyrings/say-hi.asc and /etc/apt/sources.list.d/say-hi.list, /etc/yum.repos.d/say-hi.repo, or /etc/apk/keys/say-hi.rsa.pub and a line in /etc/apk/repositories (PACKAGING.md).

Build and release artifacts

All under dist/ in the checkout (packaging/mkpkg.sh --outdir moves it).

Path What
dist/staging/ the tree as install.sh --prefix /usr/share lays it out, before nfpm
dist/*.deb, *.rpm, *.apk the packages
dist/say-hi-<version>.tar.gz the source tarball
dist/SHA256SUMS, SHA256SUMS.minisig checksums of the above, and their signature when the release key is present
dist/ARTIFACTS the file list the release workflow uploads
dist/manifests/ the bumped PKGBUILD, SRCINFO, and say-hi.rb
dist/say-hi.spdx.json the SBOM, alongside build-provenance attestations
dist/repo/, dist/package-repo.tar.gz the signed apt, rpm, and apk repositories, and the archive the docs site serves

This site uses Just the Docs, a documentation theme for Jekyll.