TL;DR:

  • Atuin replaces your shell history file with a SQLite database that records exit codes, working directories, durations, and timestamps alongside every command
  • Ctrl+R becomes a fuzzy-search TUI showing full context — you can filter to “only commands that succeeded in this directory” with a keystroke
  • Optional end-to-end encrypted sync keeps history consistent across your laptop, work machine, remote servers, and dev containers

Your shell history is one of the most underrated productivity tools you have. It contains a searchable log of every problem you’ve solved, every command you’ve run, and every workflow you’ve developed. The default implementation — a flat text file with a size cap and no metadata — throws most of that value away. Atuin fixes this.

What Atuin Stores

Every command you run gets stored in a SQLite database with:

  • The command itself
  • Exit code (0 = success, non-zero = failure)
  • Working directory at the time
  • Duration (how long the command took)
  • Hostname
  • Timestamp
  • Session ID

This context transforms how you search history. Instead of “find the ffmpeg command I used once”, you can ask “find successful ffmpeg commands I ran in the video-projects directory in the past month.” The fuzzy TUI lets you filter by directory, host, session, and exit code interactively.

Installation

# macOS
brew install atuin

# Linux (cargo)
cargo install atuin

# Or with the install script
curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh

Then add to your shell config:

Zsh (add to ~/.zshrc):

eval "$(atuin init zsh)"

Bash (add to ~/.bashrc):

eval "$(atuin init bash)"

Fish (add to ~/.config/fish/config.fish):

atuin init fish | source

Restart your shell or source the config file. Atuin imports your existing history during initialisation — you don’t lose anything.

The Search Interface

Hit Ctrl+R (or Ctrl+R twice to toggle full-screen mode) to open the Atuin search TUI. You’ll see recent commands with their exit codes, timestamps, and directories listed.

Navigation:

  • Type to fuzzy-search
  • Ctrl+D — filter to current directory only
  • Ctrl+H — toggle showing only successful commands (exit code 0)
  • Ctrl+G — filter by host (useful in synced setups)
  • Arrow keys or Ctrl+N/P to navigate results
  • Enter to select, Escape to cancel

The directory filter (Ctrl+D) alone is a significant workflow improvement. In a project directory, you immediately see only the commands run in that context — not the noise from every other project and system task.

Configuration

Atuin’s config lives at ~/.config/atuin/config.toml:

# How many results to show in the TUI
max_preview_height = 4

# Start in full-screen mode by default
style = "full"

# Filter mode: "global" | "host" | "session" | "directory"
# Controls what Ctrl+R shows by default (can be toggled interactively)
filter_mode = "host"

# Only show history from the current host by default
# (disable if you want to see synced history from other machines immediately)
filter_mode_shell_up_arrow = "session"

# Show exit code in the TUI
show_preview = true

# Fuzzy search algorithm: "fuzzy" or "prefix"
search_mode = "fuzzy"

The filter_mode_shell_up_arrow setting is useful: you can configure the regular up-arrow to navigate only the current session’s history (so it behaves like normal), while Ctrl+R searches across everything.

Sync Setup

Atuin’s sync is optional and free for personal use. It uses end-to-end encryption — your key is derived from your password and never sent to the server. Even if Atuin’s sync server were compromised, your history would be unintelligible.

# Create an account
atuin register -u your_username -e your@email.com

# Log in on another machine
atuin login -u your_username

# Manual sync (or set up automatic sync)
atuin sync

# Check sync status
atuin status

Sync happens automatically in the background by default after login. The database is append-only from the sync server’s perspective — your client holds the encryption key.

Self-hosting: Atuin’s sync server is open source and straightforward to self-host if you prefer not to use the official server. The atuin-server binary runs as a simple Rust service backed by PostgreSQL.

Import and Search from Scripts

Atuin exposes a search subcommand for scripting:

# Find all git commands run in the last 30 days that succeeded
atuin search --exit 0 --after "30 days ago" -- git

# Count how many times you've run a particular command
atuin search --count -- "docker build"

# Export history as JSON for analysis
atuin search --format json -- "" | jq '.[] | select(.exit != 0)' | head -20

This is useful for auditing: “what commands am I running most often that could be aliased?” or “what commands keep failing that I should investigate?”

Integration with fzf and Other Tools

If you already use fzf for fuzzy finding, Atuin’s native TUI may feel redundant. You can configure Atuin to use fzf as the search backend instead:

# ~/.config/atuin/config.toml
search_mode = "fuzzy"

# Or use the --search-mode flag
# atuin search --search-mode fuzzy

Alternatively, since Atuin exposes a history list command, you can pipe into fzf directly if you prefer fzf’s keybindings:

# Use fzf to pick from atuin history
alias fzh='atuin search --format "{command}" -- "" | fzf --tac | xargs -I{} bash -c "{}"'

Stats

atuin stats

This gives a breakdown of your most-used commands, top directories, and command frequency by time of day. It’s a good way to identify candidates for aliases or shell functions.

Why This Matters

The average developer runs thousands of commands per month. The default history tools preserve almost none of the context that makes that history useful. Atuin’s investment — ten minutes to install and configure — pays off every time you need to reconstruct a command you ran three weeks ago in a different project, or when you want to see whether that database migration script actually succeeded or silently failed.

The sync feature makes it particularly valuable for developers who work across multiple machines. Your history becomes a persistent log across your entire working life, not a transient buffer that gets lost when you rotate machines.