termroam
TermRoam · field guide

Why your agent dies when you close the laptop

Close a laptop with an AI agent mid-task and the work can simply vanish — not from a bug, but from how terminals, shells, and processes are actually wired together. This guide explains the mechanism precisely: what severs the connection, which signal kills the process, and the one structural fix — a session that outlives any single window — that makes closing the lid safe again.

01

The chain: terminal, shell, agent

An AI coding agent isn't a cloud service humming along independently while it works — it's an ordinary operating-system process, no different in kind from a text editor or a browser tab. What keeps that process alive comes down to three things it's connected to, in order.

First, a terminal — the window you're looking at, or, if you're on a remote machine, the SSH client making the connection. Second, a shell — the command interpreter (bash, zsh) that the terminal starts the moment it opens, and that reads and runs whatever you type. Third, your agent itself: Claude Code, Codex, or whatever CLI you launched, which the shell started as a child process the instant you ran its command. Three links, one chain: the terminal owns the shell, the shell owns the agent.

The operating system tracks this formally. All three processes belong to the same session — the kernel's word for a group of processes sharing one controlling terminal, the terminal that receives their output, takes your keystrokes, and holds the authority to interrupt or kill them. As long as the terminal at the top of the chain exists, everything below it runs exactly as expected. The chain only breaks when that top link disappears — and on a laptop, that happens more often, and more invisibly, than most people realize.

02

What actually severs it: the hangup signal

When a terminal goes away — the window closes, the SSH connection drops, the machine sleeps — the kernel doesn't just quietly stop delivering keystrokes. It sends a signal: a small asynchronous interrupt, not data, whose entire job is to tell a process that something happened. Signals are numbered and named; the one that matters here is SIGHUP — "hangup," signal 1 — a name inherited from dial-up modems, where a hangup meant the phone line had gone dead. It still means the same thing in spirit: your controlling terminal is gone.

The kernel delivers SIGHUP to the foreground process group attached to that terminal, which, per the chain above, includes your shell and, through it, your agent. Unless a process has explicitly told the operating system to ignore or handle that signal, its default behavior is to terminate immediately, with no cleanup. Not "finish this step and stop" — just stop, wherever it happened to be standing. A file half-written stays half-written. A test that was mid-run never reports a result. Whatever step your agent was on when the connection died simply never finishes, and nothing tells you afterward that it happened cleanly — because it didn't.

Watch the sequence below. The agent is midway through a nine-step task; closing the laptop in plain-terminal mode delivers exactly the chain described above.

close-the-lid — mode: plain terminal
Step 4 of 9 is in progress. Click close laptop to see what happens to it.
precision notes — signals and shell behavior

Exact defaults vary by shell and configuration. Bash's interactive, non-login default is to leave background jobs alone when the shell exits, unless the huponexit option is set — but that's irrelevant to an agent running in the foreground, which is where it almost always runs, since it needs your terminal for output and prompts. Foreground processes are torn down by the kernel delivering SIGHUP directly to the whole foreground process group; no shell logic is even involved.

SSH adds its own layer, not a different one. When an SSH client disconnects, the server closes the session's pseudo-terminal, and that closure is exactly what triggers the kernel's hangup delivery on the remote machine. The mechanism is identical whether the terminal in question is local or reached over a network.

03

Laptop realities: the terminal goes away more than you think

None of this requires anything exotic. The chain breaks during completely ordinary laptop use, potentially several times a day.

Closing the lid suspends the machine; depending on configuration, suspending can itself terminate remote connections and local processes outright, and even when it doesn't, the machine is now frozen mid-execution with no guarantee of a clean resume on wake. Waking up on a different network is its own event — moving from home wifi to a phone hotspot, or simply reassociating after sleep, usually means a new IP address, which drops an SSH connection that was mid-stream. The remote end sees the same hangup it would see from a closed window. A dead battery ends everything at once, with no shutdown sequence at all. OS updates that force a restart kill every local process regardless of network state, on a timeline the operating system chose, not you.

Each of these is a different trigger with the same downstream effect: the terminal your agent depends on stops existing, SIGHUP fires, and the agent dies wherever it was standing. A laptop is built to sleep, roam between networks, and restart itself — which makes it a genuinely poor home for a process that needs to survive unattended. A small always-on machine that never sleeps and never changes networks — a VPS — removes the environmental half of the problem. It doesn't, on its own, fix the other half: even on a server that never sleeps, your SSH connection to it can still drop, and the same chain still applies unless something changes about who actually owns the agent process.

04

Half-measures, and why they fall short

The obvious first fix is to make the process immune to the signal, or hide it from the signal entirely. Two standard tools do exactly that, and both share the same blind spot.

