How the Cursor Mirror Sync Keeps the Canonical SKILL.md in Perfect Sync
TLDR: The ayghri/i-have-adhd repository enforces a canonical skills/i-have-adhd/SKILL.md as the single source of truth and uses a GitHub Actions workflow that runs cmp to fail any pull request where the .cursor/skills/i-have-adhd/SKILL.md mirror copy has drifted.
The ayghri/i-have-adhd repository stores the authoritative definition of its ADHD coaching skill in skills/i-have-adhd/SKILL.md. However, Cursor-compatible tools and runtimes expect the skill to live in the hidden path .cursor/skills/i-have-adhd/SKILL.md. Because these are two separate file copies (not a symlink), they can easily diverge — especially on Windows clones or when the repository is downloaded as a ZIP archive. This article explains exactly how the cursor mirror sync mechanism enforces that both files always match.
Why the Cursor Mirror Copy Exists
The core problem is straightforward: a single skill definition must serve two different consumers.
The canonical file (skills/i-have-adhd/SKILL.md) is the human-maintained, authoritative definition of the skill. It's what contributors edit, review, and discuss in pull requests.
The mirror copy (.cursor/skills/i-have-adhd/SKILL.md) is the file that Cursor-compatible runtimes actually load when the skill is invoked.
Since these are independent copies rather than symlinks, they can diverge. A symlink would solve the problem on Linux and macOS, but Windows clones and ZIP downloads destroy symlinks by default. The project solves this with an automated CI enforcement instead of relying on filesystem features.
How the Sync Workflow Enforces the Cursor Mirror
The sync mechanism is built around a single GitHub Actions workflow located at [.github/workflows/cursor-skill-sync.yml](https://github.com/ayghri/i-have-adhd/blob/main/.github/workflows/cursor-skill-sync.yml). It works through three stages.
Stage 1: Trigger Condition
The workflow triggers on two types of events:
- Every pull request that touches either the canonical file
skills/i-have-adhd/SKILL.mdor any file inside.cursor/skills/ - Any push to the
mainbranch
This ensures that even a trivial whitespace change to the canonical skill triggers the sync check.
Stage 2: The cmp Comparison
Once triggered, the job checks out the repository and runs a file comparison with cmp:
cmp skills/i-have-adhd/SKILL.md .cursor/skills/i-have-adhd/SKILL.md \
|| { echo "::error::.cursor copy is out of sync. Run: cp skills/i-have-adhd/SKILL.md .cursor/skills/i-have-adhd/SKILL.md"; exit 1; }
If the files differ, cmp returns a non-zero exit code. The || conditional catches that, prints a clearly formatted error message via GitHub Actions' ::error:: annotation, and exits with status 1 — failing the job.
Stage 3: Merge Block
Because the workflow fails the check when the comparison fails, GitHub blocks the pull request from being allowed. This forces every contributor to sync the mirror before merging, either manually or with a script. The result is a single source of truth with a fully automated consistency check.
How to Fix a Sync Drift (Manual Workflow)
When the CI check fails, the error message itself tells you the exact fix. From the repository root, run:
# From the repository root
cp skills/i-have-adhd/SKILL.md .cursor/skills/i-have-adhd/SKILL.md
git add .cursor/skills/i-have-adhd/SKILL.md
git commit -m "Sync Cursor mirror of SKILL.md"
After pushing the fix, the workflow will re-run and pass because the byte-level cmp now matches.
The Automated Check in Action
Here is the simplified YAML that CI runs to enforce the mirror relationship:
# .github/workflows/cursor-skill-sync.yml
- name: Fail if the .cursor copy differs from SKILL.md
run: |
cmp skills/i-have-adhd/SKILL.md .cursor/skills/i-have-adhd/SKILL.md || {
echo "::error::.cursor copy is out of sync. Run: cp skills/i-have-adhd/SKILL.md .cursor/skills/i-have-adhd/SKILL.md"
exit 1
}
No custom scripting logic, no hash comparisons — just a single command-line utility that does exactly what it says.
Key Files in the Sync System
| File | Role | Link |
|---|---|---|
| Canonical skill definition | The single source of truth for the i-have-adhd skill | [skills/i-have-adhd/SKILL.md](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) |
| Cursor mirror copy | The file read by Cursor-compatible runtimes | [.cursor/skills/i-have-adhd/SKILL.md](https://github.com/ayghri/i-have-adhd/blob/main/.cursor/skills/i-have-adhd/SKILL.md) |
| Sync workflow | CI job that enforces the mirror relationship | [.github/workflows/cursor-skill-sync.yml](https://github.com/ayghri/i-have-adhd/blob/main/.github/workflows/cursor-skill-sync.yml) |
| Agent guide | Documentation of the overall sync policy | [AGENTS.md](https://github.com/ayghri/i-have-adhd/blob/main/AGENTS.md) |
Why This Approach Works
This design supports any platform, including Windows where symlinks are problematic. It also gives contributors a deterministic, reproducible error message with the exact command to run — there's no guesswork about how to recover from drift. The result is a canonical ↔ mirror relationship that's robust, auditable, and self-documenting in the CI output.
Summary
- The cursor mirror sync relies on a single GitHub Actions workflow at
.github/workflows/cursor-skill-sync.yml - The workflow triggers on any PR or push touching either the canonical
SKILL.mdor its.cursor/copy - A
cmpcomparison fails the job instantly, prints the exactcpcommand, and blocks the merge - The design is platform-agnostic because it avoids symlinks entirely
- The human-readable fix is always one command:
cp skills/i-have-adhd/SKILL.md .cursor/skills/i-have-adhd/SKILL.md
Frequently Asked Questions
Does the cursor mirror sync use a symlink or a copy?
The mirror is a separate file copy. The repository deliberately avoids symlinks because they don't survive on Windows filesystems or in ZIP downloads, which would silently break the skill mapping. The workflow uses byte-level comparison instead.
What happens if I forget to sync the mirror in my pull request?
The CI pipeline fails the check with a specific error message that clearly instructs you to run cp skills/i-have-adhd/SKILL.md .cursor/skills/i-have-adhd/SKILL.md. The merge request is blocked until you commit that mirrored file.
Can I edit the .cursor/skills/ file directly instead of the canonical one?
No. The canonical path skills/i-have-adhd/SKILL.md is the only place you should edit. The shadow is automatically enforced to match via the workflow — editing the mirror directly would cause the reverse drift and fail the same check.
Which events trigger the sync check in CI?
The workflow runs whenever a pull request touches either skills/i-have-adhd/SKILL.md or any file under .cursor/skills/, plus every push to main. This guarantees the sync check never misses a change that could create drift.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →