Project Aliases
Project aliases live in a .aliases file at your project root. They load automatically when you cd into the directory and unload when you leave — like direnv, but for aliases.
Adding Project Aliases
Use the -l (local) flag:
cd ~/my-project
am add -l t "./x.py test"
am add -l b "./x.py build"If no .aliases file exists, one is created in the current directory. If a .aliases already exists further up the directory tree, you'll be asked whether you meant to add to that one instead.
Removing Project Aliases
Use the same -l flag with am remove:
am remove -l t
am remove -l bThis updates the .aliases file and refreshes the cryptographic hash automatically, so no trust warning is triggered.
The .aliases File
You can also create or edit the file directly:
# /path/to/my-project/.aliases
[aliases]
t = "./x.py test"
b = "./x.py build"Trust Model
Project .aliases files can contain arbitrary shell commands. Since anyone could put a .aliases file into a repository, amoxide requires you to explicitly trust each file before its aliases are loaded — similar to how direnv handles .envrc files.
First encounter
When you cd into a directory with an untrusted .aliases file, you'll see:
am: .aliases found but not trusted. Run 'am trust' to review and allow.No aliases are loaded until you review and approve them.
Reviewing and trusting
Run am trust to review the aliases and decide:
❯ am trust
Reviewing .aliases at /home/user/projects/my-app
b → make build
t → cargo test
cb → cargo build
Trust these aliases? [Y/n]If the file contains suspicious content (hidden escape sequences or control characters), a warning is shown before the prompt.
Answering yes trusts the file — aliases are loaded immediately:
am: loaded .aliases
b → make build
t → cargo test
cb → cargo buildAnswering no marks the directory as untrusted. Future cds into it will be silent — no warnings, no aliases.
Revoking trust
am untrust # mark as untrusted (silent on cd)
am untrust --forget # remove from tracking entirely (will prompt again)Tamper detection
amoxide stores a cryptographic hash (BLAKE3) of every trusted .aliases file. If the file changes outside of am, the hash won't match and you'll see:
am: .aliases was modified since last trusted. Run 'am trust' to review and allow.This happens when the file is edited manually, updated by git pull, or changed by any tool other than am. The warning repeats on every cd until you review the changes with am trust.
When you use am itself to modify the file — via am add -l or am remove -l — the hash is updated automatically, so those changes never trigger this warning.
Load and Unload Messages
When you cd into a directory with a trusted .aliases file, amoxide shows which commands became available. When you leave, it reports what changed. Both messages can be configured independently.
These messages only appear when entering or leaving the directory containing the .aliases file — not when navigating subdirectories within the same project.
Loading (cd into a project)
The default ("verbose") shows an aligned table:
am: loaded .aliases
b → make build
t → cargo testSet to "short" for a compact one-liner:
am: loaded .aliases: b, tSet to "off" to suppress the message entirely.
Unloading (cd out of a project)
The default ("verbose") shows a change summary including which aliases were unloaded and which were added back (e.g. a profile alias becoming active after the project alias that was shadowing it is removed):
am: .aliases unloaded — 2 added: i, t | 2 unloaded: docs, fSet to "short" for a brief confirmation:
am: .aliases unloadedSet to "off" to suppress the message entirely.
Configuring verbosity
Add a [logging] section to ~/.config/amoxide/config.toml:
[logging]
project_loading = "verbose" # "off" | "short" | "verbose"
project_unloading = "short" # "off" | "short" | "verbose"Both default to "verbose" if omitted. See Config File Reference for the full reference. Introduced in #109.
How It Works
The am init shell hook calls am sync <shell> on every directory change. Sync:
- Walks up from the current directory looking for a
.aliasesfile (stopping before$HOME) - Checks whether the file is trusted (path + hash match in
security.toml) - Merges all layers with precedence — global < profile < project — and computes the minimal set of shell operations needed
- Emits only the unloads/loads that actually change the shell (unchanged aliases stay put)
- If the file is not trusted, shows a warning or stays silent, depending on the trust state
This means aliases automatically follow your context — switch to a Rust project and get Rust aliases, switch to a Node project and get Node aliases — as long as you've trusted the respective .aliases files. When a project alias shares a name with a profile alias, the project value wins; when you leave the project, the profile value takes over automatically.
Workflow
A natural workflow is to start with project-local aliases, then refactor duplicates into profiles:
Step 1: Add project-specific aliases:
am add -l t cargo test
am add -l l cargo clippy --all-targets -- -D warnings
am add -l i cargo install --path .Step 2: Notice t and l are the same across Rust projects. Extract to a profile:
am profile add rust
am add -p rust t cargo test
am add -p rust l cargo clippy --all-targets -- -D warnings
am profile use rustNow the project .aliases keeps only truly project-specific aliases like i.
TIP
am tui lets you move aliases between project and profile levels visually — select an alias and press m to move it.
Moving Aliases with the TUI
Use am tui to move aliases from project level to a profile visually — select an alias and press m: