exploring Zellij inside Zellij over SSH, conquering keybinding conflicts with Locked mode and remapping, plus integrating the modern terminal protocols OSC 52, OSC-99, and CSI 2031 theme switching.

After episode 20 closed Phase 5 with multiplayer and shared sessions, the Learn Zellij series enters Phase 6: Advanced Topics, Security & Optimization. The next four episodes are the maturing act — episode 21 covers nested Zellij and advanced input handling, episode 22 covers security hardening, episode 23 covers troubleshooting and debugging, and episode 24 covers performance optimization. This is the part that separates ordinary Zellij users from users who understand how the system behind the scenes really works.
Episode 21 focuses on one reality you'll definitely meet in the real world: running Zellij inside Zellij. Picture yourself working from a workstation already running Zellij, then SSHing into a production server that also runs Zellij. Two multiplexer layers are now fighting over the same input — every keystroke, every mouse click, every resize. On top of that, modern Zellij interacts with terminal emulator features that often go unnoticed: remote clipboard via OSC 52, desktop notifications via OSC-99, and dark/light theme switching via CSI 2031. Mastering these layers makes Zellij feel like it reaches right out of the terminal.
Why does this episode matter? Two reasons. First, nested Zellij is the most common scenario behind "Zellij is frozen" — which is really just a keybinding conflict, not a bug, not a dead process. Second, understanding terminal protocols determines whether clipboard, notification, and auto-theme features work or silently fail with no error message. Let's take them apart one by one, starting with the nested scenario itself.
The nested scenario happens when you run Zellij inside another Zellij's pane. The most concrete example: you open a local session, SSH into a server, then type zellij there. The server, also using Zellij, renders its full interface — tab-bar, panes, status-bar — inside a pane belonging to your local Zellij.
zellij attach work
ssh dev@server
zellijThe problem appears immediately: both Zellij levels use the same keybinding set. When you press Ctrl+p, it's the outer-level Zellij that responds — not the inner level you're aiming at. Input never reaches the inner Zellij, and you feel like the keyboard is jammed for no clear reason. The same happens with the mouse: the outer level captures all click and drag events, so the inner Zellij never receives a single pointer interaction.
Understand the following mental model: each Zellij level is a layer covering the terminal beneath it. For one level to receive input, the level above it must be willing to release that input. There are two main strategies for managing "who holds the keyboard": Locked mode for temporary release, and keybinding remapping for permanent separation. We'll dissect both now.
| Strategy | How It Works | Best For |
|---|---|---|
Locked mode (Ctrl+g) | Temporarily releases all input to the lower level | Occasional sessions, brief entries into the inner level |
| Remap keybindings | Changes one level's keybinding set | Daily use, two levels active continuously |
| Disable the outer level's mouse | Hands all mouse events to the inner level | Mouse-dependent workflows inside |
Locked mode is the emergency button most often used for nested Zellij. Press Ctrl+g at the outer level, and Zellij immediately locks itself: all input — including keybinding combinations — is passed through verbatim to the pane below. The status-bar shows a red LOCKED indicator so you're always aware you're in passthrough mode.
The working scenario goes like this: press Ctrl+g on the outer Zellij to lock, so all keystrokes now go into the inner Zellij and you're free to use Ctrl+p, Ctrl+t, and so on at the inner level. When done, exit the inner Zellij with Ctrl+q or detach, then press Ctrl+g once more at the outer level to unlock. Simple on paper, but there's one trap you must avoid.
Warning
Beware the double Ctrl+g trap. While the outer level is locked, the Ctrl+g you press is passed to the inner level and will lock the inner level too. If the screen looks frozen two layers deep, don't panic — press Ctrl+g once more, because you've likely just locked the inner level, not unlocked the outer one.
Locked mode is also useful beyond the nested context. It's the fastest way to disable Zellij briefly when running an app inside a pane that's hungry for its own shortcuts, like vim with mouse capture or a TUI app using many key combinations. Instead of fiddling with configuration, just lock when needed and unlock when done.
Locked mode is only a temporary release. For daily use, you need permanent separation: one level uses a different keybinding set so both coexist without swallowing each other's input. The cleanest strategy is giving the Zellij running on the server — the inner level — a dedicated configuration, then launching it with the --config flag.
keybinds {
unbind "Ctrl p"
bind "Alt p" {
SwitchToMode "Pane";
}
}With this configuration, Alt+p at the inner level replaces Ctrl+p. Because the outer level keeps using Ctrl+p, the two never fight over the same key. The same principle can be applied to other modes: Ctrl+t becomes Alt+t, Ctrl+o becomes Alt+o, and so on. Adjust them to be easy to remember and not to clash with your editor shortcuts.
zellij --config ~/.config/zellij/server.kdlTip
Store the dedicated configuration for the inner level in your dotfiles repo. When logging into a new server, just copy one file then run zellij --config with the keybindings you've already memorized. Consistent keybindings across machines are far more valuable than a "most comfortable" binding that differs on every server.
Note that remapping doesn't have to touch all modes at once. If only Ctrl+p keeps colliding, just remap that. The fewer changes, the less you have to relearn, and the smaller the risk of breaking habits already built at the outer level.
Zellij has supported the mouse from the start, active by default via the mouse_mode option. With the mouse on, you can click to move focus to another pane, drag on the separator between panes to resize, and scroll to browse scrollback. It's a convenient alternative when the keyboard is busy, for example when copying text from long output.
| Mouse Action | Behavior |
|---|---|
| Click on a pane | Moves focus to that pane |
| Drag on a pane border | Resizes the pane directly |
| Drag from inside a pane | Opens selection mode and copies text |
| Scroll over a pane | Browses the pane's scrollback |
| Click on the tab-bar | Switches tabs |
In the nested scenario, the mouse is always captured by the outer level first. There are two ways to handle it: lock the outer level with Ctrl+g so clicks pass through to the inner level, or disable the mouse at the outer level so nothing steals the events:
options {
mouse_mode false
}When the mouse is off, resizing still works via the keyboard: Ctrl+n enters Resize mode then use the arrow keys, or Alt+= and Alt+- for quick resizing. A mouse at the inner level and a keyboard at the outer level is the division of labor that least often confuses, because each input already knows its destination.
Besides manual typing, Zellij lets you send input to a pane programmatically. This matters when you want to forward keystrokes from one level to another, or automate a sequence of commands inside a session without touching the keyboard. The two mechanisms used most often are zellij action and pipes.
zellij action write-chars sends a sequence of characters to the focused pane, while zellij action write sends keystrokes by keycode. Both can be targeted at a specific session with --session:
zellij action --session dev write-chars "git status"
zellij action --session dev write 13The sequence above types git status then presses Enter in the dev session's pane — exactly as if you'd typed it yourself. Use this pattern to sync commands to many panes at once, or to forward input from the outer level to the inner level in a controlled way without surrendering the whole keyboard.
Note
Pipes are the counterpart to zellij action: pipes channel data to and from panes or plugins in real-time, while action sends a one-shot command. For continuous keypress-forwarding flows — for example replicating input across several panes — combine write-chars with a small script that monitors pane output.
Be careful: write-chars doesn't validate your shell. If you send text to a pane that's running another program, the text is received as-is. Always make sure the target pane is actually waiting for input at a shell prompt, and never send destructive commands to a session a colleague is using in a shared session.
Zellij sits between panes and the terminal emulator. This position lets it translate modern terminal protocols that older multiplexers don't understand. The three protocols most useful for daily workflows are OSC 52 (clipboard), OSC-99 (notifications), and CSI 2031 (theme switching).
OSC 52 — remote clipboard. When you copy text inside Zellij on a remote server, that text is actually on the remote machine. To get it to your local clipboard, Zellij sends the escape sequence ESC]52;c;base64-content;BEL to the terminal emulator. If the terminal supports OSC 52, the text lands directly in your local clipboard without copying via files or a separate SSH.
TEXT=$(printf '%s' 'Hello Zellij' | base64)
printf '\033]52;c;%s\007' "$TEXT"As an alternative, you can set a platform-specific copy command through the copy_command option. If copy_command is set, Zellij uses it for copying; if not, Zellij tries passing through OSC 52.
copy_command "xclip -selection clipboard"OSC-99 — desktop notifications. Programs inside a pane can trigger system notifications via OSC-99. Zellij forwards this sequence to the terminal emulator, and supporting terminals display it as a desktop notification. Useful for signaling "build done" or "deploy succeeded" without staring at the terminal constantly.
printf '\033]99;i=0:d=Deploy finished;\a'CSI 2031 — dark/light theme switching. When the operating system toggles between light and dark mode, modern terminal emulators send a CSI 2031 sequence. Zellij version 0.44 listens for this signal and automatically switches between theme_dark and theme_light, so your workspace appearance always blends with the system theme:
options {
theme_dark "nord"
theme_light "solarized-light"
}Important
All three protocols above only work if your terminal emulator supports them. OSC 52 needs remote clipboard support, OSC-99 needs notification support, and CSI 2031 needs a terminal that sends theme-change signals. If a feature doesn't react, check your terminal's documentation before blaming Zellij.
Ctrl+g twice in nested Zellij. Instead of unlocking the outer level, you lock the inner level. Fix: watch the LOCKED indicator in the status-bar — if the screen is still locked after one Ctrl+g, press it once more.Ctrl+g, or disable mouse_mode on one of the levels.copy_command on the wrong platform. pbcopy doesn't exist on Linux and wl-copy doesn't exist on macOS. Fix: match the platform (wl-copy or xclip for Linux, pbcopy for macOS, clip.exe for Windows).copy_command, or choose a terminal with OSC 52 support.Episode 21 settled Zellij's input layer: you now understand the nested Zellij scenario where two multiplexers coexist, the Locked mode strategy with Ctrl+g for releasing input temporarily, keybinding remapping for permanent separation between levels, mouse navigation and resize, programmatic input via zellij action, and the integration of OSC 52, OSC-99, and CSI 2031 that connects Zellij with modern terminal features.
The points to take away:
Ctrl+g releases input to the lower level; don't press it twice unaware.mouse_mode to hand it over.Now you can control Zellij anywhere — including inside Zellij. In episode 22 next we shift perspective from convenience to security: Security & Hardening Best Practice — securing sessions with Ctrl+g, controlling shared-session access, managing sockets and the cache directory, keeping secrets safe, limiting dangerous plugins and pipes, up to Zellij best practices on production servers. See you in episode 22, and make sure your workspace isn't just advanced, but also secure.