# How Plugin Manifest Synchronization Works Across AI Runtimes

> Discover how plugin manifest synchronization works across AI runtimes in the ayghri/i-have-adhd repository. Learn about GitHub Actions and Node.js utilities for seamless metadata propagation.

- Repository: [Ayoub Ghriss/i-have-adhd](https://github.com/ayghri/i-have-adhd)
- Tags: internals
- Published: 2026-09-10

---

**Plugin manifest synchronization in the `ayghri/i-have-adhd` repository is achieved through a GitHub Actions workflow and a local Node.js utility that propagate core metadata from a canonical [`plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/plugin.json) file to all runtime-specific manifests while preserving platform-specific configurations for Claude, Codex, Kimi, Qwen, Gemini, and OpenCode.**

The `ayghri/i-have-adhd` project distributes plugins across multiple AI platforms, each requiring distinct manifest formats and file locations. Maintaining identical core metadata—such as the plugin **name** and **description**—across these disparate runtime environments demands a robust plugin manifest synchronization strategy that prevents configuration drift between the canonical definition and platform-specific implementations.

## The Canonical Source of Truth: [`plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/plugin.json)

At the repository root, [`plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/plugin.json) serves as the single source of truth for universal plugin metadata. This file contains the definitive `name` and `description` fields that must remain consistent across every supported runtime environment. According to the source code architecture, no runtime-specific configuration should be stored in this central file; it exists solely to define the plugin's core identity and descriptive content.

## Runtime-Specific Manifest Files

Each AI platform consumes its own manifest format, requiring the repository to maintain separate files that extend the core metadata with platform-specific properties. The project supports six distinct runtimes with the following manifest locations:

- **Claude**: [`.claude-plugin/plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/.claude-plugin/plugin.json)
- **Codex**: [`.codex-plugin/plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/.codex-plugin/plugin.json)
- **Kimi**: [`kimi.plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/kimi.plugin.json)
- **Qwen**: [`qwen-extension.json`](https://github.com/ayghri/i-have-adhd/blob/main/qwen-extension.json)
- **Gemini**: [`gemini-extension.json`](https://github.com/ayghri/i-have-adhd/blob/main/gemini-extension.json)
- **OpenCode**: [`opencode.json`](https://github.com/ayghri/i-have-adhd/blob/main/opencode.json)

These files contain runtime-unique fields such as `runtime`, `entrypoint`, or platform-specific API versions, while inheriting the canonical `name` and `description` values from the root manifest.

## Automated Synchronization Strategies

The project employs a two-pronged approach to ensure plugin manifest synchronization remains consistent without manual intervention.

### CI-Driven Manifest Propagation

The GitHub Actions workflow defined in [`.github/workflows/cursor-skill-sync.yml`](https://github.com/ayghri/i-have-adhd/blob/main/.github/workflows/cursor-skill-sync.yml) executes on every push to the `main` branch. This automation reads the canonical [`plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/plugin.json) and propagates its core fields to all runtime-specific manifests using `jq` for JSON manipulation.

The workflow performs the following operations:

1. Loads the central manifest into a JSON variable
2. Iterates over the target manifest files for each runtime
3. Uses `jq` to merge the canonical `name` and `description` while preserving existing runtime-specific properties
4. Commits the modified files back to the repository

```yaml

# .github/workflows/cursor-skill-sync.yml

name: Sync Plugin Manifests
on:
  push:
    branches: [ main ]

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install jq
        run: sudo apt-get install -y jq
      - name: Propagate core metadata
        run: |
          CORE=$(cat plugin.json)
          for FILE in .claude-plugin/plugin.json .codex-plugin/plugin.json \
                      kimi.plugin.json qwen-extension.json \
                      gemini-extension.json opencode.json; do
            jq --argjson core "$CORE" \
               '.name = $core.name | .description = $core.description' "$FILE" > tmp && mv tmp "$FILE"
          done
      - name: Commit changes
        uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: "chore: sync plugin manifests"

```

### Local Development Sync

For pre-commit validation, the repository includes a local synchronization utility accessible via npm. The [`package.json`](https://github.com/ayghri/i-have-adhd/blob/main/package.json) defines a `sync-manifests` script that executes [`scripts/sync-manifests.js`](https://github.com/ayghri/i-have-adhd/blob/main/scripts/sync-manifests.js), allowing developers to align all manifests before pushing changes.

```javascript
// scripts/sync-manifests.js
const fs = require('fs');
const path = require('path');

const core = JSON.parse(fs.readFileSync('plugin.json', 'utf8'));
const targets = [
  '.claude-plugin/plugin.json',
  '.codex-plugin/plugin.json',
  'kimi.plugin.json',
  'qwen-extension.json',
  'gemini-extension.json',
  'opencode.json',
];

targets.forEach(file => {
  const manifest = JSON.parse(fs.readFileSync(file, 'utf8'));
  manifest.name = core.name;
  manifest.description = core.description;
  fs.writeFileSync(file, JSON.stringify(manifest, null, 2) + '\n');
});
console.log('All manifests synced to core metadata.');

```

Running `npm run sync-manifests` updates every runtime manifest to match the canonical [`plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/plugin.json), ensuring local changes are validated before the CI workflow executes.

## How the Synchronization Logic Preserves Runtime Configuration

The synchronization process employs a non-destructive merge strategy. When updating runtime-specific manifests, the system:

- **Overwrites** only the `name` and `description` fields from the canonical source
- **Preserves** all runtime-specific properties such as `entrypoint`, `runtime`, version constraints, and platform API configurations
- **Maintains** JSON formatting consistency with 2-space indentation and trailing newlines

This approach guarantees that platform-specific capabilities remain intact while enforcing universal branding and descriptive content across all AI runtime environments.

## Summary

- **Single source of truth**: The root [`plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/plugin.json) defines canonical `name` and `description` values for all runtimes.
- **Multi-runtime support**: Six distinct manifest files support Claude, Codex, Kimi, Qwen, Gemini, and OpenCode platforms.
- **Automated CI sync**: The [`.github/workflows/cursor-skill-sync.yml`](https://github.com/ayghri/i-have-adhd/blob/main/.github/workflows/cursor-skill-sync.yml) workflow automatically propagates changes on every push to `main`.
- **Local validation**: The [`scripts/sync-manifests.js`](https://github.com/ayghri/i-have-adhd/blob/main/scripts/sync-manifests.js) utility enables developers to synchronize manifests during local development via `npm run sync-manifests`.
- **Non-destructive updates**: Synchronization preserves runtime-specific configuration while enforcing core metadata consistency.

## Frequently Asked Questions

### What is the purpose of having separate manifest files for each runtime?

Each AI platform (Claude, Codex, Kimi, Qwen, Gemini, and OpenCode) expects a specific JSON structure, file location, or additional properties that are incompatible with other platforms. Runtime-specific manifests allow the project to satisfy these individual requirements while maintaining a unified plugin identity through synchronized core metadata.

### How does the synchronization process prevent overwriting runtime-specific settings?

The synchronization logic—implemented in both the CI workflow and the local script—uses targeted field assignment that only modifies the `name` and `description` properties. When processing each manifest, the system reads the existing file, updates only the canonical fields, and writes back the complete object, thereby preserving all other runtime-specific configurations such as entry points and API versions.

### Can I run the manifest synchronization locally before committing changes?

Yes. The repository includes a local synchronization script at [`scripts/sync-manifests.js`](https://github.com/ayghri/i-have-adhd/blob/main/scripts/sync-manifests.js) that can be executed by running `npm run sync-manifests`. This script performs the same merge operation as the CI workflow, allowing you to verify that all runtime manifests correctly reflect updates to the canonical [`plugin.json`](https://github.com/ayghri/i-have-adhd/blob/main/plugin.json) before pushing to the repository.

### What triggers the automatic synchronization in the CI pipeline?

The GitHub Actions workflow defined in [`.github/workflows/cursor-skill-sync.yml`](https://github.com/ayghri/i-have-adhd/blob/main/.github/workflows/cursor-skill-sync.yml) triggers on every `push` event to the `main` branch. When triggered, the workflow checks out the repository, installs `jq`, executes the propagation logic across all six runtime manifests, and automatically commits any changes back to the branch using the `git-auto-commit-action`.