Merge pull request #71 from pbakaus/chore/update-develop-docs

Update DEVELOP.md for factory-based build system
This commit is contained in:
Paul Bakaus
2026-03-24 15:49:03 -07:00
committed by GitHub
+99 -170
View File
@@ -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., `<target> [FORMAT=<value>]`)
### 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?