Building a /reload Command for Claude Code

I often want to reload Claude Code mid-session to pick up changes to MCP servers, hooks, or other settings. The default workflow is a little clunky: I need to manually exit, then restart, then tell Claude that I restarted.

As a result, I wanted a /reload command that I could run to restart Claude and automatically continue the conversation. Also, by making it a command, Claude can actually invoke it itself when it detects a need to reload. This allows Claude to restart itself when needed without human intervention, so it can run more autonomously.

I figured this out when making (yet another) Google Drive MCP. I wanted to have Claude build it and automatically reload to test it.

Initial exploration

Since I was in Claude Code already, I worked on this with Claude. I figured we could find an approach that worked and then codify.

First attempt: Exit with a special code

Claude's initial idea was to have the skill exit Claude with some special exit code. Perhaps exit 42 to signal "please reload", and a wrapper script to listen for that code. This would work well since I already typically run Claude via short custom commands, so we could hook into that.

I asked about reasonable or semantic exit codes, and Claude suggested using 129 rather than an arbitrary code.

Exit code details Claude says: SIGHUP (signal 1) is the Unix convention for "reload configuration". Daemons like nginx and Apache reload their config on SIGHUP rather than terminating. And exit code 128+N is the shell convention for "terminated by signal N." So 129 would mean "reload requested" -- semantically correct and following established Unix patterns.

However, merely exiting from a Bash tool use doesn't work. Bash commands run in subprocesses, so exiting the subprocess with a special code just kills that subshell.

Second attempt: Find a built-in flag

We looked at Claude Code's docs and --help for a way to pass an exit code to /exit, but there's no /exit <code>, /reload, or /restart built-in.

Sending SIGHUP to the Claude process

Then I asked about the Bash command terminating the parent process, which would be Claude.

The key insight was that from within a bash command, $PPID would point to the Claude process. So then:

kill -HUP $PPID

sends SIGHUP (signal 1) to Claude, which causes it to exit with code 129 (128 + 1).

The Wrapper Function

The second part of this approach is to turn my short startup command into a Claude invocation that detects that special exit code and restarts.

Before I had:

alias CL="claude --dangerously-skip-permissions"

But we need to check for the special exit code and generally be a good Unix user (preserving exit codes, etc.):

function CL {
  local continue_flag=""               # Whether to continue or not
  local restart_msg=""                 # Don't send restart message the first invocation
  local rc
  while true; do                       # Loop forever
    claude \                           # Start Claude
      --dangerously-skip-permissions \ #  Don't ask for permission    >:D
      $continue_flag \                 #  Second invocation? Pass `-c` to continue last session
      "$@" \                           #  Pass along any original additional parameters
      $restart_msg                     #  On restarts, start Claude with a "restarted" message (see below)
    rc=$?                              # Store the Claude exit code
    [ $rc -eq 129 ] || return $rc      # If Claude exited with code 129, restart.
                                       # Otherwise, don't restart, and exit with the original exit code.
    echo "Reloading Claude Code..."    # Tell the human we're restarting
    sleep 0.5                          # Seems to somewhat improve restart likelihood?
    continue_flag="-c"                 # Restart the previously used session
    restart_msg="restarted"            # Send this message to Claude when the session resumes
  done
}

Sending the restart_msg message is quite helpful. Without it, Claude waits for user input after restart. So this allows it to continue working on whatever it was working on without needing user intervention. If you wanted to send a different message, I usually just hit esc to cancel the send when Claude starts up.

I have some other wrappers like:

  • CLC for running with --dangerously-skip-permissions and --continue
  • CLR for running with --dangerously-skip-permissions and --resume

Claude was easily able to modify those as well. Note you'll need to reload config or start a new session to pick up wrapper changes, especially if going from alias to function.

I had a little trouble getting the restart consistently working and added the short sleep, and while it might not be necessary, it seems like it improves the likelihood that the restart works.

The Skill

The /reload skill is then just a markdown file that tells Claude to run kill -HUP $PPID. Simple, but it took a few iterations to arrive at.

First versions

I had Claude write the skill based on our learnings about the $PPID.

The initial working version was something like this:

# Reload Claude Code (restart Claude)

Reload Claude Code to pick up configuration changes (MCP servers, hooks, settings).

## Steps

Send SIGHUP to the Claude process (which is $PPID from bash):

```bash
kill -HUP $PPID
```

The user will let you know when the reload is complete.

This had Claude read the instruction and then decide to run the Bash command. That works, but it meant that Claude had to decide to call the Bash tool. Occasionally it would add commentary, ask me to restart, write current status to file (it would be reloaded soon anyway), or ask for confirmation first. This makes it less likely the restart actually happens, and it also takes longer when it does work.

Final Iteration: ! Prefix in Skill / Command file

To try to get around the non-determinism, I wanted to see if there was a way to execute a command directly from the skill.

It turns out that Claude Code supports a ! prefix in skill files for immediate command execution. So then the command can run directly without the LLM processing it at all.

The final version of ~/.claude/commands/reload.md is simply:

# Reload Claude Code (restart Claude)

!`kill -HUP $PPID`

The ! makes it fire instantly: you type /reload, the signal sends, and Claude restarts. The whole thing takes about a second, and either you or Claude can initiate.

Wrap up

This exploration was fun and educational. It has been really useful in the last couple of days when adding skills and MCP servers.

Want to install it for yourself? Just point your Claude Code instance to this blog post and have it add the skill and shell wrapper!

« External Monitor Brightness Control on Mac