#5624·zellij

Per-client fit toggle for terminal clients, and a client id on CLI actions

Author: rafa-garciaCreated Sep 16, 2026Updated Sep 16, 2026

Summary

Since #5133 (0.45.0) tabs are sized per viewing client: a tab takes the minimum rows and columns among the clients whose active tab it is (Screen::recompute_tab_size). That removed the whole-session shrink of #4253's scenario for tabs nobody shares, but a shared tab is still pinned to its smallest viewer, and a terminal client has no way to say "I am only looking, don't size for me". The mobile web client has exactly that switch (Fit to my screen); terminal clients do not. I would like the same preference for terminal clients, and a way to address one specific client from the CLI.

The case

Two clients on one session: Ghostty on an external monitor at 68x360, and an SSH session from a laptop at 42x200 that stays attached for days to babysit long-running processes, parked on one tab. Every tab the SSH client sits on renders at 200 columns in the wide terminal, while the other tabs follow the wide window. After plugging the monitor in it looks like a redraw bug until you find the second client.

What 0.45.1 offers today, and where each falls short

  • Detach the small client, or Ctrl+x (disconnect others) in the session manager. Loses the attachment I want to keep.
  • Park the small client on a tab of its own. Works, but only from that client's own keyboard: a CLI action runs as the last client to have issued a keystroke (the cli_client comment in route.rs), list-clients prints client ids, and no action accepts one, so nothing can move or detach a specific client from another shell.
  • zellij watch. Read-only, so the babysitter cannot answer a prompt.
  • The mobile web client with Fit to my screen off: mobile_web_prefs.fit = false excludes that client from the minimum and gives it the largest other viewer on the tab as its reference (reference_size_for_client). This is the right mechanism, but it is web-only, and revert_fit_disabled_without_reference_client turns fit back on whenever no other client shares the tab, so it has to be switched off again every time sharing resumes.
  • Outside zellij: stty rows R cols C < /dev/ttysN on the small client's tty. It goes through the normal resize path and it is a hack: the small terminal renders an oversized screen until it next reports its real size.

Proposal

  1. A per-client fit preference for terminal clients, reusing the mobile path in recompute_tab_size:
    • zellij attach --no-fit <session> (or --fit=false), a bindable action SetFit true|false or ToggleFit, and the matching plugin command.
    • Semantics: a fit-disabled client is excluded from the tab's minimum, takes the largest other viewer's size as its reference and renders cropped or padded, the way a watcher's followed view is rendered today. When it is the only viewer the tab takes its real size, and the preference persists instead of flipping back as the web one does.
    • Alternatively, or as well, a session option tab_size_policy "smallest"|"largest", where largest lets the biggest viewer set the tab and smaller viewers crop.
  2. Client targeting on the CLI: zellij action --client-id <id> <action> for the actions that take a client context (go-to-tab, go-to-tab-name, switch-session, detach, and the new SetFit). list-clients already exposes the ids, so an operator can park or drop one client from another shell, and a plugin gets the same reach through run_action with a client id.

Either half alone helps. Together they cover "keep the small client attached without it pinning my tab" and "move or drop that one client". #4253 asks for fully independent per-client layouts; this is the smaller step that fits the current model, and the fit preference already exists for one client type.

Environment

zellij 0.45.1 (nixpkgs build), macOS 26 (Darwin 25.6.0) on Apple silicon, Ghostty locally, an SSH session from a laptop remotely. Related: #5133, #4253, #4999, discussions #3816, #5066, #5309.

Happy to test a branch or attempt the change with a pointer to where the web fit preference is plumbed from the client side.