Published
- 10 min read
Zellij + Atuin: A Complete Guide to Shared Shell History
Introduction: Why Does My History Disappear Across Panes?
You open Zellij, split your terminal into two panes, run a few commands in the first pane, switch to the second, and expect your history to follow you. Instead, it feels fragmented. One pane remembers one thing, another pane remembers something else, and searching past commands becomes inconsistent.
This is one of those terminal problems that feels mysterious until you understand the moving parts underneath it. The good news is that the fix is not magic. Once you understand how shells, panes, history files, and hooks work together, the behavior becomes predictable.
In this guide, we will build that mental model from scratch. Then we will install Zellij and Atuin, connect Atuin properly to both Zsh and Bash, reproduce the common failure modes, and fix them step by step.
Part 1: The Foundations - Shell, Pane, History, and Hooks
Before we touch configuration files, we need a clean vocabulary. Most confusion around terminal history starts when these concepts get mixed together.
Q: What exactly is a shell?
A: A shell is the program that reads the commands you type and asks the operating system to execute them. It is your command-line interpreter.
The two shells that matter for this article are:
- Bash: The default shell in many Linux distributions and common in WSL setups.
- Zsh: The default shell on modern macOS systems and a popular upgrade path for terminal-heavy users.
When you type ls, cd, or git status, your shell is the layer that interprets that input.
Q: What is a terminal multiplexer?
A: A terminal multiplexer lets you divide one terminal window into multiple working areas, usually called panes or tabs. Tools like Zellij and Tmux do this so you can keep several shell sessions alive at the same time.
This is the key point: a multiplexer does not give you one giant shell. It gives you multiple shell sessions living inside one visual container.
Q: So what is a pane, really?
A: A pane is not just a visual split. Each pane usually starts a fresh shell process of its own.
That means:
- Pane A has its own shell session.
- Pane B has its own shell session.
- Each shell can have its own in-memory history state until that history is written out.
This is the root of the “why is my history inconsistent?” problem.
Q: What do we mean by shell history?
A: History is the record of commands you have entered in the shell. In a traditional setup, shells often keep part of that history in memory during the current session and write it to a file later, often when the shell exits.
That delay matters. If one pane has not flushed its commands yet, another pane cannot reliably see them through the old history-file model.
Q: What is a hook or pre-exec mechanism?
A: A hook is a small mechanism that runs code before or after a command executes.
For history tools, this matters because a hook gives the tool a reliable moment to say:
- “A command is about to run."
- "A command just finished."
- "Store this command now.”
Without a proper hook, a tool like Atuin may be installed but still fail to capture commands consistently.
Part 2: Meet the Tools - Why Zellij and Why Atuin?
Now that the terminology is clear, the roles of the tools are much easier to understand.
Q: What does Zellij solve?
A: Zellij is a modern terminal multiplexer. It lets you split a terminal into panes, open multiple tabs, keep long-running sessions alive, and organize parallel workflows cleanly.
If you are working on a backend service in one pane, logs in another, and a database shell in a third, Zellij becomes your workspace manager.
For many developers, it is a friendlier alternative to Tmux.
You can install it with one of these common methods:
brew install zellij
bash <(curl -L zellij.dev/launch)
Q: What does Atuin solve?
A: Atuin upgrades command history from a plain text list into a searchable, structured history experience. It is designed to make finding past commands much faster and more reliable.
Instead of treating history as “whatever the shell eventually writes to a file,” Atuin builds a richer model around your command history and stores it in a database-backed format.
In practical terms, that means:
- much better search,
- better context handling,
- and a path toward history that feels shared and immediate rather than delayed and fragile.
You can install it with the official setup script:
curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
Q: Why do these tools work well together?
A: Zellij creates many shell sessions. Atuin gives those sessions a better history system.
Zellij gives you parallelism. Atuin gives you recall.
The entire goal of this guide is to make those two tools cooperate cleanly instead of fighting over history behavior.
Part 3: Shell Integration - Where Most Problems Actually Begin
Installing Atuin is not enough. The shell still needs to know how to talk to it.
Q: Why is installation alone not enough?
A: Because Atuin is not just a standalone binary you run manually. It also needs to integrate with your shell so it can intercept history behavior at the right moments.
That integration happens through your shell configuration file.
For Zsh, add this to the end of ~/.zshrc:
eval "$(atuin init zsh)"
For Bash, add this to the end of ~/.bashrc:
eval "$(atuin init bash)"
After that, either restart your terminal or reload the file:
source ~/.zshrc
source ~/.bashrc
Q: Why do people say “put it at the end of the file”?
A: Because shell configuration files are executed top to bottom. If another script later overrides key bindings, prompt hooks, or history behavior, it can weaken or fully break Atuin’s integration.
For Zsh users, things are usually smoother because Zsh has a stronger built-in hook model.
For Bash users, the hook story is weaker, and that is where the most common failure mode appears.
Part 4: Reproducing the Problem Inside Zellij
Before fixing anything, let us recreate the confusing behavior in a controlled way.
- Open Zellij.
- Create two panes.
- In Pane A, run a command like
ls -la. - Move to Pane B.
- Try to recall or search recent history.
If your setup is not correct yet, you may see one of two problems:
- Atuin opens, but only shows commands from the current pane or context.
- Atuin does not seem to receive newly executed commands at all.
Q: Why does this happen if all panes are inside the same terminal window?
A: Because visually shared does not mean process-shared.
Each pane is running its own shell instance. Traditional shell history behavior is often session-local first and file-based later. That means the command you just ran in Pane A may still be sitting in that shell’s memory instead of being immediately exposed in a way Pane B can reuse.
Atuin is supposed to improve this story, but it can only do that if:
- its shell integration is active,
- it sees commands through working hooks,
- and you are looking at the right filter scope inside the Atuin interface.
One more important nuance: on many setups, Atuin is primarily opened with Ctrl-r. Some users also bind the Up Arrow or other keys, but the diagnosis in this guide is the same either way.
Part 5: Troubleshooting Scenario 1 - Atuin Opens, but the Scope Is Wrong
This is the easier of the two problems, and it fools people into thinking synchronization is broken when it is actually a filtering issue.
Q: Atuin opens, but I only see commands from this pane. Is sync broken?
A: Not necessarily. You may simply be looking at the wrong filter mode.
Atuin can scope history to different contexts, such as:
- the current session,
- the current directory,
- or your broader history.
If the interface is filtering too narrowly, it will look like commands from other panes do not exist.
Q: How do I confirm that this is just a filter problem?
A: Open Atuin and switch filter modes with:
Ctrl-r
Depending on your setup and version, the interface should show which scope you are currently browsing. If it is set to something narrow like session or directory, switch until you reach global.
Once you are in a global-style history view, commands from other panes should become visible if Atuin is successfully recording them.
Q: What is the core lesson here?
A: A missing result does not always mean missing data. Sometimes it means the UI is asking a narrower question than you intended.
That is why this should be the first troubleshooting step.
Part 6: Troubleshooting Scenario 2 - Bash, Preexec, and the Missing Hook
If global filtering still does not show new commands, the problem is deeper. Atuin may not be receiving command events from the shell reliably.
Q: How do I check whether Atuin is actually hooked in correctly?
A: Run:
atuin doctor
If the output indicates something like:
"preexec": "none"
then Atuin is telling you it does not have the command-tracking hook it needs.
Q: Why does this usually hurt Bash more than Zsh?
A: Because Zsh has a stronger native hook model, while Bash often needs extra help for this kind of pre-execution tracking.
So even if you added:
eval "$(atuin init bash)"
that may still not be enough in some Bash environments.
Q: What is the fix?
A: Install a Bash pre-exec helper and make sure your .bashrc ends with the correct integration order.
First, download bash-preexec:
curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
Then open ~/.bashrc, remove duplicate or conflicting Atuin init lines near the bottom, and make the final section look like this:
# Atuin integration for Bash with preexec support
[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh
eval "$(atuin init bash)"
Reload the file:
source ~/.bashrc
Q: Why does the order matter here?
A: Because Atuin needs the pre-exec capability to exist before it initializes its Bash integration. If the helper is missing, or if some later shell configuration overrides the relevant behavior, Atuin can load in a half-working state where the UI exists but fresh commands do not flow in correctly.
This is the classic Bash trap: the tool looks installed, but the event pipeline is incomplete.
Part 7: Verifying the Final Setup
Once you have made the fixes, do a clean verification instead of assuming it works.
Q: What is the simplest end-to-end test?
A: Use this checklist:
- Start a fresh terminal session.
- Reload your shell config or open a brand new shell.
- Launch Zellij.
- Open two panes.
- In Pane A, run
echo pane-a-test. - In Pane B, run
echo pane-b-test. - Open Atuin search.
- Switch to the broadest history scope, typically
global. - Confirm that both commands appear.
If they do, your history path is working end to end:
- shell integration is active,
- commands are being captured,
- and cross-pane lookup is behaving as intended.
Q: What should a correct mental model look like now?
A: It should look like this:
- Zellij creates multiple shell sessions.
- Each pane is its own process boundary.
- Traditional shell history is often delayed and local first.
- Atuin improves history, but only when shell hooks are correctly wired.
- Bash may need explicit pre-exec support.
- UI filters can make healthy history look broken.
Once you understand those five facts, this stops being a mysterious bug and becomes a predictable system.
Conclusion: From Fragile Recall to Reliable Command Memory
With the right setup, Zellij and Atuin complement each other extremely well. You keep the power of multi-pane terminal workflows without accepting fragmented command history as the price.
The real win is not just convenience. It is confidence. Once your shell history becomes searchable, shared across panes, and understandable at a systems level, your terminal stops feeling like a set of isolated sessions and starts feeling like one coherent workspace.
If you are using Zsh, the path is usually straightforward. If you are using Bash, the difference between a frustrating setup and a reliable one is often the missing pre-exec hook.
Either way, once that last piece is in place, your terminal history stops disappearing and starts working for you.