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

View File

@@ -0,0 +1,457 @@
# meta.command - Command Creator Meta-Agent
Creates complete, production-ready command manifests from natural language descriptions.
## Purpose
The `meta.command` meta-agent transforms command descriptions into properly structured YAML manifests that can be registered in the Betty Framework Command Registry. It handles all the details of command creation including parameter validation, execution configuration, and documentation.
## What It Does
- ✅ Parses natural language command descriptions (Markdown or JSON)
- ✅ Generates complete command manifests in YAML format
- ✅ Validates command structure and execution types
- ✅ Supports all three execution types: agent, skill, workflow
- ✅ Creates proper parameter definitions with type validation
- ✅ Prepares commands for registration via `command.define` skill
- ✅ Supports traceability tracking
## Usage
```bash
python3 agents/meta.command/meta_command.py <description_file>
```
### With Traceability
```bash
python3 agents/meta.command/meta_command.py examples/api_validate_command.md \
--requirement-id "REQ-2025-042" \
--requirement-description "Create command for API validation" \
--rationale "Simplify API validation workflow for developers"
```
## Input Format
### Markdown Format
Create a description file with the following structure:
```markdown
# Name: /api-validate
# Version: 0.1.0
# Description: Validate API specifications against standards
# Execution Type: skill
# Target: api.validate
# Parameters:
- spec_file: string (required) - Path to API specification file
- format: enum (optional, default=openapi, values=[openapi,asyncapi,grpc]) - API specification format
- strict: boolean (optional, default=true) - Enable strict validation mode
# Execution Context:
- format: json
- timeout: 300
# Status: active
# Tags: api, validation, quality
```
### JSON Format
Alternatively, use JSON:
```json
{
"name": "/api-validate",
"version": "0.1.0",
"description": "Validate API specifications against standards",
"execution_type": "skill",
"target": "api.validate",
"parameters": [
{
"name": "spec_file",
"type": "string",
"required": true,
"description": "Path to API specification file"
},
{
"name": "format",
"type": "enum",
"values": ["openapi", "asyncapi", "grpc"],
"default": "openapi",
"description": "API specification format"
}
],
"execution_context": {
"format": "json",
"timeout": 300
},
"status": "active",
"tags": ["api", "validation", "quality"]
}
```
## Command Execution Types
### 1. Agent Execution
Use for complex, context-aware tasks requiring reasoning:
```markdown
# Name: /api-design
# Execution Type: agent
# Target: api.architect
# Description: Design a complete API architecture
```
**When to use:**
- Tasks requiring multi-step reasoning
- Context-aware decision making
- Complex analysis or design work
### 2. Skill Execution
Use for atomic, deterministic operations:
```markdown
# Name: /api-validate
# Execution Type: skill
# Target: api.validate
# Description: Validate API specifications
```
**When to use:**
- Direct, predictable operations
- Fast, single-purpose tasks
- Composable building blocks
### 3. Workflow Execution
Use for orchestrated multi-step processes:
```markdown
# Name: /api-pipeline
# Execution Type: workflow
# Target: workflows/api-pipeline.yaml
# Description: Execute full API development pipeline
```
**When to use:**
- Multi-agent/skill coordination
- Sequential or parallel task execution
- Complex business processes
## Parameter Types
### Supported Types
| Type | Description | Example |
|------|-------------|---------|
| `string` | Text values | `"api-spec.yaml"` |
| `integer` | Whole numbers | `42` |
| `boolean` | true/false | `true` |
| `enum` | Fixed set of values | `["openapi", "asyncapi"]` |
| `array` | Lists of values | `["tag1", "tag2"]` |
| `object` | Structured data | `{"key": "value"}` |
### Parameter Options
- `required: true/false` - Whether parameter is mandatory
- `default: value` - Default value if not provided
- `values: [...]` - Allowed values (for enum type)
- `description: "..."` - What the parameter does
## Examples
### Example 1: Simple Validation Command
**Input:** `examples/api-validate-cmd.md`
```markdown
# Name: /api-validate
# Description: Validate API specification files
# Execution Type: skill
# Target: api.validate
# Parameters:
- spec_file: string (required) - Path to specification file
- format: enum (optional, default=openapi, values=[openapi,asyncapi]) - Spec format
# Status: active
# Tags: api, validation
```
**Output:** `commands/api-validate.yaml`
```yaml
name: /api-validate
version: 0.1.0
description: Validate API specification files
parameters:
- name: spec_file
type: string
required: true
description: Path to specification file
- name: format
type: enum
values:
- openapi
- asyncapi
default: openapi
description: Spec format
execution:
type: skill
target: api.validate
status: active
tags:
- api
- validation
```
### Example 2: Agent-Based Design Command
**Input:** `examples/api-design-cmd.md`
```markdown
# Name: /api-design
# Description: Design a complete API architecture
# Execution Type: agent
# Target: api.architect
# Parameters:
- requirements: string (required) - Path to requirements document
- style: enum (optional, default=rest, values=[rest,graphql,grpc]) - API style
# Execution Context:
- reasoning_mode: iterative
- max_iterations: 10
# Status: active
# Tags: api, design, architecture
```
**Output:** `commands/api-design.yaml`
```yaml
name: /api-design
version: 0.1.0
description: Design a complete API architecture
parameters:
- name: requirements
type: string
required: true
description: Path to requirements document
- name: style
type: enum
values:
- rest
- graphql
- grpc
default: rest
description: API style
execution:
type: agent
target: api.architect
context:
reasoning_mode: iterative
max_iterations: 10
status: active
tags:
- api
- design
- architecture
```
### Example 3: Workflow Command
**Input:** `examples/deploy-cmd.md`
```markdown
# Name: /deploy
# Description: Deploy application to specified environment
# Execution Type: workflow
# Target: workflows/deploy-pipeline.yaml
# Parameters:
- environment: enum (required, values=[dev,staging,production]) - Target environment
- version: string (required) - Version to deploy
- skip_tests: boolean (optional, default=false) - Skip test execution
# Status: draft
# Tags: deployment, devops
```
## Output
The meta-agent creates:
1. **Command Manifest** - Complete YAML file in `commands/` directory
2. **Console Output** - Summary of created command
3. **Next Steps** - Instructions for registration
Example console output:
```
🎯 meta.command - Creating command from examples/api-validate-cmd.md
✨ Command '/api-validate' created successfully!
📄 Created file:
- commands/api-validate.yaml
✅ Command manifest is ready for registration
Name: /api-validate
Execution: skill → api.validate
Status: active
📝 Next steps:
1. Review the manifest: cat commands/api-validate.yaml
2. Register command: python3 skills/command.define/command_define.py commands/api-validate.yaml
3. Verify in registry: cat registry/commands.json
```
## Integration with command.define
After creating a command manifest, register it using the `command.define` skill:
```bash
# Register the command
python3 skills/command.define/command_define.py commands/api-validate.yaml
# Verify registration
cat registry/commands.json
```
The `command.define` skill will:
- Validate the manifest structure
- Check that the execution target exists
- Add the command to the Command Registry
- Make the command available for use
## Artifact Flow
```
┌──────────────────────────┐
│ Command Description │
│ (Markdown or JSON) │
└──────────┬───────────────┘
│ consumes
┌──────────────┐
│ meta.command │
└──────┬───────┘
│ produces
┌──────────────────────────┐
│ Command Manifest (YAML) │
│ commands/*.yaml │
└──────────┬───────────────┘
┌──────────────┐
│command.define│
│ (skill) │
└──────┬───────┘
┌──────────────────────────┐
│ Commands Registry │
│ registry/commands.json │
└──────────────────────────┘
```
## Command Naming Conventions
- ✅ Must start with `/` (e.g., `/api-validate`)
- ✅ Use kebab-case for multi-word commands (e.g., `/api-validate-all`)
- ✅ Be concise but descriptive
- ✅ Avoid generic names like `/run` or `/execute`
- ✅ Use domain prefix for related commands (e.g., `/api-*`, `/db-*`)
## Validation
The meta-agent validates:
- ✅ Required fields present (name, description, execution_type, target)
- ✅ Valid execution type (agent, skill, workflow)
- ✅ Command name starts with `/`
- ✅ Parameter types are valid
- ✅ Enum parameters have values defined
- ✅ Version follows semantic versioning
- ✅ Status is valid (draft, active, deprecated, archived)
## Error Handling
Common errors and solutions:
**Missing required fields:**
```
❌ Error: Missing required fields: execution_type, target
```
→ Add all required fields to your description
**Invalid execution type:**
```
❌ Error: Invalid execution type: service. Must be one of: agent, skill, workflow
```
→ Use only valid execution types
**Invalid parameter type:**
```
❌ Error: Invalid parameter type: float
```
→ Use supported parameter types
## Best Practices
1. **Clear Descriptions** - Write concise, actionable command descriptions
2. **Proper Parameters** - Define all parameters with types and validation
3. **Appropriate Execution Type** - Choose the right execution model (agent/skill/workflow)
4. **Meaningful Tags** - Add relevant tags for discoverability
5. **Version Management** - Start with 0.1.0, increment appropriately
6. **Status Lifecycle** - Use draft → active → deprecated → archived
## Files Generated
```
commands/
└── {command-name}.yaml # Command manifest
```
## Integration with Meta-Agents
The `meta.command` agent works alongside:
- **meta.skill** - Create skills that commands can execute
- **meta.agent** - Create agents that commands can delegate to
- **meta.artifact** - Define artifact types for command I/O
- **meta.compatibility** - Find compatible agents for command workflows
## Traceability
Track command creation with requirement metadata:
```bash
python3 agents/meta.command/meta_command.py examples/api-validate-cmd.md \
--requirement-id "REQ-2025-042" \
--requirement-description "API validation command" \
--issue-id "BETTY-123" \
--requested-by "dev-team" \
--rationale "Streamline API validation process"
```
View trace:
```bash
python3 betty/trace_cli.py show command.api_validate
```
## See Also
- **command.define skill** - Register command manifests
- **meta.skill** - Create skills for command execution
- **meta.agent** - Create agents for command delegation
- **Command Registry** - `registry/commands.json`
- **Command Infrastructure** - `docs/COMMAND_HOOK_INFRASTRUCTURE.md`

