Add skill testing workflow and clarify Nix integration
- Add scripts/test-skill.sh for testing skills without deploying - Update AGENTS.md with accurate Nix integration details - Explain agent config nuance (embedded vs symlinked) - Fix quick_validate.py missing skill_md variable - Update README.md to match documentation changes
This commit is contained in:
178
AGENTS.md
178
AGENTS.md
@@ -29,7 +29,8 @@ This repository serves as a foundation for any Opencode-compatible skill or agen
|
||||
|
||||
```
|
||||
.
|
||||
├── agent/ # AI agent configurations (chiron.md)
|
||||
├── agent/ # Agent definitions (agents.json)
|
||||
├── prompts/ # Agent system prompts (chiron.txt, chiron-forge.txt)
|
||||
├── context/ # User profiles and preferences
|
||||
├── command/ # Custom command definitions
|
||||
├── skill/ # Opencode Agent Skills (8 skills)
|
||||
@@ -41,32 +42,10 @@ This repository serves as a foundation for any Opencode-compatible skill or agen
|
||||
│ ├── mem0-memory/
|
||||
│ ├── research/
|
||||
│ └── knowledge-management/
|
||||
├── .beads/ # Issue tracking database
|
||||
├── scripts/ # Repository-level utility scripts
|
||||
└── AGENTS.md # This file
|
||||
```
|
||||
|
||||
## Issue Tracking with Beads
|
||||
|
||||
This project uses **bd** (beads) for AI-native issue tracking.
|
||||
|
||||
### Quick Reference
|
||||
|
||||
```bash
|
||||
bd ready # Find available work
|
||||
bd show <id> # View issue details
|
||||
bd update <id> --status in_progress # Claim work
|
||||
bd close <id> # Complete work
|
||||
bd sync # Sync with git
|
||||
bd list # View all issues
|
||||
bd create "title" # Create new issue
|
||||
```
|
||||
|
||||
### Beads Workflow Integration
|
||||
|
||||
- Issues live in `.beads/` directory (git-tracked)
|
||||
- Auto-syncs with commits
|
||||
- CLI-first design for AI agents
|
||||
- No web UI needed
|
||||
|
||||
## Skill Development
|
||||
|
||||
@@ -235,37 +214,43 @@ items:
|
||||
|
||||
## Nix Flake Integration
|
||||
|
||||
This repository is designed to be consumed by a Nix flake via home-manager.
|
||||
This repository is the central source for all Opencode configuration, consumed as a **non-flake input** by your NixOS configuration.
|
||||
|
||||
### Expected Deployment Pattern
|
||||
### Integration Reference
|
||||
|
||||
**NixOS config location**: `~/p/NIX/nixos-config/home/features/coding/opencode.nix`
|
||||
|
||||
**Flake input definition** (in `flake.nix`):
|
||||
```nix
|
||||
# In your flake.nix or home.nix
|
||||
xdg.configFile."opencode" = {
|
||||
source = /path/to/AGENTS;
|
||||
recursive = true;
|
||||
agents = {
|
||||
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
|
||||
flake = false; # Pure files, not a Nix flake
|
||||
};
|
||||
```
|
||||
|
||||
This deploys:
|
||||
- `agent/` → `~/.config/opencode/agent/`
|
||||
- `skill/` → `~/.config/opencode/skill/`
|
||||
- `context/` → `~/.config/opencode/context/`
|
||||
- `command/` → `~/.config/opencode/command/`
|
||||
### Deployment Mapping
|
||||
|
||||
### Best Practices for Nix
|
||||
| Source | Deployed To | Method |
|
||||
|--------|-------------|--------|
|
||||
| `skill/` | `~/.config/opencode/skill/` | xdg.configFile (symlink) |
|
||||
| `context/` | `~/.config/opencode/context/` | xdg.configFile (symlink) |
|
||||
| `command/` | `~/.config/opencode/command/` | xdg.configFile (symlink) |
|
||||
| `prompts/` | `~/.config/opencode/prompts/` | xdg.configFile (symlink) |
|
||||
| `agent/agents.json` | `programs.opencode.settings.agent` | **Embedded into config.json** |
|
||||
|
||||
### Important: Agent Configuration Nuance
|
||||
|
||||
The `agent/` directory is **NOT** deployed as files to `~/.config/opencode/agent/`. Instead, `agents.json` is read at Nix evaluation time and embedded directly into the opencode `config.json` via:
|
||||
|
||||
```nix
|
||||
programs.opencode.settings.agent = builtins.fromJSON (builtins.readFile "${inputs.agents}/agent/agents.json");
|
||||
```
|
||||
|
||||
**Implications**:
|
||||
- Agent changes require `home-manager switch` to take effect
|
||||
- Skills, context, and commands are symlinked (changes visible immediately after rebuild)
|
||||
- The `prompts/` directory is referenced by `agents.json` via `{file:./prompts/chiron.txt}` syntax
|
||||
|
||||
1. **Keep original structure** - Don't rename directories; Opencode expects this layout
|
||||
2. **Use recursive = true** - Required for directory deployment
|
||||
3. **Exclude .git and .beads** - These are development artifacts:
|
||||
```nix
|
||||
xdg.configFile."opencode" = {
|
||||
source = /path/to/AGENTS;
|
||||
recursive = true;
|
||||
# Or filter with lib.cleanSource
|
||||
};
|
||||
```
|
||||
4. **No absolute paths in configs** - All references should be relative
|
||||
|
||||
## Quality Gates
|
||||
|
||||
@@ -282,41 +267,78 @@ Before committing changes, verify:
|
||||
|
||||
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
||||
|
||||
### MANDATORY WORKFLOW
|
||||
|
||||
1. **File issues for remaining work** - Create beads issues for anything that needs follow-up
|
||||
2. **Run quality gates** - Validate modified skills, check file structure
|
||||
3. **Update issue status** - Close finished work, update in-progress items
|
||||
4. **PUSH TO REMOTE** - This is MANDATORY:
|
||||
```bash
|
||||
git pull --rebase
|
||||
bd sync
|
||||
git push
|
||||
git status # MUST show "up to date with origin"
|
||||
```
|
||||
5. **Clean up** - Clear stashes, prune remote branches
|
||||
6. **Verify** - All changes committed AND pushed
|
||||
7. **Hand off** - Provide context for next session
|
||||
## Testing Skills
|
||||
|
||||
### CRITICAL RULES
|
||||
Since this repo deploys via Nix/home-manager, changes require a rebuild to appear in `~/.config/opencode/`. Use these methods to test skills during development.
|
||||
|
||||
- Work is NOT complete until `git push` succeeds
|
||||
- NEVER stop before pushing - that leaves work stranded locally
|
||||
- NEVER say "ready to push when you are" - YOU must push
|
||||
- If push fails, resolve and retry until it succeeds
|
||||
### Method 1: XDG_CONFIG_HOME Override (Recommended)
|
||||
|
||||
## Common Operations
|
||||
|
||||
### Test a Skill Locally
|
||||
Test skills by pointing opencode to this repository directly:
|
||||
|
||||
```bash
|
||||
# Validate structure
|
||||
# From the AGENTS repository root
|
||||
cd ~/p/AI/AGENTS
|
||||
|
||||
# List skills loaded from this repo (not the deployed ones)
|
||||
XDG_CONFIG_HOME=. opencode debug skill
|
||||
|
||||
# Run an interactive session with development skills
|
||||
XDG_CONFIG_HOME=. opencode
|
||||
|
||||
# Or use the convenience script
|
||||
./scripts/test-skill.sh # List all development skills
|
||||
./scripts/test-skill.sh task-management # Validate specific skill
|
||||
./scripts/test-skill.sh --run # Launch interactive session
|
||||
```
|
||||
|
||||
**Note**: The convenience script creates a temporary directory with proper symlinks since opencode expects `$XDG_CONFIG_HOME/opencode/skill/` structure.
|
||||
|
||||
### Method 2: Project-Local Skills
|
||||
|
||||
For quick iteration on a single skill, use `.opencode/skill/` in any project:
|
||||
|
||||
```bash
|
||||
cd /path/to/any/project
|
||||
mkdir -p .opencode/skill/
|
||||
|
||||
# Symlink the skill you're developing
|
||||
ln -s ~/p/AI/AGENTS/skill/my-skill .opencode/skill/
|
||||
|
||||
# Skills in .opencode/skill/ are auto-discovered alongside global skills
|
||||
opencode debug skill
|
||||
```
|
||||
|
||||
### Method 3: Validation Only
|
||||
|
||||
Validate skill structure without running opencode:
|
||||
|
||||
```bash
|
||||
# Validate a single skill
|
||||
python3 skill/skill-creator/scripts/quick_validate.py skill/<skill-name>
|
||||
|
||||
# Check skill triggers by reading SKILL.md frontmatter
|
||||
grep -A5 "^description:" skill/<skill-name>/SKILL.md
|
||||
# Validate all skills
|
||||
for dir in skill/*/; do
|
||||
python3 skill/skill-creator/scripts/quick_validate.py "$dir"
|
||||
done
|
||||
```
|
||||
|
||||
### Verification Commands
|
||||
|
||||
```bash
|
||||
# List all loaded skills (shows name, description, location)
|
||||
opencode debug skill
|
||||
|
||||
# Show resolved configuration
|
||||
opencode debug config
|
||||
|
||||
# Show where opencode looks for files
|
||||
opencode debug paths
|
||||
```
|
||||
|
||||
|
||||
## Common Operations
|
||||
|
||||
### Create New Skill
|
||||
|
||||
```bash
|
||||
@@ -340,11 +362,10 @@ Edit `context/profile.md` to update:
|
||||
|
||||
### Modify Agent Behavior
|
||||
|
||||
Edit `agent/chiron.md` to adjust:
|
||||
- Skill routing logic
|
||||
- Communication protocols
|
||||
- Daily rhythm support
|
||||
- Operating principles
|
||||
Edit `agent/agents.json` to adjust agent definitions, and `prompts/*.txt` for system prompts:
|
||||
- `agent/agents.json` - Agent names, models, permissions
|
||||
- `prompts/chiron.txt` - Chiron (Plan Mode) system prompt
|
||||
- `prompts/chiron-forge.txt` - Chiron-Forge (Worker Mode) system prompt
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
@@ -352,8 +373,7 @@ Edit `agent/chiron.md` to adjust:
|
||||
**Workflow patterns**: `skill/skill-creator/references/workflows.md`
|
||||
**Output patterns**: `skill/skill-creator/references/output-patterns.md`
|
||||
**User profile**: `context/profile.md`
|
||||
**Agent config**: `agent/chiron.md`
|
||||
**Beads docs**: `.beads/README.md`
|
||||
**Agent config**: `agent/agents.json`
|
||||
|
||||
## Notes for AI Agents
|
||||
|
||||
|
||||
74
README.md
74
README.md
@@ -17,8 +17,8 @@ This repository serves as a **personal AI operating system** - a collection of s
|
||||
|
||||
```
|
||||
.
|
||||
├── agent/ # AI agent configurations
|
||||
│ └── chiron.md # Personal assistant agent
|
||||
├── agent/ # Agent definitions (agents.json)
|
||||
├── prompts/ # Agent system prompts (chiron.txt, chiron-forge.txt)
|
||||
├── context/ # User profiles and preferences
|
||||
│ └── profile.md # Work style, PARA areas, preferences
|
||||
├── command/ # Custom command definitions
|
||||
@@ -32,6 +32,8 @@ This repository serves as a **personal AI operating system** - a collection of s
|
||||
│ ├── mem0-memory/ # Persistent memory
|
||||
│ ├── research/ # Investigation workflows
|
||||
│ └── knowledge-management/ # Note capture & organization
|
||||
├── scripts/ # Repository utility scripts
|
||||
│ └── test-skill.sh # Test skills without deploying
|
||||
├── .beads/ # Issue tracking database
|
||||
├── AGENTS.md # Developer documentation
|
||||
└── README.md # This file
|
||||
@@ -50,22 +52,26 @@ This repository serves as a **personal AI operating system** - a collection of s
|
||||
|
||||
#### Option 1: Nix Flake (Recommended)
|
||||
|
||||
Add to your Nix flake configuration:
|
||||
This repository is consumed as a **non-flake input** by your NixOS configuration:
|
||||
|
||||
```nix
|
||||
# In your flake.nix or home.nix
|
||||
{
|
||||
inputs.agents = {
|
||||
url = "github:yourusername/AGENTS"; # Update with your repo
|
||||
flake = false;
|
||||
};
|
||||
# In your flake.nix
|
||||
inputs.agents = {
|
||||
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
|
||||
flake = false; # Pure files, not a Nix flake
|
||||
};
|
||||
|
||||
# In your home-manager configuration
|
||||
xdg.configFile."opencode" = {
|
||||
source = inputs.agents;
|
||||
recursive = true;
|
||||
};
|
||||
}
|
||||
# In your home-manager module (e.g., opencode.nix)
|
||||
xdg.configFile = {
|
||||
"opencode/skill".source = "${inputs.agents}/skill";
|
||||
"opencode/context".source = "${inputs.agents}/context";
|
||||
"opencode/command".source = "${inputs.agents}/command";
|
||||
"opencode/prompts".source = "${inputs.agents}/prompts";
|
||||
};
|
||||
|
||||
# Agent config is embedded into config.json, not deployed as files
|
||||
programs.opencode.settings.agent = builtins.fromJSON
|
||||
(builtins.readFile "${inputs.agents}/agent/agents.json");
|
||||
```
|
||||
|
||||
Rebuild your system:
|
||||
@@ -73,6 +79,8 @@ Rebuild your system:
|
||||
home-manager switch
|
||||
```
|
||||
|
||||
**Note**: The `agent/` directory is NOT deployed as files. Instead, `agents.json` is read at Nix evaluation time and embedded into the opencode `config.json`.
|
||||
|
||||
#### Option 2: Manual Installation
|
||||
|
||||
Clone and symlink:
|
||||
@@ -134,9 +142,18 @@ compatibility: opencode
|
||||
python3 skill/skill-creator/scripts/quick_validate.py skill/my-skill-name
|
||||
```
|
||||
|
||||
### 4. Test in Opencode
|
||||
### 4. Test the Skill
|
||||
|
||||
Open Opencode and trigger your skill naturally in conversation. The skill will load based on the `description` field in the frontmatter.
|
||||
Test your skill without deploying via home-manager:
|
||||
|
||||
```bash
|
||||
# Use the test script to validate and list skills
|
||||
./scripts/test-skill.sh my-skill-name # Validate specific skill
|
||||
./scripts/test-skill.sh --list # List all dev skills
|
||||
./scripts/test-skill.sh --run # Launch opencode with dev skills
|
||||
```
|
||||
|
||||
The test script creates a temporary config directory with symlinks to this repo's skills, allowing you to test changes before committing.
|
||||
|
||||
## 📚 Available Skills
|
||||
|
||||
@@ -155,7 +172,7 @@ Open Opencode and trigger your skill naturally in conversation. The skill will l
|
||||
|
||||
### Chiron - Personal Assistant
|
||||
|
||||
**Location**: `agent/chiron.md`
|
||||
**Configuration**: `agent/agents.json` + `prompts/chiron.txt`
|
||||
|
||||
Chiron is a personal AI assistant focused on productivity and task management. Named after the wise centaur from Greek mythology, Chiron provides:
|
||||
|
||||
@@ -164,6 +181,10 @@ Chiron is a personal AI assistant focused on productivity and task management. N
|
||||
- Skill routing based on user intent
|
||||
- Integration with productivity tools (Anytype, ntfy, n8n)
|
||||
|
||||
**Modes**:
|
||||
- **Chiron** (Plan Mode) - Read-only analysis and planning (`prompts/chiron.txt`)
|
||||
- **Chiron-Forge** (Worker Mode) - Full write access with safety prompts (`prompts/chiron-forge.txt`)
|
||||
|
||||
**Triggers**: Personal productivity requests, task management, reviews, planning
|
||||
|
||||
## 🛠️ Development Workflow
|
||||
@@ -184,9 +205,9 @@ bd sync # Sync with git
|
||||
|
||||
Before committing:
|
||||
|
||||
1. **Validate skills**: `python3 skill/skill-creator/scripts/quick_validate.py skill/<name>`
|
||||
2. **Check formatting**: Ensure YAML frontmatter is valid
|
||||
3. **Test locally**: Use the skill in Opencode to verify behavior
|
||||
1. **Validate skills**: `./scripts/test-skill.sh --validate` or `python3 skill/skill-creator/scripts/quick_validate.py skill/<name>`
|
||||
2. **Test locally**: `./scripts/test-skill.sh --run` to launch opencode with dev skills
|
||||
3. **Check formatting**: Ensure YAML frontmatter is valid
|
||||
4. **Update docs**: Keep README and AGENTS.md in sync
|
||||
|
||||
### Session Completion
|
||||
@@ -232,11 +253,12 @@ See `AGENTS.md` for complete developer documentation.
|
||||
|
||||
### Modify Agent Behavior
|
||||
|
||||
Edit `agent/chiron.md` to customize:
|
||||
- Skill routing logic
|
||||
- Communication style
|
||||
- Operating principles
|
||||
- Integration awareness
|
||||
Edit `agent/agents.json` for agent definitions and `prompts/*.txt` for system prompts:
|
||||
- `agent/agents.json` - Agent names, models, permissions
|
||||
- `prompts/chiron.txt` - Chiron (Plan Mode) system prompt
|
||||
- `prompts/chiron-forge.txt` - Chiron-Forge (Worker Mode) system prompt
|
||||
|
||||
**Note**: Agent changes require `home-manager switch` to take effect (config is embedded, not symlinked).
|
||||
|
||||
### Update User Context
|
||||
|
||||
|
||||
151
scripts/test-skill.sh
Executable file
151
scripts/test-skill.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test skills by launching opencode with this repo's config
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/test-skill.sh # List all development skills
|
||||
# ./scripts/test-skill.sh <skill> # Validate specific skill
|
||||
# ./scripts/test-skill.sh --run # Launch interactive opencode session
|
||||
#
|
||||
# This script creates a temporary XDG_CONFIG_HOME with symlinks to this
|
||||
# repository's skill/, context/, command/, and prompts/ directories,
|
||||
# allowing you to test skill changes before deploying via home-manager.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
setup_test_config() {
|
||||
local tmp_base="${TMPDIR:-/tmp}/opencode-test-$$"
|
||||
local tmp_config="$tmp_base/opencode"
|
||||
|
||||
mkdir -p "$tmp_config"
|
||||
ln -sf "$REPO_ROOT/skill" "$tmp_config/skill"
|
||||
ln -sf "$REPO_ROOT/context" "$tmp_config/context"
|
||||
ln -sf "$REPO_ROOT/command" "$tmp_config/command"
|
||||
ln -sf "$REPO_ROOT/prompts" "$tmp_config/prompts"
|
||||
|
||||
echo "$tmp_base"
|
||||
}
|
||||
|
||||
cleanup_test_config() {
|
||||
local tmp_base="$1"
|
||||
rm -rf "$tmp_base"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTIONS] [SKILL_NAME]"
|
||||
echo ""
|
||||
echo "Test Opencode skills from this repository without deploying."
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --run Launch interactive opencode session with dev skills"
|
||||
echo " --list List all skills (default if no args)"
|
||||
echo " --validate Validate all skills"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
echo "Arguments:"
|
||||
echo " SKILL_NAME Validate a specific skill by name"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # List all development skills"
|
||||
echo " $0 task-management # Validate task-management skill"
|
||||
echo " $0 --validate # Validate all skills"
|
||||
echo " $0 --run # Launch interactive session"
|
||||
}
|
||||
|
||||
list_skills() {
|
||||
local tmp_base
|
||||
tmp_base=$(setup_test_config)
|
||||
trap "cleanup_test_config '$tmp_base'" EXIT
|
||||
|
||||
echo -e "${YELLOW}Skills in development (from $REPO_ROOT):${NC}"
|
||||
echo ""
|
||||
XDG_CONFIG_HOME="$tmp_base" opencode debug skill
|
||||
}
|
||||
|
||||
validate_skill() {
|
||||
local skill_name="$1"
|
||||
local skill_path="$REPO_ROOT/skill/$skill_name"
|
||||
|
||||
if [[ ! -d "$skill_path" ]]; then
|
||||
echo -e "${RED}❌ Skill not found: $skill_name${NC}"
|
||||
echo "Available skills:"
|
||||
ls -1 "$REPO_ROOT/skill/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Validating skill: $skill_name${NC}"
|
||||
if python3 "$REPO_ROOT/skill/skill-creator/scripts/quick_validate.py" "$skill_path"; then
|
||||
echo -e "${GREEN}✅ Skill '$skill_name' is valid${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Skill '$skill_name' has validation errors${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
validate_all() {
|
||||
echo -e "${YELLOW}Validating all skills...${NC}"
|
||||
echo ""
|
||||
|
||||
local failed=0
|
||||
for skill_dir in "$REPO_ROOT/skill/"*/; do
|
||||
local skill_name=$(basename "$skill_dir")
|
||||
echo -n " $skill_name: "
|
||||
if python3 "$REPO_ROOT/skill/skill-creator/scripts/quick_validate.py" "$skill_dir" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✅${NC}"
|
||||
else
|
||||
echo -e "${RED}❌${NC}"
|
||||
python3 "$REPO_ROOT/skill/skill-creator/scripts/quick_validate.py" "$skill_dir" 2>&1 | sed 's/^/ /'
|
||||
((failed++)) || true
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
if [[ $failed -eq 0 ]]; then
|
||||
echo -e "${GREEN}All skills valid!${NC}"
|
||||
else
|
||||
echo -e "${RED}$failed skill(s) failed validation${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_opencode() {
|
||||
local tmp_base
|
||||
tmp_base=$(setup_test_config)
|
||||
trap "cleanup_test_config '$tmp_base'" EXIT
|
||||
|
||||
echo -e "${YELLOW}Launching opencode with development skills...${NC}"
|
||||
echo -e "Config path: ${GREEN}$tmp_base/opencode${NC}"
|
||||
echo ""
|
||||
XDG_CONFIG_HOME="$tmp_base" opencode
|
||||
}
|
||||
|
||||
# Main
|
||||
case "${1:-}" in
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--run)
|
||||
run_opencode
|
||||
;;
|
||||
--list)
|
||||
list_skills
|
||||
;;
|
||||
--validate)
|
||||
validate_all
|
||||
;;
|
||||
"")
|
||||
list_skills
|
||||
;;
|
||||
*)
|
||||
validate_skill "$1"
|
||||
;;
|
||||
esac
|
||||
@@ -9,18 +9,20 @@ import re
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def validate_skill(skill_path):
|
||||
"""Basic validation of a skill"""
|
||||
skill_path = Path(skill_path)
|
||||
skill_md = skill_path / "SKILL.md"
|
||||
|
||||
if not skill_md.exists():
|
||||
return False, "SKILL.md not found"
|
||||
|
||||
content = skill_md.read_text()
|
||||
if not content.startswith('---'):
|
||||
if not content.startswith("---"):
|
||||
return False, "No YAML frontmatter found"
|
||||
|
||||
match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
|
||||
match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
|
||||
if not match:
|
||||
return False, "Invalid frontmatter format"
|
||||
|
||||
@@ -33,7 +35,14 @@ def validate_skill(skill_path):
|
||||
except yaml.YAMLError as e:
|
||||
return False, f"Invalid YAML in frontmatter: {e}"
|
||||
|
||||
ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata', 'compatibility'}
|
||||
ALLOWED_PROPERTIES = {
|
||||
"name",
|
||||
"description",
|
||||
"license",
|
||||
"allowed-tools",
|
||||
"metadata",
|
||||
"compatibility",
|
||||
}
|
||||
|
||||
unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
|
||||
if unexpected_keys:
|
||||
@@ -42,35 +51,48 @@ def validate_skill(skill_path):
|
||||
f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
|
||||
)
|
||||
|
||||
if 'name' not in frontmatter:
|
||||
if "name" not in frontmatter:
|
||||
return False, "Missing 'name' in frontmatter"
|
||||
if 'description' not in frontmatter:
|
||||
if "description" not in frontmatter:
|
||||
return False, "Missing 'description' in frontmatter"
|
||||
|
||||
name = frontmatter.get('name', '')
|
||||
name = frontmatter.get("name", "")
|
||||
if not isinstance(name, str):
|
||||
return False, f"Name must be a string, got {type(name).__name__}"
|
||||
name = name.strip()
|
||||
if name:
|
||||
if not re.match(r'^[a-z0-9-]+$', name):
|
||||
return False, f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)"
|
||||
if name.startswith('-') or name.endswith('-') or '--' in name:
|
||||
return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens"
|
||||
if not re.match(r"^[a-z0-9-]+$", name):
|
||||
return (
|
||||
False,
|
||||
f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)",
|
||||
)
|
||||
if name.startswith("-") or name.endswith("-") or "--" in name:
|
||||
return (
|
||||
False,
|
||||
f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens",
|
||||
)
|
||||
if len(name) > 64:
|
||||
return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters."
|
||||
return (
|
||||
False,
|
||||
f"Name is too long ({len(name)} characters). Maximum is 64 characters.",
|
||||
)
|
||||
|
||||
description = frontmatter.get('description', '')
|
||||
description = frontmatter.get("description", "")
|
||||
if not isinstance(description, str):
|
||||
return False, f"Description must be a string, got {type(description).__name__}"
|
||||
description = description.strip()
|
||||
if description:
|
||||
if '<' in description or '>' in description:
|
||||
if "<" in description or ">" in description:
|
||||
return False, "Description cannot contain angle brackets (< or >)"
|
||||
if len(description) > 1024:
|
||||
return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters."
|
||||
return (
|
||||
False,
|
||||
f"Description is too long ({len(description)} characters). Maximum is 1024 characters.",
|
||||
)
|
||||
|
||||
return True, "Skill is valid!"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python quick_validate.py <skill_directory>")
|
||||
|
||||
Reference in New Issue
Block a user