---
name: sync-gists
description: Use when the user says "sync gists", "sync global instructions", "/sync-gists", or similar, and when a gist-backed global file has just been edited locally (~/AGENTS.md, ~/.claude/CLAUDE.md, this skill, a tracked reference, or a tracked script) and the remote copy may now be stale.
---

# sync-gists

## Overview

Gist-backed personal files are the durability layer for global agent instructions and support files: the local copy is what runs, the gist is what survives a machine rebuild. This skill audits every tracked target for local-vs-gist drift and syncs each one in a direction the user confirms.

This skill file is itself a tracked target, and it is canonical at `~/.agents/skills/sync-gists/SKILL.md`. Host skill directories hold symbolic links to it, never copies.

## Scope

Optional argument. If the invocation carries one, interpret it as a filter against the `Sync target` column of the table below (case-insensitive substring match). If there is no argument, sync every row in the table.

**Note:** the workflow command suite (handover, ready, init-workflow, the revise family, and their scripts) lives in the public **nightshift** plugin at https://github.com/astenlund/nightshift; edits to those land in the plugin repo clone at `C:/Git/nightshift` and are versioned by git, not gists. The retired commands gist (`5be756d9e40436d68bbf38566e74336c`) is frozen with a redirect README and is not a sync target. Pre-plugin local copies are archived under `~/.claude/archive/pre-flightdeck/`.

## Procedure

0. Validate the host adapters before comparing any target. Each pair below is one canonical file or directory plus one or more host adapters that must be relative symbolic links pointing at it:

   |          Canonical           |          Host adapter          |      Expected stored target      |
   |------------------------------|--------------------------------|----------------------------------|
   | `~/AGENTS.md`                | `~/.codex/AGENTS.md`           | `../AGENTS.md`                   |
   | `~/.agents/skills/sync-gists` | `~/.claude/skills/sync-gists`  | `../../.agents/skills/sync-gists` |
   | `~/.agents/skills/sync-gists` | `~/.codex/skills/sync-gists`   | `../../.agents/skills/sync-gists` |

   Apply these rules to every pair:

   - If the canonical file or directory is missing, stop before every gist write. The gist copy may be fetched into scratch and offered for restoration, but do not write locally or remotely without confirmation.
   - Before comparing a symbolic link's stored target, require the stored value to be relative, normalize only its path separators from `\` to `/`, and compare the normalized text ordinally with the expected stored target. Separator normalization does not relax the resolved-path or link-type checks.
   - Continue only for a symbolic link whose normalized stored target matches the expected value and whose resolved path is exactly the canonical path. For a file adapter, also require bytes read through the link to equal canonical bytes. For a directory adapter, require `SKILL.md` to be readable through both paths and byte-identical; exact resolved-path identity establishes that the remaining tree is the canonical directory, so do not attempt to compare directory bytes.
   - If an adapter is missing but its parent directory exists, recreate the relative symbolic link automatically and verify it. If the parent directory is absent, treat that host as unavailable: report it, continue auditing the available targets, and do not create a new host configuration tree.
   - Replace a byte-identical regular file or directory adapter with the relative symbolic link automatically, then verify it. File equality is a direct byte comparison. Directory equality requires the same recursive relative file set and byte-identical content for every file.
   - Preserve a divergent regular file or directory adapter, show its complete diff against canonical, and require a decision about which content wins.
   - For a wrong-target symbolic link, report stored and resolved paths without reading or changing the unexpected target, then require confirmation before repair.
   - Stop for a dangling symbolic link.
   - Treat probe, permission, and link-creation failures as stop states. Preserve recoverable files and never substitute a copy or hard link.

   After every repair, rerun the applicable link-type, stored-target, resolved-target, and content checks. Host adapters are local structure and are never uploaded.

1. For each in-scope target, compare the gist's stored bytes (`gh gist view {id} --filename {filename} --raw`) against the local file at `{local_path}`. For the common-case match outcome, do the byte comparison in bash so file contents stay out of the conversation context; redirect the gist content to a temp file and `cmp -s` it against the local file (command substitution strips trailing newlines and produces false mismatches). Only pull contents into context when a diff exists and needs to be shown. If they match, report "already in sync" for that target and move on.
2. If they differ, show what differs and suggest a sync direction based on context (e.g. if the user just edited `{local_path}` this session, suggest local -> gist). Get confirmation before overwriting.
   - **Surface drift cases individually**, not batched. Especially when a drift cannot be attributed to the current session's work, call it out as its own item and require explicit per-target confirmation. Bundling unattributable drift with session-attributable drift hides the unattributable case.
   - Auto mode does not bypass this confirmation; the procedure's "get confirmation" step is workflow design, not permission gating.
   - **Local -> Gist (file already in gist):** `gh gist edit {id} -f {filename} {local_path}`
   - **Local -> Gist (first publication of a new file):** `gh gist edit {id} --add {local_path}`. The `-f` form fails with `gist has no file "{filename}"` when the file doesn't exist in the gist yet; use `--add` instead. After the first add, subsequent updates use `-f`.
   - **Gist -> Local:** `gh gist view {id} --filename {filename} --raw > {local_path}`
