Source profileQuality 92/100

laurigates/claude-plugins/macos-plugin/skills/kitty-session-persistence/SKILL.md

kitty-session-persistence

Snapshot and restore kitty terminal sessions on macOS. Use when surviving WindowServer hangs without losing tabs, configuring snapshots, or restoring after a force-reboot.

Source repository stars
54
Declared platforms
0
Static risk flags
1
Last source update
2026-08-28
Source checked
2026-08-28

Decision brief

What it does: where it fits

Snapshot and restore kitty terminal sessions on macOS.

Best for

  • Use when surviving WindowServer hangs without losing tabs, configuring snapshots, or restoring after a force-reboot.

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/laurigates/claude-plugins --skill "macos-plugin/skills/kitty-session-persistence"
Safe inspection promptEditorial

Inspect the Agent Skill "kitty-session-persistence" from https://github.com/laurigates/claude-plugins/blob/c056e44b978db58648ad20440dc1515cb09af09d/macos-plugin/skills/kitty-session-persistence/SKILL.md at commit c056e44b978db58648ad20440dc1515cb09af09d. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    Setup

    Add to /.config/kitty/kitty.conf:

    Add to /.config/kitty/kitty.conf:Using {kittypid} makes each kitty instance addressable on its own socket. For the persistent-socket pattern this skill needs, use the user-stable form instead:Replace USER with the actual username. The snapshot LaunchAgent points at this exact path.
  2. 02

    When to Use This Skill

    Review the “When to Use This Skill” section in the pinned source before continuing.

    Review and apply the “When to Use This Skill” source section.
  3. 03

    Platform Guard

    This skill is macOS-only. All commands assume Darwin and launchctl-managed LaunchAgents. Refuse to act if uname -s is not Darwin.

    This skill is macOS-only. All commands assume Darwin and launchctl-managed LaunchAgents. Refuse to act if uname -s is not Darwin.
  4. 04

    Core Expertise

    Kitty exposes a remote control protocol via a Unix socket. With listenon configured, kitten @ ls returns a JSON description of every OS window, tab, and window inside kitty — enough to reconstruct the layout from scratch.

    Always-listen socket — listenon unix:/tmp/kitty-$USER in kitty.conf so the snapshot script can always reach the running instance.Snapshot script — captures kitten @ ls output to a timestamped JSON file under /.local/state/kitty-sessions/, with a latest.json symlink.LaunchAgent — runs the snapshot script every 5 minutes (default) so the worst-case loss is one window of work.
  5. 05

    Architectural notes

    Kitty's remote control requires allowremotecontrol yes in kitty.conf or --allow-remote-control yes at launch.

    Kitty's remote control requires allowremotecontrol yes in kitty.conf or --allow-remote-control yes at launch.The socket path must match between listenon and the kitten @ --to flag the snapshot script uses.LaunchAgent StandardOutPath and StandardErrorPath are essential — failing snapshots are otherwise silent.

Permission review

Static risk signals and limitations

Network access

medium · line 102

The documentation includes network, browsing, or remote request actions.

"http://www.apple.com/DTDs/PropertyList-1.0.dtd">

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score92/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars54SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
laurigates/claude-plugins
Skill path
macos-plugin/skills/kitty-session-persistence/SKILL.md
Commit
c056e44b978db58648ad20440dc1515cb09af09d
License
MIT
Collected
2026-08-28
Default branch
main
View the original SKILL.md

Kitty Session Persistence (macOS)

When to Use This Skill

Use this skill when...Use something else when...
Terminal sessions need to survive WindowServer hangs and force-rebootsThe user's terminal is iTerm2 / Terminal.app / Ghostty / Wezterm — kitty-specific
Configuring kitty's listen_on socket and a snapshot LaunchAgentCross-platform terminal config — this is macOS LaunchAgents
Restoring a previous session after a crashOne-off "open these tabs" — kitty @ launch directly is enough
Auditing whether snapshot capture is still runningGeneral system diagnostics — see macos-incident-postmortem

Platform Guard

This skill is macOS-only. All commands assume Darwin and launchctl-managed LaunchAgents. Refuse to act if uname -s is not Darwin.

test "$(uname -s)" = "Darwin" || { echo "macos-plugin: not Darwin, refusing"; exit 1; }

Core Expertise

Kitty exposes a remote control protocol via a Unix socket. With listen_on configured, kitten @ ls returns a JSON description of every OS window, tab, and window inside kitty — enough to reconstruct the layout from scratch.

