| name | sync-xips |
| description | Create and maintain XerahS Improvement Proposals (XIPs) with GitHub as source of truth and docs/proposals/xip folder as backup. Use when creating or editing XIPs, syncing XIPs between GitHub issues and the docs/proposals/xip folder, or when the user mentions XIP, GitHub issues for XIP, or local XIP files. |
XIP Sync Skill
Source of truth: GitHub issues (label xip).
Backup: docs/proposals/xip/ folder (generated from GitHub via sync).
Create and edit XIPs in GitHub; keep a local backup in docs/proposals/xip/ by running sync. Do not treat the local folder as the primary place to write XIPs.
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.