3. After each sync, re-run step 1 for that target to confirm the post-sync state.

When one file in a multi-file gist succeeds and another fails, report the successful and failed targets separately. The sync remains safely rerunnable; do not roll back a successful remote write without explicit direction.

|     Sync target      |              Gist ID               |       Gist filename        |                 Local path                  |
|----------------------|------------------------------------|----------------------------|---------------------------------------------|
| Global AGENTS.md     | `427b43883661b68e4963b05c91b896fb` | `AGENTS.md`                | `~/AGENTS.md`                               |
| Claude wrapper       | `427b43883661b68e4963b05c91b896fb` | `CLAUDE.md`                | `~/.claude/CLAUDE.md`                       |
| sync-gists           | `bdbac4a606c99b33243fada609dba764` | `sync-gists.md`            | `~/.agents/skills/sync-gists/SKILL.md`      |
| Windows gotchas ref  | `d331f1705a9363bb751e69203af18024` | `windows-gotchas.md`       | `~/.claude/references/windows-gotchas.md`   |
| JetBrains Air ref    | `d331f1705a9363bb751e69203af18024` | `jetbrains-air-acp.md`     | `~/.claude/references/jetbrains-air-acp.md` |
| context-warn hook    | `69cd4c36864c011faf6afd2e789278f9` | `context-warn.mjs`         | `~/.claude/scripts/context-warn.mjs`        |
| Update repair script | `d331f1705a9363bb751e69203af18024` | `claude-finish-update.ps1` | `~/.local/bin/claude-finish-update.ps1`     |

The gist filename for this skill stays `sync-gists.md` rather than `SKILL.md`: gist filenames share one flat namespace across the gist, so the name has to identify the file on its own. Restoring that row writes the gist bytes to the canonical path, which is what the host adapters point at.

The sync-gists row is self-referential: this skill maintains the gist backing its own definition, so a drift between the local file and the gist is resolved by the next sync-gists invocation.

## Orphan check

After processing the in-scope targets, recursively enumerate files under `~/.agents/skills/`, and glob `~/.claude/commands/*.md`, `~/.claude/scripts/*`, and `~/.claude/references/*`. Flag any file that has no table row and is not part of the pre-plugin migration archive as **untracked -- not durable across machines**.

Also enumerate the immediate entries under the host adapter roots `~/.claude/skills/` and `~/.codex/skills/`. Exempt the platform-owned `~/.codex/skills/.system` directory. A relative symbolic link into the same-named canonical directory under `~/.agents/skills/` is covered by that canonical target. Report any other symbolic link with its stored and resolved targets; flag any other real file or directory as an untracked host-local skill. For a new workflow command or script, the default proposal is now to add it to the nightshift plugin repo (where git provides durability and distribution) rather than to a gist; a gist row is only for personal files that don't belong in the public plugin. The user decides per file; some local files are legitimately machine-only.

## Post-sync README check

When the sync run has substantially changed a gist's contents (a file added, a file removed, or a content shift that alters what a tracked file does), fetch that gist's `README.md` and check whether it still describes the current file set accurately. If stale, propose an update inline and push after confirmation. Routine within-file edits (typos, phrasing, small logic tweaks) don't trigger this check. The README has no local mirror; this is a gist-only check. Not every tracked gist has a README; skip the check for those that don't.

## Common mistakes

Entries in this list are earned, never guessed. A plausible-sounding failure mode does not belong here; one that has actually happened does.

The promotion path:

1. **First occurrence.** Write it as a memory. Leave this section alone.
2. **Second occurrence.** Promote it from the memory into the list below.

An entry here therefore means the mistake has been made at least twice. Adding one on any other basis defeats the purpose of the list, and "it is obviously a mistake" or "another variant of this skill lists it" is not a second occurrence.

*No entries yet.*
