Zellij, Fish Shell, and the Illusion of "The First Terminal"
Abstract
Zellij is often praised as a modern terminal multiplexer with a clean architecture and strong defaults.
However, when users attempt to automate Zellij—especially when integrating it with Fish shell—they frequently encounter confusing behavior: unexpected session sharing, nested Zellij instances, or race conditions during startup.
This article documents a real-world investigation into these issues and explains why certain intuitive solutions fail, what Zellij actually guarantees, and which design principles lead to a stable setup.
The goal is not to propose clever hacks, but to align automation with Zellij’s actual model.
1. Understanding Zellij’s Mental Model
To use Zellij reliably, it’s essential to understand one core idea:
In Zellij, a session is the shared state.
Terminals are merely clients.
This has several implications:
- Multiple terminals can attach to the same session
- All attached terminals are equal peers
- Zellij does not track “who came first”
- There is no concept of a primary or owner terminal
This model is deliberate and differs subtly from how many users mentally model terminal multiplexers.
2. The Common Goal — and Why It’s Deceptive
A frequent goal sounds reasonable on the surface:
“Automatically enter a shared
worksession — but only from the first terminal.”
In practice, users attempt logic like:
- If the
worksession exists → create a new one - If it does not exist → attach to
work
This often relies on checking existing sessions at shell startup.
Unfortunately, this approach is fundamentally flawed.
3. Why list-sessions Cannot Be Used for Control Logic
Zellij session creation is not an atomic operation.
When two terminals start at nearly the same time:
- Terminal A checks for existing sessions — none found
- Terminal B checks at the same moment — none found
- Both attempt to create or attach to the same session
This race condition is unavoidable and cannot be reliably eliminated with shell logic alone.
Important distinction:
zellij list-sessionsis safe for inspection- It is unsafe for coordination
Any logic built on it will eventually fail under concurrency.
4. Why Lock Files Are the Wrong Tool Here
A natural next idea is to use a lock file to ensure only one terminal enters the shared session.
This also fails, for structural reasons:
- Shell processes are replaced via
exec - Terminal closure is not a reliable lifecycle event
- Lock files can easily outlive the process that created them
Without tight coupling to Zellij’s internal lifecycle, such locks become stale state, which is worse than no state at all.
5. The Key Insight: Zellij Has No “First Terminal”
At this point, a crucial realization emerges:
Zellij does not—and intentionally does not—model the concept of a “first client”.
All clients are equal.
All attachments are valid.
The session exists independently of who attached when.
Trying to impose “first terminal” semantics on top of this model creates fragile systems.
6. The Only Stable Design Principle
The investigation leads to a single, reliable principle:
Automatic behavior must be stateless.
Shared state must be explicit.
Translated into practical terms:
| Behavior | Automatic? |
|---|---|
| Creating a session | Yes |
| Naming a session | Yes |
| Sharing a session | No (explicit only) |
| Detecting “first terminal” | Not possible |
Once this principle is accepted, the system becomes predictable.
7. A Minimal, Reliable Fish + Zellij Setup
Below is a minimal Fish shell configuration that avoids all known pitfalls:
1 | if status is-interactive |
What this guarantees:
- No nested Zellij instances
- No race conditions
- No hidden shared state
- One session per terminal by default
To collaborate or resume work:
1 | zellij attach work |
Sharing becomes an intentional action, not a side effect.
8. Why This Works Long-Term
This approach succeeds because it:
- Aligns with Zellij’s internal model
- Avoids inferring intent from shell state
- Requires no external locks or heuristics
- Degrades gracefully under concurrency
It favors explicit control over clever automation.
9. Conclusion
Zellij is not difficult to automate — but it is easy to automate incorrectly.
Most problems arise from assuming semantics that Zellij does not provide, such as “first terminal” or “implicit ownership”.
Once automation is reduced to stateless defaults and collaboration is made explicit, Zellij becomes stable, predictable, and a pleasure to use.
Sometimes, the most reliable automation is the one that does less.
P.S.
This article is very subjective. If you do not feel comfortable viewing it, please close it as soon as possible.
If you think my article can help you, you can subscribe to this site by using RSS.
Zellij, Fish Shell, and the Illusion of "The First Terminal"
https://iiiyu.com/2026/01/10/Zellij-Fish-Shell-and-the-Illusion-of-The-First-Terminal/
