From epieczko-betty
Automatically generate plugin.yaml from Betty Framework registries
npx claudepluginhub joshuarweaver/cascade-code-general-misc-1 --plugin epieczko-bettyThis skill uses the workspace's default tool permissions.
**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.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
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.
Automates the generation of plugin.yaml to maintain consistency between:
registry/skills.json) – Active skills with entrypointsregistry/commands.json) – Slash commandsregistry/hooks.json) – Event-driven hooksplugin.yaml) – Claude Code plugin manifestThis eliminates manual editing of plugin.yaml and prevents drift between what's registered and what's exposed to Claude Code.
skills.json, commands.json, and hooks.jsonstatus: active and defined entrypointsplugin.yaml command formatpython skills/plugin.sync/plugin_sync.py
No arguments required - reads from standard registry locations.
/plugin/sync
The skill expects these registry files:
betty/
├── registry/
│ ├── skills.json # Registered skills
│ ├── commands.json # Registered commands
│ └── hooks.json # Registered hooks
└── plugin.yaml # Generated output
Reads JSON files from:
registry/skills.jsonregistry/commands.jsonregistry/hooks.jsonIf a registry file is missing, logs a warning and continues with available data.
For each skill in skills.json:
status: activeskills/{skill_name}/{handler}Creates a command entry for each active skill entrypoint:
- 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
For each handler reference:
skills/{skill_name}/{handler_filename}Preserves existing plugin.yaml metadata:
Replaces the commands section with generated entries.
Writes plugin.yaml with:
{
"ok": true,
"status": "success",
"output_path": "/home/user/betty/plugin.yaml",
"commands_generated": 18,
"warnings": []
}
{
"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"
]
}
{
"ok": false,
"status": "failed",
"error": "Failed to parse JSON from registry/skills.json: Expecting value: line 1 column 1"
}
The skill generates a plugin.yaml like this:
# 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 ...
For each skill entrypoint, the skill checks:
full_path = f"skills/{skill_name}/{handler_filename}"
if not os.path.exists(full_path):
warnings.append(f"Handler not found: {full_path}")
| 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 |
Scenario: You've added several new skills and want to sync them to plugin.yaml
# 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
Scenario: A skill's handler file was moved or deleted
# 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
Scenario: Setting up Betty Framework plugin for the first time
# 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.
After defining a skill, sync the plugin:
/skill/define skills/my.skill/skill.yaml
/plugin/sync
Include plugin sync as a workflow step:
# 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: []
Auto-sync when skills are updated:
# .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
status: activeentrypoint definedstatus: draft| 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 |
registry/skills.json – Skill registryregistry/commands.json – Command registry (future use)registry/hooks.json – Hook registry (future use)plugin.yaml – Existing plugin config (for metadata preservation)skills/*/ – Handler file validationplugin.yaml – Overwritten with generated configurationLogs 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
Problem: Changes to skills.json don't appear in plugin.yaml
Solutions:
activeentrypoints definedcommand and handler fields/skill/define before /plugin/syncProblem: Warnings about missing handler files
Solutions:
skills/{skill_name}/{handler_filename}Problem: Active skill not generating command
Solutions:
entrypoints array in skill.yamlcommand field (e.g., /skill/validate)handler field points to correct fileInfrastructure – Plugin.sync maintains the foundation layer by syncing registry state to plugin configuration.
Active – Production-ready infrastructure skill