[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C5AVSC1F26XCVE9NZBB54A":3,"skill-same:01M6C5AVSC1F26XCVE9NZBB54A":85},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":6,"ownerHtmlUrl":62,"ownerBlogUrl":6,"ownerDescription":63,"updatedAt":64,"install":65,"resources":78},"01M6C5AVSC1F26XCVE9NZBB54A","agent-cli-worktree-safety",null,"Data-loss invariants for a CLI that runs an agent SDK in a git worktree then force-removes it. Use when building or reviewing such a CLI, or when an agent run reports \"no changes\" after writing files.","laurigates\u002Fclaude-plugins","laurigates","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F13014001?v=4","01M6C59YHWS9C7KMXKSRX1YXNP","Lauri Gates","01M6C59YP2APG9YAM4DWYQYGFJ",60,"MIT","https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fagent-patterns-plugin\u002Fskills\u002Fagent-cli-worktree-safety\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"cli","agent cli","worktree","Safety","agent cli worktree safety","2026","writing","when","invariants","files","reports","use","edit","write","read","grep","git worktree","Bash","data","git","code","run","sdk","2026-11-10 10:12:30",false,"---\ncreated: 2026-09-02\nmodified: 2026-10-02\nreviewed: 2026-09-02\nname: agent-cli-worktree-safety\ndescription: Data-loss invariants for a CLI that runs an agent SDK in a git worktree then force-removes it. Use when building or reviewing such a CLI, or when an agent run reports \"no changes\" after writing files.\nallowed-tools: Glob, Grep, Read, Edit, Write, Bash\nmodel: opus\ncompatibility: claude-code\n---\n\n# Agent-CLI Worktree Safety\n\nData-loss prevention for CLIs that create a git worktree, run an LLM\norchestrator (`claude-agent-sdk` or similar) that writes files there, and then\nclean up with `git worktree remove --force`.\n\n## When to Use This Skill\n\n| Use this skill when... | Use something else when... |\n|------------------------|----------------------------|\n| Building or reviewing a CLI that runs an agent SDK in a worktree it later removes | Isolating a Claude Code subagent with `isolation: \"worktree\"` → `.claude\u002Frules\u002Fagent-runtime.md` § Worktree Isolation |\n| An agent run wrote files but reported \"No changes were made\" | Pruning other sessions' worktrees → `.claude\u002Frules\u002Fagent-coworker-detection.md` § Cleanup |\n| Wiring the SDK's two-phase or `create_worktree` flow → [REFERENCE.md](REFERENCE.md) | Coordinating parallel agents → `agent-patterns-plugin:agent-teams` |\n\n## The core failure mode\n\nThree independent mistakes compound into silent data loss:\n\n1. **Driver phases write but never commit** — \"the outer orchestrator handles git state\".\n2. **The outer orchestrator ends without committing** — it stalls on an interactive tool call that cannot render (see *Interactive tools in SDK subprocess mode* below), or simply finishes.\n3. **The \"has changes\" check only counts commits** (`git log base..HEAD`), so it reports nothing to preserve — and cleanup force-removes the worktree.\n\nNet result: many files are written, the user is told **\"No changes were made\"**,\nand the work is destroyed. No error, no traceback. That user-visible message is\nthe diagnostic tell — if a run wrote files and reported no changes, check\ninvariant 1 before anything else.\n\n## Required invariants\n\n### 1. \"Has changes\" means commits OR a dirty tree\n\nAny function deciding whether a worktree is worth preserving must return true\nwhen the working tree is dirty, even with no commits beyond base:\n\n```python\ndef worktree_has_changes(worktree_path, base_branch):\n    commits = subprocess.run(\n        [\"git\", \"log\", \"--oneline\", f\"{base_branch}..HEAD\"],\n        cwd=worktree_path, capture_output=True, text=True,\n    )\n    if commits.stdout.strip():\n        return True\n    dirty = subprocess.run(\n        [\"git\", \"status\", \"--porcelain\"],\n        cwd=worktree_path, capture_output=True, text=True,\n    )\n    return bool(dirty.stdout.strip())\n```\n\nA commits-only check is a data-loss bug. `--porcelain` (not `git diff`) is\nload-bearing: a brand-new file the agent created is **untracked**, and\n`git diff` cannot see it.\n\nIf uncommitted files matter for the next operation — push, PR, cleanup — they\nmatter for this check.\n\n### 2. Safety-net commit before any destructive cleanup\n\nIf the agent phase was supposed to commit and didn't, capture the work anyway:\n\n```python\ndef auto_commit_if_dirty(worktree_path, message):\n    status = subprocess.run(\n        [\"git\", \"status\", \"--porcelain\"],\n        cwd=worktree_path, capture_output=True, text=True, check=True,\n    )\n    if not status.stdout.strip():\n        return False\n    subprocess.run([\"git\", \"add\", \"-A\"], cwd=worktree_path, check=True)\n    subprocess.run(\n        [\"git\", \"commit\", \"-m\", message],\n        cwd=worktree_path, check=True, capture_output=True, text=True,\n    )\n    return True\n```\n\nCall it from every post-run path — interactive and non-interactive — with a\nmessage naming the workflow, and print a warning so the user learns the safety\nnet fired. A silent safety net hides the bug it is compensating for.\n\n### 3. Pre-validate before git touches the path\n\nTyper's `exists=True, dir_okay=True` is not enough. Call explicit guards at the\ntop of every command that will later run `git rev-parse`, `git worktree add`,\nor a domain operation:\n\n```python\ndef _ensure_git_repo(path):\n    inside = subprocess.run(\n        [\"git\", \"rev-parse\", \"--is-inside-work-tree\"],\n        cwd=path, capture_output=True, text=True,\n    )\n    if inside.returncode != 0 or inside.stdout.strip() != \"true\":\n        raise typer.Exit(code=EXIT_CONFIG_ERROR)\n    head = subprocess.run(\n        [\"git\", \"rev-parse\", \"--verify\", \"HEAD\"],\n        cwd=path, capture_output=True, text=True,\n    )\n    if head.returncode != 0:  # unborn HEAD — no commits yet\n        raise typer.Exit(code=EXIT_CONFIG_ERROR)\n```\n\n**Unborn HEAD is its own failure class.** A fresh `git init` with no commits\npasses `--is-inside-work-tree` but fails every downstream `rev-parse HEAD` and\n`worktree add -b \u003Cbr> \u003Cpath> HEAD`. Check both, always.\n\nAdd a domain check beside it — an Obsidian vault wants `.obsidian\u002F` or any\n`*.md`; a code repo wants a language marker — so \"pointed at the wrong\ndirectory\" is a friendly config error, not a `CalledProcessError` traceback.\n\n### 4. Branch-name collisions are not free\n\nTimestamp branch names (`%Y-%m-%dT%H-%M`) collide when two runs start in the\nsame minute. If `create_worktree` force-removes a pre-existing worktree at the\ntarget path, the second run destroys the first run's uncommitted agent output.\n\nEither use second granularity plus a short random suffix, or refuse:\n\n```python\nif worktree_path.exists():\n    dirty = subprocess.run(\n        [\"git\", \"status\", \"--porcelain\"],\n        cwd=worktree_path, capture_output=True, text=True,\n    )\n    if dirty.returncode == 0 and dirty.stdout.strip():\n        raise RuntimeError(\n            f\"Refusing to overwrite worktree at {worktree_path}: has \"\n            f\"uncommitted changes from a concurrent or prior run.\"\n        )\n```\n\nAn advisory lock that only guards `--non-interactive` runs does not cover\ninteractive or concurrent invocations. Those need the in-tree probe.\n\n## Interactive tools in SDK subprocess mode\n\nWhen the SDK runs the CLI as a subprocess, stdin\u002Fstdout carry the SDK's JSON\nprotocol. An interactive tool call such as `AskUserQuestion` has no terminal to\nreach: the call fires, nothing renders, and the model wraps up as if the user\ndeclined. This is failure mode 2 above, and it is silent.\n\n- **Do not rely on mid-pipeline interactive tool calls** in any driver flow.\n- Use a two-phase pattern instead: the agent emits findings and stops → the host collects input (`console.input()`) → a second `client.query()` executes the selection.\n- Remove the interactive tool from `allowed_tools` on paths that must not fail silently, so the attempt is an error rather than a shrug.\n\nWorked example: [git-repo-agent ADR-003](https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fgit-repo-agent\u002Fblob\u002Fmain\u002Fdocs\u002Fadr\u002F003-switch-to-claude-sdk-client-for-interactive-workflows.md).\n\nThe `query()` vs `ClaudeSDKClient` split, the full two-phase snippet, and\ncreating the worktree in Python (`ClaudeAgentOptions` has no `isolation`\nparameter) are in [REFERENCE.md](REFERENCE.md).\n\n## Required tests\n\n| Test | Verifies |\n|------|----------|\n| `test_worktree_has_changes_detects_untracked` | Dirty-tree detection covers \"wrote files, never committed\" |\n| `test_auto_commit_if_dirty` | The safety net captures uncommitted state and leaves the tree clean |\n| `test_create_worktree_refuses_to_overwrite_dirty` | Collision protection for same-minute runs |\n| `test_cli_rejects_non_git_target` | Friendly config error, not a traceback |\n| `test_cli_rejects_empty_git_repo` | Unborn-HEAD detection |\n| `test_cli_rejects_non_domain_target` | Catches \"pointed at the wrong directory\" |\n\nReference layouts: [`git-repo-agent\u002Ftests\u002Ftest_worktree_changes.py`](https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fgit-repo-agent\u002Fblob\u002Fmain\u002Ftests\u002Ftest_worktree_changes.py) and [`vault-agent\u002Ftests\u002Ftest_worktree.py`](https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fvault-agent\u002Fblob\u002Fmain\u002Ftests\u002Ftest_worktree.py) (`TestWorktreeCollisionSafety`).\n\n## Checklist when adding a new agent CLI\n\n- [ ] `_ensure_git_repo()` + a domain guard at the top of every write command\n- [ ] \"Has changes\" covers uncommitted **and** untracked state\n- [ ] Safety-net commit runs before any `cleanup_worktree(--force)` or push\n- [ ] `create_worktree` refuses to force-remove a dirty pre-existing worktree\n- [ ] A regression test for each of the six rows above\n- [ ] Interactive flows use the two-phase pattern, not a mid-session interactive tool call\n\n## Related\n\n- `python-plugin:typer-cli-completion` — sibling convention for the same family of Typer CLIs\n- `agent-patterns-plugin:parallel-agent-dispatch` — the orchestrator-side contract for worktree-isolated agents\n- `git-plugin:git-coworker-check` — detecting a peer agent in a shared checkout before destructive git ops\n","# Agent-CLI Worktree Safety\n\nData-loss prevention for CLIs that create a git worktree, run an LLM\norchestrator (`claude-agent-sdk` or similar) that writes files there, and then\nclean up with `git worktree remove --force`.\n\n## When to Use This Skill\n\n| Use this skill when... | Use something else when... |\n|------------------------|----------------------------|\n| Building or reviewing a CLI that runs an agent SDK in a worktree it later removes | Isolating a Claude Code subagent with `isolation: \"worktree\"` → `.claude\u002Frules\u002Fagent-runtime.md` § Worktree Isolation |\n| An agent run wrote files but reported \"No changes were made\" | Pruning other sessions' worktrees → `.claude\u002Frules\u002Fagent-coworker-detection.md` § Cleanup |\n| Wiring the SDK's two-phase or `create_worktree` flow → [REFERENCE.md](REFERENCE.md) | Coordinating parallel agents → `agent-patterns-plugin:agent-teams` |\n\n## The core failure mode\n\nThree independent mistakes compound into silent data loss:\n\n1. **Driver phases write but never commit** — \"the outer orchestrator handles git state\".\n2. **The outer orchestrator ends without committing** — it stalls on an interactive tool call that cannot render (see *Interactive tools in SDK subprocess mode* below), or simply finishes.\n3. **The \"has changes\" check only counts commits** (`git log base..HEAD`), so it reports nothing to preserve — and cleanup force-removes the worktree.\n\nNet result: many files are written, the user is told **\"No changes were made\"**,\nand the work is destroyed. No error, no traceback. That user-visible message is\nthe diagnostic tell — if a run wrote files and reported no changes, check\ninvariant 1 before anything else.\n\n## Required invariants\n\n### 1. \"Has changes\" means commits OR a dirty tree\n\nAny function deciding whether a worktree is worth preserving must return true\nwhen the working tree is dirty, even with no commits beyond base:\n\n```python\ndef worktree_has_changes(worktree_path, base_branch):\n    commits = subprocess.run(\n        [\"git\", \"log\", \"--oneline\", f\"{base_branch}..HEAD\"],\n        cwd=worktree_path, capture_output=True, text=True,\n    )\n    if commits.stdout.strip():\n        return True\n    dirty = subprocess.run(\n        [\"git\", \"status\", \"--porcelain\"],\n        cwd=worktree_path, capture_output=True, text=True,\n    )\n    return bool(dirty.stdout.strip())\n```\n\nA commits-only check is a data-loss bug. `--porcelain` (not `git diff`) is\nload-bearing: a brand-new file the agent created is **untracked**, and\n`git diff` cannot see it.\n\nIf uncommitted files matter for the next operation — push, PR, cleanup — they\nmatter for this check.\n\n### 2. Safety-net commit before any destructive cleanup\n\nIf the agent phase was supposed to commit and didn't, capture the work anyway:\n\n```python\ndef auto_commit_if_dirty(worktree_path, message):\n    status = subprocess.run(\n        [\"git\", \"status\", \"--porcelain\"],\n        cwd=worktree_path, capture_output=True, text=True, check=True,\n    )\n    if not status.stdout.strip():\n        return False\n    subprocess.run([\"git\", \"add\", \"-A\"], cwd=worktree_path, check=True)\n    subprocess.run(\n        [\"git\", \"commit\", \"-m\", message],\n        cwd=worktree_path, check=True, capture_output=True, text=True,\n    )\n    return True\n```\n\nCall it from every post-run path — interactive and non-interactive — with a\nmessage naming the workflow, and print a warning so the user learns the safety\nnet fired. A silent safety net hides the bug it is compensating for.\n\n### 3. Pre-validate before git touches the path\n\nTyper's `exists=True, dir_okay=True` is not enough. Call explicit guards at the\ntop of every command that will later run `git rev-parse`, `git worktree add`,\nor a domain operation:\n\n```python\ndef _ensure_git_repo(path):\n    inside = subprocess.run(\n        [\"git\", \"rev-parse\", \"--is-inside-work-tree\"],\n        cwd=path, capture_output=True, text=True,\n    )\n    if inside.returncode != 0 or inside.stdout.strip() != \"true\":\n        raise typer.Exit(code=EXIT_CONFIG_ERROR)\n    head = subprocess.run(\n        [\"git\", \"rev-parse\", \"--verify\", \"HEAD\"],\n        cwd=path, capture_output=True, text=True,\n    )\n    if head.returncode != 0:  # unborn HEAD — no commits yet\n        raise typer.Exit(code=EXIT_CONFIG_ERROR)\n```\n\n**Unborn HEAD is its own failure class.** A fresh `git init` with no commits\npasses `--is-inside-work-tree` but fails every downstream `rev-parse HEAD` and\n`worktree add -b \u003Cbr> \u003Cpath> HEAD`. Check both, always.\n\nAdd a domain check beside it — an Obsidian vault wants `.obsidian\u002F` or any\n`*.md`; a code repo wants a language marker — so \"pointed at the wrong\ndirectory\" is a friendly config error, not a `CalledProcessError` traceback.\n\n### 4. Branch-name collisions are not free\n\nTimestamp branch names (`%Y-%m-%dT%H-%M`) collide when two runs start in the\nsame minute. If `create_worktree` force-removes a pre-existing worktree at the\ntarget path, the second run destroys the first run's uncommitted agent output.\n\nEither use second granularity plus a short random suffix, or refuse:\n\n```python\nif worktree_path.exists():\n    dirty = subprocess.run(\n        [\"git\", \"status\", \"--porcelain\"],\n        cwd=worktree_path, capture_output=True, text=True,\n    )\n    if dirty.returncode == 0 and dirty.stdout.strip():\n        raise RuntimeError(\n            f\"Refusing to overwrite worktree at {worktree_path}: has \"\n            f\"uncommitted changes from a concurrent or prior run.\"\n        )\n```\n\nAn advisory lock that only guards `--non-interactive` runs does not cover\ninteractive or concurrent invocations. Those need the in-tree probe.\n\n## Interactive tools in SDK subprocess mode\n\nWhen the SDK runs the CLI as a subprocess, stdin\u002Fstdout carry the SDK's JSON\nprotocol. An interactive tool call such as `AskUserQuestion` has no terminal to\nreach: the call fires, nothing renders, and the model wraps up as if the user\ndeclined. This is failure mode 2 above, and it is silent.\n\n- **Do not rely on mid-pipeline interactive tool calls** in any driver flow.\n- Use a two-phase pattern instead: the agent emits findings and stops → the host collects input (`console.input()`) → a second `client.query()` executes the selection.\n- Remove the interactive tool from `allowed_tools` on paths that must not fail silently, so the attempt is an error rather than a shrug.\n\nWorked example: [git-repo-agent ADR-003](https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fgit-repo-agent\u002Fblob\u002Fmain\u002Fdocs\u002Fadr\u002F003-switch-to-claude-sdk-client-for-interactive-workflows.md).\n\nThe `query()` vs `ClaudeSDKClient` split, the full two-phase snippet, and\ncreating the worktree in Python (`ClaudeAgentOptions` has no `isolation`\nparameter) are in [REFERENCE.md](REFERENCE.md).\n\n## Required tests\n\n| Test | Verifies |\n|------|----------|\n| `test_worktree_has_changes_detects_untracked` | Dirty-tree detection covers \"wrote files, never committed\" |\n| `test_auto_commit_if_dirty` | The safety net captures uncommitted state and leaves the tree clean |\n| `test_create_worktree_refuses_to_overwrite_dirty` | Collision protection for same-minute runs |\n| `test_cli_rejects_non_git_target` | Friendly config error, not a traceback |\n| `test_cli_rejects_empty_git_repo` | Unborn-HEAD detection |\n| `test_cli_rejects_non_domain_target` | Catches \"pointed at the wrong directory\" |\n\nReference layouts: [`git-repo-agent\u002Ftests\u002Ftest_worktree_changes.py`](https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fgit-repo-agent\u002Fblob\u002Fmain\u002Ftests\u002Ftest_worktree_changes.py) and [`vault-agent\u002Ftests\u002Ftest_worktree.py`](https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fvault-agent\u002Fblob\u002Fmain\u002Ftests\u002Ftest_worktree.py) (`TestWorktreeCollisionSafety`).\n\n## Checklist when adding a new agent CLI\n\n- [ ] `_ensure_git_repo()` + a domain guard at the top of every write command\n- [ ] \"Has changes\" covers uncommitted **and** untracked state\n- [ ] Safety-net commit runs before any `cleanup_worktree(--force)` or push\n- [ ] `create_worktree` refuses to force-remove a dirty pre-existing worktree\n- [ ] A regression test for each of the six rows above\n- [ ] Interactive flows use the two-phase pattern, not a mid-session interactive tool call\n\n## Related\n\n- `python-plugin:typer-cli-completion` — sibling convention for the same family of Typer CLIs\n- `agent-patterns-plugin:parallel-agent-dispatch` — the orchestrator-side contract for worktree-isolated agents\n- `git-plugin:git-coworker-check` — detecting a peer agent in a shared checkout before destructive git ops\n",{"name":5,"model":52,"created":53,"modified":54,"reviewed":53,"description":7,"allowed-tools":55,"compatibility":56},"opus",1788307200000,1790899200000,"Glob, Grep, Read, Edit, Write, Bash","claude-code","main","bdd0582f1a2ba53d21061835bfd72d45f2f954f4","agent-patterns-plugin\u002Fskills\u002Fagent-cli-worktree-safety",6,"https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins","https:\u002F\u002Fgithub.com\u002Flaurigates","Linux enthusiast, cloud engineer, neovim addict, electronics hobbyist.","2026-11-13 20:24:11",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":77},[67,70,73],{"tool":68,"command":69},"npx","npx skills add laurigates\u002Fclaude-plugins --skill agent-cli-worktree-safety",{"tool":71,"command":72},"bunx","bunx skills add laurigates\u002Fclaude-plugins --skill agent-cli-worktree-safety",{"tool":74,"command":75},"pnpm","pnpm dlx skills add laurigates\u002Fclaude-plugins --skill agent-cli-worktree-safety","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fagent-patterns-plugin\u002Fskills\u002Fagent-cli-worktree-safety\u002FSKILL.md",true,[79],{"path":80,"resourceType":81,"resourceTypeDesc":82,"sizeBytes":83,"sourceHtmlUrl":84},"REFERENCE.md","REFERENCE","参考文档",3704,"https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fagent-patterns-plugin\u002Fskills\u002Fagent-cli-worktree-safety\u002FREFERENCE.md",[86,111,130,146,168,196],{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":95,"publishedAt":47},"01M70PFHMH9ADY0CRE6047Y4B2","kitty-show-image","Show the user an image with a note on what to judge, via a file send or a labelled kitty tab. Use when the user must see an image, or icat fails with no \u002Fdev\u002Ftty.","https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fkitty-plugin\u002Fskills\u002Fkitty-show-image\u002FSKILL.md",[92],{"categoryNo":93,"categoryName":94,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",[96,97,98,99,100,101,102,103,104,105,35,31,41,106,107,108,109,110,29,38],"show","kitty show image","image","kitty","show image","ls","get","send","open","dev","file","text","with","xdg","via",{"skillNo":112,"name":113,"nameZh":6,"description":114,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":47},"01M70PFEN18HKQ4RCQ1VPGMPTB","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.","https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fkitty-plugin\u002Fskills\u002Fkitty-session-persistence\u002FSKILL.md",[],[99,118,119,120,121,122,31,41,123,124,125,29,38,37,36,126,127,128,129,35],"kitty session persistence","session","persistence","false","snapshots","uname","reboot","terminal","snapshot","macos","sessions","restore",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":136,"publishedAt":47},"01M70PFC77XGXCVQ1543VGZHYR","kitty-remote-control","Safe kitty remote control from an agent — read panes with kitty @ ls\u002Fget-text, notify, and never mutate the live terminal unasked. Use when running inside kitty.","https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fkitty-plugin\u002Fskills\u002Fkitty-remote-control\u002FSKILL.md",[],[137,138,99,139,140,101,141,142,102,143,144,35,31,145,41,107,108,125,29,38],"kitty remote control","remote","control","remote control","running","never","panes","notify","query",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":150,"categories":151,"keywords":152,"publishedAt":47},"01M70P6WVMCT5JG4SACTM69AF9","docs-reference-check","Dangling doc-reference gate: flag markdown naming repo paths or relative links that no longer exist. Use when docs cite moved\u002Fdeleted files, or wiring a doc-drift lint.","https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fdocumentation-plugin\u002Fskills\u002Fdocs-reference-check\u002FSKILL.md",[],[153,154,155,156,157,158,159,160,33,161,35,31,41,162,106,163,164,165,166,167],"docs reference check","check","reference check","reference","docs","links","python3","repo","auto","drift","lint","wiring","chezmoi","references","cp",{"skillNo":169,"name":170,"nameZh":6,"description":171,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":172,"categories":173,"keywords":183,"publishedAt":47},"01M6C6NDE7DAQGNWSF22J5CJ0Z","youtube-upload","Upload a video to YouTube via the Data API v3 and edit its title, description, tags or thumbnail afterwards. Use when publishing or retitling a YouTube video.","https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fyoutube-plugin\u002Fskills\u002Fyoutube-upload\u002FSKILL.md",[174,177,178],{"categoryNo":175,"categoryName":176,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":93,"categoryName":94,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":179,"categoryName":180,"taxonomyType":181,"taxonomyTypeDesc":182},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[184,185,186,187,159,45,38,188,36,189,42,190,35,41,106,191,192,31,193,194,195,110,29],"youtube upload","upload","youtube","Video","uv run","publishing","uv","api","v3","tags","id","title",{"skillNo":197,"name":198,"nameZh":6,"description":199,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":200,"categories":201,"keywords":203,"publishedAt":47},"01M6C6NABWW1X58KJJM4F6GQMQ","youtube-studio-share","Share a private YouTube video with a whole Google Workspace organization by scripting YouTube Studio in the browser. Use when a video must be org-only.","https:\u002F\u002Fgithub.com\u002Flaurigates\u002Fclaude-plugins\u002Fblob\u002Fmain\u002Fyoutube-plugin\u002Fskills\u002Fyoutube-studio-share\u002FSKILL.md",[202],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[204,205,206,207,186,187,208,209,210,211,212,38,213,214,215,216,35,217,31,108,218,29],"youtube studio share","share","youtube studio","studio","browser","javascript","scripting","google workspace","workspace","tool","google","only","MCP","chrome","organization"]