A macOS CLI tool for project-specific command aliases. Define commands locally within project directories, making team workflows more efficient and discoverable.
Features
- Project-scoped storage - Aliases live in
.ez_cli.jsonfiles at the directory level, keeping commands tethered to their respective projects - Safety through locality - No global aliases means no accidental damage in a different directory
- Team collaboration - Commit the config file to version control so new team members get immediate access to established commands. As with a
Makefileornpm run, running an alias from a cloned repo runs whatever commands that repo's authors defined — review.ez_cli.jsonbefore running aliases from sources you don't trust - Fast - Built in Swift with instant startup times and no third-party dependencies — the only package used is Apple's own swift-argument-parser
- Secrets management - Store API keys and tokens in Apple Keychain, reference them in aliases without exposing values in terminal output or the process table
- Private - Makes no network calls; run history is recorded locally in
~/.ez/runs.dband never leaves your machine - Interactive support - Full terminal passthrough for interactive applications like vim and ssh
- Shell integration - zsh tab completion for command discovery
- Built-in analytics - Local runtime tracking;
ez statsshows per-alias duration history and trends
Installation
brew tap urtti/ez && brew install ezUpgrade an existing install:
brew update && brew upgrade ezSee CHANGELOG.md for what changed in each release.
Usage
Add an alias:
ez add deploy "./scripts/deploy.sh --env prod"Run an alias:
List all aliases:
Remove an alias:
Parameterized aliases with {1}, {2}, ... placeholders:
ez add tag 'git tag -a {1} -m "Release {1}"' ez tag v2.0.0 # → git tag -a v2.0.0 -m "Release v2.0.0"
Extra arguments are automatically appended to the end of the command:
ez add gs "git stash" ez gs pop # → git stash pop ez add greet 'echo hello {1}' ez greet world a b # → echo hello world a b
Store secrets in Apple Keychain and reference them in aliases:
ez add-secret --key EZ_API_KEY # prompts for the value with typing hidden ez add deploy 'curl -H "Authorization: {EZ_API_KEY}" https://api.example.com/deploy' ez deploy # secret is injected at runtime, never shown in terminal output
In scripts, pipe the value on stdin instead:
op read "op://vault/api/key" | ez add-secret --key EZ_API_KEY --force
(--value is also accepted but deprecated — it leaves the secret in shell history and ps — and will be removed in a future release.)
Remove a secret:
ez remove-secret EZ_API_KEY
Run multiple commands sequentially:
ez build && ez test && ez deploy
Run commands in parallel:
How It Works
Aliases are stored in .ez_cli.json files within each directory. This keeps commands context-specific and prevents conflicts between projects. To clear all aliases in a directory, simply delete the .ez_cli.json file.
Every alias run is also recorded in a local SQLite database at ~/.ez/runs.db (override the location with $EZCLI_HOME): working directory, alias name, the command template — never substituted arguments or secret values — exit code, duration, and timestamp, plus machine context for reading the timing series later (hardware model, CPU, core counts, RAM, macOS version, a locally generated random machine ID stored at ~/.ez/machine_id, and a runs-since-boot counter — nothing derived from your hostname or username). View it with ez stats <alias> -v. Nothing is ever sent anywhere; delete the files to clear all history.
Requirements
- macOS 15.0+
Development
Building
Running from source
Testing
Run the acceptance test suite:
The script builds the binary, runs it in an isolated temp directory, and asserts on output — nothing touches your real aliases, run history, or (aside from a dedicated canary key it cleans up) your Keychain.
Interactive TTY features (vim, less, signal handling) can't be automated; verify those manually with:
./acceptance-test-interactive.sh
Project Structure
ezcli/- Source codeacceptance-test.sh- Automated test suiteacceptance-test-interactive.sh- Manual tests for interactive/TTY features
Build Requirements
- Swift 6.0+
- Xcode 16.4+
Xcode Setup
If building for device or distribution, set your own Apple Development Team in the Xcode project settings.
License
MIT
