The /spawn skill in Claude Code opens a new terminal window with a fresh Claude session pre-loaded with context from the current one. It works by writing a context brief to /tmp/spawn-brief.md and a launcher script to /tmp/spawn-launch.sh, then using AppleScript to open a new iTerm2 window that runs the launcher. The file-based approach avoids the bash quoting problems that break when trying to pass context inline through nested AppleScript and shell commands.
There’s a moment that happens constantly when you’re deep in Claude Code: you’re working on one project and you realize the thing you just built or learned belongs somewhere else entirely. Maybe you solved a problem in a client project that your personal project also has. Maybe you want to start a fresh conversation but seed it with everything the current one knows.
The usual answer is: copy-paste your notes into a new terminal window and start over. That works. It also sucks.
Here’s how to make Claude do it for you.
What a Claude Code session actually is
Claude Code is a terminal-based AI coding assistant. When you type claude in your terminal and start chatting, that’s a session. A session has its own context window, meaning Claude can only “see” and remember the conversation happening inside it. When you close the terminal or start a new claude instance, you get a blank slate. Anything you learned or built in the previous session doesn’t automatically carry over.
This is fine for focused work. It becomes annoying when you want to branch a conversation, hand off what you’ve learned, or spin up a parallel thread on a different project.
The idea: a /spawn command
A command (also called a skill) in Claude Code is a custom instruction file that Claude loads when you reference it. You define them in your .claude/skills/ folder. When you type /spawn, Claude reads those instructions and executes whatever workflow you set up.
The goal of /spawn is this: take what we know right now, write it down, open a new terminal window, and start a fresh Claude session inside it with that context already loaded.
Simple in theory. The first attempt was a mess.
v1: bash quoting nightmare
The obvious approach was to have Claude run a shell command that opened a new terminal and passed the context directly as a command-line argument. Something like:
osascript -e 'tell application "iTerm2" to create window with default profile command "claude --context \"here is everything you need to know: ...\""'
iTerm2 is a popular terminal emulator for Mac. AppleScript is a Mac scripting language that lets you control apps like iTerm2 programmatically. osascript is the command-line tool for running AppleScript.
The problem: the context brief had quotes in it. So you needed to escape the quotes. But the AppleScript string also had quotes. And the shell command wrapping all of it had quotes. You end up with something like:
osascript -e 'tell application "iTerm2" to create window with default profile command "claude --resume abc123 --fork-session --context \"learned: use \\\"double quotes\\\" carefully\""'
Four levels of quoting. The command never parsed correctly. It would error out, or worse, it would run but silently fail, or (this actually happened) it would kill the current session instead of opening a new one alongside it.
The --fork-session flag was supposed to clone the current session. But the session ID it was passing didn’t exist in the new context. It was an ID from the current process that the new process had no way to resolve.
After enough time watching this break in creative new ways, the fix became obvious.
The fix: write a file first
When you can’t pass complex data between processes inline, write it to a file. This is a very old idea in Unix. It’s obvious in hindsight.
/tmp is a temporary directory on your computer. On Mac and Linux, it’s at /tmp/ and it gets cleared on restart. It’s a good place to put short-lived data that one process writes and another reads, because it doesn’t require knowing where your project lives or setting up anything.
The spawn skill now does three things:
- Writes a context brief to
/tmp/spawn-brief.md - Writes a tiny launcher shell script to
/tmp/spawn-launch.sh - Runs AppleScript to open a new iTerm2 window that executes the launcher
The launcher script just does one thing: cd to the right directory and run claude with a startup message that points at the context brief.
Here’s what the skill’s instructions tell Claude to do:
## /spawn
Generate a context handoff and open a new Claude session with it.
1. Write a context brief to /tmp/spawn-brief.md. Include:
- What we were working on
- What was decided or built
- What directory to work in
- Any relevant file paths
- What the new session should do first
2. Write a launcher to /tmp/spawn-launch.sh:
cd /path/to/working/directory && claude
3. Make it executable and open it in a new iTerm2 window:
chmod +x /tmp/spawn-launch.sh
osascript -e 'tell application "iTerm2"
activate
set newWindow to (create window with default profile)
tell current session of newWindow
write text "bash /tmp/spawn-launch.sh"
end tell
end tell'
4. Tell the user that the new session will start with the context from /tmp/spawn-brief.md
When Claude runs this, it generates the brief from the actual conversation, no manual copy-pasting. The new window opens, the launcher runs, and when Claude starts in the new session, you can immediately say “read /tmp/spawn-brief.md and pick up from there.”
Why this works when the inline approach didn’t
The quoting problem disappears. The context brief is just a file. Claude writes it with normal file operations, no shell escaping required. The AppleScript command is short, predictable, and doesn’t include any user-generated text. It just runs a script from a known path.
The file is the interface. This is the pattern: whenever you need to pass something complicated between two processes, don’t try to inline it. Write it to a file with one process and read it with the other.
The /handoff connection
If you’ve already set up a /handoff skill, you know it generates notes about what you were doing so you can pick up later. /spawn is the action version of that. Handoff writes notes for you to read. Spawn writes notes for a new Claude to read, then actually opens the new session.
You can wire them together if you want: have /spawn call your handoff workflow as part of step 1, then use that output as the context brief. Same content, different destination.
Setting this up yourself
If you don’t have a .claude/skills/ directory yet, create one:
mkdir -p ~/.claude/skills/spawn
A skill is just a folder with a SKILL.md file inside. The file contains the instructions Claude reads when you call the skill. How to Make a Claude Code Skill covers the full process.
touch ~/.claude/skills/spawn/SKILL.md
Then paste the skill instructions from above into SKILL.md. After that, you can type /spawn in any Claude Code session and it will generate the handoff brief and open the new window.
If you’re running a lot of parallel sessions, tmux is a better approach than managing individual terminal windows.
If you’re on a Mac but don’t use iTerm2, the AppleScript will need to be adjusted for whatever terminal you use. Terminal.app has a different AppleScript API. If you’re on Linux, you’d use a different approach to open a new terminal window (something like gnome-terminal -- or xterm -e), or skip the auto-open entirely and just have Claude write the brief to /tmp/spawn-brief.md for you to load manually.
The meta point
This is the thing that makes Claude Code different from a chat interface. When something is annoying enough to do manually, you can just build the fix inside the same tool you’re working in. The session where you ask “what’s the best way to hand off context between sessions?” is the same session where you build the command that does it.
The feedback loop is tight. Annoyance, question, build, done. You end up with tooling that fits exactly how you work because you made it while you were doing the work.
Further reading
- Claude Code documentation for an overview of how Claude Code works and what’s configurable
- skills.sh for a community catalog of pre-built Claude Code skills you can install instead of building from scratch
- CLAUDE.md guide for how Claude loads memory and instructions across sessions
- AppleScript for iTerm2 if you want to extend or customize how the new window opens
Common Questions
How do I start a new Claude Code session with context from the current one?
Build a /spawn skill that writes a context brief to /tmp/spawn-brief.md, creates a launcher script, and opens a new iTerm2 window. In the new session, say “read /tmp/spawn-brief.md and pick up from there.” Claude generates the brief from the current conversation automatically.
Why does passing context inline to a new terminal fail?
The context contains quotes that conflict with AppleScript quotes and shell quotes, creating four levels of escaping. The command either errors out, silently fails, or kills the current session. Writing context to a file eliminates the quoting problem entirely.
What is the /tmp directory?
/tmp is a temporary directory on Mac and Linux that gets cleared on restart. It is a standard location for short-lived data that one process writes and another reads. No setup is needed, and it doesn’t require knowing your project directory structure.
What is the difference between /spawn and /handoff?
/handoff writes notes for you to read later and resume manually. /spawn writes notes for a new Claude to read and then opens the new session automatically. Spawn is the action version of handoff. They can be wired together.
A note from Alex: hi i’m alex - i run code for creatives. i’m a writer so i feel that it is important to say - i had claude write this piece based on my ideas and ramblings, voice notes, and teachings. the concepts were mine but the words themselves aren’t. i want to say that because its important for me to distinguish, as a writer, what is written ‘by me’ and what’s not. maybe that idea will seem insane and antiquated in a year, i’m not sure, but for now it helps me feel okay about putting stuff out there like this that a) i know is helpful and b) is not MY voice but exists within the umbrella of my business and work. If you have any thoughts or musings on this, i’d genuinely love to hear them - its an open question, all of this stuff, and my guess is as good as yours.