Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:26:08 +08:00
commit 8f22ddf339
295 changed files with 59710 additions and 0 deletions

504
skills/plugin.sync/SKILL.md Normal file
View 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