117 comments

[ 5.3 ms ] story [ 226 ms ] thread
Atuin has been the absolute best CLI tool I’ve found in years.

I use it every single day that I’m at a computer. It's very easy to learn (2 or 3 essential hotkeys), and makes finding old shell commands a breeze. I was able to self-host the sync server in well under an hour, start to finish.

(@ellie - if you see this thread, thanks for all the elbow grease you put in! You’ve built something really special.)

Recently installed Atuin and found it to be overall net positive. A couple of habitual keystroke combos had to be reprogrammed from my brain but the persistence of shell history + better searching is pretty awesome.

Also the stats are a neat add-on.

Overall would recommend to almost any developer.

Really impressed with the self-host setup.

I've found these are usually a bit of an afterthought, involving a bunch of service dependencies and an arcane config process.

Postgres 14 and a few tweaks to a TOML file and you're running.

Not wild about the password-only Postgres connection though.

> Not wild about the password-only Postgres connection though.

>> A valid PostgreSQL URI, for saving history (default: false)

Looks like you are free to specify socket or ssl if you prefer?

I was recently shocked to learn that the postgres standard "sslmode=require" only check host name vs cert - not if the cert is trusted (ie meaningless).

https://www.postgresql.org/docs/current/libpq-ssl.html#LIBQ-...

Why is this better than a shell's built-in history, possibly paired with fzf?

I'm not asking sarcastically, either. Is this something awesome I should be using? What about it is going to blow my mind?

The features listed on the site already tell you what it has that regular shell history + fzf doesn't have. You can decide if that makes it better.
All that jumps out to me from that page is sync, which is nice, but not life-changing.

I guess I’m looking for more of a personal experience anecdote, where someone could explain how its other features made it worth signing up for another sync service and learning a new thing. It may be the best thing since sliced bread but that page doesn’t say why I should try it.

- all the data is stored in a sqlite db, so it's actually structured, as opposed to just being in an adhoc text format

- this matters because it's capturing not just what commands were run, but metadata about the commands as well. Of particular interest to me is that ot captures the start and end time for every history entry so you can get timing data even if you forget to use `time`

- it provides much more fine-grained control over what makes it into the database than shells provide for controlling what makes it into their built-in history. For example, it has built-in support for filtering out common kinds of secrets/tokens/etc.

It's also in active development with a friendly and helpful creator/project lead, an active community, and an ever growing feature set.

I'd recommend giving it a try; as far as I'm concerned, it's best-in-class for managing shell history

> Of particular interest to me is that ot captures the start and end time for every history entry so you can get timing data even if you forget to use `time`

That’s potentially an incredible useful feature to integrate with all that metadata! Very very interesting.

I just watched this video: https://youtu.be/WB7qojkkVVU?si=_sqnKlXrblLSwrs8 and there still seems to be nothing that stands out about atuin. I do think it might be easier to work with the data in a database. Personally I don't see a reason to use this service .
As I commented elsewhere, you can:

- Filter by commands run within the current shell session

- Filter by commands run within the current working directory

- Filter by commands run across hosts (as opposed to filtering commands run on your local machine)

- Filter by commands run within the current shell session

- All of the above searching functionality, with nice fuzzy finding support, time stamps, etc.

Before atuin I used zsh's builtin history, with ctrl+r rebound to present that builtin history through the `fzf` fuzzy finding tool, and zsh configured to share history across shells. The deficiencies I found: I couldn't optionally filter by commands _only_ run in the current shell, I couldn't filter by commands run in the current directory (useful for quickly finding commands I often need to re-run for a given project), and I can't search for commands run across hosts.

If you don't find yourself valuing these things, you may find that you have little to gain from using atuin.

(comment deleted)
For me, syncing across machines and other shell sessions was enough to justify shelling out the $0 and 5 minutes it took to install and learn the tool.
Fair point, I've been using atuin for a few years on a few machines but never once felt the need to set up sync. I forgot sync was even a feature! It's certainly over-emphasized on the web page.

I use it mainly because a) it stores data about command history in a proper database that's easy to query (what century is this? How do other tools justify dumping what should be structured information into some god-awful mess of semi-structured text files?) and b) it makes a clean separation between SESSION, DIRECTORY and GLOBAL scopes which means you can explicitly use a recency or a locality filter (I don't want irrelevant commands cluttering my history).

Even without sync, atuin is a gem.

(comment deleted)
You could probably make shell history + fzf do a lot of what atuin does, but you'd have to write a bunch of glue code to make it happen. That's what atuin is doing. I particularly like the high configurability as well as the ability to switch between host, global, session, and directory history.
I have a one-liner zsh function that does the same thing, been using it for years, too powerful for me to switch it, and probably has better search capabilities, thanks to fzf.

    function hist() {
      print -z $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf | sed -E 's/ *[0-9]*\*? *//' | sed -E 's/\\/\\\\/g')
    }
"I have a one-liner zsh function that does the same thing"

I think you mean "I have a one-liner zsh function that does a tiny subset". It's lacking:

- The ability to filter by current directory

- The ability to filter by current shell session, instead of across all shell sessions (that's assuming you use zsh's shared_history; if not, then the opposite is true: you can only search within the current shell session. See https://zsh.sourceforge.io/Doc/Release/Options.html#index-SH...)

- Search history across hosts

Until recently, I used zsh+fzf, with the default ctrl+r binding replacement provided by fzf. It's been great, but it has lacked functionality that I've wanted for a while now. Atuin fills in these gaps for me.

Now use your function to give you a list of all find commands that took over 10 seconds to run.

Atuin stores _everything_ it can about each command run, what you see when you press C-r is only a tiny subset. And even it gives you the duration and success/failure information immediately.

If you want to, try pressing C-r, select a command from history and press C-o. Normal shell history doesn't store any of that.

I've recently switched from zsh's built-in history + fzf, so perhaps I can answer.

First, a bit more about my zsh+fzf use: I use `share_history` so that my history is available across shells, allowing me to quickly find and re-run commands. (https://zsh.sourceforge.io/Doc/Release/Options.html#index-SH...)

Sometimes I want to switch back to some terminal tab/window and find a command that I nkow I ran in that session, but now it's flooded with 1000+ commands that I've entered elsewhere, making it difficult to find what I'm looking for. So the shared history is both useful and a hindrance, depending on the scenario.

Compare with atuin: I can filter by commands entered specifically within the current shell, or across all shell sessions, and possibly even across other hosts (when using atuin's sync functionality -- haven't tried that yet).

Given the metadata that atuin collects (current working directory, start time, exit status, duration, etc) I'm sure there are some other clever things that can be done with my shell history now, vs the the "line per entry, with optional start timestamp" approach used by zsh's builtin history functionality. Actually, more on that first point: you can also filter by commands entered within the current directory.

I’m a largely happy fzf+history user, but I think filtering across hosts is the killer app I was missing with atuin.
It works for multiple shells and synchronizes history between devices.
I had something similar set up Fish and fzf. When I first did that, I thought it was magic. Atuin brought back more of the magic.

It syncs across devices. I’ve got a number of raspberry pi devices I use and I never remember what command I used. Also preserves history when I inevitably need to replace the SD card.

Atuin also preserves information about the exit code. So you can filter on commands that worked. Which is great.

And, you can still use fzf to search your history if you want. I’ve got ctrl-r bound to search Atuin with fzf and ctrl-t to use native Atuin search.

If you’ve got an extensive history already, Atuin easily imports it. So I didn’t miss anything.

And because I wrote an ansible playbook to install it everywhere, including provisioning my self-hosted Atuin server, it just works.

Biggest downside was compiling for Raspberry Pis - which may be running slightly different versions of Raspbian. The project doesn’t provide the arm7 binaries. Eventually I figured out how to do fully static compilation with rust and that solved my problems.

I just started using this tool locally and it's pretty nice. The default UI doesn't highlight the matching substring like fzf does which isn't as nice.
I switched a year or two ago

It wasn't until I switched that I realized how poor bash and zsh are in comparison, even with fzf

10 min install, never looked back

Not to mention the safety. Never could figure it out, but once every 15 months or so, zsh would disappear my history. Certainly a mistake on my end, but still too easy to blow away history

I would occasionally manage to start a bash shell without executing my profile, which means HISTFILESIZE is not set and bash would truncate my history on the first command I ran. zsh history may have a similar problem.
Yes, bad defaults strike again!
I think that's it! I've been wondering why Bash sometimes deletes most of my history for ages. My .bashrc sets up an EXIT trap that git-commits my history, so I just looked at the commits that remove lines and found that 7 out of 8 of those commits change the size of the history file to about 1000 lines. Since my history file contains timestamps, that matches the 500-command default of HISTSIZE, so the truncation mechanism you described seems to be what's happening.

A few days ago I actually made my history file append-only to prevent truncation.

Setting HISTFILE to a non-default value in the same place as HISTSIZE/HISTFILESIZE seems like it would solve this problem nicely.
This is exactly why I'm considering using atuin also. My zsh history on my mac will sometimes just completely disappear and then I have to go lookup what I was trying to do again. It is driving me crazy.
This happens to me also!! Does anybody know why? I ignore it as macos is a secondary and less critical environment for me but it’s really annoying.
Atuin is simply fantastic. Ellie keeps adding interesting new features. Just an all around fantastically useful tool. Bravo.
Please oh please, can someone hack a way to get shell history expansion!? The most objectionable thing about shell history to me is that it's not what I typed!

Mainly a zsh user & I've looked up & down & all around, but I cannot find a way to keep track of what I actually typed, versus what got ran! I really want to better be able to identify patterns, look at what I was typing. Show me !-1$, the last word of the last command!

I need this to learn & improve my expansion capabilities better. I need this to see how my history evolved, to backtrack & see where else any given line was pointing at. Shell history feels devoid of the most important context I craft; I summon birds from hats and my shell history just says: there was a bird here. Hiss boo.

I mostly really like atuin, but it has been causing some random other breakage in my shell that has me on the verge of replacing it with something simpler. A quick search comes up with https://github.com/atuinsh/atuin/issues/1696 , which indicates I'm not alone.
That bug report is 12 days old...
And some bug reports are 20 years old. A broken workflow is a broken workflow.
I mean, that literally does not logically follow. Yes, some bug reports are 20 years old. My point is precisely that this one hasn't become a 20-year-old bug and the way the parent comment read made it sound like it's a glaring, long-lasting issue when it's not.

"A broken workflow is a broken workflow" is just a tautology. I guess you're implying "any kind of broken workflow is bad" but yeah, I don't agree with that especially with regards to free tools. The project literally has weekly commits, devs are open and engaged and... patches are welcome

I mean, it is a glaring issue for me, but often it causes the most frustration in another task, so I didn’t personally report it much sooner, but it has been broken for a while.
> "A broken workflow is a broken workflow" is just a tautology. I guess you're implying "any kind of broken workflow is bad" but yeah, I don't agree with that especially with regards to free tools. The project literally has weekly commits, devs are open and engaged and... patches are welcome

I just wanted to respond to this a bit more. My moving away from a project is my choice. Just because it has active devs and regular commits doesn’t mean that I’m in any way obligated to continue to use it, or contribute to it. It doesn’t fit my workflow, and the issues are longstanding and glaring. Might they be fixed in the future? Sure. Am I interested in sending patches in or tracking that effort? Actually it really doesn’t even matter, a broken workflow is a broken workflow, even when the tool is free. It doesn’t work for me as is and I will find something else if I want.

This seems to be some sort of defensive response as if I was attacking the project. On the contrary, and like I said before, I generally like it, but the issues I have, which are to be both glaring and longstanding, means that it doesn’t fit my workflow and I’m considering moving. Not all tools need to suit everyone’s workflows, and “patches are welcome” is very beside the point.

I've now explained in that issue why it's broken, why it's probably unfixable for atuin, but why replacing fc with an equivalent feature in atuin sounds pretty doable.

Feel free to open a feature request before I do.

I love how it looks and I love some of the fancy features.

But above all, it's a solution to two real problems I had.

I work in several terminals. Sometimes tabs or Windows in my emulator, sometimes screen or tmux. And all those sessions would overwrite eachothers history. I lost many actual important history entries that way. And I (almost) ran many wrong commands, expecting another one to be my last entry. Arrow-up enter. Woops.

Atuin solved this.

I had my history as large as possible. Ctrl-r is my friend to search for "that old thing I did to pgsql piping something from zcat a year ago". But it's ever slower, zsh and bash history clearly not designed to handle (tens of) thousands of entries.

Atuin solved this.

Agreed! This is my exact use case for Atuin and it works great, except it replaces the default, minimal control-r interface.
Interesting -- I have histappend (? I think) enabled and no problems with 20+ simultaneous tmux panes + tabs.

Just checked yesterday* and have well over 100k lines in bash history and it loads / searches instantly in skim.

* Was trying to check out mcfly vs atuin for the third time and again didn't understand why the extra complexity was worthwhile.

- For your 1st issue, you can setup bash to append commands rather than overwrite them. Here the part of my .bashrc about history:

  # append rather than overwrite
  shopt -s histappend
  # attempts to save all lines of a multiple-line command in the same history entry
  shopt -s cmdhist
  # with cmdhist, saved with embedded newlines rather than semicolon separators 
  shopt -s lithist
  
  HISTCONTROL=ignoreboth
  HISTSIZE=10000
  HISTFILESIZE=20000
  HISTTIMEFORMAT="%y/%m/%d %T "
  HISTIGNORE="history:ls:l:pwd:exit:"
  if [[ ${BASH_VERSION:0:1} -gt 5 || ${BASH_VERSION:0:1} -ge 5 && ${BASH_VERSION:2:1} -ge 1 ]]; then
    PROMPT_COMMAND=("history -a" "history -c" "history -r")
  else
    PROMPT_COMMAND="history -a; history -c; history -r"
  fi

- And about the 2nd issue, you should use fzf or skim (probably faster) to replace the ctrl-r binding. fzf includes such a script that you just need to call from .bashrc.

  # Enable key bindings for fzf
  if command -v fzf 1> /dev/null && [[ -f "/usr/share/doc/fzf/examples/key-bindings.bash" ]]; then
    source /usr/share/doc/fzf/examples/key-bindings.bash
  fi
I had been using the history append for years before finding atuin a couple years ago. I still occassionally lost history through some combination of events I was never able to understand.

I've been using atuin happily for a few years now and it blows bash history out of the water.

I had nearly the exact setup. But I never fully understood it. And despite tweaks, it kept loosing some history entries. Not a huge problem, until it was :)

I have far more confidence in atuin handling race-conditions and upserts than in my bash-spagetti not doing that.

Also, fzf, has a better append-history, but even there I managed to get it into some race-condition now and again. I presume it has to do with when the append happens: after the command ran and finished vs when I hit enter? Again, I don't know the details, and frankly, don't really want to know them either, if I can just lean on a tool by people who truly understand the problem.

>For your 1st issue, you can setup bash to append commands rather than overwrite them.

Good, but even better (IMHO) is to write one history file for each terminal window, shell and level as in

  export HISTFILE=$HOME/.history/${TTY##*/}.$SHLVL
And then I tell zsh to add timestamps

  setopt APPENDHISTORY            # don't overwrite HISTFILE
  setopt EXTENDEDHISTORY        # add timestamps to HISTFILE
setopt HISTIGNORESPACE # aka setopt -g set HIST_FIND_NO_DUPS # don't show duplicates on ctrl-R

Now I can grep my history and, based on other work notes I take, can even limit my search by date/time if needed.

Looks like whoever created the examples uses LunarVim.
just commenting for my discworld homies
i came here for this
I used to have histdb set up really well with r-i-search etc. but recently I can't get it to really do that any more. It's a pity. Does anyone have a histdb + fzf r-i-search solution that works well for them?
Anyone try this and fish shell? How do they compare? Thanks!
I use it with Fish. It's basically a nice UI around doing history | rg pipes.
Agreed, I use this in conjunction with Starship [1], both initialized specifically for Fish in the config. I love this shell so much.

[1] - https://starship.rs/

I've tried it with fish and found that, for me, it didn't add much and wasn't worth the switch, but it is arguably slightly better than fish's built-in history; so I'd say only bother if you particularly love learning new things of this type.
The only downside is that fish has no way to allow atuin to override the autosuggestions as you type. We can get that in zsh but fish doesn't expose that.
Fish + Atuin (with up arrow disabled) + Starship is what I use on every platform I can
Looks neat and I'd like to try it. I wonder how well it would work from within a GNU Emacs shell buffer (comint based, I think) running bash. Has anyone given this a shot?
Bash in general is problematic for Atuin, since it plugs into the prompt and Bash prompt is a bit crap =)

But it should still work

I've been using this for a couple months after using McFly in zsh for over a year. I think I can say that I like it better, but the only thing I sometimes don't like is how it completely takes over your screen when you press the up arrow. I usually just want to get the previous command I entered instead of the whole searchable history (which I use Control-R to bring up), and it's really jarring to have the entire screen change. Aside from that, it's really awesome to have everything synced across a bunch of machines.
If you're comfortable with shell scripting, you can get that today. There's code for a number of shells in this issue https://github.com/atuinsh/atuin/issues/798

Adding it to Atuin will take a bit of work to keep it from being too brittle, so it hasn't yet been done.

You can adjust the size of the "window". I have my inline_height set to 20 and it's a bit less jarring when it pops up.
This is why I have

   atuin init fish --disable-up-arrow | source
in my fish.config. C-r with Atuin is great. It taking up the whole screen when I want to run the previous command again? Not grat.
Used as a daily driver for a couple years now. Love it!!
Been using atuin for a couple months now on Windows in bash. Its a very nice tool however I've been experiencing a huge lag sometimes after typing just one character. Intuition says there could be the database performance is lacking or Im missing some configuration. Anyone else experiencing something similar?
Could be a disk Io issue. I know git used to use a nieve approach on windows and it make git incredibly slow. Something you wouldn't notice just using git but when you made it part of your prompt it would lag for a good second and a half just pressing enter.
Yup, I'm getting this sometimes on Linux.

There's been a recent update (not sure which version, I don't have my Linux box on hand to check) where it now started logging some timeout waiting for a lock on the database.

