mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
Merge pull request #71 from pbakaus/chore/update-develop-docs
Update DEVELOP.md for factory-based build system
This commit is contained in:
+99
-170
@@ -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?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user