--- name: skill-creator description: Create new OpenCode skills with proper structure, SKILL.md format, and script templates. Use this skill when you need to create a new OpenCode skill. --- # Skill Creator Guide and tools for creating new OpenCode skills. ## Quick Start ```bash python3 scripts/create_skill.py "" ``` ## SKILL.md Format (Required) Every skill must have a `SKILL.md` file with YAML frontmatter: ```yaml --- name: skill-name description: Brief description. Use when user wants to [specific action]. --- # Skill Name Brief explanation of what this skill does. ## Commands | Command | Args | Description | |---------|------|-------------| | `command1` | `` | What it does | ## Options | Option | Default | Range | Description | |--------|---------|-------|-------------| | `--option` | 100 | 1-1000 | What it does | ## Examples ```bash python3 scripts/script.py command "arg" --option 50 ``` ## Output Format - Success: `Result: filename [id]` - Error: `Error: message` (to stderr) ## Notes - Required environment variables - Important constraints ``` ## Frontmatter Rules | Field | Required | Rules | |-------|----------|-------| | `name` | Yes | 1-64 chars, lowercase alphanumeric + hyphens, no leading/trailing/consecutive hyphens | | `description` | Yes | 1-1024 chars, specific enough for agent to choose correctly | | `license` | No | e.g., MIT | | `compatibility` | No | e.g., opencode | | `metadata` | No | String-to-string map | ## Directory Structure ``` skills/ └── skill-name/ ├── SKILL.md # Required: skill definition └── scripts/ ├── main_script.py # Executable script ├── .env.example # Required: env var template └── requirements.txt # Optional: Python deps ``` ## Script Best Practices ### 1. Load Environment Variables ```python def load_env(): env_path = Path(__file__).parent / ".env" if env_path.exists(): for line in env_path.read_text().splitlines(): line = line.strip() if line and not line.startswith("#") and "=" in line: k, v = line.split("=", 1) os.environ.setdefault(k.strip(), v.strip().strip("\"'")) load_env() API_TOKEN = os.environ.get("API_TOKEN") ``` ### 2. Handle API Responses (Binary + JSON) APIs may return raw binary or JSON with base64. Handle both: ```python response = requests.post(url, headers=headers, json=payload, timeout=300) response.raise_for_status() content_type = response.headers.get("Content-Type", "") if "image/" in content_type or "application/octet-stream" in content_type: # Raw binary response data = response.content else: # JSON with base64 result = response.json() if isinstance(result, list) and len(result) > 0: image_data = result[0].get("data", "") if image_data.startswith("data:"): data = base64.b64decode(image_data.split(",", 1)[1]) else: data = base64.b64decode(image_data) ``` ### 3. Send Base64 (Plain, Not Data URI) Some APIs expect plain base64, not data URI: ```python import base64 with open(image_path, "rb") as f: image_bytes = f.read() # Plain base64 (no data: prefix) b64_string = base64.b64encode(image_bytes).decode("utf-8") ``` ### 4. Output Format Follow OpenCode conventions: ```python # Success with ID print(f"Result: {filename} [{timestamp}]") # Error to stderr print(f"Error: {message}", file=sys.stderr) sys.exit(1) ``` ### 5. CLI Arguments Use argparse for clean CLI: ```python parser = argparse.ArgumentParser(description="What this does") parser.add_argument("required_arg", help="Description") parser.add_argument("--optional", type=int, default=100, help="Description") args = parser.parse_args() ``` ## .env.example Template ``` # API credentials # Get your token from https://service.com/account # # WARNING: Never commit actual credentials! API_TOKEN=your_api_token_here ``` ## Installation Paths | Type | Path | |------|------| | Global | `~/.config/opencode/skills//SKILL.md` | | Project | `./.opencode/skills//SKILL.md` | ## Common Issues | Issue | Solution | |-------|----------| | 400 Bad Request | Check payload format - may need flat JSON, not nested | | Skill not found | Verify path is `skills//SKILL.md` (plural "skills") | | API token not loaded | Check .env is in same directory as script | | Binary response fails | Check Content-Type header, handle raw bytes | ## Checklist for New Skills - [ ] `SKILL.md` with required frontmatter (name, description) - [ ] `scripts/` directory with main script - [ ] `scripts/.env.example` with placeholder credentials - [ ] `scripts/requirements.txt` if external deps needed - [ ] Script handles both binary and JSON responses - [ ] Output follows format: `Result: name [id]` - [ ] Errors go to stderr with `sys.exit(1)`