diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index b1efbec13..bab5c161f 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -182,6 +182,7 @@ brews:
install: |
bin.install "aicr"
bin.install "aicr-attestation.sigstore.json" if File.exist? "aicr-attestation.sigstore.json"
+ generate_completions_from_executable(bin/"aicr", "completion")
test: |
assert_match version.to_s, shell_output("#{bin}/aicr version")
caveats: |
diff --git a/docs/user/installation.md b/docs/user/installation.md
index 61cda62a0..107cc7a3f 100644
--- a/docs/user/installation.md
+++ b/docs/user/installation.md
@@ -40,6 +40,7 @@ This script:
- Detects your OS and architecture automatically
- Downloads the appropriate binary from GitHub releases
- Installs to `/usr/local/bin/aicr` by default (use `-d
` for a custom location)
+- Installs shell completions for bash, zsh, and fish (set `AICR_NO_COMPLETIONS=1` to skip)
- Verifies the installation
- Uses `GITHUB_TOKEN` environment variable for authenticated API calls (avoids rate limits)
@@ -99,26 +100,41 @@ Expected output shows version information and available commands.
## Post-Installation
-### Shell Completion (Optional)
+### Shell Completion
-Enable shell auto-completion for command and flag names:
+Tab completion for commands and flags is installed automatically by both the Homebrew formula and the install script. No manual setup is required.
+
+**Opt out** (install script only): set `AICR_NO_COMPLETIONS=1` before running the script:
-**Bash:**
```shell
-# Add to ~/.bashrc
-source <(aicr completion bash)
+AICR_NO_COMPLETIONS=1 curl -sfL https://raw.githubusercontent.com/NVIDIA/aicr/main/install | bash -s --
```
-**Zsh:**
+**Manual setup** (build from source or `go install`):
+
+Bash:
```shell
-# Add to ~/.zshrc
-source <(aicr completion zsh)
+aicr completion bash > "${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions/aicr"
+```
+
+Zsh:
+```shell
+aicr completion zsh > "${XDG_DATA_HOME:-$HOME/.local/share}/zsh/site-functions/_aicr"
```
-**Fish:**
+Fish:
```shell
-# Add to ~/.config/fish/config.fish
-aicr completion fish | source
+aicr completion fish > ~/.config/fish/completions/aicr.fish
+```
+
+Alternatively, source completions dynamically in your shell RC file (evaluates on every shell start):
+
+```shell
+# Bash (~/.bashrc)
+source <(aicr completion bash)
+
+# Zsh (~/.zshrc)
+source <(aicr completion zsh)
```
## Container Images
@@ -180,8 +196,15 @@ nvidia-smi
# Remove binary
sudo rm /usr/local/bin/aicr
-# Remove shell completion (if configured)
-# Remove the source line from your shell RC file
+# Remove shell completions (remove whichever exist)
+sudo rm -f /usr/share/bash-completion/completions/aicr
+sudo rm -f /usr/local/share/zsh/site-functions/_aicr
+sudo rm -f /opt/homebrew/share/zsh/site-functions/_aicr
+sudo rm -f /opt/homebrew/etc/bash_completion.d/aicr
+sudo rm -f /usr/local/etc/bash_completion.d/aicr
+rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions/aicr"
+rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/zsh/site-functions/_aicr"
+rm -f "${XDG_CONFIG_HOME:-$HOME/.config}/fish/completions/aicr.fish"
```
## Getting Help
diff --git a/install b/install
index aa9d22d12..e5922eddb 100755
--- a/install
+++ b/install
@@ -30,7 +30,8 @@ Install utility for $BIN_NAME
Usage: $0 [-d install_dir]
Environment Variables:
- GITHUB_TOKEN GitHub token to avoid API rate limits (no special scopes required)
+ GITHUB_TOKEN GitHub token to avoid API rate limits (no special scopes required)
+ AICR_NO_COMPLETIONS Set to 1 to skip shell completion installation
Examples:
$0 # Install to /usr/local/bin
@@ -106,6 +107,97 @@ get_archive_name() {
echo "${BIN_NAME}_${ver}_${2}_${3}.tar.gz" # version, os, arch
}
+# ==============================================================================
+# Shell Completion Setup
+# ==============================================================================
+
+write_completion() {
+ local bin_path="$1" shell="$2" target="$3"
+ local target_dir tmp_file
+ target_dir=$(dirname "$target")
+ mkdir -p "$target_dir" 2>/dev/null || sudo mkdir -p "$target_dir" 2>/dev/null || return 1
+ tmp_file=$(mktemp) || return 1
+ if ! "$bin_path" completion "$shell" > "$tmp_file" 2>/dev/null || [[ ! -s "$tmp_file" ]]; then
+ rm -f "$tmp_file"
+ return 1
+ fi
+ chmod 644 "$tmp_file"
+ if [[ -w "$target_dir" ]]; then
+ mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; }
+ else
+ sudo mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; }
+ fi
+}
+
+setup_bash_completions() {
+ local bin_path="$1" os="$2" xdg_data="$3"
+ local sys_dir
+ if [[ "$os" == "darwin" ]]; then
+ local brew_prefix="/usr/local"
+ [[ -d /opt/homebrew ]] && brew_prefix="/opt/homebrew"
+ sys_dir="${brew_prefix}/etc/bash_completion.d"
+ else
+ sys_dir="/usr/share/bash-completion/completions"
+ fi
+
+ if write_completion "$bin_path" bash "${sys_dir}/aicr"; then
+ ok "Bash completions installed"
+ elif write_completion "$bin_path" bash "${xdg_data}/bash-completion/completions/aicr"; then
+ ok "Bash completions installed (user-local)"
+ else
+ warn "Could not install bash completions"
+ fi
+}
+
+setup_zsh_completions() {
+ local bin_path="$1" os="$2" xdg_data="$3"
+ local sys_dir
+ if [[ "$os" == "darwin" ]]; then
+ local brew_prefix="/usr/local"
+ [[ -d /opt/homebrew ]] && brew_prefix="/opt/homebrew"
+ sys_dir="${brew_prefix}/share/zsh/site-functions"
+ else
+ sys_dir="/usr/local/share/zsh/site-functions"
+ fi
+
+ if write_completion "$bin_path" zsh "${sys_dir}/_aicr"; then
+ ok "Zsh completions installed"
+ elif write_completion "$bin_path" zsh "${xdg_data}/zsh/site-functions/_aicr"; then
+ ok "Zsh completions installed (user-local)"
+ else
+ warn "Could not install zsh completions"
+ fi
+}
+
+setup_fish_completions() {
+ local bin_path="$1"
+ local sys_dir="/usr/share/fish/vendor_completions.d"
+ local user_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish/completions"
+
+ if [[ -d "$sys_dir" ]] && write_completion "$bin_path" fish "${sys_dir}/aicr.fish"; then
+ ok "Fish completions installed"
+ elif [[ -d "${user_dir%/*}" ]] && write_completion "$bin_path" fish "${user_dir}/aicr.fish"; then
+ ok "Fish completions installed (user-local)"
+ fi
+}
+
+setup_completions() {
+ if [[ "${AICR_NO_COMPLETIONS:-0}" == "1" ]]; then
+ info "Skipping shell completion setup (AICR_NO_COMPLETIONS=1)"
+ return 0
+ fi
+
+ local bin_path="${INSTALL_DIR}/${BIN_NAME}"
+ local os xdg_data
+ os=$(get_os)
+ xdg_data="${XDG_DATA_HOME:-$HOME/.local/share}"
+ step "Setting up shell completions..."
+
+ setup_bash_completions "$bin_path" "$os" "$xdg_data"
+ setup_zsh_completions "$bin_path" "$os" "$xdg_data"
+ setup_fish_completions "$bin_path"
+}
+
# ==============================================================================
# GitHub API Functions
# ==============================================================================
@@ -313,6 +405,9 @@ main() {
[[ -f "${INSTALL_DIR}/${BIN_NAME}-attestation.sigstore.json" ]] && \
msg "Attestation: ${INSTALL_DIR}/${BIN_NAME}-attestation.sigstore.json"
+ # Install shell completions
+ setup_completions || warn "Shell completion setup failed (non-fatal)"
+
# Fetch latest Sigstore trusted root for offline verification.
# The trusted root enables 'aicr verify' to check attestation signatures
# without contacting Sigstore infrastructure. If this fails (e.g., no network),