Create, manage, and run shell aliases from a single interface. Works cross-platform with bash, zsh, fish, PowerShell, cmd, Nushell, and Xonsh.
Two ways to run any alias:
gs— native shell command (after one-time hook install)qwik -r gs— works anywhere, no setup needed
- Installation
- Quick Start
- Core Concepts
- Commands
- Alias Templates & Arguments
- Shell Integration
- Conflict Detection
- Storage & Backups
- Environment Variables
- Development
pipx install qwikOr with uv:
uv tool install qwikqwik add gs "git status"
qwik init zsh --install
source ~/.zshrc
gs # native shell alias
qwik -r gs # same thing, no hook needed| Way | Example | When to use |
|---|---|---|
| Native | gs |
Daily use after one-time shell hook setup |
| Via qwik | qwik -r gs |
Scripts, CI, restricted shells, or pre-setup |
Both share the same store and substitution engine — behavior is identical.
- You register aliases with
qwik add - You install a one-line shell hook with
qwik init --install - Every new shell session regenerates shell-native aliases from the store
- You type
gsjust like a normal alias — because it is one
qwik add gs "git status"
qwik add gs "git status" --tag git --description "Repo status"
qwik add gs "git status" --group git
qwik add gs "git status" --force # overwrite existing
qwik add # interactive modeqwik rm gs
qwik rm gs --yes # skip confirmationqwik rename gs gstat # preserves statsqwik edit gs
# Opens TOML snippet in your $EDITOR:
# command = "git status"
# tag = ["git"]
# group = ""
# description = ""
# enabled = true
# Save and quit to apply changes.qwik disable gs # hides from shell hook
qwik enable gs # re-enablesqwik list # all aliases
qwik -l # shortcut
qwik list --tag git # filter by tag
qwik list --group git # filter by group
qwik list --search stat # filter by queryOutput:
Name Command Group Tag Used Last
───── ────────────────────────── ────── ───── ───── ───────────
gs git status git git 42 2 min ago
gco git checkout {1} git git 18 1 hour ago
k kubectl — k8s 7 yesterday
qwik show gs # full metadataqwik search "git"
qwik -s "git" # shortcut
qwik search "git" --group git # restrict to a groupqwik # bare invocation
qwik pick- Type characters to filter matching aliases live
↑/↓navigateEnterruns the selected aliasCtrl+Eedits itCtrl+Ddeletes itEsccancels
qwik run gs
qwik run gs --short # pass extra args
qwik -r gs --short # shortcut flagqwik tag gs git
qwik tag gs work
qwik untag gs workqwik group gs git # assign primary group
qwik ungroup gs # remove the groupAn alias has at most one group (the canonical primary namespace it
belongs to) but may carry many tags (free-form labels). Use --group
on add, list, and search to filter by group.
qwik export ~/aliases.toml # share / backup
qwik import ~/aliases.toml # merge
qwik import ~/aliases.toml --overwrite # replace the whole store — aliases
# not in the file are deleted; the
# preview lists them before you confirmqwik sync keeps a separate git repo at <config_dir>/qwik-sync/ so your aliases travel between machines. push exports the live store → commits → pushes; pull pulls the remote → import-merges into your live store (with the same trust-boundary preview as qwik import).
qwik sync init --remote <git-url> # one-time setup; exports current store + first commit
qwik sync push [-m "msg"] # export → commit (if dirty) → push
qwik sync pull [-y] # pull → preview → merge into live store
qwik sync status # branch, remote, dirty, ahead/behind, alias countsync init writes sync.toml (remote + branch) and aliases.toml (your store) into the sync repo and makes the first commit. sync push overwrites aliases.toml with the current live store, commits only if the tree is dirty, then pushes to origin <branch>. sync pull runs git pull, then shows the same trust-boundary preview as qwik import — incoming commands run under shell=True, so review the preview before confirming.
Trust warning: pulled stores are a code-execution vector. Always review the command preview before confirming a
sync pull; only sync with repos you control.
qwik overlay add --url https://github.com/team/qwik-aliases --branch main
qwik overlay list # show overlay aliases
qwik overlay update # fetch and show added/changed/removed before applying
qwik overlay copy --name gs # copy an overlay alias to your user store
qwik overlay remove # remove the overlayoverlay add and overlay update show the same trust-boundary preview as
qwik import/qwik sync pull — the incoming (or changed) commands, and a
confirmation prompt — before anything is applied; pass --yes to skip the
prompt. update reports "already up to date" and doesn't prompt when
nothing changed. The overlay repo is managed with git clone on add and
git fetch + git reset --hard on update, so it always exactly mirrors
the remote branch and can't enter a merge-conflict state.
Trust warning: overlay aliases are a code-execution vector — anyone with push access to the overlay repo can add or change a command that runs under
shell=Truethe next time you use it. Always review the preview before confirming anoverlay add/update; only point the overlay at a repo you control.
Overlay aliases appear in qwik list, qwik search, qwik init, and the
picker — marked (overlay) in list/search — but cannot be edited or
removed (they're read-only). A user alias with the same name shadows the
overlay one. Running an overlay alias copies it to your user store for
usage tracking.
qwik doctor # shell, hook, store, conflicts, sync repoqwik init zsh # print hook to stdout
qwik init zsh --install # append to ~/.zshrc with backupSupported shells: bash, zsh, fish, pwsh.
Every qwik invocation defers importing prompt_toolkit (used only by
the interactive pick screen) and caches shell-renderer discovery
instead of re-scanning installed-package metadata on each call — so a
qwik call your shell hook makes on every prompt, like qwik init,
isn't paying for either.
Generate or install shell completion scripts for qwik itself (so qwik <Tab> offers command/alias suggestions).
qwik completion bash # print completion script to stdout
qwik completion zsh --install # install into ~/.zshrc + ~/.zfunc/_qwik| Shell | --install action |
|---|---|
| bash | writes ~/.bash_completions/qwik.sh + appends source line to ~/.bashrc |
| zsh | writes ~/.zfunc/_qwik + appends fpath/compinit to ~/.zshrc |
| fish | writes <fish config>/completions/qwik.fish (auto-loaded, no rc edit) |
| pwsh / powershell | appends the script to $PROFILE |
Installs are idempotent (a # qwik completion (<shell>) marker is checked before appending) and back up the rc file with a timestamp before modifying it.
Typer's built-in
qwik --install-completion <shell>/qwik --show-completion <shell>also works;qwik completionprovides the same scripts with qwik's own backup + idempotency behavior.
qwik supports third-party shell renderers and CLI commands via Python entry points:
- Shell renderers: Register a class implementing
ShellRendererunder theqwik.shell_renderersentry-point group in yourpyproject.toml. - CLI commands: Register a Typer-compatible callable under the
qwik.commandsentry-point group.
# In your plugin's pyproject.toml
[project.entry-points."qwik.shell_renderers"]
myshell = "my_package.shell:MyShellRenderer"qwik --version
qwik -v
qwik --help
qwik -h
qwik --no-color # disable colored output for this invocationAliases can pass arguments through unchanged or interpolate them into the command.
Extra args are appended after quoting.
qwik add gs "git status"
gs --short # → git status --shortUse {…} markers to substitute arguments into the command.
| Placeholder | Meaning |
|---|---|
{1}, {2}, {3}… |
Nth positional argument (1-based) |
{name} |
Named slot — mapped to a positional index by order of first appearance (see below) |
{@} |
All arguments joined with spaces |
{*} |
All arguments as a single quoted string |
{1:-default} |
Nth positional, falling back to default if missing |
{name:-default} |
Named slot, falling back to default if the arg is missing |
Single positional:
qwik add gco "git checkout {1}"
gco main # → git checkout mainNote:
{1},{@}, and{N:-default}interpolations are quoted at runtime, so args containing shell metacharacters are passed safely.{*}is shell-quoted as a single string. For example,qwik run gco '; rm -rf /'expands togit checkout '; rm -rf /'on a POSIX shell — the;is quoted and treated as a literal argument, not a command separator.The quoting rule depends on which shell will actually run the expanded command — chosen by
qwik run's shell detection, not by the host platform (a user can be running POSIX bash under Git Bash or WSL on a Windows host).shlex.quote's POSIX single-quote syntax is used for bash/zsh/fish; cmd.exe gets caret-escaped metacharacters wrapped in doubled double quotes; PowerShell gets single-quoted strings with embedded'doubled, invoked viapwsh/powershellexplicitly rather than throughcmd.exe's defaultshell=Trueinterpreter. The guarantee above holds on all three; it does not extend tonuorxonsh, which currently fall back to POSIX quoting.
Multiple positionals:
qwik add gcm 'git commit -m "{1}: {2}"'
gcm feat "add login"
# → git commit -m "feat: add login"Named placeholders (readable):
qwik add gco "git checkout {branch}"
gco main # → git checkout main
qwik add gcm 'git commit -m "{type}: {scope}"'
gcm feat login # → git commit -m "feat: login"Named placeholders are mapped to positional arguments by order of first appearance: the first distinct name is {1}, the second is {2}, and so on. Repeating a name reuses its index (echo {a} {a} with arg x → echo x x). Named and numeric placeholders share the same index space — echo {1} {name} with args a b → echo a b ({1}=a, {name}=b at index 2).
Note: Named placeholder names must start with a letter or underscore and contain only letters, digits, underscores, and hyphens (
^[A-Za-z_][A-Za-z0-9_-]*$). A{…}that doesn't match this pattern and isn't a numeric/@/*placeholder is left as a literal — so{123bad}and{some text}in a command are passed through untouched.
Default value:
qwik add gpo "git push origin {1:-main}"
gpo # → git push origin main
gpo feature/x # → git push origin feature/xAll args joined:
qwik add gc-chore 'git commit -m "chore: {@}"'
gc-chore init version
# → git commit -m "chore: init version"All args as one quoted string:
qwik add note 'echo "Note: {*}"'
note hello world
# → echo "Note: 'hello world'"Mixed — template + appended extras:
qwik add k "kubectl {1}"
k get pods -n kube-system
# → kubectl get pods -n kube-system
# {1}=get, "pods -n kube-system" appended after template{N:-default} is especially useful for aliases with a sensible fallback:
qwik add co "git checkout {1:-main}"
co feature # → git checkout feature
co # → git checkout main (default){0}is rejected at add-time and at run-time — positional placeholders are 1-based- Named placeholders (
{name}) are 1-based by order of appearance, so there is no{0name}form;{0name}is a literal - Invalid brace content (e.g.
{123bad},{some text}) is left untouched as a literal, not an error - Missing required args produce a clear error at runtime instead of silently expanding to empty strings
Make aliases available as real shell commands.
bash:
qwik init bash --install
source ~/.bashrczsh:
qwik init zsh --install
source ~/.zshrcfish:
qwik init fish --install
source ~/.config/fish/config.fishPowerShell:
qwik init pwsh --installThe --install flag:
- Creates a timestamped backup of your rc file
- Appends the hook (idempotent — safe to run multiple times)
If you prefer to edit your rc file directly, qwik init <shell> prints the hook:
eval "$(qwik init zsh)"The hook generates native aliases/functions for each shell:
| Shell | Append mode | Template mode |
|---|---|---|
| bash / zsh | alias gs='git status' |
gs() { git checkout "$1" ; } |
| fish | alias gs 'git status' |
function gs ; … ; end |
| PowerShell | function gs { & ([ScriptBlock]::Create('git status')) @args } |
function gs { qwik run "gs" @args } |
| nu | def gs [...args] { qwik run "gs" ...$args } |
def gs [...args] { qwik run "gs" ...$args } |
| cmd | doskey gs=git status $* |
(best-effort, no template) |
PowerShell's append mode wraps the command as a string literal compiled into a script block at call time rather than splicing it into the function body as source, and cmd's doskey macros are $/metacharacter-escaped — both so a command containing }, &, $, or another shell's syntax can't break out of the generated definition. Nu has no equivalent to a compiled-string script block, so both modes delegate to qwik run. Supported characters in a command are documented per shell in docs/shell-quoting.md.
On cmd and pwsh, %VAR% and $VAR in alias commands are expanded by the
shell at run time, not treated as literal text. qwik add warns when it
detects these patterns. On bash/zsh/fish, $VAR expansion is the expected
behavior and no warning is shown. When the active shell is cmd and a template
alias ({1}, {name}) is created, qwik add also warns that cmd/doskey
cannot expand parameters and the alias will be omitted from cmd hooks.
Every add and rename validates the new name:
| # | Check | Result |
|---|---|---|
| 1 | Already an alias? | Refuse unless --force |
| 2 | Shell builtin? (cd, echo, alias, …) |
Refuse unless --force |
| 3 | Binary on $PATH? |
Warn but allow |
| 4 | Valid syntax? | Refuse if it contains spaces, slashes, $, backticks, semicolons |
Example UX:
qwik add ls "ls --color=auto"
⚠ Warning: "ls" shadows /usr/bin/ls.
Continue? [y/N]
qwik add cd "echo nope"
✗ "cd" is a shell builtin. Shadowing it can break your shell.
qwik add "my alias" "echo hi"
✗ Invalid name "my alias": contains whitespace.- Linux/macOS:
$XDG_CONFIG_HOME/qwik/aliases.toml(usually~/.config/qwik/aliases.toml) - Windows:
%APPDATA%\qwik\aliases.toml - Backups: every destructive operation writes to
qwik/backups/aliases-<timestamp>.toml(last 20 kept) - Atomic writes: temp file + rename to prevent corruption
- Format: human-readable TOML, safe to edit by hand
Example store file:
version = 1
[aliases.gs]
command = "git status"
tag = ["git"]
group = "git"
description = "Quick git status"
enabled = true
created_at = "2026-05-10T10:00:00Z"
updated_at = "2026-05-10T10:00:00Z"
last_used = "2026-05-10T11:30:00Z"
run_count = 42qwik writes a version = N field to the top of aliases.toml describing the schema of the file. On load, if the file's version is older than the current schema, qwik auto-migrates it forward (one migrator per version step) and backs up the pre-migration file before writing the new shape. Migration is forward-only — downgrade is not supported; restore from a backup (see qwik doctor) instead.
If the file's version is newer than the version qwik understands, qwik refuses to load it and points at qwik doctor — typically you need to upgrade qwik to a newer release.
| Variable | Purpose |
|---|---|
EDITOR |
Editor for qwik edit (default: vi) |
QWIK_CONFIG_DIR |
Override default config directory |
XDG_CONFIG_HOME |
Base config dir (used by fish rc resolution) |
QWIK_DEBUG=1 |
Enable debug logs to stderr |
NO_COLOR |
Disable colored output (also --no-color) |
QWIK_SHELL |
Force shell detection (bash, zsh, fish, pwsh, cmd, nu, xonsh) instead of auto-detecting from the environment/parent process |
# Install with dev dependencies
pip install -e ".[dev]"
# Run the test suite
pytest
# With coverage report
pytest --cov=qwik --cov-report=term-missingMIT