Initial commit
This commit is contained in:
504
skills/plugin.sync/SKILL.md
Normal file
504
skills/plugin.sync/SKILL.md
Normal file
@@ -0,0 +1,504 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user