Claude
Skills
Sign in
Back

Plugin Sync

Included with Lifetime
$97 forever

Automatically generate plugin.yaml from Betty Framework registries

General

What this skill does


# plugin.sync

## Overview

**plugin.sync** is the synchronization tool that generates `plugin.yaml` from Betty Framework's registry files. It ensures that Claude Code's plugin configuration stays in sync with registered skills, commands, and hooks.

## Purpose

Automates the generation of `plugin.yaml` to maintain consistency between:
- **Skill Registry** (`registry/skills.json`) – Active skills with entrypoints
- **Command Registry** (`registry/commands.json`) – Slash commands
- **Hook Registry** (`registry/hooks.json`) – Event-driven hooks
- **Plugin Configuration** (`plugin.yaml`) – Claude Code plugin manifest

This eliminates manual editing of `plugin.yaml` and prevents drift between what's registered and what's exposed to Claude Code.

## What It Does

1. **Reads Registries**: Loads `skills.json`, `commands.json`, and `hooks.json`
2. **Filters Active Skills**: Processes only skills with `status: active` and defined entrypoints
3. **Validates Handlers**: Checks if handler files exist on disk
4. **Generates Commands**: Converts skill entrypoints to `plugin.yaml` command format
5. **Preserves Metadata**: Maintains existing plugin metadata (author, license, etc.)
6. **Writes plugin.yaml**: Outputs formatted plugin configuration to repo root
7. **Reports Issues**: Warns about missing handlers or inconsistencies

## Usage

### Basic Usage

```bash
python skills/plugin.sync/plugin_sync.py
```

No arguments required - reads from standard registry locations.

### Via Betty CLI

```bash
/plugin/sync
```

### Expected Registry Structure

The skill expects these registry files:

```
betty/
├── registry/
│   ├── skills.json      # Registered skills
│   ├── commands.json    # Registered commands
│   └── hooks.json       # Registered hooks
└── plugin.yaml          # Generated output
```

## Behavior

### 1. Registry Loading

Reads JSON files from:
- `registry/skills.json`
- `registry/commands.json`
- `registry/hooks.json`

If a registry file is missing, logs a warning and continues with available data.

### 2. Skill Processing

For each skill in `skills.json`:
- **Checks status**: Only processes skills with `status: active`
- **Looks for entrypoints**: Requires at least one entrypoint definition
- **Validates handler**: Checks if handler file exists at `skills/{skill_name}/{handler}`
- **Converts format**: Maps skill entrypoint to plugin command schema

### 3. Command Generation

Creates a command entry for each active skill entrypoint:

```yaml
- name: skill/validate
  description: Validate a skill manifest
  handler:
    runtime: python
    script: skills/skill.define/skill_define.py
  parameters:
    - name: manifest_path
      type: string
      required: true
      description: Path to skill.yaml file
  permissions:
    - filesystem:read
    - filesystem:write
```

### 4. Handler Validation

For each handler reference:
- Constructs full path: `skills/{skill_name}/{handler_filename}`
- Checks file existence on disk
- Logs warning if handler file is missing

### 5. Plugin Generation

Preserves existing `plugin.yaml` metadata:
- Plugin name, version, description
- Author information
- License
- Requirements
- Permissions
- Config sections

Replaces the `commands` section with generated entries.

### 6. Output Writing

Writes `plugin.yaml` with:
- Auto-generated header comment
- Properly formatted YAML (2-space indent)
- Generation timestamp in metadata
- Skill and command counts

## Outputs

### Success Response

```json
{
  "ok": true,
  "status": "success",
  "output_path": "/home/user/betty/plugin.yaml",
  "commands_generated": 18,
  "warnings": []
}
```

### Response with Warnings

```json
{
  "ok": true,
  "status": "success",
  "output_path": "/home/user/betty/plugin.yaml",
  "commands_generated": 18,
  "warnings": [
    "Handler not found for 'api.validate': skills/api.validate/api_validate_missing.py",
    "Skill 'test.broken' has entrypoint without handler"
  ]
}
```

### Failure Response

