← All posts

claude respawn: when a background session misses your plugin update.

2026-09-25 · 6 min read · by Nabil BA-MOH

You update a plugin. A new Claude Code session has the change. The background session you have been working in all day does not, and /reload-plugins doesn't fix it. The command you want is claude respawn <id>: it restarts the session, keeps the conversation, and starts it fresh on what is installed now.

The official docs describe respawn as the way to move sessions onto a new Claude Code binary. They don't warn that a session UUID won't work, that a plugin theme is not among what /reload-plugins reloads, or what the home-directory refusal means. Here is what we measured on 25 September 2026.

What happened

Most of our Claude Code work runs in background sessions: started with claude --bg, listed by claude agents. Our plugin, Klyr, shipped a light theme through its experimental.themes directory.

Our own mistake is worth naming: we went round in circles on "reload again" and "open a new terminal" before we looked up the lifecycle command. A new terminal gives you a new session, not the one you are working in.

Why /reload-plugins wasn't enough

The docs are clear that a running session keeps the plugin versions it loaded, and that /reload-plugins or a new session brings changes in. What they don't spell out is that a reload is not a restart. Look at what it reports:

Reloaded: N plugins · N skills · N agents · N hooks · N plugin MCP servers · N plugin LSP servers

No themes. The plugin loading reference already admits one component needs a real restart: monitors. On our machine, a plugin theme behaved the same way in a background session. (We did not test a reload in an interactive session, so we won't claim anything about that case.)

Don't be misled by the themes page either: ~/.claude/themes/ is watched live, but that is your own theme folder. A plugin's theme lives in the plugin.

The rule we now follow: if a reload doesn't show the change, respawn.

What each gesture actually does

In a background sessionWhat happens
/reload-pluginsReloads plugins, skills, agents, hooks, MCP and LSP servers. Same process
/exit, ←, Ctrl+ZDetaches. The session keeps running, unchanged
/stop or claude stop <id>Ends the process. The conversation is kept
claude respawn <id>Restarts the session on what is installed now, conversation kept
claude respawn --allRestarts every running session, the one you are typing in included

Pass the short id, not the session UUID

claude agents --json gives every background session two ids:

The docs call the short id the one you use from the shell, and list it for attach, logs and stop. They don't warn that a sessionId fails, or that the short id is not always the start of the UUID. We checked: respawn matches its argument against the start of the short id. A sessionId doesn't work.

The easy trap is to assume the short id is just the first 8 characters of the UUID. Often it is. Not for resumed sessions: on our Mac (Claude Code 2.1.282), 5 of our 14 background sessions had an id that is not the start of their sessionId. Always read id from claude agents --json.

Which sessions are stale?

There is no plugin version in claude agents --json, so no field says "this session runs an old plugin". What you can do is compare two dates: when the session started, and when the plugin was last updated. A live session started before the update may still be running the old version.

import json, subprocess, sys
from datetime import datetime

def cli(*args):
    return json.loads(subprocess.run(["claude", *args, "--json"], capture_output=True, text=True).stdout)

def epoch_ms(iso):
    return datetime.fromisoformat(iso.replace("Z", "+00:00")).timestamp() * 1000

plugin = sys.argv[1]
updated = max((epoch_ms(p.get("lastUpdated") or p["installedAt"])
               for p in cli("plugin", "list") if p["id"] == plugin), default=None)
if updated is None:
    sys.exit(f"{plugin} is not installed")

for s in cli("agents"):
    if s["kind"] == "background" and "pid" in s and s["startedAt"] < updated:
        print(s["id"], s["status"], s.get("name", ""))

Run it as python3 stale.py <plugin>@<marketplace>. It only reads. Two details it handles for you:

It is a heuristic, not a version check: a /reload-plugins already refreshes most components. It tells you which sessions to look at. On our Mac it found none: 5 sessions predated the last update, and none of them had a live process.

Three traps before you respawn

  1. --all includes you. claude respawn --all restarts every running session, the one you are typing in too. Run it from a plain shell. Or respawn one by one, the one you are in last.
  2. Check status first. busy means the session is in the middle of a turn. Let it finish, or accept that you are cutting it off.
  3. Home-directory sessions can refuse. A session rooted in your home directory may answer:
    Workspace not trusted. The home directory is trusted one session at a time — start this from an interactive terminal there, or from a project directory.
    This message is not on the docs' error page (only its Remote Control cousin is). The message itself names the way out: an interactive terminal opened in your home directory, or a project directory. The safe habit is the second one: keep long-lived sessions in a project directory.

On Windows

Same command on Windows 11 native (Claude Code 2.1.274): claude respawn <id>|--all. Background entries in claude agents --json carry id, sessionId, name, cwd, kind, startedAt, state, plus pid and status while alive. Jobs live under %USERPROFILE%\.claude\jobs\<id>\.

One difference you will hit: the plain claude agents table needs a real terminal (TTY). From a script or a pipe, use claude agents --json. The script above only calls the two JSON commands. We ran it on macOS.

The pattern, in one line

A background session is a long-lived process: it keeps what it loaded until something restarts it. When an update doesn't show up after a reload, don't open another terminal. Find the short id and respawn.

This matters to us because Klyr ships as a Claude Code plugin and does most of its work in background sessions. An update only counts once the session you actually use has loaded it. If you want an assistant that keeps up like that, get Klyr.

Background sessions have their own sign-in rules too: Claude Code background sessions and MCP auth.

FAQ

How do I restart a Claude Code background session without losing the conversation?

Run claude respawn <id> from a shell. The session restarts and resumes its saved conversation. If no conversation is on disk, it runs its original prompt again.

Which id does claude respawn take?

The short 8-hex id from claude agents --json (also the folder name under ~/.claude/jobs/), not the sessionId UUID. For resumed sessions the two differ, so don't cut the UUID down to 8 characters.

Why doesn't /reload-plugins show my plugin's new theme in a background session?

/reload-plugins reloads plugins, skills, agents, hooks and MCP/LSP servers in the same process. On our machine a new plugin theme only appeared in the background session after claude respawn <id>.

Does /exit restart a background session?

No. In a background session /exit detaches and the session keeps running, unchanged. Use /stop to end it, or claude respawn <id> to restart it.

Does claude respawn --all restart the session I'm typing in?

Yes. It restarts every running session, including the current one. Run it from a plain shell, or respawn sessions one by one.

What does "Workspace not trusted. The home directory is trusted one session at a time" mean?

You tried to respawn a session rooted in your home directory. The message suggests starting it from an interactive terminal opened there, or from a project directory. Keeping long-lived sessions in a project directory avoids it.

Share this guide