diff --git a/DEVELOP.md b/DEVELOP.md index a2f7cb8c5..96627c70c 100644 --- a/DEVELOP.md +++ b/DEVELOP.md @@ -4,17 +4,9 @@ Documentation for contributors to Impeccable. ## Architecture -This repository uses a **feature-rich source format** that transforms into provider-specific formats. We chose "Option A" architecture: maintain full metadata in source files and downgrade for providers with limited support (like Cursor), rather than limiting everyone to the lowest common denominator. +Source skills in `source/skills/` are transformed into provider-specific formats by a config-driven factory. Each provider is defined as a config object in `scripts/lib/transformers/providers.js` -- adding a new provider requires only a new config entry. -### Why This Approach? - -Different providers have different capabilities: -- **Claude Code, OpenCode, Trae**: Full metadata — args, user-invocable, allowed-tools, license, compatibility -- **Codex, Agents**: Args converted to `argument-hint` format -- **Gemini**: Minimal frontmatter, `{{arg}}` placeholders become `{{args}}` -- **Cursor, Kiro, Pi**: Basic frontmatter (name, description, license/compatibility) - -By maintaining rich source files, we preserve maximum functionality where supported while still providing working (if simpler) versions for all providers. +For detailed harness capabilities (which frontmatter fields each supports, placeholder systems, directory structures), see [HARNESSES.md](HARNESSES.md). ## Source Format @@ -24,6 +16,8 @@ By maintaining rich source files, we preserve maximum functionality where suppor --- name: skill-name description: What this skill provides +argument-hint: "[target]" +user-invocable: true license: License info (optional) compatibility: Environment requirements (optional) --- @@ -34,17 +28,19 @@ Your skill instructions here... **Frontmatter fields** (based on [Agent Skills spec](https://agentskills.io/specification)): - `name` (required): Skill identifier (1-64 chars, lowercase/numbers/hyphens) - `description` (required): What the skill provides (1-1024 chars) -- `user-invocable` (optional): Boolean — if `true`, the skill can be invoked as a slash command -- `args` (optional): Array of argument objects (for user-invocable skills) - - `name`: Argument identifier - - `description`: What it's for - - `required`: Boolean (defaults to false) +- `user-invocable` (optional): Boolean -- if `true`, the skill can be invoked as a slash command +- `argument-hint` (optional): Hint shown during autocomplete (e.g., `[target]`, `[area (feature, page...)]`) - `license` (optional): License/attribution info - `compatibility` (optional): Environment requirements (1-500 chars) - `metadata` (optional): Arbitrary key-value pairs - `allowed-tools` (optional, experimental): Pre-approved tools list -**Body**: The skill instructions for the LLM. +**Body placeholders** (replaced per-provider during build): +- `{{model}}` -- Provider-specific model name (e.g., "Claude", "Gemini", "GPT") +- `{{config_file}}` -- Provider-specific config file (e.g., "CLAUDE.md", ".cursorrules") +- `{{ask_instruction}}` -- How to ask the user for clarification +- `{{command_prefix}}` -- Slash command prefix (`/` for most, `$` for Codex) +- `{{available_commands}}` -- Comma-separated list of user-invocable commands ## Building @@ -68,123 +64,73 @@ bun run rebuild ### What Gets Generated ``` -source/ → dist/ - skills/{name}/SKILL.md cursor/.cursor/skills/{name}/SKILL.md - claude-code/.claude/skills/{name}/SKILL.md - gemini/.gemini/skills/{name}/SKILL.md - codex/.codex/skills/{name}/SKILL.md - agents/.agents/skills/{name}/SKILL.md - kiro/.kiro/skills/{name}/SKILL.md - opencode/.opencode/skills/{name}/SKILL.md - pi/.pi/skills/{name}/SKILL.md - trae/.trae-cn/skills/{name}/SKILL.md +source/ -> dist/ + skills/{name}/SKILL.md {provider}/{configDir}/skills/{name}/SKILL.md ``` -## Provider Transformations - -All providers output skills to `dist/{provider}/.{config}/skills/{name}/SKILL.md` with reference files in subdirectories. They differ in frontmatter fields and argument handling. - -### Cursor -- Output: `dist/cursor/.cursor/skills/{name}/SKILL.md` -- Frontmatter: name, description, license -- **Note**: Agent Skills require Cursor nightly channel - -### Claude Code (Full Featured) -- Output: `dist/claude-code/.claude/skills/{name}/SKILL.md` -- Frontmatter: name, description, user-invocable, args, license, compatibility, metadata, allowed-tools -- Preserves `{{arg}}` placeholders in body - -### OpenCode (Full Featured) -- Output: `dist/opencode/.opencode/skills/{name}/SKILL.md` -- Frontmatter: name, description, user-invocable, args, license, compatibility, metadata, allowed-tools -- Same format as Claude Code - -### Gemini CLI -- Output: `dist/gemini/.gemini/skills/{name}/SKILL.md` -- Frontmatter: name, description -- For user-invocable skills: remaining `{{arg}}` placeholders become `{{args}}` - -### Codex CLI -- Output: `dist/codex/.codex/skills/{name}/SKILL.md` -- Frontmatter: name, description, argument-hint, license -- For user-invocable skills: `{{argname}}` → `$ARGNAME` (uppercase) - -### Agents (VS Code Copilot, Antigravity) -- Output: `dist/agents/.agents/skills/{name}/SKILL.md` -- Frontmatter: name, description, user-invocable, argument-hint -- Args converted to `argument-hint` format (e.g., ` [FORMAT=]`) - -### Kiro -- Output: `dist/kiro/.kiro/skills/{name}/SKILL.md` -- Frontmatter: name, description, license, compatibility, metadata - -### Pi -- Output: `dist/pi/.pi/skills/{name}/SKILL.md` -- Frontmatter: name, description, license, compatibility, metadata - -### Trae (Full Featured) -- Output: `dist/trae/.trae-cn/skills/{name}/SKILL.md` (China version) -- Output: `dist/trae/.trae/skills/{name}/SKILL.md` (International version) -- Frontmatter: name, description, user-invocable, args, license, compatibility, metadata, allowed-tools -- Same format as Claude Code -- Two variants are generated automatically: - - **Trae China**: Skills installed to `~/.trae-cn/skills/` - - **Trae International**: Skills installed to `~/.trae/skills/` - -## Adding New Content - -### 1. Create Source File - -```bash -mkdir source/skills/myskill -touch source/skills/myskill/SKILL.md -``` - -Add frontmatter and content following the format above. - -### 2. Build - -```bash -bun run build -``` - -This generates all 9 provider formats automatically. - -### 3. Test - -Test with your provider of choice to ensure it works correctly. Remember that Cursor will have limited functionality. - -### 4. Commit - -Commit source files: -```bash -git add source/ -git commit -m "Add [skill name]" -``` +Each provider gets its own output directory. Two variants are generated per provider: unprefixed and prefixed (with `i-` prefix for skill names). ## Build System Details -The build system uses a modular architecture under `scripts/`: +The build system uses a factory pattern under `scripts/`: -- `build.js` — Main orchestrator -- `lib/utils.js` — Shared utilities (frontmatter parsing, file I/O, placeholder replacement) -- `lib/zip.js` — ZIP bundle generation -- `lib/transformers/*.js` — One file per provider (cursor, claude-code, gemini, codex, agents, kiro, opencode, pi, trae) +``` +scripts/ + build.js # Main orchestrator + lib/ + utils.js # Frontmatter parsing, placeholder replacement, YAML generation + zip.js # ZIP bundle generation + transformers/ + factory.js # createTransformer() -- generates transformer functions from config + providers.js # PROVIDERS config map -- one entry per provider + index.js # Re-exports factory-generated transformer functions +``` + +### Adding a New Provider + +1. Add a placeholder config to `PROVIDER_PLACEHOLDERS` in `scripts/lib/utils.js`: + ```javascript + 'my-provider': { + model: 'MyModel', + config_file: 'CONFIG.md', + ask_instruction: 'ask the user directly to clarify.', + command_prefix: '/' + } + ``` + +2. Add a provider config to `PROVIDERS` in `scripts/lib/transformers/providers.js`: + ```javascript + 'my-provider': { + provider: 'my-provider', + configDir: '.my-provider', + displayName: 'My Provider', + frontmatterFields: ['user-invocable', 'argument-hint', 'license'], + } + ``` + +3. Run `bun run build` -- the provider is automatically picked up by the build loop. + +4. Update `HARNESSES.md` with the provider's capabilities. + +### Provider Config Options + +| Field | Description | +|-------|-------------| +| `provider` | Key for output directory and placeholder lookup | +| `configDir` | Dot-directory name (e.g., `.claude`) | +| `displayName` | Human-readable name for build logs | +| `frontmatterFields` | Which optional fields to emit (see `factory.js` FIELD_SPECS) | +| `bodyTransform` | Optional `(body, skill) => body` function for post-processing | +| `placeholderProvider` | Override which PROVIDER_PLACEHOLDERS key to use (for variants sharing config) | ### Key Functions -- `parseFrontmatter()`: Extracts YAML frontmatter and body +- `createTransformer(config)`: Factory that returns a transformer function from a provider config +- `parseFrontmatter()`: Extracts YAML frontmatter and body from SKILL.md files - `readSourceFiles()`: Reads all skill directories from `source/skills/` - `replacePlaceholders()`: Substitutes `{{model}}`, `{{config_file}}`, etc. per provider -- `transformCursor()`: Basic frontmatter (name, description, license) -- `transformClaudeCode()`: Full metadata with args and allowed-tools -- `transformGemini()`: Minimal frontmatter, `{{arg}}` → `{{args}}` -- `transformCodex()`: Args → argument-hint, `{{arg}}` → `$ARGNAME` -- `transformAgents()`: Args → argument-hint, user-invocable flag -- `transformKiro()`: Basic frontmatter with license/compatibility/metadata -- `transformOpenCode()`: Full metadata (same as Claude Code) -- `transformPi()`: Basic frontmatter with license/compatibility/metadata -- `transformTrae()`: Full metadata (same as Claude Code), outputs to both `.trae-cn/skills/` and `.trae/skills/` +- `generateYamlFrontmatter()`: Serializes objects to YAML frontmatter (auto-quotes values starting with `[` or `{`) +- `prefixSkillReferences()`: Replaces `/skillname` with `/i-skillname` for prefixed variants ## Best Practices @@ -200,59 +146,42 @@ The build system uses a modular architecture under `scripts/`: ## Reference Documentation - [Agent Skills Specification](https://agentskills.io/specification) - Open standard -- [Cursor Commands](https://cursor.com/docs/agent/chat/commands) -- [Cursor Rules](https://cursor.com/docs/context/rules) +- [HARNESSES.md](HARNESSES.md) - Provider capabilities matrix - [Cursor Skills](https://cursor.com/docs/context/skills) -- [Claude Code Slash Commands](https://code.claude.com/docs/en/slash-commands) -- [Anthropic Skills (Claude Code)](https://github.com/anthropics/skills) -- [Gemini CLI Custom Commands](https://cloud.google.com/blog/topics/developers-practitioners/gemini-cli-custom-slash-commands) -- [Gemini CLI Skills](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/gemini-md.md) -- [Codex CLI Slash Commands](https://developers.openai.com/codex/guides/slash-commands#create-your-own-slash-commands-with-custom-prompts) +- [Claude Code Skills](https://code.claude.com/docs/en/skills) +- [Gemini CLI Skills](https://geminicli.com/docs/cli/skills/) - [Codex CLI Skills](https://developers.openai.com/codex/skills/) +- [VS Code Copilot Skills](https://code.visualstudio.com/docs/copilot/customization/agent-skills) +- [Kiro Skills](https://kiro.dev/docs/skills/) +- [OpenCode Skills](https://opencode.ai/docs/skills/) - [Pi Skills](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/skills.md) ## Repository Structure ``` impeccable/ -├── source/ # Edit these! Source of truth -│ └── skills/ # Skill definitions -│ ├── frontend-design/ -│ │ ├── SKILL.md -│ │ └── reference/*.md # Domain-specific references -│ ├── audit/SKILL.md -│ ├── polish/SKILL.md -│ └── ... -├── dist/ # Generated output (gitignored) -│ ├── cursor/ -│ ├── claude-code/ -│ ├── gemini/ -│ ├── codex/ -│ ├── agents/ -│ ├── kiro/ -│ ├── opencode/ -│ ├── pi/ -│ └── trae/ -├── scripts/ -│ ├── build.js # Main orchestrator -│ └── lib/ -│ ├── utils.js # Shared utilities -│ ├── zip.js # ZIP generation -│ └── transformers/ # One file per provider -│ ├── cursor.js -│ ├── claude-code.js -│ ├── gemini.js -│ ├── codex.js -│ ├── agents.js -│ ├── kiro.js -│ ├── opencode.js -│ ├── pi.js -│ └── trae.js -├── tests/ # Bun test suite -├── package.json # ESM project config -├── README.md # User documentation -├── DEVELOP.md # This file -└── .gitignore + source/ # Edit these! Source of truth + skills/ # Skill definitions + frontend-design/ + SKILL.md + reference/*.md # Domain-specific references + audit/SKILL.md + polish/SKILL.md + ... + dist/ # Generated output (gitignored) + scripts/ + build.js # Main orchestrator + lib/ + utils.js # Shared utilities + zip.js # ZIP generation + transformers/ + factory.js # Config-driven transformer factory + providers.js # Provider config map + index.js # Re-exports + tests/ # Bun test suite + HARNESSES.md # Provider capabilities reference + DEVELOP.md # This file + README.md # User documentation ``` ## Troubleshooting @@ -260,17 +189,17 @@ impeccable/ ### Build fails with YAML parsing errors - Check frontmatter indentation (YAML is indent-sensitive) - Ensure `---` delimiters are on their own lines -- Verify colons have spaces after them (`key: value`) +- Values starting with `[` or `{` are auto-quoted; other special YAML chars may need manual quoting ### Output doesn't match expectations -- Check the transformer function for your provider in `scripts/lib/transformers/` +- Check the provider config in `scripts/lib/transformers/providers.js` - Verify source file has correct frontmatter structure - Run `bun run rebuild` to ensure clean build ### Provider doesn't recognize the files - Check installation path for your provider - Verify file naming matches provider requirements -- Consult provider's documentation (links above) +- Consult [HARNESSES.md](HARNESSES.md) for provider-specific details ## Questions?