```json
{
  "ok": false,
  "status": "failed",
  "error": "Failed to parse JSON from registry/skills.json: Expecting value: line 1 column 1"
}
```

## Generated plugin.yaml Structure

The skill generates a `plugin.yaml` like this:

```yaml
# Betty Framework - Claude Code Plugin
# Auto-generated by plugin.sync skill
# DO NOT EDIT MANUALLY - Run plugin.sync to regenerate

name: betty-framework
version: 1.0.0
description: Betty Framework - Structured AI-assisted engineering
author:
  name: RiskExec
  email: [email protected]
  url: https://github.com/epieczko/betty
license: MIT

metadata:
  homepage: https://github.com/epieczko/betty
  repository: https://github.com/epieczko/betty
  generated_at: "2025-10-23T17:45:00.123456+00:00"
  generated_by: plugin.sync skill
  skill_count: 18
  command_count: 18

requirements:
  python: ">=3.11"
  packages:
    - pyyaml

permissions:
  - filesystem:read
  - filesystem:write
  - process:execute

commands:
  - name: workflow/validate
    description: Validates Betty workflow YAML definitions
    handler:
      runtime: python
      script: skills/workflow.validate/workflow_validate.py
    parameters:
      - name: workflow.yaml
        type: string
        required: true
        description: Path to the workflow YAML file
    permissions:
      - filesystem
      - read

  - name: skill/define
    description: Validate a Claude Code skill manifest
    handler:
      runtime: python
      script: skills/skill.define/skill_define.py
    parameters:
      - name: manifest_path
        type: string
        required: true
        description: Path to the skill.yaml file
    permissions:
      - filesystem
      - read
      - write

  # ... more commands ...
```

## Validation and Warnings

### Handler Existence Check

For each skill entrypoint, the skill checks:

```python
full_path = f"skills/{skill_name}/{handler_filename}"
if not os.path.exists(full_path):
    warnings.append(f"Handler not found: {full_path}")
```

### Common Warnings

| Warning | Meaning | Action |
|---------|---------|--------|
| `Handler not found for 'X'` | Handler file missing from disk | Create the handler or fix the path in skill.yaml |
| `Skill 'X' has entrypoint without handler` | Entrypoint missing `handler` field | Add handler field to entrypoint definition |
| `Registry file not found` | Registry JSON is missing | Run registry update or check file paths |

## Examples

### Example 1: Full Sync After Adding New Skills

**Scenario**: You've added several new skills and want to sync them to `plugin.yaml`

```bash
# Create skills using skill.create
/skill/create data.transform "Transform data between formats"
/skill/create api.monitor "Monitor API health" --inputs=endpoint --outputs=status

# Define skills (validates and registers)
/skill/define skills/data.transform/skill.yaml
/skill/define skills/api.monitor/skill.yaml

# Sync to plugin.yaml
/plugin/sync
```

**Output**:
```
INFO: Starting plugin.yaml generation from registries...
INFO: Loading registry files...
INFO: Generating plugin.yaml configuration...
INFO: Added command: /data/transform from skill data.transform
INFO: Added command: /api/monitor from skill api.monitor
INFO: ✅ Written plugin.yaml to /home/user/betty/plugin.yaml
INFO: ✅ Generated 20 commands
INFO: 📄 Output: /home/user/betty/plugin.yaml
```

### Example 2: Detecting Missing Handlers

**Scenario**: A skill's handler file was moved or deleted

```bash
# Remove a handler file
rm skills/api.validate/api_validate.py

# Run sync
/plugin/sync
```

**Output**:
```
INFO: Starting plugin.yaml generation from registries...
INFO: Loading registry files...
INFO: Generating plugin.yaml configuration...
INFO: Added command: /skill/define from skill skill.define
WARNING: Handler not found for 'api.validate': skills/api.validate/api_validate.py
INFO: ✅ Written plugin.yaml to /home/user/betty/plugin.yaml
INFO: ⚠️  Warnings during generation:
INFO:   - Handler not found for 'api.validate': skills/api.validate/api_validate.py
INFO: ✅ Generated 
Files: 4
Size: 24.4 KB
Complexity: 30/100
Category: General

Related in General