I don't type commands in multiple shells at the same time, so not sure what's locking the db. I also don't use remote sync (explicitly disabled in the config).

Are you on ZFS by any chance? There's a bug with SQLite which can lock the thread for a few seconds, I had the same problem. Here's the issue I created, with several workarounds included. My current workaround is to have a separate dataset without sync for the atuin directory.

https://github.com/atuinsh/atuin/issues/952

Atuin is great! Considering including it in my little stack of scripts to turn a new Ubuntu VM into a capable devbox from scratch [1].

We currently install `fzf` with the proper keybindings, so Ctrl-R is already quite nice. But we also already include one interactive "pick your $EDITOR" moment - there's no reason we couldn't provide a "pick your $HISTORIAN" with atuin vs fzf as well. It would be fun and might turn people onto new tools, which is a big aim of this project.

[1]: https://github.com/hiAndrewQuinn/shell-bling-ubuntu

Can it do the magic of deduplication, cleaning failed commands with typos so your history isn't cluttered, and use frecency for autocompletions?
Deduplication as an option or shortcut would be nice. But I think Atuin should and maybe must save all commands in the database.
Why should it store garbage in the database?
Why do you enter garbage in the terminal? But seriously from the next answer: „ The reason it saves every command is so that it can produce statistics, for example exit code distribution and runs per day etc“
Because I'm a human and err??? And what value do GIGO statistics have? The next answer doesn't defend you weird take that it must store garbage, that's still on you
It does de-duplicate. It saves every command (even duplicates), but as soon as you search it only ever shows the last version you ran.

The reason it saves every command is so that it can produce statistics, for example exit code distribution and runs per day etc.

Oh, the screencast had dupe lvim at 10s and then there are issues like this https://github.com/atuinsh/atuin/issues/409.

The runs/code can be stored as list to get the distribution, though for typo I don't want any distribution, I just want them gone, and for identical commands with different comments I'd want a single run stat

These are the cleaning type of things that would be closer to magical

That issue is closed and fixed since almost a year. And as the author said, the 'list' command is supposed to list all invocations. When you search (Ctrl+R) you don't see duplicates (I guess the screencast might be old?).

It feels like you are just trying to find issues without having tried using it for real...

It feels like you're just trying to pretend the issue isn't real

> closed and fixed ... 'list' command is supposed to list all

This is NOT a fix, but a confirmation that this design flaw is unlikely to get fixed. I don't need fzf to be flooded with useless info either.

How would using it for real help here?

ZSH removes duplicates (not typos) if you configure it to do so.
In the docs it says:

    Atuin works best in bash when using ble.sh.
However, whenever I try to use it with ble.sh, it doesn't bind to the up key like it does with plain Bash.