Files
gh-epieczko-betty/skills/plugin.sync/SKILL.md
2025-11-29 18:26:08 +08:00

505 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: Plugin Sync
description: Automatically generate plugin.yaml from Betty Framework registries
---
# 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: platform@riskexec.com
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 19 commands
```
### Example 3: Initial Plugin Setup
**Scenario**: Setting up Betty Framework plugin for the first time
```bash
# Initialize registry if needed
python -c "from betty.config import ensure_directories; ensure_directories()"
# Register all existing skills
for skill in skills/*/skill.yaml; do
/skill/define "$skill"
done
# Generate plugin.yaml
/plugin/sync
```
This creates a complete `plugin.yaml` from all registered active skills.
## Integration
### With skill.define
After defining a skill, sync the plugin:
```bash
/skill/define skills/my.skill/skill.yaml
/plugin/sync
```
### With Workflows
Include plugin sync as a workflow step:
```yaml
# workflows/skill_lifecycle.yaml
steps:
- skill: skill.create
args: ["new.skill", "Description"]
- skill: skill.define
args: ["skills/new.skill/skill.yaml"]
- skill: plugin.sync
args: []
```
### With Hooks
Auto-sync when skills are updated:
```yaml
# .claude/hooks.yaml
- event: on_file_save
pattern: "skills/*/skill.yaml"
command: python skills/skill.define/skill_define.py {file_path} && python skills/plugin.sync/plugin_sync.py
blocking: false
description: Auto-sync plugin.yaml when skills change
```
## What Gets Included
### ✅ Included in plugin.yaml
- Skills with `status: active`
- Skills with at least one `entrypoint` defined
- All entrypoint parameters and permissions
- Skill descriptions and metadata
### ❌ Not Included
- Skills with `status: draft`
- Skills without entrypoints
- Skills marked as internal-only
- Test skills (unless marked active)
## Common Errors
| Error | Cause | Solution |
|-------|-------|----------|
| "Failed to parse JSON" | Invalid JSON in registry file | Fix JSON syntax in the registry |
| "Registry file not found" | Missing registry file | Ensure registries exist in `registry/` dir |
| "Permission denied" | Cannot write plugin.yaml | Check file permissions on plugin.yaml |
| All commands missing | No active skills | Mark skills as active in registry |
## Files Read
- `registry/skills.json` Skill registry
- `registry/commands.json` Command registry (future use)
- `registry/hooks.json` Hook registry (future use)
- `plugin.yaml` Existing plugin config (for metadata preservation)
- `skills/*/` Handler file validation
## Files Modified
- `plugin.yaml` Overwritten with generated configuration
## Exit Codes
- **0**: Success (plugin.yaml generated successfully)
- **1**: Failure (error during generation)
## Logging
Logs generation progress:
```
INFO: Starting plugin.yaml generation from registries...
INFO: Loading registry files...
INFO: Loaded existing plugin.yaml as template
INFO: Generating plugin.yaml configuration...
INFO: Added command: /skill/create from skill skill.create
INFO: Added command: /skill/define from skill skill.define
INFO: Added command: /agent/define from skill agent.define
INFO: ✅ Written plugin.yaml to /home/user/betty/plugin.yaml
INFO: ✅ Generated 18 commands
INFO: 📄 Output: /home/user/betty/plugin.yaml
```
## Best Practices
1. **Run After Registry Changes**: Sync after adding, updating, or removing skills
2. **Include in CI/CD**: Add plugin sync to your deployment pipeline
3. **Review Before Commit**: Check generated plugin.yaml before committing
4. **Keep Registries Clean**: Remove inactive skills to keep plugin.yaml focused
5. **Use Hooks**: Set up auto-sync hooks for convenience
6. **Version Control**: Always commit plugin.yaml changes with skill changes
## Troubleshooting
### Plugin.yaml Not Updating
**Problem**: Changes to skills.json don't appear in plugin.yaml
**Solutions**:
- Ensure skill status is `active`
- Check that skill has `entrypoints` defined
- Verify entrypoint has `command` and `handler` fields
- Run `/skill/define` before `/plugin/sync`
### Handler Not Found Warnings
**Problem**: Warnings about missing handler files
**Solutions**:
- Check handler path in skill.yaml
- Ensure handler file exists at `skills/{skill_name}/{handler_filename}`
- Verify file permissions
- Update skill.yaml if handler was renamed
### Commands Not Appearing
**Problem**: Active skill not generating command
**Solutions**:
- Verify skill has `entrypoints` array in skill.yaml
- Check entrypoint has `command` field (e.g., `/skill/validate`)
- Ensure `handler` field points to correct file
- Check that skill.yaml is in skills registry
## Architecture
### Skill Categories
**Infrastructure** Plugin.sync maintains the foundation layer by syncing registry state to plugin configuration.
### Design Principles
- **Single Source of Truth**: Registry files are the source of truth
- **Idempotent**: Can be run multiple times safely
- **Validation First**: Checks handlers before generating config
- **Preserve Metadata**: Keeps existing plugin metadata intact
- **Clear Reporting**: Detailed warnings about issues
## See Also
- **skill.define** Validate and register skills ([SKILL.md](../skill.define/SKILL.md))
- **registry.update** Update skill registry ([SKILL.md](../registry.update/SKILL.md))
- **skill.create** Create new skills ([SKILL.md](../skill.create/SKILL.md))
- **Betty Architecture** Framework overview ([betty-architecture.md](../../docs/betty-architecture.md))
## Dependencies
- **registry.update**: Registry management
- **betty.config**: Configuration constants and paths
- **betty.logging_utils**: Logging infrastructure
## Status
**Active** Production-ready infrastructure skill
## Version History
- **0.1.0** (Oct 2025) Initial implementation with registry sync and handler validation