Run everything in one terminal with screen
On this page
screen (GNU Screen) is a terminal multiplexer: one terminal window holding as many shell sessions as you like, each carrying on in the background whether you are watching it or not. Close a normal terminal and the session closes too; a screen session keeps running until killed.
Why screen and not tmux? Great question. Availability. tmux is more modern, and nicer once configured, but if you're using macOS, or SSHing into Linux servers, screen will already be waiting.
By default macOS ships an old build (4.00.03, from 2006) that does everything here except vertical splits, so it's worth upgrading to a current screen 5 first (an easy how-to is below).
Getting started
Open a terminal and type:
$ screen
The screen clears (or shows some intro text first), then you get a fresh shell prompt, and nothing looks different. You are now inside screen. Everything you do stays in a session it controls.
Using the command key
You'll also want to learn the command key. It is how you give screen an instruction, as opposed to just typing into the shell. That signal is Ctrl-a: you hold Ctrl, tap a, let go, then press one more key that says what you want. Every screen command is Ctrl-a followed by something.
Ctrl-a is a prefix; press, release it, then press the command key. Ctrl-a then c creates a window; Ctrl-a then d detaches.
Opening and switching windows
Start a screen session, then Ctrl-a then c to open a new window inside it. Do that a few times and you have a stack of shells in a single terminal (or none on screen at all, once you detach them to the background). Every key mentioned in this note is referenced in the cheatsheet at the bottom.
Worth setting expectations here: each window fills the whole terminal. Ctrl-a then c opens a new one and switches to it while the others wait in the background, like browser tabs. If you were expecting them side by side, that is a split, a separate feature covered further down (and Ctrl-a c does not split, you split first, then open a window in the new region).
Navigating between them:
- Ctrl-a then a number (
0,1,2...) jumps straight to that window. - Ctrl-a then
nandpstep to the next and previous one. - Ctrl-a then
"lists every window so you can pick from a menu.
Make them even more usable by naming them, so you can choose "the stock one", instead of "window 3". You can name a window as you create it, or rename one after the fact:
$ screen -t menu-api # launches with the first window already named "menu-api" # # inside a running session: # Ctrl-a : opens screen's ":" command line, then type: # screen -t stock-bug new window, named on creation # Ctrl-a A rename the window you are in
Name them after the jobs in front of you (menu-api, stock-bug, loyalty) and you can jump straight to one by name: Ctrl-a then ' (single quote) prompts for a window, and you type stock-bug instead of remembering it was window 1. Ctrl-a then " does the same from a labelled list you pick off. Either way you are choosing the job, not the number, without once reaching for the mouse. That alone is worth the ten minutes it takes to get the muscle memory.
Detach and walk away
Detaching is how you offload a process to the background and come back to it later. Press Ctrl-a then d and you detach: screen lets go of the window and hands you back your plain terminal, with a confirmation line naming the session you just left (that leading number is its pid):
$ # Ctrl-a d [detached from 48213.ttys000.macbook] $
Everything you had running is still running. Close the terminal window and screen doesn't care, it carries on in the background. Two caveats: put the machine to sleep and the process pauses until it wakes. Reboot, and the whole thing is killed. Short of that, the session is there whenever you want it back, just list the detached screens and reattach.
Reattach and carry on
$ screen -ls There is a screen on: 48213.ttys000.macbook (Detached) 1 Socket in /var/folders/screen. $ screen -r
screen -ls lists your sessions and whether each is attached or detached; screen -r reattaches, dropping you back exactly where you left off. With one session, screen -r on its own is enough. With several, a bare screen -r lists them and you pick by the pid on the front of the label, e.g. screen -r 48213.
This is really powerful if you're working on a remote server with an unstable connection. SSH into a dev box, start screen there, and when your connection drops on the train (and it will), nothing dies. The session stays alive on the server. You reconnect, run screen -r, and pick up as if you never left. A long job no longer lives or dies with your wifi.
Naming sessions and windows
That pid.tty.host label is fine to reattach by, but a pain to read and remember. So once you keep sessions around, name them as you start: screen -S sundae makes the session "sundae", and screen -r sundae reattaches without needing to remember a five-digit pid.
Something to keep in mind: -S names the session, the thing you reattach to; -t names a window inside it, the thing you switch between with Ctrl-a ". If you only set one, make it -S: the session name is what you type on every reattach.
Killing a session
You can end a session from the shell without needing to attach first. screen -X -S sundae quit kills the named session and everything running in it (a pid works as well: screen -X -S 48213 quit). When a pile of them are sitting detached and you want a clean slate, pkill screen stops the lot in one go.
$ screen -X -S sundae quit # kill one session by name (or pid) $ pkill screen # kill every screen session, attached or not
Splitting screens
Splitting only carves out an empty region, it does not put a window in it, so there are two moves to it:
- Split it. Ctrl-a then
S(capital) splits into stacked rows, one region above the other; Ctrl-a then|(pipe) splits into side-by-side columns instead. Either way, focus stays in the original region and the new one sits blank. - Fill it. Ctrl-a then Tab moves focus into that blank region. Now give it something to show: Ctrl-a then a number for an existing window, or Ctrl-a then
cfor a fresh shell.
Closing a split is its own pair of keys. Ctrl-a then X removes whichever region is active; the window it was showing keeps running, you just stop looking at it. Ctrl-a then Q goes further, collapsing every split back to one full-screen region. Either way you are closing the view, never the window or what is running in it.
A plain split vanishes when you reattach, dropping you back to a single region. To make it stick, screen has a layout feature (screen 4.1+): with layout autosave on, the split comes back on screen -r. You can even open already split by putting the setup in a config file and launching with screen -c <file>:
layout autosave on
layout new agents
screen -t menu-api 0
screen -t stock-bug 1
split # split -v for side-by-side columns
focus
select 0
Now screen -c ~/.screen-agents drops you straight into the split with every window in view.
Upgrading screen
The screen that ships with macOS is ancient and only splits horizontally. For just holding windows and detaching, the old one is completely fine.
Side-by-side (vertical) splits arrived in screen 4.1, so getting columns means a newer build. Here's how you can build it from source in about five commands: fetch Apple's compiler tools once (if you don't have them already), then download the current source, unpack it, and compile.
$ xcode-select --install # one-time: Apple's command-line tools $ curl -LO https://ftp.gnu.org/gnu/screen/screen-5.0.1.tar.gz $ tar xzf screen-5.0.1.tar.gz $ cd screen-5.0.1 $ ./configure && make && sudo make install
make install puts the new binary in /usr/local/bin, which sits ahead of /usr/bin on the default macOS PATH, so typing screen now starts the build you just made (check with screen --version). The stock one stays where it is underneath, so you've not broken anything. Ctrl-a then | (pipe) now splits into side-by-side columns, the layout you want for watching two agents at once.
Grab whatever version is newest from ftp.gnu.org/gnu/screen (5.0.1 used above is the latest at time of writing) and match the folder name to it.
Streamline your AI agents
Running six separate terminal windows, each with its own AI agent? This is a perfect use case for screen.
Long-running agents don't need babysitting: An agent working through a task can take minutes, not seconds. Run screen, prompt the goodness, detach it, grab a coffee. Come back, reattach, read what it did, and keep on working.
Organise parallel agents: One session, one window per agent, each named for the job it's on: menu-api, stock-bug, loyalty-fix. Ctrl-a then " gives you the list, and you pick them one at a time instead of hunting across a wall of identical-looking windows.
They survive everything: Detached agents keep going. If they're running on a remote box, your laptop sleeping or an SSH drop doesn't kill them. You can kick off a long run on a remote dev server, detach, close the lid, and reattach from a different machine entirely.
If you still want full visibility, split-screen puts them all in front of you at once.
Cheatsheet
- Ctrl-a
c: new window - Ctrl-a
n/p: next / previous window - Ctrl-a number : jump to a window by position
- Ctrl-a
': jump to a window by number or name - Ctrl-a
": list windows to pick from - Ctrl-a
A: rename the current window - Ctrl-a
d: detach (everything keeps running in the background) - Ctrl-a
S: split horizontally - Ctrl-a
|: split vertically (|needs screen 4.1+) - Ctrl-a Tab : move between regions
- Ctrl-a
X/Q: close the current split / collapse all splits screen -t <name>: start with the first window namedscreen -S <name>: start a named sessionscreen -ls: list sessionsscreen -r: reattach (needs the pid if more than one detached session)screen -X -S <name> quit: kill a session by name or pidpkill SCREEN: kill every session (uppercase for macOS, lowercase elsewhere)