How Plugin Manifest Synchronization Works Across AI Runtimes

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 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

At the repository root, 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:

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 executes on every push to the main branch. This automation reads the canonical 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

# .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 defines a sync-manifests script that executes scripts/sync-manifests.js, allowing developers to align all manifests before pushing changes.

// 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, 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 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 workflow automatically propagates changes on every push to main.
  • Local validation: The 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 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 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 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →