Guide
Everything scrn does, in the order you'll meet it.
Install
curl -fsSL https://raw.githubusercontent.com/w0zro/scrn/main/install.sh | sh
The script fetches the release built for this machine, verifies it against the release's checksums.txt, and puts the binary in ~/.local/bin. Two variables change its mind:
SCRN_INSTALL_DIR | install somewhere else |
SCRN_VERSION | a release other than the latest |
Building from source works too, with Go 1.22 or later:
go install github.com/w0zro/scrn@latest
First run
scrn
There is nothing else to set up. The first window starts the daemon — the same binary — and later windows attach to it. By default scrn looks for repositories under ~/projects; point it elsewhere in the config.
The list opens showing what is running, so on a quiet machine it may say nothing running. Two keys from there:
- . shows every repository, running or not
- / finds one by name
The navigator
The left column is a tree, at most four levels deep: group → repository → sub-project → process.
Repositories
Every git repository under your project roots. The scan skips node_modules, vendor, target, .build, Pods, .venv and venv, plus anything you add to skipDirs.
Groups
A folder inside a root that holds two or more repositories groups them — the common shape of a project that spans sibling repos. The group is a place of its own: s opens a shell at the folder, r runs the folder's plan, x covers everything beneath it.
Sub-projects
In a monorepo, a directory with a manifest is a project of its own and gets a row under its repository. The manifests, in the order they are trusted: .scrn, Procfile, package.json, deno.json, composer.json, go.mod, Cargo.toml, Gemfile, mix.exs, pyproject.toml, pom.xml, build.gradle. They are found through git ls-files — no tree walk, ignores respected, untracked files included.
Processes
Each place lists the processes running in it, attributed to the innermost place they belong to, and named by what you would call them — npm run dev, not node. A few keys shape the list:
| space | fold or unfold the selected node; a folded node shows +n for what it hides |
| - | fold or unfold everything; unfolded rows also show pids |
| . | toggle between everything and only what's running |
Dim rows are processes that exist but were started outside scrn, on some other terminal. They are listed and killable, but there is nothing to step into.
Shells
s opens a shell at the selected place. enter on a shell's row steps into it: keystrokes go to the shell, and ctrlo is the one key scrn keeps for itself, to step back out.
Shells live in the daemon, so they survive the window — close the terminal, reboot the terminal app, come back and everything is where it was. The pane is a real emulator: the alternate screen, mouse reporting, window title and progress all pass through, so full-screen programs behave.
Scroll up (wheel or k after entering scrollback) to read what has scrolled away; j k move, esc returns to live. Each shell keeps 10,000 lines of transcript by default — scrollback in the config raises it.
When several windows watch the same shell, it is sized for the smallest of them, so no window sees a torn screen.
Agents
a starts Claude Code in the selected place, in a shell like any other. scrn reads the session files Claude leaves behind, so the navigator can say more than "claude":
- a turning marker — an instance is working
- a bright
◆— blocked mid-turn on something specific: a permission prompt, a question - an amber
●— finished its turn, waiting for whatever you ask next - a quiet
○— idle since it started, owed nothing
That mark is what tells you, from across the list, which projects need your attention — the ◆ most of all, since answering it resumes work already underway. The detail pane for a Claude row names what a blocked instance is waiting on, and shows the tail of its transcript.
Plans
Working on a project usually means the same processes every time: the dev server, the test watcher, an agent. A project writes them down in .scrn — Procfile format, a name and a command per line:
.scrn
dev: npm run dev api: go run ./cmd/api agent: claude
Without one, scrn reads the conventions in the order they are trustworthy: a Procfile means every line is a process; a package.json means only that its dev or start script probably is, so exactly one of those is taken.
r starts the plan's entries that aren't running, each in its own shell named for its entry. It is a list to run, not a supervisor: nothing restarts on its own, and a dead server shows as dead until you start it again.
Killing
| x | kill the selected process |
| X | kill it and everything under it |
| x on a repository or group | kill everything running in it |
Every kill asks first — x, y or enter confirms, anything else cancels. Processes get SIGTERM, and a signalled row wears a red marker until a rescan actually observes the exit; the list never claims an exit it hasn't seen. Kills work on any listed process, including ones scrn didn't start.
Configuration
One JSON file, entirely optional. It lives at ~/.config/scrn/config.json (XDG_CONFIG_HOME is honored).
~/.config/scrn/config.json
{
"projectsDirs": ["~/projects", "~/work/mono"],
"scrollback": 50000,
"navWidth": 34,
"skipDirs": ["bazel-out", "dist"]
}
| Field | Default | |
|---|---|---|
projectsDir | $HOME/projects | the directory searched for repositories; ~ and $VARS expand |
projectsDirs | — | several roots; when set, it is the whole answer and projectsDir is ignored. A root that only exists on your other machine is fine |
scrollback | 10000 | transcript lines each shell keeps. Read by the daemon at start, so raising it takes R to reach running shells |
navWidth | 28 | the navigator column's width, 16–60 |
skipDirs | — | directory names the project scan never enters, on top of the built-in list |
The daemon
The daemon is the same scrn binary, started by the first window that finds none listening. It owns the ptys, holds the transcripts, and serves every window over a unix socket at ~/.local/state/scrn/scrnd-<uid>.sock (SCRN_SOCKET overrides). One daemon per user, for all projects.
It never outstays its purpose: holding no shells and watched by no window for a minute, it exits. A window that loses its daemon says so and reconnects when one is back.
Upgrading
Install the new binary (the install script again, or go install), then press R in any window. The running daemon replaces itself with the binary on disk by exec — same process, new code — and every shell carries across: pids, ptys, transcripts, screen state. The programs in them never notice.
Linux
Linux builds are published for arm64 and amd64, cross-compiled and so far untested — reports welcome. scrn reads the process list through lsof, so it must be installed:
apt install lsof # or dnf, pacman, apk…