| name | Plugin Build |
| description | Bundle plugin directory into a deployable Claude Code plugin package |
plugin.build
Overview
plugin.build is the packaging tool that bundles your Betty Framework plugin into a distributable archive ready for deployment to Claude Code. It validates all entrypoints, gathers necessary files, and creates versioned packages with checksums.
Purpose
Automates the creation of deployable plugin packages by:
- Validating all declared entrypoints and handler files
- Gathering all necessary plugin files (skills, utilities, registries)
- Packaging into
.tar.gzor.ziparchives - Generating checksums for package verification
- Reporting validation results and build metrics
This eliminates manual packaging errors and ensures consistent, reproducible plugin distributions.
What It Does
- Loads plugin.yaml: Reads the plugin configuration
- Validates Entrypoints: Checks that all command handlers exist on disk
- Gathers Files: Collects skills, utilities, registries, and documentation
- Creates Package: Bundles everything into a versioned archive
- Calculates Checksums: Generates MD5 and SHA256 hashes
- Generates Manifest: Creates manifest.json with entrypoint summary and checksums
- Creates Preview: Generates plugin.preview.yaml for review before deployment
- Generates Report: Outputs detailed build metrics as JSON
- Reports Issues: Identifies missing files or validation errors
Usage
Basic Usage
python skills/plugin.build/plugin_build.py
Builds with defaults:
- Plugin:
./plugin.yaml - Format:
tar.gz - Output:
./dist/
Via Betty CLI
/plugin/build
Custom Plugin Path
python skills/plugin.build/plugin_build.py /path/to/plugin.yaml
Specify Output Format
python skills/plugin.build/plugin_build.py --format=zip
python skills/plugin.build/plugin_build.py --format=tar.gz
Custom Output Directory
python skills/plugin.build/plugin_build.py --output-dir=/tmp/packages
Full Options
python skills/plugin.build/plugin_build.py \
/custom/path/plugin.yaml \
--format=zip \
--output-dir=/var/packages
Command-Line Arguments
| Argument | Type | Default | Description |
|---|---|---|---|
plugin_path |
Positional | ./plugin.yaml |
Path to plugin.yaml file |
--format |
Option | tar.gz |
Package format (tar.gz or zip) |
--output-dir |
Option | ./dist |
Output directory for packages |
Output Files
Package Archive
Naming convention: {plugin-name}-{version}.{format}
Examples:
betty-framework-1.0.0.tar.gzbetty-framework-1.0.0.zip
Location: {output-dir}/{package-name}.{format}
Manifest File
Naming convention: manifest.json
Location: {output-dir}/manifest.json
Contains plugin metadata, entrypoint summary, and package checksums. This is the primary file for plugin distribution and installation.
Plugin Preview
Naming convention: plugin.preview.yaml
Location: {output-dir}/plugin.preview.yaml
Contains the current plugin configuration for review before deployment. Useful for comparing changes or validating the plugin structure.
Build Report
Naming convention: {plugin-name}-{version}-build-report.json
Example:
betty-framework-1.0.0-build-report.json
Location: {output-dir}/{package-name}-build-report.json
Package Structure
The generated archive contains:
betty-framework-1.0.0/
├── plugin.yaml # Plugin manifest
├── requirements.txt # Python dependencies
├── README.md # Documentation (if exists)
├── LICENSE # License file (if exists)
├── CHANGELOG.md # Change log (if exists)
├── betty/ # Core utility package
│ ├── __init__.py
│ ├── config.py
│ ├── validation.py
│ ├── logging_utils.py
│ ├── file_utils.py
│ └── errors.py
├── registry/ # Registry files
│ ├── skills.json
│ ├── commands.json
│ ├── hooks.json
│ └── agents.json
└── skills/ # All active skills
├── api.define/
│ ├── skill.yaml
│ ├── SKILL.md
│ └── api_define.py
├── api.validate/
│ ├── skill.yaml
│ ├── SKILL.md
│ └── api_validate.py
└── ... (all other skills)
Manifest Schema
The manifest.json file is the primary metadata file for plugin distribution:
{
"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",
"documentation": "https://github.com/epieczko/betty/tree/main/docs",
"tags": ["framework", "api-development", "workflow"],
"generated_at": "2025-10-23T12:34:56.789012+00:00"
},
"requirements": {
"python": ">=3.11",
"packages": ["pyyaml"]
},
"permissions": ["filesystem:read", "filesystem:write", "process:execute"],
"package": {
"filename": "betty-framework-1.0.0.tar.gz",
"size_bytes": 245760,
"checksums": {
"md5": "a1b2c3d4e5f6...",
"sha256": "1234567890abcdef..."
}
},
"entrypoints": [
{
"command": "skill/define",
"handler": "skills/skill.define/skill_define.py",
"runtime": "python"
}
],
"commands_count": 18,
"agents": [
{
"name": "api.designer",
"description": "Design APIs with iterative refinement"
}
]
}
Build Report Schema
{
"build_timestamp": "2025-10-23T12:34:56.789012+00:00",
"plugin": {
"name": "betty-framework",
"version": "1.0.0",
"description": "Betty Framework - Structured AI-assisted engineering"
},
"validation": {
"total_commands": 18,
"valid_entrypoints": 18,
"missing_files": [],
"has_errors": false
},
"package": {
"path": "/home/user/betty/dist/betty-framework-1.0.0.tar.gz",
"size_bytes": 245760,
"size_human": "240.00 KB",
"files_count": 127,
"format": "tar.gz",
"checksums": {
"md5": "a1b2c3d4e5f6...",
"sha256": "1234567890abcdef..."
}
},
"entrypoints": [
{
"command": "skill/define",
"handler": "skills/skill.define/skill_define.py",
"runtime": "python",
"path": "/home/user/betty/skills/skill.define/skill_define.py"
}
]
}
Outputs
Success Response
{
"ok": true,
"status": "success",
"package_path": "/home/user/betty/dist/betty-framework-1.0.0.tar.gz",
"report_path": "/home/user/betty/dist/betty-framework-1.0.0-build-report.json",
"build_report": { ... }
}
Success with Warnings
{
"ok": false,
"status": "success_with_warnings",
"package_path": "/home/user/betty/dist/betty-framework-1.0.0.tar.gz",
"report_path": "/home/user/betty/dist/betty-framework-1.0.0-build-report.json",
"build_report": {
"validation": {
"missing_files": [
"Command 'api.broken': handler not found at skills/api.broken/api_broken.py"
],
"has_errors": true
}
}
}
Failure Response
{
"ok": false,
"status": "failed",
"error": "plugin.yaml not found: /home/user/betty/plugin.yaml"
}
Behavior
1. Plugin Loading
Reads and parses plugin.yaml:
- Validates YAML syntax
- Extracts plugin name, version, description
- Identifies all command entrypoints
2. Entrypoint Validation
For each command in plugin.yaml:
- Extracts handler script path
- Checks file existence on disk
- Reports valid and missing handlers
- Logs validation results
Valid entrypoint:
- name: skill/validate
handler:
runtime: python
script: skills/skill.define/skill_define.py
Missing handler (reports warning):
- name: broken/command
handler:
runtime: python
script: skills/broken/missing.py # File doesn't exist
3. File Gathering
Automatically includes:
Always included:
plugin.yaml– Plugin manifestskills/*/– All skill directories referenced in commandsbetty/– Core utility packageregistry/*.json– All registry files
Conditionally included (if exist):
requirements.txt– Python dependenciesREADME.md– Plugin documentationLICENSE– License fileCHANGELOG.md– Version history
Excluded:
__pycache__/directories.pyccompiled Python files- Hidden files (starting with
.) - Build artifacts and temporary files
4. Package Creation
tar.gz format:
- GZIP compression
- Preserves file permissions
- Cross-platform compatible
- Standard for Python packages
zip format:
- ZIP compression
- Wide compatibility
- Good for Windows environments
- Easy to extract without CLI tools
5. Checksum Generation
Calculates two checksums:
MD5: Fast, widely supported
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
SHA256: Cryptographically secure
1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Use checksums to verify package integrity after download or transfer.
Examples
Example 1: Standard Build
Scenario: Build Betty Framework plugin for distribution
# Ensure plugin.yaml is up to date
/plugin/sync
# Build the package
/plugin/build
Output:
INFO: 🏗️ Starting plugin build...
INFO: 📄 Plugin: /home/user/betty/plugin.yaml
INFO: 📦 Format: tar.gz
INFO: 📁 Output: /home/user/betty/dist
INFO: ✅ Loaded plugin.yaml from /home/user/betty/plugin.yaml
INFO: 📝 Validating 18 command entrypoints...
INFO: 📦 Gathering files from 16 skill directories...
INFO: 📦 Adding betty/ utility package...
INFO: 📦 Adding registry/ files...
INFO: 📦 Total files to package: 127
INFO: 🗜️ Creating tar.gz archive: /home/user/betty/dist/betty-framework-1.0.0.tar.gz
INFO: 🔐 Calculating checksums...
INFO: MD5: a1b2c3d4e5f6...
INFO: SHA256: 1234567890ab...
INFO: 📊 Build report: /home/user/betty/dist/betty-framework-1.0.0-build-report.json
INFO: 📋 Manifest: /home/user/betty/dist/manifest.json
INFO: 📋 Preview file created: /home/user/betty/dist/plugin.preview.yaml
INFO:
============================================================
INFO: 🎉 BUILD COMPLETE
============================================================
INFO: 📦 Package: /home/user/betty/dist/betty-framework-1.0.0.tar.gz
INFO: 📊 Report: /home/user/betty/dist/betty-framework-1.0.0-build-report.json
INFO: 📋 Manifest: /home/user/betty/dist/manifest.json
INFO: 👁️ Preview: /home/user/betty/dist/plugin.preview.yaml
INFO: ✅ Commands: 18/18
INFO: 📏 Size: 240.00 KB
INFO: 📝 Files: 127
============================================================
Example 2: Build as ZIP
Scenario: Create Windows-friendly package
python skills/plugin.build/plugin_build.py --format=zip
Result: dist/betty-framework-1.0.0.zip
Example 3: Build with Custom Output
Scenario: Build to specific release directory
python skills/plugin.build/plugin_build.py \
--format=tar.gz \
--output-dir=releases/v1.0.0
Result:
releases/v1.0.0/betty-framework-1.0.0.tar.gzreleases/v1.0.0/betty-framework-1.0.0-build-report.json
Example 4: Detecting Missing Handlers
Scenario: Some handlers are missing
# Remove a handler file
rm skills/api.validate/api_validate.py
# Try to build
/plugin/build
Output:
INFO: 📝 Validating 18 command entrypoints...
WARNING: ❌ skill/api/validate: skills/api.validate/api_validate.py (not found)
INFO: ⚠️ Found 1 missing files:
INFO: - Command 'skill/api/validate': handler not found at skills/api.validate/api_validate.py
INFO: 📦 Gathering files from 15 skill directories...
...
INFO: ============================================================
INFO: 🎉 BUILD COMPLETE
INFO: ============================================================
INFO: ✅ Commands: 17/18
INFO: ⚠️ Warnings: 1
Exit code: 1 (failure due to validation errors)
Example 5: Build Workflow
Scenario: Complete release workflow
# 1. Update registries
/registry/update
# 2. Sync plugin.yaml
/plugin/sync
# 3. Build package
/plugin/build
# 4. Verify package
tar -tzf dist/betty-framework-1.0.0.tar.gz | head -20
# 5. Check build report
cat dist/betty-framework-1.0.0-build-report.json | jq .
Integration
With plugin.sync
Always sync before building:
/plugin/sync && /plugin/build
With Workflows
Include in release workflow:
# workflows/plugin_release.yaml
name: plugin_release
version: 1.0.0
description: Release workflow for Betty Framework plugin
steps:
- skill: registry.update
description: Update all registries
- skill: plugin.sync
description: Generate plugin.yaml
- skill: plugin.build
args: ["--format=tar.gz"]
description: Build tar.gz package
- skill: plugin.build
args: ["--format=zip"]
description: Build zip package
With CI/CD
Add to GitHub Actions:
# .github/workflows/release.yml
- name: Build Plugin Package
run: |
python skills/plugin.sync/plugin_sync.py
python skills/plugin.build/plugin_build.py --format=tar.gz
python skills/plugin.build/plugin_build.py --format=zip
- name: Upload Packages
uses: actions/upload-artifact@v3
with:
name: plugin-packages
path: dist/betty-framework-*
Validation Rules
Entrypoint Validation
Valid entrypoint:
- Command name is defined
- Handler section exists
- Handler script path is specified
- Handler file exists on disk
- Runtime is specified
Invalid entrypoint (triggers warning):
- Missing handler script path
- Handler file doesn't exist
- Empty command name
File Gathering Rules
Skill directories included if:
- Referenced in at least one command handler
- Contains valid handler file
Files excluded:
- Python cache files (
__pycache__,.pyc) - Hidden files (
.git,.env, etc.) - Build artifacts (
dist/,build/) - IDE files (
.vscode/,.idea/)
Common Errors
| Error | Cause | Solution |
|---|---|---|
| "plugin.yaml not found" | Missing plugin.yaml | Run /plugin/sync first |
| "Invalid YAML" | Syntax error in plugin.yaml | Fix YAML syntax |
| "Unsupported output format" | Invalid --format value | Use tar.gz or zip |
| "Handler not found" | Missing handler file | Create handler or fix path |
| "Permission denied" | Cannot write to output dir | Check directory permissions |
Files Read
plugin.yaml– Plugin manifestskills/*/skill.yaml– Skill manifests (indirect via handlers)skills/*/*.py– Handler scriptsbetty/*.py– Utility modulesregistry/*.json– Registry filesrequirements.txt– Dependencies (if exists)README.md,LICENSE,CHANGELOG.md– Documentation (if exist)
Files Modified
{output-dir}/{plugin-name}-{version}.{format}– Created package archive{output-dir}/{plugin-name}-{version}-build-report.json– Created build report{output-dir}/manifest.json– Created plugin manifest with checksums and entrypoints{output-dir}/plugin.preview.yaml– Created plugin preview for review
Exit Codes
- 0: Success (all handlers valid, package created)
- 1: Failure (missing handlers or build error)
Logging
Logs build progress with emojis for clarity:
INFO: 🏗️ Starting plugin build...
INFO: 📄 Plugin: /home/user/betty/plugin.yaml
INFO: ✅ Loaded plugin.yaml
INFO: 📝 Validating entrypoints...
INFO: 📦 Gathering files...
INFO: 🗜️ Creating tar.gz archive...
INFO: 🔐 Calculating checksums...
INFO: 📊 Build report written
INFO: 🎉 BUILD COMPLETE
Best Practices
- Always Sync First: Run
/plugin/syncbefore/plugin/build - Validate Before Building: Ensure all skills are registered and active
- Check Build Reports: Review validation warnings before distribution
- Verify Checksums: Use checksums to verify package integrity
- Version Consistently: Match plugin version with git tags
- Test Extraction: Verify packages extract correctly
- Document Changes: Keep CHANGELOG.md updated
Troubleshooting
Missing Files in Package
Problem: Expected files not in archive
Solutions:
- Ensure files exist in source directory
- Check that skills are referenced in commands
- Verify files aren't excluded (e.g.,
.pyc,__pycache__) - Check file permissions
Handler Validation Failures
Problem: Handlers marked as missing but files exist
Solutions:
- Verify exact path in plugin.yaml matches file location
- Check case sensitivity in file paths
- Ensure handler files have correct names
- Run
/plugin/syncto update paths
Package Size Too Large
Problem: Archive file is very large
Solutions:
- Remove unused skills from plugin.yaml
- Check for accidentally included large files
- Review skill directories for unnecessary data
- Consider splitting into multiple plugins
Build Fails with Permission Error
Problem: Cannot write to output directory
Solutions:
- Create output directory with proper permissions
- Check disk space availability
- Verify write access to output directory
- Try different output directory with
--output-dir
Architecture
Skill Category
Infrastructure – Plugin.build is part of the distribution layer, preparing plugins for deployment.
Design Principles
- Validation First: Check all handlers before packaging
- Complete Packages: Include all necessary dependencies
- Reproducible: Same source creates identical packages
- Verifiable: Checksums ensure package integrity
- Transparent: Detailed reporting of included files
- Flexible: Support multiple archive formats
Package Philosophy
The package includes everything needed to run the plugin:
- Skills: All command handlers and manifests
- Utilities: Core betty package for shared functionality
- Registries: Skill, command, and hook definitions
- Dependencies: Python requirements
- Documentation: README, LICENSE, CHANGELOG
This creates a self-contained, portable plugin distribution.
See Also
- plugin.sync – Generate plugin.yaml (SKILL.md)
- skill.define – Validate and register skills (SKILL.md)
- registry.update – Update registries (SKILL.md)
- Betty Distribution – Plugin marketplace guide (docs/distribution.md)
Dependencies
- plugin.sync: Generate plugin.yaml before building
- 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 tar.gz/zip support, validation, and checksums