View File

@@ -0,0 +1,211 @@
name: meta.command
version: 0.1.0
description: |
Creates complete command manifests from natural language descriptions.
This meta-agent transforms command descriptions into production-ready command
manifests that can be registered in the Betty Framework Command Registry.
Command manifests can delegate to:
- Agents: For intelligent, context-aware operations
- Skills: For direct, atomic operations
- Workflows: For orchestrated multi-step processes
The meta.command agent generates properly structured YAML manifests with:
- Command name and metadata
- Parameter definitions with types and validation
- Execution configuration (agent/skill/workflow)
- Documentation and examples
After creation, commands can be registered using the command.define skill.
artifact_metadata:
consumes:
- type: command-description
file_pattern: "**/command_description.md"
content_type: "text/markdown"
description: "Natural language description of command requirements"
schema: "schemas/command-description.json"
produces:
- type: command-manifest
file_pattern: "commands/*.yaml"
content_type: "application/yaml"
description: "Complete command manifest ready for registration"
schema: "schemas/command-manifest.json"
- type: command-documentation
file_pattern: "commands/*/README.md"
content_type: "text/markdown"
description: "Command documentation with usage examples"
status: draft
reasoning_mode: iterative
capabilities:
- Transform natural language specifications into validated command manifests
- Recommend appropriate execution targets across agents, skills, and workflows
- Produce documentation and registration-ready assets for new commands
skills_available:
- command.define # Register command in registry
- artifact.define # Generate artifact metadata
permissions:
- filesystem:read
- filesystem:write
system_prompt: |
You are meta.command, the command creator for Betty Framework.
Your purpose is to transform natural language command descriptions into complete,
production-ready command manifests that follow Betty conventions.
## Automatic Pattern Detection
You automatically analyze command descriptions to determine the best pattern:
- COMMAND_ONLY: Simple 1-3 step orchestration
- SKILL_AND_COMMAND: Complex 10+ step tasks requiring a skill backend
- SKILL_ONLY: Reusable building blocks without user-facing command
- HYBRID: Commands that orchestrate multiple existing skills
Analysis factors:
- Step count (from numbered/bulleted lists)
- Complexity keywords (analyze, optimize, evaluate, complex, etc.)
- Autonomy requirements (intelligent, adaptive, sophisticated, etc.)
- Reusability indicators (composable, shared, library, etc.)
When you detect high complexity or autonomy needs, you recommend creating
the skill first before the command wrapper.
## Your Workflow
1. **Parse Description** - Understand command requirements
- Extract command name, purpose, and target audience
- Identify required parameters and their types
- Determine execution type (agent, skill, or workflow)
- Understand execution context needs
2. **Generate Command Manifest** - Create complete YAML definition
- Proper naming (must start with /)
- Complete parameter specifications with types, validation, defaults
- Execution configuration pointing to correct target
- Version and status information
- Appropriate tags
3. **Validate Structure** - Ensure manifest completeness
- All required fields present
- Valid execution type
- Proper parameter type definitions
- Target exists (agent/skill/workflow)
4. **Generate Documentation** - Create usage guide
- Command purpose and use cases
- Parameter descriptions with examples
- Expected outputs
- Integration examples
5. **Ready for Registration** - Prepare for command.define
- Validate against schema
- Check for naming conflicts
- Ensure target availability
## Command Execution Types
**agent** - Delegates to an intelligent agent
- Use for: Complex, context-aware tasks requiring reasoning
- Example: `/api-design` → `api.architect` agent
- Benefits: Full agent capabilities, multi-step reasoning
- Target format: `agent_name` (e.g., "api.architect")
**skill** - Calls a skill directly
- Use for: Atomic, deterministic operations
- Example: `/api-validate` → `api.validate` skill
- Benefits: Fast, predictable, composable
- Target format: `skill.name` (e.g., "api.validate")
**workflow** - Executes a workflow
- Use for: Orchestrated multi-step processes
- Example: `/api-pipeline` → workflow YAML
- Benefits: Coordinated agent/skill execution
- Target format: Path to workflow file
## Parameter Types
Supported parameter types:
- `string` - Text values
- `integer` - Whole numbers
- `boolean` - true/false
- `enum` - Fixed set of allowed values
- `array` - Lists of values
- `object` - Structured data
Each parameter can have:
- `name` - Parameter identifier
- `type` - Data type
- `required` - Whether mandatory (true/false)
- `default` - Default value if not provided
- `description` - What the parameter does
- `values` - Allowed values (for enum type)
## Command Naming Conventions
- Must start with `/` (e.g., `/api-validate`)
- Use kebab-case for multi-word commands
- Should be concise but descriptive
- Avoid generic names like `/run` or `/execute`
## Command Status
- `draft` - Under development, not ready for production
- `active` - Production-ready and available
- `deprecated` - Still works but discouraged
- `archived` - No longer available
## Structure Example
```yaml
name: /api-validate
version: 0.1.0
description: "Validate API specifications against standards"
parameters:
- name: spec_file
type: string
required: true
description: "Path to API specification file"
- name: format
type: enum
values: [openapi, asyncapi, grpc]
default: openapi
description: "API specification format"
execution:
type: skill
target: api.validate
context:
format: json
status: active
tags: [api, validation, quality]
```
## Quality Standards
- ✅ Follows Betty command conventions
- ✅ Proper parameter definitions with validation
- ✅ Correct execution type and target
- ✅ Clear, actionable descriptions
- ✅ Appropriate status and tags
- ✅ Ready for command.define registration
## Integration with command.define
After generating the command manifest, users should:
1. Review the generated YAML file
2. Test the command locally
3. Register using: `python3 skills/command.define/command_define.py <manifest.yaml>`
4. Verify registration in `registry/commands.json`
Remember: You're creating user-facing commands that make Betty's capabilities
accessible. Make commands intuitive, well-documented, and easy to use.

