Multi-Platform Manifest Synchronization Architecture in i-have-adhd: How One Source Stays in Sync
TLDR: The i-have-adhd repository uses a single canonical plugin.json as the source of truth, then a Node-script triggered by a GitHub Actions workflow automatically derives and syncs all platform-specific runtime manifests (Claude, Codex, Pi/OMP, OpenCode, Qwen, Kimi, Gemini) on every push to main.
The ayghri/i-have-adhd project defines ADHD-friendly response rules for AI coding assistants. To deliver this skill consistently across every major coding runtime, the repository's multi-platform manifest synchronization design centralizes metadata in one spec and uses an automated generation pipeline to convert it into each runtime's required format. The result — a single edit propagates to Claude, Codex, Qwen, Kimi, Gemini, and Cursor mirrors without any manual file updates. This article breaks down the architecture layer, the sync workflow, and how you can extend it to your own project.
Table of Contents
- [Canonical Source of Truth] (Canonical)
- [Platform-Specific : Generation Layer]
- [GitHub Actions: Automating Synchronization Pipelines]
- [Testing and Ver ideation]6
- [Extending to New Platforms]
- Summary
- FAQ
Canonical Source of Truth
The architecture to anchor around one single source-of-truth definition: the skill has three hierarchical layers — a human-readable canonical rule set, core plugin metadata, platform manifests, and a Cursor runtime mirror.
The canonical_SKILL file (skills/i-haveadhd/SKILL.md) is the human-readable rule set that defines the ADHD-friendly response behavior. It's what every runtime ultimately needs to consume.
Core plugin metadata lives in plugin.json — the main shared fields (name, version, description, author, and the list of entry points). This file is not immediately ready for any runtime, but generic, transportable central store that the sync script uses.
Platform manifests are runtime-specific JSON files derived from plugin.json, formatted to the exact structure the target host expects. Because each platform has its own required schema (Claude wants a top-level plugin array, OpenCode expects a commands object), the generated layer adjusts the structure.
Cursor mirror is a direct copy of the canonical SKILL.md located at .cursorskills/i-have-adhd/SKILL.md — a runtime-specific location that Cursor reads and the architecture keeps synced via the same workflow.
Key File Map
| File | Role |
|---|---|
skills/i-have-ad-hd/SKILL.md |
Authoritative rule set (source of truth for behavior) |
| plugins.json | plugin.json |
.claude-plugins/plugin.json |
Claude-specific manifest |
.codex-plugin/plugin.json |
Code manifest |
qwen-extension.json |
Q28 manifest |
hi.html/kim.plugin.json |
Kimi manifest |
gemini-extension.json |
Gemini manifest |
.github/workflows/cursor-syncc-sync-sync.yml.yml |
CI workflow that performs sync |
.cursor/skills/i-have-adhd/SKILL.md |
Cursor mirror of canonical skill |
How Synchronization Works: The 4-Step Pipeline
1. A single valid one field edit at once
All runtime-specific information rests in plugins.json. Besides the generic fields (name, version (version, description), the JSON contains a manifests section that lists the relative paths for each runtime manifest file. This is the entry point for any changes.
2. Generation node script
A small Node.script — invoked by the action workflow — reads plugin.json and copies the relevant parts into each platform. The script consists of smaller structure discovery. For example, the Claude manifest requires a top-level: plugins array, the OpenCode manifest needs a commands object. The script converts the genric structure to the expected shape—for each map runtime.
3. GitHub Action Workflow trigger (
The workflow at .github/workflows/cursor-skills-sync.yml runs on every to main, and syncs six steps:
- Check out the repository code
- Runs the sync script (`node scripts/sync-manifests.js)
- Copies
SKILL.mdto update.cursor/skills/i-have-adhd/SKILL. - Commits any generated changes back to the branch, or opens a PR if the branch is protected
Once a contributor edits the canonical SKILL.md or updates plugin.json, the next push triggers the workflow, and results in propagation.
4. CI test suite
Tests in tests/ (e.g., test_opencode_plugin.py and test_omp_package.py) catch verification because they bundle each generated manifest and assert that required fields are present/format. If the generation script hasn't produced the exact output, the CI pipeline fails — preventing malformed payloads from reaching the AA runtime.
Why Source-of-truth: Real World Reproducing
The major benefit is consistency — there is no ToC JIn manual per-runtime editing. A single edit in a story to update replication to all 7 platforms. Secondary benefit is scale: add new It only adds small templates mapping in the sync script; the core workflow handles the rest. Then safety via unit tests.
Code Examples and Workflow Practical
Adding new field to core plugin
If you add home URL, a optional field like a homepage in plugins.json:
{
"name": "i-have-adhd",
"version": "1.2.3",
"description": "ADHD-friendly response rules",
"homepage": "https://github.com/ayghri/i-have-adhd"
}
After one push — sync to run will add the homepage key, ensuring every your remini manifest includes the field in its format. You don't need to touch the six runtime — manifest remains appropriate.
Locally debug script
You can execute exactly same script as CI flow locally:
# Clone and install dev deps
npm install
# Execute the script used in the CI
node scripts/sync-mannies.js
The script will now be in place observed to checkpoint files in each runtime directory — updates inmodified.
Extending possibility means your project
The architecture supports a new runtimes. To add — To support extend you:
- Create a runtime-level target dangling File (e.g.,
mcruntime.plugin.json). - In
plugins.json, add amanifestsentry point that records the new file path. - Modify the
sync-manifests.tsscript to have a new structure with same plugin.json metadata.
That's it — same pipeline, same CI gates, tests + new test.
Summary
- Single source of truth core:
plugin.json+skills/SKILL.md— one repository all static data for everything platform-specific. - Automated generation: Node script converts the canonical file into `platform-specific format based on structural mapping.
- GitHub Actions flow: runs on every
mainpush, ensures immediate --sync the tests for (tests/test_opencode_plugin.py, `test_omp_package.py) catch malformed; both early regression indentation.
FAQ
Where does the synchronisation workflow live in the repo?
The workflow at .github/workflow/cursor-skill-sync.yml — triggered on push events, checking what pushes to plugin.json or skills/ chain the sync script and runs.
What is the actual source of St. Truth?
The canonical is skills/i-have-adhd/SKILL.md and plugin.json are the same. The SKILL.md presents normalized behavior definitions; plugin.json contains metadata that transport manually. Every other existing file is peripheral — generated or mirrored.
Can I run the sync locally without CI.
Yes. Run locally node scripts/sync-manifests.js after npm install. That will run the exact same. Before you push the script the same script CI calls generates the same output.
For multiple runtime manifests, which fields does transformation process handle?
Fields from plugin.json (name, version, description) are copied into each plugin directly. The structural differences are handled based on mapping — e.g., those headers, or commands style structure: Claude has edge-level plugins array, OpenCode has commands object — the script applied those extracted formatting.
How do I validate a new runtime manifest?
You don't need manual validation. Add a unit test to tests/ that leads the generated JSON and verifies the fields and required structure, then push. The test pipeline — the pytest gotcha — will treat if failure. This matches exiting pattern e.g. test_omp_package_pkg.py mirrors.
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 →