XIP Sync Skill
Source of truth: GitHub issues (label xip).
Backup: docs/proposals/xip/ folder (generated from GitHub via sync).
For requested issue creation or updates, edit XIPs in GitHub and sync the local backup. Reading, auditing, or implementing an XIP does not authorize issue edits, label repairs, or recovery uploads. Apply the mutation steps below only when requested; otherwise report differences.
For XIP structure, templates, and writing patterns, use XIP writing reference. This skill is the operational workflow for issue creation, issue editing, sync, and recovery.
Principles
- Create and edit XIPs in GitHub – Use
gh issue create / gh issue edit (or the GitHub UI). The issue body holds the full XIP markdown. Status (open/closed/parked) lives only in GitHub via issue state and labels.
- Sync GitHub → docs/proposals/xip – Run the sync script to write one
.md file per XIP under docs/proposals/xip/ (single folder). Files do not move; status is not reflected in paths.
- docs/proposals/xip folder is read-only for XIP content – Do not edit XIP content in the local folder; edit the GitHub issue, then sync.
- Recovery – If the only copy of a XIP is in
docs/proposals/xip/, create a new issue with that content and then sync.
Workflows
Audit local XIPs against GitHub issues
Use this when the user says the local docs/proposals/xip/ folder has XIPs that are missing from GitHub.
Compare by canonical ID only
- Extract local IDs from filenames matching
XIP####.
- Fetch all GitHub issues, not just issues with the
xip label, because existing XIP issues can be missing the label.
- Extract
XIP#### from issue titles and ignore all other title text differences.
- Treat a GitHub issue as present if any title contains the same
XIP####, even if punctuation, casing, or wording differs.
$repo = "ShareX/XerahS"
$xipDir = "docs/proposals/xip"
$issues = gh issue list --repo $repo --state all --limit 500 --json number,title,url,state,labels | ConvertFrom-Json
$issueIds = New-Object "System.Collections.Generic.HashSet[string]"
foreach ($issue in $issues) {
foreach ($match in [regex]::Matches($issue.title, "XIP[0-9]{4}")) {
[void]$issueIds.Add($match.Value)
}
}
$localIds = Get-ChildItem -LiteralPath $xipDir -Filter "XIP*.md" |
ForEach-Object { if ($_.Name -match "^(XIP[0-9]{4})") { $Matches[1] } } |
Sort-Object -Unique
$missing = $localIds | Where-Object { -not $issueIds.Contains($_) }
$missing
Repair labels before running label-based sync
- If an issue title contains
XIP#### but does not have the xip label, add the label instead of creating a duplicate issue.
- This matters because
sync-from-github.ps1 reads only issues with label xip.
foreach ($issue in $issues) {
if ($issue.title -match "XIP[0-9]{4}") {
$labelNames = $issue.labels | ForEach-Object { $_.name }
if (-not ($labelNames -contains "xip")) {
gh issue edit $issue.number --repo $repo --add-label "xip"
}
}
}
Create only true missing issues
- For each local-only
XIP####, create one issue using the matching local file as the body and label it xip.
- Build the issue title from the file's first markdown heading when available.
- Normalize the title to
XIP#### Short Descriptive Title: single space after the ID; no brackets, colon, or dash after the ID.
Verify after creation
- Re-fetch all issues and repeat the ID-only comparison.
- Confirm local ID count and GitHub issue ID count match.
- Confirm every issue whose title contains
XIP#### has the xip label.
- Check
git status --short; uploading missing issues should not leave local file changes unless you intentionally ran the sync script.
Be deliberate with local sync
sync-from-github.ps1 removes and rewrites docs/proposals/xip/XIP*.md from label-matched GitHub issues. It can rename files and rewrite old bodies, causing broad local churn.
- Do not run the sync script just to upload missing local XIPs unless the user also wants the backup folder normalized from GitHub.
- If you do run it to verify label-based sync, inspect
git status --short and git diff --stat -- docs/proposals/xip afterwards. Keep or discard the generated backup churn deliberately.
Create a new XIP
Choose the next XIP number
- List existing across all issues when choosing or auditing IDs:
gh issue list --repo ShareX/XerahS --state all --limit 500 --json number,title,labels
- Do not rely only on
--label xip for ID discovery; it can miss an existing XIP issue whose label was accidentally omitted.
- Or check highest in
docs/proposals/xip/*.md (e.g. XIP0044).
Draft the XIP body
- Use the structure in XIP writing reference: Overview, Prerequisites, Implementation Phases, Non-Negotiable Rules, Deliverables, Affected Components.
- Title format:
XIP0044 Short Descriptive Title (4-digit zero-padded number, single space, no brackets, no colon, no dash).
Create the GitHub issue
- Title:
XIP0044 Short Descriptive Title
- Body: full XIP markdown (no wrapper; the body is the XIP).
- Label:
xip. Add parked if the XIP is parked.
gh issue create --title "XIP0044 Your Title" --label "xip" --body-file path/to/draft.md
Sync to docs/proposals/xip
- Run:
./.ai/skills/sync-xips/scripts/sync-from-github.ps1
- The new XIP appears as
docs/proposals/xip/XIP####-title-slug.md.
Edit an existing XIP
Edit on GitHub
gh issue edit <number> --title "XIP0044 New Title" --body-file path/to/updated.md
- Or edit title/body in the GitHub issue in the browser.
Sync to docs/proposals/xip
- Run
./.ai/skills/sync-xips/scripts/sync-from-github.ps1 so the backup in docs/proposals/xip/ is updated.
Sync GitHub → docs/proposals/xip (backup)
Run from repo root:
.\.ai\skills\sync-xips\scripts\sync-from-github.ps1
- Reads all issues with label
xip.
- Writes/overwrites one
.md file per XIP under docs/proposals/xip/ (single folder). Status is not synced to paths; it stays in GitHub (issue state and labels).
- Filename:
XIP####-title-slug.md (number from title, rest from lower-case slug of title).
- File content: issue body only (no extra “issue” wrapper). If the body contains a “XIP Document” block from an old migration, the script strips it and uses the actual XIP content.
Recovery: docs/proposals/xip → GitHub
If the only good copy of a XIP is in the local folder:
- Create a new issue with that file as the body and label
xip:gh issue create --title "XIP0044 Title From File" --label "xip" --body-file "docs/proposals/xip/XIP0044-Something.md"
- Run sync so the local copy is consistent with GitHub.
Backup layout
- All XIP backup files live in
docs/proposals/xip/ as XIP####-title-slug.md. Status (open/closed/parked) is not reflected in folder structure; it lives only in GitHub issues (state and labels). This avoids moving files and breaking links when status changes.
XIP naming (quick reference)
- Issue title and first heading:
XIP0044 Short Descriptive Title
- 4-digit zero-padded number, single space, no
[ ], no :, no - between number and title.
- File name:
XIP0044-short-descriptive-title.md (number + lower-case slug with hyphens).
Full structure, templates, and patterns: XIP writing reference.
Script location
- Sync (GitHub → docs/proposals/xip):
.ai/skills/sync-xips/scripts/sync-from-github.ps1
- One-time merge of legacy files:
.ai/skills/sync-xips/scripts/merge-old-xips.ps1 – merges old-named XIP*.md (e.g. in docs/proposals/xip/) into the corresponding GitHub issue body, runs sync, then deletes the old files. Use after migrating to single-folder backup or when cleaning duplicates.
Run from repo root; requires gh CLI and PowerShell.
Key takeaways
- GitHub first – Create and edit XIPs as issues (label
xip); issue body = full XIP.
- docs/proposals/xip = backup – One folder (
docs/proposals/xip/); status only in GitHub. Run sync-from-github.ps1 after changes.
- Don't edit XIP content locally – Edit the issue, then sync.
- Naming –
XIP0044 Title (no brackets/colon/dash); file XIP0044-title-slug.md.
1---2name: sync-xips3description: Synchronize XIP GitHub issues and local backups when requested. Do not trigger for reading or implementing an XIP.4---56# XIP Sync Skill78**Source of truth**: GitHub issues (label `xip`). 9**Backup**: `docs/proposals/xip/` folder (generated from GitHub via sync).1011For requested issue creation or updates, edit XIPs in GitHub and sync the local backup. Reading, auditing, or implementing an XIP does not authorize issue edits, label repairs, or recovery uploads. Apply the mutation steps below only when requested; otherwise report differences.1213For XIP structure, templates, and writing patterns, use [XIP writing reference](../write-xip/SKILL.md). This skill is the operational workflow for issue creation, issue editing, sync, and recovery.1415---1617## Principles18191. **Create and edit XIPs in GitHub** – Use `gh issue create` / `gh issue edit` (or the GitHub UI). The issue body holds the full XIP markdown. Status (open/closed/parked) lives only in GitHub via issue state and labels.202. **Sync GitHub → docs/proposals/xip** – Run the sync script to write one `.md` file per XIP under `docs/proposals/xip/` (single folder). Files do not move; status is not reflected in paths.213. **docs/proposals/xip folder is read-only for XIP content** – Do not edit XIP content in the local folder; edit the GitHub issue, then sync.224. **Recovery** – If the only copy of a XIP is in `docs/proposals/xip/`, create a new issue with that content and then sync.2324---2526## Workflows2728### Audit local XIPs against GitHub issues2930Use this when the user says the local `docs/proposals/xip/` folder has XIPs that are missing from GitHub.31321. **Compare by canonical ID only**33 - Extract local IDs from filenames matching `XIP####`.34 - Fetch **all** GitHub issues, not just issues with the `xip` label, because existing XIP issues can be missing the label.35 - Extract `XIP####` from issue titles and ignore all other title text differences.36 - Treat a GitHub issue as present if any title contains the same `XIP####`, even if punctuation, casing, or wording differs.3738 ```powershell39 $repo = "ShareX/XerahS"40 $xipDir = "docs/proposals/xip"41 $issues = gh issue list --repo $repo --state all --limit 500 --json number,title,url,state,labels | ConvertFrom-Json42 $issueIds = New-Object "System.Collections.Generic.HashSet[string]"43 foreach ($issue in $issues) {44 foreach ($match in [regex]::Matches($issue.title, "XIP[0-9]{4}")) {45 [void]$issueIds.Add($match.Value)46 }47 }48 $localIds = Get-ChildItem -LiteralPath $xipDir -Filter "XIP*.md" |49 ForEach-Object { if ($_.Name -match "^(XIP[0-9]{4})") { $Matches[1] } } |50 Sort-Object -Unique51 $missing = $localIds | Where-Object { -not $issueIds.Contains($_) }52 $missing53 ```54552. **Repair labels before running label-based sync**56 - If an issue title contains `XIP####` but does not have the `xip` label, add the label instead of creating a duplicate issue.57 - This matters because `sync-from-github.ps1` reads only issues with label `xip`.5859 ```powershell60 foreach ($issue in $issues) {61 if ($issue.title -match "XIP[0-9]{4}") {62 $labelNames = $issue.labels | ForEach-Object { $_.name }63 if (-not ($labelNames -contains "xip")) {64 gh issue edit $issue.number --repo $repo --add-label "xip"65 }66 }67 }68 ```69703. **Create only true missing issues**71 - For each local-only `XIP####`, create one issue using the matching local file as the body and label it `xip`.72 - Build the issue title from the file's first markdown heading when available.73 - Normalize the title to `XIP#### Short Descriptive Title`: single space after the ID; no brackets, colon, or dash after the ID.74754. **Verify after creation**76 - Re-fetch all issues and repeat the ID-only comparison.77 - Confirm local ID count and GitHub issue ID count match.78 - Confirm every issue whose title contains `XIP####` has the `xip` label.79 - Check `git status --short`; uploading missing issues should not leave local file changes unless you intentionally ran the sync script.80815. **Be deliberate with local sync**82 - `sync-from-github.ps1` removes and rewrites `docs/proposals/xip/XIP*.md` from label-matched GitHub issues. It can rename files and rewrite old bodies, causing broad local churn.83 - Do not run the sync script just to upload missing local XIPs unless the user also wants the backup folder normalized from GitHub.84 - If you do run it to verify label-based sync, inspect `git status --short` and `git diff --stat -- docs/proposals/xip` afterwards. Keep or discard the generated backup churn deliberately.8586### Create a new XIP87881. **Choose the next XIP number** 89 - List existing across all issues when choosing or auditing IDs: `gh issue list --repo ShareX/XerahS --state all --limit 500 --json number,title,labels`90 - Do not rely only on `--label xip` for ID discovery; it can miss an existing XIP issue whose label was accidentally omitted.91 - Or check highest in `docs/proposals/xip/*.md` (e.g. XIP0044).92932. **Draft the XIP body** 94 - Use the structure in [XIP writing reference](../write-xip/SKILL.md): Overview, Prerequisites, Implementation Phases, Non-Negotiable Rules, Deliverables, Affected Components. 95 - **Title format**: `XIP0044 Short Descriptive Title` (4-digit zero-padded number, single space, no brackets, no colon, no dash).96973. **Create the GitHub issue** 98 - Title: `XIP0044 Short Descriptive Title` 99 - Body: full XIP markdown (no wrapper; the body is the XIP). 100 - Label: `xip`. Add `parked` if the XIP is parked.101102 ```powershell103 gh issue create --title "XIP0044 Your Title" --label "xip" --body-file path/to/draft.md104 ```1051064. **Sync to docs/proposals/xip** 107 - Run: `./.ai/skills/sync-xips/scripts/sync-from-github.ps1` 108 - The new XIP appears as `docs/proposals/xip/XIP####-title-slug.md`.109110### Edit an existing XIP1111121. **Edit on GitHub** 113 - `gh issue edit <number> --title "XIP0044 New Title" --body-file path/to/updated.md` 114 - Or edit title/body in the GitHub issue in the browser.1151162. **Sync to docs/proposals/xip** 117 - Run `./.ai/skills/sync-xips/scripts/sync-from-github.ps1` so the backup in `docs/proposals/xip/` is updated.118119### Sync GitHub → docs/proposals/xip (backup)120121Run from repo root:122123```powershell124.\.ai\skills\sync-xips\scripts\sync-from-github.ps1125```126127- Reads all issues with label `xip`.128- Writes/overwrites one `.md` file per XIP under **`docs/proposals/xip/`** (single folder). Status is not synced to paths; it stays in GitHub (issue state and labels).129- Filename: `XIP####-title-slug.md` (number from title, rest from lower-case slug of title).130- File content: issue body only (no extra “issue” wrapper). If the body contains a “XIP Document” block from an old migration, the script strips it and uses the actual XIP content.131132### Recovery: docs/proposals/xip → GitHub133134If the only good copy of a XIP is in the local folder:1351361. Create a new issue with that file as the body and label `xip`:137 ```powershell138 gh issue create --title "XIP0044 Title From File" --label "xip" --body-file "docs/proposals/xip/XIP0044-Something.md"139 ```1402. Run sync so the local copy is consistent with GitHub.141142---143144## Backup layout145146- All XIP backup files live in **`docs/proposals/xip/`** as `XIP####-title-slug.md`. Status (open/closed/parked) is **not** reflected in folder structure; it lives only in GitHub issues (state and labels). This avoids moving files and breaking links when status changes.147148---149150## XIP naming (quick reference)151152- **Issue title and first heading**: `XIP0044 Short Descriptive Title` 153 - 4-digit zero-padded number, single space, no `[ ]`, no `:`, no `-` between number and title.154- **File name**: `XIP0044-short-descriptive-title.md` (number + lower-case slug with hyphens).155156Full structure, templates, and patterns: [XIP writing reference](../write-xip/SKILL.md).157158---159160## Script location161162- **Sync (GitHub → docs/proposals/xip)**: `.ai/skills/sync-xips/scripts/sync-from-github.ps1`163- **One-time merge of legacy files**: `.ai/skills/sync-xips/scripts/merge-old-xips.ps1` – merges old-named `XIP*.md` (e.g. in `docs/proposals/xip/`) into the corresponding GitHub issue body, runs sync, then deletes the old files. Use after migrating to single-folder backup or when cleaning duplicates.164165Run from repo root; requires `gh` CLI and PowerShell.166167---168169## Key takeaways1701711. **GitHub first** – Create and edit XIPs as issues (label `xip`); issue body = full XIP.1722. **docs/proposals/xip = backup** – One folder (`docs/proposals/xip/`); status only in GitHub. Run `sync-from-github.ps1` after changes.1733. **Don't edit XIP content locally** – Edit the issue, then sync.1744. **Naming** – `XIP0044 Title` (no brackets/colon/dash); file `XIP0044-title-slug.md`.