The pattern this skill installs:

  1. Always-listen socketlisten_on unix:/tmp/kitty-$USER in kitty.conf so the snapshot script can always reach the running instance.
  2. Snapshot script — captures kitten @ ls output to a timestamped JSON file under ~/.local/state/kitty-sessions/, with a latest.json symlink.
  3. LaunchAgent — runs the snapshot script every 5 minutes (default) so the worst-case loss is one window of work.
  4. Restore command — reads latest.json and re-launches tabs with the recorded cwd and command.

Architectural notes

  • Kitty's remote control requires allow_remote_control yes in kitty.conf or --allow-remote-control yes at launch.
  • The socket path must match between listen_on and the kitten @ --to flag the snapshot script uses.
  • LaunchAgent StandardOutPath and StandardErrorPath are essential — failing snapshots are otherwise silent.
  • Use RunAtLoad: false and rely on StartInterval so a kitty restart doesn't spawn a backlog of immediate snapshots.

Setup

1. Configure kitty

Add to ~/.config/kitty/kitty.conf:

allow_remote_control yes
listen_on unix:/tmp/kitty-{kitty_pid}

Using {kitty_pid} makes each kitty instance addressable on its own socket. For the persistent-socket pattern this skill needs, use the user-stable form instead:

allow_remote_control yes
listen_on unix:/tmp/kitty-USER

Replace USER with the actual username. The snapshot LaunchAgent points at this exact path.

Reload kitty after editing:

kitty @ --to unix:/tmp/kitty-USER load-config

2. Install the snapshot script

Create ~/.local/bin/kitty-snapshot (mode 0755):

#!/usr/bin/env bash
set -uo pipefail

[ "$(uname -s)" = "Darwin" ] || exit 0

SOCKET="unix:/tmp/kitty-${USER}"
STATE_DIR="${HOME}/.local/state/kitty-sessions"
mkdir -p "$STATE_DIR"

ts="$(date -u +%Y%m%dT%H%M%SZ)"
out="${STATE_DIR}/${ts}.json"

if ! kitten @ --to "$SOCKET" ls >"$out" 2>>"${STATE_DIR}/snapshot.err"; then
  rm -f "$out"
  exit 0   # kitty not running — silent success
fi

ln -sfn "$out" "${STATE_DIR}/latest.json"

# Keep ~7 days of 5-min snapshots = 2016 files; cap at 4032 (14 days)
ls -1t "$STATE_DIR"/*.json 2>/dev/null | tail -n +4033 | xargs -r rm -f

The exit 0 on kitten @ ls failure is intentional — the LaunchAgent fires every 5 minutes regardless of whether kitty is running.

3. Install the LaunchAgent

Write ~/Library/LaunchAgents/com.<reverse-dns>.kitty-snapshot.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.example.kitty-snapshot</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/USER/.local/bin/kitty-snapshot</string>
  </array>
  <key>StartInterval</key>
  <integer>300</integer>
  <key>RunAtLoad</key>
  <false/>
  <key>StandardOutPath</key>
  <string>/Users/USER/.local/state/kitty-sessions/launchd.out</string>
  <key>StandardErrorPath</key>
  <string>/Users/USER/.local/state/kitty-sessions/launchd.err</string>
</dict>
</plist>

Replace com.example with a stable reverse-DNS prefix and USER with the literal username (LaunchAgents do not expand $HOME).

Validate, load, and verify:

plutil -lint ~/Library/LaunchAgents/com.example.kitty-snapshot.plist
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.example.kitty-snapshot.plist
launchctl print "gui/$(id -u)/com.example.kitty-snapshot" | grep -E 'state|last exit'

bootstrap replaces the deprecated launchctl load; on macOS 11+ prefer it.

4. Confirm capture is working

After ~5 minutes:

ls -lt ~/.local/state/kitty-sessions/*.json | head -3

There should be JSON files newer than the LaunchAgent install time. The newest file's content should match what kitty has open right now.

Restore

Read latest.json and re-launch each window/tab. A minimal restore script:

#!/usr/bin/env bash
set -euo pipefail

[ "$(uname -s)" = "Darwin" ] || exit 1

LATEST="${HOME}/.local/state/kitty-sessions/latest.json"
SOCKET="unix:/tmp/kitty-${USER}"

[ -L "$LATEST" ] || { echo "no snapshot found"; exit 1; }

jq -c '.[] | .tabs[] | .windows[] | {cwd, foreground_processes}' "$LATEST" |
while IFS= read -r win; do
  cwd=$(printf '%s' "$win" | jq -r '.cwd')
  cmd=$(printf '%s' "$win" | jq -r '.foreground_processes[0].cmdline | join(" ")')
  kitten @ --to "$SOCKET" launch --type=tab --cwd="$cwd" "$cmd"
done

The shape of kitten @ ls output is [{tabs:[{windows:[{cwd, foreground_processes:[{cmdline}]}]}]}]. Adjust the jq query if a future kitty release changes it.

Common Patterns

Audit recent snapshots

ls -1t ~/.local/state/kitty-sessions/*.json | head -10
jq '. | length, [.[].tabs | length] | add' ~/.local/state/kitty-sessions/latest.json
# → window count, tab count

Confirm LaunchAgent is healthy

launchctl print "gui/$(id -u)/com.example.kitty-snapshot" | \
  grep -E 'state|last exit|on demand'

state = running (briefly, every 5 minutes) and last exit code = 0 indicate health. Persistent non-zero exit means something is broken — check launchd.err.

Disable / unload temporarily

launchctl bootout "gui/$(id -u)/com.example.kitty-snapshot"

bootout is the modern equivalent of launchctl unload.

Snapshot interval tuning

IntervalWhen to use
60s (StartInterval=60)Heavy editing days — minimum loss-on-crash
300s (default)Balanced — typical workflow
900s (15 min)Stable, low-edit days — less noise in ls -lt

Reload after editing the plist:

launchctl bootout "gui/$(id -u)/com.example.kitty-snapshot"
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.example.kitty-snapshot.plist

Agentic Optimizations

ContextCommand
Snapshot count last hourfind ~/.local/state/kitty-sessions -name '*.json' -newermt '1 hour ago' | wc -l
Most recent snapshot agestat -f '%Sm %N' ~/.local/state/kitty-sessions/latest.json
Validate a plistplutil -lint ~/Library/LaunchAgents/com.example.kitty-snapshot.plist
Last exit codelaunchctl print "gui/$(id -u)/com.example.kitty-snapshot" | awk '/last exit code/{print $NF}'
Live socket reachablekitten @ --to unix:/tmp/kitty-$USER ls | jq '. | length'

Quick Reference

LaunchAgent commands (macOS 11+)

OperationCommand
Load (modern)launchctl bootstrap "gui/$(id -u)" <plist>
Unload (modern)launchctl bootout "gui/$(id -u)/<label>"
Inspectlaunchctl print "gui/$(id -u)/<label>"
Run nowlaunchctl kickstart -k "gui/$(id -u)/<label>"
List user agentslaunchctl print-disabled "gui/$(id -u)"

Kitty remote control

OperationCommand
List sessionskitten @ --to <socket> ls
Launch tabkitten @ --to <socket> launch --type=tab --cwd=<path> <cmd>
Reload configkitten @ --to <socket> load-config
Send textkitten @ --to <socket> send-text --match "title:foo" "ls\n"

Snapshot file structure

~/.local/state/kitty-sessions/
├── 20260503T120000Z.json
├── 20260503T120500Z.json
├── ...
├── latest.json -> 20260503T143000Z.json
├── snapshot.err
├── launchd.out
└── launchd.err

Error Handling

SymptomCauseFix
kitten @ ls fails with "remote control not allowed"allow_remote_control no in kitty.confSet to yes, reload config
LaunchAgent loads but last exit code = 78Script not executablechmod +x ~/.local/bin/kitty-snapshot
LaunchAgent loads but never firesStartInterval missing or zeroSet to a positive integer (seconds)
All snapshots empty []No kitty windows running, or wrong socket pathCheck listen_on path matches --to
bootstrap fails with "already loaded"Old load form still activelaunchctl bootout first, then bootstrap
Restore opens windows with wrong shellcmdline[0] is the shell, not the user commandUse cwd only and let the user re-run

Frequently asked questions

What to verify before installation and use

What does the kitty-session-persistence source document cover?

Snapshot and restore kitty terminal sessions on macOS.

How do I install kitty-session-persistence?

The source record exposes this install command: npx skills add https://github.com/laurigates/claude-plugins --skill "macos-plugin/skills/kitty-session-persistence". Inspect the command and pinned source before running it.

Which permission-related actions were detected?

Static rules flagged network in the source; the page lists the matching lines and excerpts.