ez

PROJECT-SCOPED ALIASES

Stop memorizing context-specific commands.
Define aliases per directory. Share them with your team.
Performance of every run is locally tracked, giving insights on performance trends over time.

Terminal recording: ez test reports the run was 74% slower than its median, ez stats shows three weeks of drift, and ez stats lists each alias with its duration trend
Install
brew tap urtti/ez && brew install ez
Update
brew update && brew upgrade ez

Core Features

Project-scoped

Aliases are defined in a .ez_cli.json file per directory. They only exist where they are defined.

Team sharing

Commit the config file. New team members get all project aliases with the repository.

Keychain secrets

Secrets live in Apple Keychain and are handed to the command through its environment โ€” never written to disk, never printed, never visible in ps.

Parameterized

Aliases support {1} {2} placeholders. Arguments are substituted at runtime, and extra arguments append automatically.

NEW IN 1.3

Run history

Every run is recorded locally. ez stats reports success rate, median, p90, and a duration trend per alias.

NEW IN 1.3

Outlier alerts

A run that is meaningfully off its own median flags a notice directly on its timing line.

NEW IN 1.3

Parallel mode

Aliases added with -p run commands concurrently, each with individual timing and shared Ctrl+C handling.

Real exit codes

Aliases pass through the exit code of their driven process, ensuring ez test && ez deploy behaves in CI and scripts.

Interactive passthrough

Full terminal passthrough for interactive CLI tools like vim, less, and ssh.

Swift CLI

A single native Swift binary with instant startup and zero runtime dependencies.

Private & Local

ez itself makes zero telemetry or external network calls. Run history is stored strictly in a local SQLite file at ~/.ez/runs.db.

MIT license

Open source. Read the code, fork it, contribute, or ship it.

Usage

Create alias & use it

$ ez add deploy "./scripts/deploy.sh --env prod"๐Ÿ˜ ez deploy now stores ./scripts/deploy.sh --env prod. Execute in this directory with ez deploy.
$ ez deploy๐Ÿ˜ Executing: ./scripts/deploy.sh --env prod
Deploying to production...
๐Ÿ˜โฑ๏ธ 47.900 s

List aliases

$ ez list
๐Ÿ˜ Aliases
ez test npm test -- --coverage
ez deploy ./scripts/deploy.sh --env prod

Add & use secrets

$ ez add-secret --key EZ_API_KEYEnter value for EZ_API_KEY:
๐Ÿ˜ Secret 'EZ_API_KEY' stored in keychain.
$ ez add upload 'curl -H "Authorization: {EZ_API_KEY}" ...'๐Ÿ˜ ez upload now stores curl -H "Authorization: {EZ_API_KEY}" ... Execute in this directory with ez upload.
$ ez upload๐Ÿ˜ Executing: curl -H "Authorization: {EZ_API_KEY}" https://api.example.com
The value is read from Keychain and passed through the environment โ€” it never reaches the screen, the process table, or disk.

Create alias with parameters

$ ez add tag 'git tag -a {1} -m "Release {1}"'๐Ÿ˜ ez tag now stores git tag -a {1} -m "Release {1}". Execute in this directory with ez tag.
$ ez tag v2.0.0๐Ÿ˜ Executing: git tag -a v2.0.0 -m "Release v2.0.0"

See which commands got slower

โœจ NEW IN 1.3

Every alias run is recorded in a local SQLite file, scoped to the directory it ran in. Only the alias definition is stored โ€” arguments and resolved secrets are never written to disk.

$ ez stats
๐Ÿ˜ Run history
alias success rate median duration duration trend
ez build 18 of 18 12.400 s โ†‘ 33% slower
ez deploy 6 of 6 47.900 s ยท needs 4 more runs
ez test 22 of 25 4.135 s โ†’ steady
$ ez stats build
๐Ÿ˜ Recent runs ez build (18)
2026-08-19 15:29:02 16.800 s ok
2026-08-19 14:29:02 15.900 s ok
2026-08-19 10:29:02 12.100 s ok
...
๐Ÿ˜ Summary ez build (18 successful run(s))
min 11.600 s median 12.400 s p90 16.800 s max 17.200 s
trend โ†‘ 33% slower โ€” last 5 median 16.100 s vs 12.100 s before

Automatic Outlier Alerts

โœจ NEW IN 1.3
$ ez test
๐Ÿ˜ Executing: npm test -- --coverage
...
๐Ÿ˜โฑ๏ธ 6.410 s โ†‘ 56% slower than median 4.115 s

The note only appears when there is something to say: enough history for a trustworthy median, and a difference big enough to matter. Ordinary runs print the timing and nothing else.

Run commands concurrently

โœจ NEW IN 1.3
$ ez add -p checks "npm run lint" "npm run typecheck"๐Ÿ˜ ez checks now stores npm run lint | npm run typecheck. Execute in this directory with ez checks.
$ ez checks
๐Ÿ˜ Executing: npm run lint | npm run typecheck
๐Ÿ˜ Running in parallel: npm run lint, npm run typecheck
Started [PID:41482] npm run lint...
Started [PID:41483] npm run typecheck...
๐Ÿ˜โฑ๏ธ [PID:41482] npm run lint 2.110 s
๐Ÿ˜โฑ๏ธ [PID:41483] npm run typecheck 3.810 s
$ ez checks && ez deployAn alias exits with the code of the work it ran, so a failed check stops the chain.