From c3828a747cb34decb42be6c43326f6958c91c0a0 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Mon, 5 Oct 2026 11:00:15 -0400 Subject: [PATCH] fix(atuin): use the packaged binary only ~/.atuin/bin held an old standalone atuin (18.19.0) that the shells prepended to PATH, shadowing pacman's /usr/bin/atuin (18.21.0). The daemon runs the packaged binary and migrated the history DB, so every shell command through the old one failed with "migration 20260818000000 was previously applied but is missing in the resolved migrations". Drop conf.d/atuin.env.fish, the `. ~/.atuin/bin/env` lines in .bashrc and .zshrc (atuin init is now guarded on `command -v atuin`), the cargo-dist receipt, and atuin-pick's ~/.atuin/bin fallback. Also drop `atuin ai init fish`, which 18.21 removed; config.fish already carries the `?` binding it emitted. --- docs/shell/atuin.mdx | 33 ++++++--------------------- docs/shell/bash-zsh.mdx | 4 ++-- docs/shell/fish.mdx | 5 ++-- docs/shell/scripts.mdx | 2 +- dot_bashrc | 6 +++-- dot_config/atuin/atuin-receipt.json | 1 - dot_config/fish/conf.d/atuin.env.fish | 2 -- dot_config/fish/config.fish | 3 ++- dot_local/bin/executable_atuin-pick | 7 +++--- dot_zshrc | 5 ++-- 10 files changed, 23 insertions(+), 45 deletions(-) delete mode 100644 dot_config/atuin/atuin-receipt.json delete mode 100644 dot_config/fish/conf.d/atuin.env.fish diff --git a/docs/shell/atuin.mdx b/docs/shell/atuin.mdx index 010f4d8..1001221 100644 --- a/docs/shell/atuin.mdx +++ b/docs/shell/atuin.mdx @@ -9,38 +9,22 @@ description: Shell history search with a daemon, directory-scoped up-arrow, tmux | --- | --- | --- | | `dot_config/atuin/private_config.toml` | `~/.config/atuin/config.toml` | `private_`: written as a regular `0600` file, not a symlink | | `dot_config/atuin/themes/cyberdream.toml` | `~/.config/atuin/themes/cyberdream.toml` | symlink | -| `dot_config/atuin/atuin-receipt.json` | `~/.config/atuin/atuin-receipt.json` | symlink | chezmoi runs in symlink mode, but `private_` files are written as real files, so edits to `~/.config/atuin/config.toml` do not reach the repo on their own. Copy them back with `chezmoi re-add` (or `czs`, see [fish](/shell/fish#functions)). None of the files are templates, and they apply on every role. ## Installation -`atuin` is listed in `.chezmoidata/packages.yaml` for pacman and Homebrew. The shells also expect atuin's standalone installer layout in `~/.atuin/bin`: +`atuin` is listed in `.chezmoidata/packages.yaml` for pacman and Homebrew, and the shells use that package's binary (`/usr/bin/atuin` on Arch). Each shell runs `atuin init` only if `atuin` is on `PATH`. -- fish: `conf.d/atuin.env.fish` sources `~/.atuin/bin/env.fish`. -- bash and zsh: `. "$HOME/.atuin/bin/env"` just before `atuin init`. - -Neither line checks that the file exists, so a machine without `~/.atuin/bin` prints a sourcing error at shell start. - -### atuin-receipt.json - -The receipt that atuin's [cargo-dist](https://opensource.axo.dev/cargo-dist/) installer writes. It records how atuin was installed, which the self-updater (`atuin update`) needs: - -| Field | Value | -| --- | --- | -| `binaries` | `["atuin"]` | -| `install_prefix` | `~/.atuin/bin` (stored as an absolute path under `/home/prad`) | -| `install_layout` | `flat` | -| `modify_path` | `true` | -| `provider` | cargo-dist `0.31.0` | -| `source` | GitHub release `atuinsh/atuin` | -| `version` | `18.19.0` | +:::note[No standalone install] +An earlier setup also kept atuin's standalone installer layout in `~/.atuin/bin` (with a cargo-dist `atuin-receipt.json` in the repo) and prepended it to `PATH` from `conf.d/atuin.env.fish` and `. "$HOME/.atuin/bin/env"` in `.bashrc`/`.zshrc`. That copy fell behind the package: the daemon, from the newer package, migrated the history database, and every command the shells ran through the old binary failed with `migration 20260818000000 was previously applied but is missing in the resolved migrations`. The standalone install, its receipt, and the `PATH` lines are gone. Do not reinstall atuin with its curl installer on this setup. +::: ## Shell integration | Shell | Where | What | | --- | --- | --- | -| fish | `config.fish`, interactive only | `atuin init fish \| source`, `atuin ai init fish \| source`, and the `?` binding | +| fish | `config.fish`, interactive only | `atuin init fish \| source`, and a copy of the `?` binding (atuin 18.21 removed the `atuin ai init` command that used to emit it) | | fish | `functions/fish_user_key_bindings.fish` | ctrl-w runs `atuin ai inline` | | bash | end of `~/.bashrc` | `eval "$(atuin init bash)"` | | zsh | end of `~/.zshrc` | `eval "$(atuin init zsh)"` | @@ -61,10 +45,7 @@ Under tmux, atuin's `[tmux]` settings open the search in a tmux popup (80% wide, ## AI inline -Commit `a82921c` ("add Atuin AI inline integration and keybinding") added the ctrl-w bind to `fish_user_key_bindings.fish` and the following to `config.fish`: - -1. `atuin ai init fish | source`, in the interactive block next to `atuin init fish`. -2. A copy of the `_atuin_ai_question_mark` function that `atuin ai init fish` prints, and `bind "?" _atuin_ai_question_mark`. +Commit `a82921c` ("add Atuin AI inline integration and keybinding") added the ctrl-w bind to `fish_user_key_bindings.fish`, `atuin ai init fish | source` to `config.fish`, and a copy of the `_atuin_ai_question_mark` function that command printed, with `bind "?" _atuin_ai_question_mark`. atuin 18.21 removed `atuin ai init`, so `config.fish` keeps only the copied function and binding; `atuin ai inline --hook` still works. The config also sets `[ai] enabled = true`. @@ -84,7 +65,7 @@ The config also sets `[ai] enabled = true`. `bind "?"` in `config.fish` has no `-M` flag, so it applies to fish's `default` mode, which is vi **normal** mode here. In insert mode ? types a question mark. To ask for a command, press Esc and then ? on an empty line, or press ctrl-w from either mode. The ctrl-w bind calls `atuin ai inline` without `--hook` and replaces fish's default ctrl-w word deletion. -bash and zsh do not load `atuin ai init`. +bash and zsh have no AI binding. ## Configuration diff --git a/docs/shell/bash-zsh.mdx b/docs/shell/bash-zsh.mdx index cad50ea..2df0e32 100644 --- a/docs/shell/bash-zsh.mdx +++ b/docs/shell/bash-zsh.mdx @@ -34,7 +34,7 @@ Interactive shells only (`[[ $- != *i* ]] && return`). In order: 7. Sources `~/.config/envman/load.sh` if it is non-empty. 8. **Prompt.** `eval "$(starship init bash)"` if starship is installed. 9. **television.** `eval "$(tv init bash)"` if `tv` is installed (the `_tv` completion), then sources `~/.config/bash/keybinds.bash`. -10. **atuin.** Sources `~/.atuin/bin/env`, then `eval "$(atuin init bash)"`. atuin comes after tv, so it keeps ctrl-r and up. +10. **atuin.** `eval "$(atuin init bash)"` if atuin is installed (the package's binary; see [atuin](/shell/atuin#installation)). atuin comes after tv, so it keeps ctrl-r and up. ## ~/.zshrc @@ -49,7 +49,7 @@ Interactive shells only (`[[ $- != *i* ]] && return`). In order: 9. `eval "$(starship init zsh)"` if starship is installed. 10. `eval "$(tv init zsh)"` if `tv` is installed (ctrl-t smart autocomplete). 11. **Syntax highlighting.** Sources the first `zsh-syntax-highlighting.zsh` found in `/usr/share/zsh/plugins/zsh-syntax-highlighting/`, `/opt/homebrew/share/zsh-syntax-highlighting/`, or `/usr/local/share/zsh-syntax-highlighting/`. The comment says this must stay last, because it wraps every zle widget defined before it. -12. **atuin.** Sources `~/.atuin/bin/env` and runs `eval "$(atuin init zsh)"`. These lines come after the syntax-highlighting block, so despite the comment, syntax highlighting is not actually last. atuin loads after tv, so it keeps ctrl-r. +12. **atuin.** `eval "$(atuin init zsh)"` if atuin is installed. This line comes after the syntax-highlighting block, so despite the comment, syntax highlighting is not actually last. atuin loads after tv, so it keeps ctrl-r. ## zsh key bindings diff --git a/docs/shell/fish.mdx b/docs/shell/fish.mdx index a3141c5..9b873c9 100644 --- a/docs/shell/fish.mdx +++ b/docs/shell/fish.mdx @@ -43,7 +43,6 @@ fish sources `conf.d/*.fish` in name order and then `config.fish`. The numbered | `30-ssh-agent.fish` | One ssh-agent shared across shells | | `40-tools.fish` | mise, television, starship, zoxide, entire, hishtory, unsloth | | `50-terminal-title.fish` | tmux/screen window name from `$PWD` | -| `atuin.env.fish` | Sources `~/.atuin/bin/env.fish` (puts atuin's install dir on `PATH`) | | `inir-env.fish` | `INIR_VENV` and `ILLOGICAL_IMPULSE_VIRTUAL_ENV` → `~/.local/state/quickshell/.venv` | | `inir-path.fish` | Prepends `~/.local/bin` to `PATH` if missing | | `nvm.fish` | nvm.fish plugin events and default-version activation | @@ -169,10 +168,10 @@ The header comment says the file should stay empty, but it holds the following: 2. **Bottom-pinned prompt.** In interactive shells with `FISH_BOTTOM_PROMPT=1`, `tput cup $LINES 0` moves the cursor to the last row. The comment calls `1` the default, but `10-env.fish` sets `0`, so the prompt stays at the top unless you export `FISH_BOTTOM_PROMPT=1`. 3. `fish_add_path ~/.grok/bin` (grok installer block). 4. Sources `~/.config/envman/load.fish` if it is non-empty. -5. **atuin.** Interactive shells run `atuin init fish | source` and `atuin ai init fish | source`. See [atuin](/shell/atuin). +5. **atuin.** Interactive shells run `atuin init fish | source`. See [atuin](/shell/atuin). 6. `fish_add_path ~/.cmux/bin` and `~/.cache/.bun/bin`. 7. Sources the first readable `~/.config/herdr/plugins/github/herdr-automatic-rename-*/shell/hook.fish`. This is herdr's automatic pane-rename hook ([herdr](/terminal/herdr)). -8. A copy of the `_atuin_ai_question_mark` function that `atuin ai init fish` emits, followed by `bind "?" _atuin_ai_question_mark`. +8. A copy of the `_atuin_ai_question_mark` function that `atuin ai init fish` used to emit (atuin 18.21 removed that command), followed by `bind "?" _atuin_ai_question_mark`. ## Key bindings diff --git a/docs/shell/scripts.mdx b/docs/shell/scripts.mdx index e04249a..7636fd6 100644 --- a/docs/shell/scripts.mdx +++ b/docs/shell/scripts.mdx @@ -68,7 +68,7 @@ atuin-pick Opens atuin's interactive search (`atuin search -i --filter-mode directory`), limited to history from the current directory. It then `exec`s an interactive `fish`. If you picked a command, the new fish runs `echo '❯ '; ` via `-C` (`--init-command`), so aliases resolve, a `cd` persists, and the prompt appears below the output. Esc starts a plain fish. -It is written for launch contexts where atuin's shell init never ran. It resolves `atuin` from `PATH` or `~/.atuin/bin/atuin`, and seeds `ATUIN_SESSION` from `atuin uuid` if unset. +It is written for launch contexts where atuin's shell init never ran. It runs `atuin` from `PATH` and seeds `ATUIN_SESSION` from `atuin uuid` if unset. **Launched by:** ctrl+shift+p in kitty. `kitty.conf` opens it in a horizontal split (`launch_hs atuin-pick`). Under the kitty-tmux profile, `tmux.conf` runs it with `tmux split-window -v -l 25%` in the current pane's directory. See [kitty](/terminal/kitty) and [atuin](/shell/atuin). diff --git a/dot_bashrc b/dot_bashrc index f0640e3..4745761 100644 --- a/dot_bashrc +++ b/dot_bashrc @@ -65,8 +65,10 @@ command -v tv >/dev/null 2>&1 && eval "$(tv init bash)" # Readline keybinds — bash ports of fish_user_key_bindings.fish (tv cables) [ -f "$HOME/.config/bash/keybinds.bash" ] && . "$HOME/.config/bash/keybinds.bash" -. "$HOME/.atuin/bin/env" -eval "$(atuin init bash)" +# atuin comes from the package manager (/usr/bin). No ~/.atuin/bin: an old +# standalone install there shadowed it on PATH and its older schema rejected +# the history DB the newer daemon had migrated. +command -v atuin >/dev/null 2>&1 && eval "$(atuin init bash)" # >>> termium >>> case ":$PATH:" in *:'/home/prad/.local/bin':*) ;; *) export PATH='/home/prad/.local/bin':"$PATH" ;; esac diff --git a/dot_config/atuin/atuin-receipt.json b/dot_config/atuin/atuin-receipt.json deleted file mode 100644 index 54886ca..0000000 --- a/dot_config/atuin/atuin-receipt.json +++ /dev/null @@ -1 +0,0 @@ -{"binaries":["atuin"],"binary_aliases":{},"cdylibs":[],"cstaticlibs":[],"install_layout":"flat","install_prefix":"/home/prad/.atuin/bin","modify_path":true,"provider":{"source":"cargo-dist","version":"0.31.0"},"source":{"app_name":"atuin","name":"atuin","owner":"atuinsh","release_type":"github"},"version":"18.19.0"} diff --git a/dot_config/fish/conf.d/atuin.env.fish b/dot_config/fish/conf.d/atuin.env.fish deleted file mode 100644 index d058327..0000000 --- a/dot_config/fish/conf.d/atuin.env.fish +++ /dev/null @@ -1,2 +0,0 @@ - -source "$HOME/.atuin/bin/env.fish" diff --git a/dot_config/fish/config.fish b/dot_config/fish/config.fish index 20c49e6..0796692 100644 --- a/dot_config/fish/config.fish +++ b/dot_config/fish/config.fish @@ -35,7 +35,8 @@ test -s ~/.config/envman/load.fish; and source ~/.config/envman/load.fish if status is-interactive atuin init fish | source - atuin ai init fish | source + # atuin 18.21 dropped `atuin ai init`; the `?` binding it used to emit is + # copied below as _atuin_ai_question_mark. end # cmux diff --git a/dot_local/bin/executable_atuin-pick b/dot_local/bin/executable_atuin-pick index 1708877..df89662 100755 --- a/dot_local/bin/executable_atuin-pick +++ b/dot_local/bin/executable_atuin-pick @@ -9,12 +9,11 @@ output in the split, and the prompt drops down below it. """ import os import shlex -import shutil import subprocess -# kitty's launch env has neither ~/.atuin/bin on PATH nor ATUIN_SESSION -# (atuin's shell init never ran), so resolve and seed both here. -atuin = shutil.which("atuin") or os.path.expanduser("~/.atuin/bin/atuin") +# kitty's launch env has no ATUIN_SESSION (atuin's shell init never ran), so +# seed it here. atuin itself comes from the package manager, on PATH. +atuin = "atuin" if "ATUIN_SESSION" not in os.environ: os.environ["ATUIN_SESSION"] = subprocess.run( [atuin, "uuid"], stdout=subprocess.PIPE, text=True diff --git a/dot_zshrc b/dot_zshrc index a090a3a..f7c790e 100644 --- a/dot_zshrc +++ b/dot_zshrc @@ -80,9 +80,8 @@ for _zsh_hl in \ done unset _zsh_hl -. "$HOME/.atuin/bin/env" - -eval "$(atuin init zsh)" +# atuin comes from the package manager (/usr/bin); see ~/.bashrc. +command -v atuin >/dev/null 2>&1 && eval "$(atuin init zsh)" # >>> termium >>> case ":$PATH:" in *:'/home/prad/.local/bin':*) ;; *) export PATH='/home/prad/.local/bin':"$PATH" ;; esac