A "no hangup" launcher starts a process with SIGHUP explicitly ignored, and redirects its input and output away from the terminal so a closed window has nothing left to disrupt. It works — the process survives — but the price is interactivity. An agent that hits a permission prompt, wants to show you a diff before applying it, or needs a clarifying answer now has nowhere to put that question, because you severed its only live channel to you on purpose. You've traded "it dies" for "it's now a black box you can only inspect afterward, through a log file."

Detaching a job from your shell's job table has the same effect from a different angle: the shell stops treating the process as something it's responsible for, so a shell exit won't chase it down with a signal. Same tradeoff — the process is safe, but you're no longer attached to it in any live sense.

"Keep awake" utilities — tools that jiggle the mouse, simulate a keypress, or otherwise convince the operating system a user is present — solve a narrower, different problem: they stop the machine from sleeping on idle. They do nothing for a closed lid, since that's a hardware switch rather than an idle timer, and most of them stop working the instant you actually close it. They do nothing for a dropped wifi connection or a forced restart. And running a laptop permanently awake inside a closed bag creates a problem of its own — the heat has nowhere to go.

None of these change the underlying fact: your agent's controlling terminal is still, ultimately, your laptop's terminal or SSH session. They manage the symptom. The actual fix means changing who owns the process.

05

The real fix: a session that outlives the window

The structural solution is to stop making your terminal window the direct parent of your agent process at all. Instead, a small program runs permanently on the machine — a session server — whose only job is to own long-running terminal sessions on behalf of clients that come and go. This is the terminal multiplexer model: one long-lived server process holds the actual session, and everything running inside it, open; any number of thin clients — a terminal window, an SSH connection, a browser tab — can attach to that session, watch it, type into it, and detach again, without the session itself starting, stopping, or even noticing.

The distinction that matters is ownership. Your agent's controlling terminal is now the session server's, not your laptop's. When your laptop closes, sleeps, or loses its network, exactly one thing goes away: a client. The kernel still delivers SIGHUP — but it delivers it to the client connection that just vanished, not to the agent, because the agent was never a child of that connection in the first place. The session, and every process inside it, keeps running, on a machine that isn't the one you just closed.

Reattaching is symmetric: a new client connects to the same still-running session and is handed its full scrollback — not a fresh, empty shell, but the actual terminal state, redrawn instantly, as though you'd never left. Try both modes in the simulation above by switching to session-server mode and closing the laptop again — same nine-step task, same action, opposite outcome.

The model extends past one client at a time. A laptop and a phone can attach to the identical live session simultaneously, both watching the same output, because "attached" was never the same thing as "keeping it alive" — it never had to be.

one session, two devices

laptop — attached

phone — attached

Both devices are attached to the same session. Click agent writes output to see it mirrored live to both.
06

What this unlocks

Once the agent's process lives inside a session instead of inside your terminal window, a handful of things that used to be impossible become routine. You can start a long task on your laptop before leaving the house, close it, and check progress from your phone at lunch — the same session, a different thin client attaching to it. You can hand a teammate the address of a running session so you both watch the same live output at once, useful for showing exactly what an agent did and when, instead of reconstructing it from a log afterward. You can switch from a terminal window to a browser tab mid-task with no interruption, because neither one was ever the thing keeping the process alive.

From the agent's point of view, none of this is visible. It never receives a hangup, never restarts, never loses state, because nothing about its actual environment changed — only who, if anyone, happened to be watching at a given moment. That's the property worth naming plainly: a persistent terminal session decouples "is this task still running" from "is anyone currently looking at it," which is exactly the coupling that made the plain-terminal chain fragile in the first place.

07

Why this matters more for AI agents than for you

A dropped connection has always been mildly annoying for a human at a prompt — you retype a command, maybe lose an in-progress edit. It stayed a minor issue for decades because human terminal sessions are short: run a command, read the output, move on. Coding agents break that assumption. A single task can mean reading a codebase, forming a plan, editing files, running a test suite, reading the failure, and editing again — a loop of proposing and observing changes that repeats dozens of times before it's done, minutes at the fast end, hours at the slow end.

Duration changes the math on disconnection risk in two ways at once. First, probability: a task running for two hours has vastly more opportunity to intersect a lid closing, a network roam, or a forced restart than a command that runs for two seconds — the ordinary events from section three stop being rare edge cases and become near-certainties over a long enough session. Second, cost: losing two seconds of typing is nothing; losing two hours of an agent's accumulated context, partial edits, and test results — work that may not be safely resumable from wherever a log file happened to leave off — is a real setback, sometimes worse than starting over, because you also have to work out what state you were actually left in. For any agent task long enough that you'd want to leave the room, a persistent session isn't a nice-to-have. It's the precondition that makes leaving the room safe.

08

How TermRoam handles this

TermRoam runs every agent inside a persistent terminal session on a dedicated, always-on server, rather than inside whatever terminal window happened to start it. You can attach from a browser tab on your laptop, hand off to your phone, close either one, and reattach later to the same live session — full scrollback, task state untouched, exactly the behavior in the simulations above, running by default instead of something you have to configure.