AI tips · No. 1
2026-09-25

Keep your Claude Code sessions running

One session per project, started at login, updated overnight, never interrupted.

Using an AI agent? Don't build this by hand. Point your agent at this page; there is a section for it at the bottom.

The problem

I keep one Claude Code session open per project — eight of them, on a Raspberry Pi 5 in the shop — and I mostly talk to them from my phone through Remote Control.

Every operating-system update ended in a reboot, and every reboot ended the same way: open a terminal, change into a project folder, type claude, eight times over. Claude Code updates itself in the background, but a session that is already running keeps the old version until it is restarted, so every update meant the same routine.

The fix

Run every session inside tmux, start them all at login, and let a script restart the idle ones when there is something new. Three pieces:

  • A tmux server of their own, one window per project. Closing the terminal no longer ends anything, and a script can restart a session without a screen.
  • A list of folders, started at every desktop login.
  • An update button on the taskbar, and the same script on a nightly timer: operating-system updates, claude update, then each idle session restarted on the new version. It offers a reboot only when a new kernel or firmware needs one.
tmux -L claude new-session -d -s claude \
  -n garage -c ~/projects/garage "claude -n garage"
tmux -L claude new-window -t claude: \
  -n farm -c ~/projects/farm "claude -n farm"
tmux -L claude attach -t claude

-L claude gives the sessions a private tmux server, so nothing else that uses tmux can collide with them. -n names each session after its folder, which is the name the phone app shows instead of a random one.

Making it safe

Never interrupt a session that is working. Claude Code keeps a small state file per running session (~/.claude/sessions/) that says whether it is busy or idle and which version it runs. The script only restarts the idle ones and reports the rest. It is not a documented interface, so a second signal backs it up: a session whose conversation file has not been written for a minute is not doing anything.

Resume instead of starting over. A restart does not have to lose the conversation:

claude --resume <session-id> -n garage \
  "The Pi just rebooted. Check that everything came back."

That line is how the session that rebooted the Pi came back afterwards and checked its own work.

What bit

  • Environment leaks. Launch sessions from inside a Claude session and the new ones inherit its CLAUDE* variables and think they are its children. Strip them before starting the tmux server.
  • systemd cleans up after itself. A oneshot timer kills everything left in its cgroup when it exits, and that includes a tmux server it started. Start the server in its own scope: systemd-run --user --scope tmux ….
  • Esc feels broken until you set escape-time 10 in tmux; the default waits half a second.
  • Ctrl-b is tmux's prefix, and Claude Code has its own Ctrl-b. Press it twice to reach Claude, or pick another prefix. Clicking the window names in the status bar (set -g mouse on) avoids the question.

The result

After a reboot the sessions are simply there: on the Pi's screen, and on my phone. Updates land overnight, and nothing I am in the middle of gets cut off. The whole thing is a 580-line Python script, a 110-line shell script and a 30-line tmux config, and Claude Code wrote all of it in one session from the problem as I described it above.

For your AI agent

Anyone with an AI agent will just tell it to read this and set it up, so this part is written for the agent. Paste something like this into Claude Code, or whatever agent you use:

Read https://jacobkunselman.com/tips/claude-code-sessions/agent.md
and set this up on my machine for the projects in ~/projects.
Adapt it to my OS. Run its acceptance tests.

agent.md is the plain-text spec: the goal, the components, the commands, the Claude Code internals it relies on (marked as undocumented), the rules that keep it safe, and seven acceptance tests. The scripts I actually run are the reference implementation, written for a Raspberry Pi and meant to be read and adapted, not copied: