Truly persistent terminals in VSCode and Cursor

There are times when I am embarrassed to realize that I have accepted a painful limitation for years. In this case, it is my resistance to restarting my IDEs because I don’t want to lose my terminals. Now, thanks to a burst of motivation and a modern chatbot, I’m setup for my IDEs to resume exactly where they left off.

TL;DR: show me the code

VSCode / Cursor Config

{
    "terminal.integrated.profiles.osx": {
        "ide-persistent-shell": {
            "path": "/Users/yourusername/.local/bin/ide-persistent-shell"
        }
    },
    "terminal.integrated.defaultProfile.osx": "ide-persistent-shell",
    "terminal.integrated.env.osx": {
        "EDITOR_ID": "cursor"
    },
    "terminal.integrated.enablePersistentSessions": true
}

Main script


#!/bin/bash

# ~/.local/bin/ide-persistent-shell

# Get editor identifier from environment variable (defaults to 'vscode')
EDITOR_ID="${EDITOR_ID:-vscode}"
PROJECT_NAME=$(basename "$(pwd)")
SESSION_PREFIX="${EDITOR_ID}-${PROJECT_NAME}"
STATE_FILE="/tmp/tmux-${EDITOR_ID}-${PROJECT_NAME}-counter"

# Initialize counter file if it doesn't exist
if [ ! -f "$STATE_FILE" ]; then
    echo "0" > "$STATE_FILE"
fi

# Find existing sessions for this project and editor
existing_sessions=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^${SESSION_PREFIX}-" || true)

if [ -n "$existing_sessions" ]; then
    # Try to find an unattached session
    for session in $existing_sessions; do
        is_attached=$(tmux list-sessions -F "#{session_name}:#{session_attached}" 2>/dev/null | grep "^${session}:" | cut -d: -f2)
        if [ "$is_attached" = "0" ]; then
            echo "Reattaching to: $session"
            tmux attach -t "$session"
            exit 0
        fi
    done
fi

# No unattached sessions found, create new one
counter=$(cat "$STATE_FILE")
counter=$((counter + 1))
echo "$counter" > "$STATE_FILE"

new_session="${SESSION_PREFIX}-${counter}"
echo "Creating new session: $new_session"
tmux new -s "$new_session"

If you’re an old head working in the terminal, you probably that the tools for this job are screen and tmux. I used to use those regularly, but something about how my brain works makes me friction-avoidant. So I fell out of using those before I ever adopted VSCode, and I kind of never bothered to reintegrate them.

To make this whole thing automatic, I knew I’d have to do some scripting, and for me, there’s no bigger rabbit hole than having to do some scripting. I don’t do it enough to have the muscle memory, so I end up having to relearn the arcane flags and best practices every time. And then I’d also have to figure out how to configure my IDEs to use my script.

Enter Claude.

I described my problem, and less than 5 minutes, I had a working solution. You might note that I still needed a strong notion of what I was doing for it to be that easy. But I have found these LLM tools to be incredibly good engines for transforming intention + background knowledge + written communication into solutions.

Now, I just need a local(ish) terminal that can survive reboots 😉

Leave a comment