View File

@@ -0,0 +1,761 @@
#!/usr/bin/env python3
"""
meta.command - Command Creator Meta-Agent
Generates command manifests from natural language descriptions.
Usage:
python3 agents/meta.command/meta_command.py <command_description_file>
Examples:
python3 agents/meta.command/meta_command.py examples/api_validate_command.md
python3 agents/meta.command/meta_command.py examples/deploy_command.json
"""
import os
import sys
import json
import yaml
import re
from pathlib import Path
from typing import Dict, List, Any, Optional
# Add parent directory to path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
from betty.config import (
BASE_DIR,
COMMANDS_REGISTRY_FILE,
)
from betty.enums import CommandExecutionType, CommandStatus
from betty.logging_utils import setup_logger
from betty.traceability import get_tracer, RequirementInfo
logger = setup_logger(__name__)
# Import artifact validation from artifact.define skill
try:
import importlib.util
artifact_define_path = Path(__file__).parent.parent.parent / "skills" / "artifact.define" / "artifact_define.py"
spec = importlib.util.spec_from_file_location("artifact_define", artifact_define_path)
artifact_define_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(artifact_define_module)
validate_artifact_type = artifact_define_module.validate_artifact_type
KNOWN_ARTIFACT_TYPES = artifact_define_module.KNOWN_ARTIFACT_TYPES
ARTIFACT_VALIDATION_AVAILABLE = True
except Exception as e:
ARTIFACT_VALIDATION_AVAILABLE = False
class CommandCreator:
"""Creates command manifests from descriptions"""
VALID_EXECUTION_TYPES = ["agent", "skill", "workflow"]
VALID_STATUSES = ["draft", "active", "deprecated", "archived"]
VALID_PARAMETER_TYPES = ["string", "integer", "boolean", "enum", "array", "object"]
# Keywords for complexity analysis
AUTONOMY_KEYWORDS = [
"analyze", "optimize", "decide", "evaluate", "assess",
"complex", "multi-step", "autonomous", "intelligent",
"adaptive", "sophisticated", "advanced", "comprehensive"
]
REUSABILITY_KEYWORDS = [
"reusable", "composable", "building block", "library",
"utility", "helper", "shared", "common", "core"
]
def __init__(self, base_dir: str = BASE_DIR):
"""Initialize command creator"""
self.base_dir = Path(base_dir)
self.commands_dir = self.base_dir / "commands"
def parse_description(self, description_path: str) -> Dict[str, Any]:
"""
Parse command description from Markdown or JSON file
Args:
description_path: Path to description file
Returns:
Dict with command configuration
"""
path = Path(description_path)
if not path.exists():
raise FileNotFoundError(f"Description file not found: {description_path}")
# Read file
content = path.read_text()
# Try JSON first
if path.suffix == ".json":
return json.loads(content)
# Parse Markdown format
cmd_desc = {}
# Extract fields using regex patterns
patterns = {
"name": r"#\s*Name:\s*(.+)",
"version": r"#\s*Version:\s*(.+)",
"description": r"#\s*Description:\s*(.+)",
"execution_type": r"#\s*Execution\s*Type:\s*(.+)",
"target": r"#\s*Target:\s*(.+)",
"status": r"#\s*Status:\s*(.+)",
}
for field, pattern in patterns.items():
match = re.search(pattern, content, re.IGNORECASE)
if match:
value = match.group(1).strip()
cmd_desc[field] = value
# Parse parameters section
params_section = re.search(
r"#\s*Parameters:\s*\n(.*?)(?=\n#|\Z)",
content,
re.DOTALL | re.IGNORECASE
)
if params_section:
cmd_desc["parameters"] = self._parse_parameters(params_section.group(1))
# Parse tags
tags_match = re.search(r"#\s*Tags:\s*(.+)", content, re.IGNORECASE)
if tags_match:
tags_str = tags_match.group(1).strip()
# Parse comma-separated or bracket-enclosed tags
if tags_str.startswith("[") and tags_str.endswith("]"):
tags_str = tags_str[1:-1]
cmd_desc["tags"] = [t.strip() for t in tags_str.split(",")]
# Parse execution context
context_section = re.search(
r"#\s*Execution\s*Context:\s*\n(.*?)(?=\n#|\Z)",
content,
re.DOTALL | re.IGNORECASE
)
if context_section:
cmd_desc["execution_context"] = self._parse_context(context_section.group(1))
# Parse artifact metadata sections
produces_section = re.search(
r"#\s*Produces\s*Artifacts:\s*\n(.*?)(?=\n#|\Z)",
content,
re.DOTALL | re.IGNORECASE
)
if produces_section:
cmd_desc["artifact_produces"] = self._parse_artifact_list(produces_section.group(1))
consumes_section = re.search(
r"#\s*Consumes\s*Artifacts:\s*\n(.*?)(?=\n#|\Z)",
content,
re.DOTALL | re.IGNORECASE
)
if consumes_section:
cmd_desc["artifact_consumes"] = self._parse_artifact_list(consumes_section.group(1))
# Validate required fields
required = ["name", "description", "execution_type", "target"]
missing = [f for f in required if f not in cmd_desc]
if missing:
raise ValueError(f"Missing required fields: {', '.join(missing)}")
# Validate execution type
if cmd_desc["execution_type"].lower() not in self.VALID_EXECUTION_TYPES:
raise ValueError(
f"Invalid execution type: {cmd_desc['execution_type']}. "
f"Must be one of: {', '.join(self.VALID_EXECUTION_TYPES)}"
)
# Ensure command name starts with /
if not cmd_desc["name"].startswith("/"):
cmd_desc["name"] = "/" + cmd_desc["name"]
# Set defaults
if "version" not in cmd_desc:
cmd_desc["version"] = "0.1.0"
if "status" not in cmd_desc:
cmd_desc["status"] = "draft"
if "parameters" not in cmd_desc:
cmd_desc["parameters"] = []
return cmd_desc
def _parse_parameters(self, params_text: str) -> List[Dict[str, Any]]:
"""Parse parameters from markdown text"""
parameters = []
# Match parameter blocks
# Format: - name: type (required/optional) - description
param_pattern = r"-\s+(\w+):\s+(\w+)(?:\s+\(([^)]+)\))?\s+-\s+(.+?)(?=\n-|\n#|\Z)"
matches = re.finditer(param_pattern, params_text, re.DOTALL)
for match in matches:
name, param_type, modifiers, description = match.groups()
param = {
"name": name.strip(),
"type": param_type.strip(),
"description": description.strip()
}
# Parse modifiers (required, optional, default=value)
if modifiers:
modifiers = modifiers.lower()
param["required"] = "required" in modifiers
# Extract default value
default_match = re.search(r"default[=:]\s*([^,\s]+)", modifiers)
if default_match:
default_val = default_match.group(1)
# Convert types
if param_type == "integer":
default_val = int(default_val)
elif param_type == "boolean":
default_val = default_val.lower() in ("true", "yes", "1")
param["default"] = default_val
# Extract enum values
values_match = re.search(r"values[=:]\s*\[([^\]]+)\]", modifiers)
if values_match:
param["values"] = [v.strip() for v in values_match.group(1).split(",")]
parameters.append(param)
return parameters
def _parse_context(self, context_text: str) -> Dict[str, Any]:
"""Parse execution context from markdown text"""
context = {}
# Simple key: value parsing
for line in context_text.split("\n"):
line = line.strip()
if not line or line.startswith("#"):
continue
match = re.match(r"-\s*(\w+):\s*(.+)", line)
if match:
key, value = match.groups()
# Try to parse as JSON for complex values
try:
context[key] = json.loads(value)
except (json.JSONDecodeError, ValueError):
context[key] = value.strip()
return context
def _parse_artifact_list(self, artifact_text: str) -> List[str]:
"""Parse artifact list from markdown text"""
artifacts = []
for line in artifact_text.split("\n"):
line = line.strip()
if not line or line.startswith("#"):
continue
# Match lines starting with - or *
match = re.match(r"[-*]\s*`?([a-z0-9-]+)`?", line)
if match:
artifacts.append(match.group(1))
return artifacts
def analyze_complexity(self, cmd_desc: Dict[str, Any], full_content: str = "") -> Dict[str, Any]:
"""
Analyze command complexity and recommend pattern
Args:
cmd_desc: Parsed command description
full_content: Full description file content for analysis
Returns:
Dict with complexity analysis and pattern recommendation
"""
analysis = {
"step_count": 0,
"complexity": "low",
"autonomy_level": "none",
"reusability": "low",
"recommended_pattern": "COMMAND_ONLY",
"should_create_skill": False,
"reasoning": []
}
# Count steps from description
# Look for numbered lists, bullet points, or explicit step mentions
step_patterns = [
r"^\s*\d+\.\s+", # Numbered lists
r"^\s*[-*]\s+", # Bullet points
r"\bstep\s+\d+\b", # Explicit "step N"
]
lines = full_content.split("\n")
step_count = 0
for line in lines:
for pattern in step_patterns:
if re.search(pattern, line, re.IGNORECASE):
step_count += 1
break
analysis["step_count"] = step_count
# Analyze content for keywords
content_lower = full_content.lower()
desc_lower = cmd_desc.get("description", "").lower()
combined = content_lower + " " + desc_lower
# Check autonomy keywords
autonomy_matches = [kw for kw in self.AUTONOMY_KEYWORDS if kw in combined]
if len(autonomy_matches) >= 3:
analysis["autonomy_level"] = "high"
elif len(autonomy_matches) >= 1:
analysis["autonomy_level"] = "medium"
else:
analysis["autonomy_level"] = "low"
# Check reusability keywords
reusability_matches = [kw for kw in self.REUSABILITY_KEYWORDS if kw in combined]
if len(reusability_matches) >= 2:
analysis["reusability"] = "high"
elif len(reusability_matches) >= 1:
analysis["reusability"] = "medium"
# Determine complexity
if step_count >= 10:
analysis["complexity"] = "high"
elif step_count >= 4:
analysis["complexity"] = "medium"
else:
analysis["complexity"] = "low"
# Estimate lines of logic (rough heuristic)
instruction_lines = sum(1 for line in lines if line.strip() and not line.strip().startswith("#"))
if instruction_lines > 50:
analysis["complexity"] = "high"
# Decide pattern based on decision tree
if step_count >= 10 or analysis["complexity"] == "high":
analysis["recommended_pattern"] = "SKILL_AND_COMMAND"
analysis["should_create_skill"] = True
analysis["reasoning"].append(f"High complexity: {step_count} steps detected")
elif analysis["autonomy_level"] == "high":
analysis["recommended_pattern"] = "SKILL_AND_COMMAND"
analysis["should_create_skill"] = True
analysis["reasoning"].append(f"High autonomy: matched keywords {autonomy_matches[:3]}")
elif analysis["reusability"] == "high":
if step_count <= 3:
analysis["recommended_pattern"] = "SKILL_ONLY"
analysis["should_create_skill"] = True
analysis["reasoning"].append("High reusability but low complexity: create skill only")
else:
analysis["recommended_pattern"] = "SKILL_AND_COMMAND"
analysis["should_create_skill"] = True
analysis["reasoning"].append(f"High reusability with {step_count} steps: create both")
elif step_count >= 4 and step_count <= 9:
# Medium complexity - could go either way
if analysis["autonomy_level"] == "medium":
analysis["recommended_pattern"] = "SKILL_AND_COMMAND"
analysis["should_create_skill"] = True
analysis["reasoning"].append(f"Medium complexity ({step_count} steps) with some autonomy needs")
else:
analysis["recommended_pattern"] = "COMMAND_ONLY"
analysis["reasoning"].append(f"Medium complexity ({step_count} steps) but simple logic: inline is fine")
else:
# Low complexity - command only
analysis["recommended_pattern"] = "COMMAND_ONLY"
analysis["reasoning"].append(f"Low complexity ({step_count} steps): inline orchestration is sufficient")
# Check if execution type already specifies skill
if cmd_desc.get("execution_type") == "skill":
analysis["recommended_pattern"] = "SKILL_AND_COMMAND"
analysis["should_create_skill"] = True
analysis["reasoning"].append("Execution type explicitly set to 'skill'")
return analysis
def generate_command_manifest(self, cmd_desc: Dict[str, Any]) -> str:
"""
Generate command manifest YAML
Args:
cmd_desc: Parsed command description
Returns:
YAML string
"""
manifest = {
"name": cmd_desc["name"],
"version": cmd_desc["version"],
"description": cmd_desc["description"]
}
# Add parameters if present
if cmd_desc.get("parameters"):
manifest["parameters"] = cmd_desc["parameters"]
# Add execution configuration
execution = {
"type": cmd_desc["execution_type"],
"target": cmd_desc["target"]
}
if cmd_desc.get("execution_context"):
execution["context"] = cmd_desc["execution_context"]
manifest["execution"] = execution
# Add status
manifest["status"] = cmd_desc.get("status", "draft")
# Add tags if present
if cmd_desc.get("tags"):
manifest["tags"] = cmd_desc["tags"]
# Add artifact metadata if present
if cmd_desc.get("artifact_produces") or cmd_desc.get("artifact_consumes"):
artifact_metadata = {}
if cmd_desc.get("artifact_produces"):
artifact_metadata["produces"] = [
{"type": art_type} for art_type in cmd_desc["artifact_produces"]
]
if cmd_desc.get("artifact_consumes"):
artifact_metadata["consumes"] = [
{"type": art_type, "required": True}
for art_type in cmd_desc["artifact_consumes"]
]
manifest["artifact_metadata"] = artifact_metadata
return yaml.dump(manifest, default_flow_style=False, sort_keys=False)
def validate_artifacts(self, cmd_desc: Dict[str, Any]) -> List[str]:
"""
Validate that artifact types exist in the known registry.
Args:
cmd_desc: Parsed command description
Returns:
List of warning messages
"""
warnings = []
if not ARTIFACT_VALIDATION_AVAILABLE:
warnings.append(
"Artifact validation skipped: artifact.define skill not available"
)
return warnings
# Validate produced artifacts
for artifact_type in cmd_desc.get("artifact_produces", []):
is_valid, warning = validate_artifact_type(artifact_type)
if not is_valid and warning:
warnings.append(f"Produces: {warning}")
# Validate consumed artifacts
for artifact_type in cmd_desc.get("artifact_consumes", []):
is_valid, warning = validate_artifact_type(artifact_type)
if not is_valid and warning:
warnings.append(f"Consumes: {warning}")
return warnings
def validate_target(self, cmd_desc: Dict[str, Any]) -> List[str]:
"""
Validate that the target skill or agent exists.
Args:
cmd_desc: Parsed command description
Returns:
List of warning messages
"""
warnings = []
execution_type = cmd_desc.get("execution_type", "").lower()
target = cmd_desc.get("target", "")
if execution_type == "skill":
# Check if skill exists in registry or skills directory
skill_registry = self.base_dir / "registry" / "skills.json"
skill_dir = self.base_dir / "skills" / target.replace(".", "/")
skill_exists = False
if skill_registry.exists():
try:
with open(skill_registry) as f:
registry = json.load(f)
if target in registry.get("skills", {}):
skill_exists = True
except Exception:
pass
if not skill_exists and not skill_dir.exists():
warnings.append(
f"Target skill '{target}' not found in registry or skills directory. "
f"You may need to create it using meta.skill first."
)
elif execution_type == "agent":
# Check if agent exists in agents directory
agent_dir = self.base_dir / "agents" / target
if not agent_dir.exists():
warnings.append(
f"Target agent '{target}' not found in agents directory. "
f"You may need to create it using meta.agent first."
)
return warnings
def create_command(
self,
description_path: str,
requirement: Optional[RequirementInfo] = None
) -> Dict[str, Any]:
"""
Create command manifest from description file
Args:
description_path: Path to description file
requirement: Optional requirement information for traceability
Returns:
Dict with creation results
"""
try:
print(f"🎯 meta.command - Creating command from {description_path}\n")
# Read full content for analysis
with open(description_path, 'r') as f:
full_content = f.read()
# Parse description
cmd_desc = self.parse_description(description_path)
# Validate artifacts
artifact_warnings = self.validate_artifacts(cmd_desc)
if artifact_warnings:
print("\n⚠️ Artifact Validation Warnings:")
for warning in artifact_warnings:
print(f" {warning}")
print()
# Validate target skill/agent
target_warnings = self.validate_target(cmd_desc)
if target_warnings:
print("\n⚠️ Target Validation Warnings:")
for warning in target_warnings:
print(f" {warning}")
print()
# Analyze complexity and recommend pattern
analysis = self.analyze_complexity(cmd_desc, full_content)
# Display analysis
print(f"📊 Complexity Analysis:")
print(f" Steps detected: {analysis['step_count']}")
print(f" Complexity: {analysis['complexity']}")
print(f" Autonomy level: {analysis['autonomy_level']}")
print(f" Reusability: {analysis['reusability']}")
print(f"\n💡 Recommended Pattern: {analysis['recommended_pattern']}")
for reason in analysis['reasoning']:
print(f"{reason}")
print()
# Generate manifest YAML
manifest_yaml = self.generate_command_manifest(cmd_desc)
# Ensure commands directory exists
self.commands_dir.mkdir(parents=True, exist_ok=True)
# Determine output filename
# Remove leading / and replace spaces/special chars with hyphens
filename = cmd_desc["name"].lstrip("/").replace(" ", "-").lower()
filename = re.sub(r"[^a-z0-9-]", "", filename)
manifest_file = self.commands_dir / f"{filename}.yaml"
# Write manifest file
manifest_file.write_text(manifest_yaml)
print(f"✨ Command '{cmd_desc['name']}' created successfully!\n")
print(f"📄 Created file:")
print(f" - {manifest_file}\n")
print(f"✅ Command manifest is ready for registration")
print(f" Name: {cmd_desc['name']}")
print(f" Execution: {cmd_desc['execution_type']}{cmd_desc['target']}")
print(f" Status: {cmd_desc.get('status', 'draft')}\n")
# Display skill creation recommendation if needed
if analysis['should_create_skill']:
print(f"⚠️ RECOMMENDATION: Create the skill first!")
print(f" Pattern: {analysis['recommended_pattern']}")
print(f"\n This command delegates to a skill ({cmd_desc['target']}),")
print(f" but that skill may not exist yet.\n")
print(f" Suggested workflow:")
print(f" 1. Create skill: python3 agents/meta.skill/meta_skill.py <skill-description.md>")
print(f" - Skill should implement: {cmd_desc['target']}")
print(f" - Include all complex logic from the command description")
print(f" 2. Test skill: python3 skills/{cmd_desc['target'].replace('.', '/')}/{cmd_desc['target'].replace('.', '_')}.py")
print(f" 3. Review this command manifest: cat {manifest_file}")
print(f" 4. Register command: python3 skills/command.define/command_define.py {manifest_file}")
print(f" 5. Verify in registry: cat registry/commands.json")
print(f"\n See docs/SKILL_COMMAND_DECISION_TREE.md for pattern details\n")
else:
print(f"📝 Next steps:")
print(f" 1. Review the manifest: cat {manifest_file}")
print(f" 2. Register command: python3 skills/command.define/command_define.py {manifest_file}")
print(f" 3. Verify in registry: cat registry/commands.json")
result = {
"ok": True,
"status": "success",
"command_name": cmd_desc["name"],
"manifest_file": str(manifest_file),
"complexity_analysis": analysis,
"artifact_warnings": artifact_warnings,
"target_warnings": target_warnings
}
# Log traceability if requirement provided
trace_id = None
if requirement:
try:
tracer = get_tracer()
# Create component ID from command name
component_id = f"command.{filename.replace('-', '_')}"
trace_id = tracer.log_creation(
component_id=component_id,
component_name=cmd_desc["name"],
component_type="command",
component_version=cmd_desc["version"],
component_file_path=str(manifest_file),
input_source_path=description_path,
created_by_tool="meta.command",
created_by_version="0.1.0",
requirement=requirement,
tags=["command", "auto-generated"] + cmd_desc.get("tags", []),
project="Betty Framework"
)
# Log validation check
validation_details = {
"checks_performed": [
{"name": "command_structure", "status": "passed"},
{"name": "execution_type_validation", "status": "passed",
"message": f"Valid execution type: {cmd_desc['execution_type']}"},
{"name": "name_validation", "status": "passed",
"message": f"Command name follows convention: {cmd_desc['name']}"}
]
}
# Check parameters
if cmd_desc.get("parameters"):
validation_details["checks_performed"].append({
"name": "parameters_validation",
"status": "passed",
"message": f"Validated {len(cmd_desc['parameters'])} parameters"
})
tracer.log_verification(
component_id=component_id,
check_type="validation",
tool="meta.command",
result="passed",
details=validation_details
)
result["trace_id"] = trace_id
result["component_id"] = component_id
except Exception as e:
print(f"⚠️ Warning: Could not log traceability: {e}")
return result
except Exception as e:
print(f"❌ Error creating command: {e}")
logger.error(f"Error creating command: {e}", exc_info=True)
return {
"ok": False,
"status": "failed",
"error": str(e)
}
def main():
"""CLI entry point"""
import argparse
parser = argparse.ArgumentParser(
description="meta.command - Create command manifests from descriptions"
)
parser.add_argument(
"description",
help="Path to command description file (.md or .json)"
)
# Traceability arguments
parser.add_argument(
"--requirement-id",
help="Requirement identifier (e.g., REQ-2025-001)"
)
parser.add_argument(
"--requirement-description",
help="What this command accomplishes"
)
parser.add_argument(
"--requirement-source",
help="Source document"
)
parser.add_argument(
"--issue-id",
help="Issue tracking ID (e.g., JIRA-123)"
)
parser.add_argument(
"--requested-by",
help="Who requested this"
)
parser.add_argument(
"--rationale",
help="Why this is needed"
)
args = parser.parse_args()
# Create requirement info if provided
requirement = None
if args.requirement_id and args.requirement_description:
requirement = RequirementInfo(
id=args.requirement_id,
description=args.requirement_description,
source=args.requirement_source,
issue_id=args.issue_id,
requested_by=args.requested_by,
rationale=args.rationale
)
creator = CommandCreator()
result = creator.create_command(args.description, requirement=requirement)
# Display traceability info if available
if result.get("trace_id"):
print(f"\n📝 Traceability: {result['trace_id']}")
print(f" View trace: python3 betty/trace_cli.py show {result['component_id']}")
sys.exit(0 if result.get("ok") else 1)
if __name__ == "__main__":
main()