Skip to content

Latest commit

 

History

History
228 lines (179 loc) · 10.1 KB

File metadata and controls

228 lines (179 loc) · 10.1 KB

Developer Guide

Documentation for contributors to Impeccable.

Architecture

The skill at skill/ is 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.

For detailed harness capabilities (which frontmatter fields each supports, placeholder systems, directory structures), see HARNESSES.md.

Source Format

Skill (skill/SKILL.src.md)

---
name: skill-name
description: What this skill provides
argument-hint: "[target]"
user-invocable: true
license: License info (optional)
compatibility: Environment requirements (optional)
---

Your skill instructions here...

Frontmatter fields (based on Agent Skills spec):

  • 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
  • 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 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

Developer Lab URLs

No-index visual harnesses and internal inspectors live under /labs/<subject>. Use a short subject noun (/labs/live-ui, later /labs/detector), not a second -lab suffix. Stable public references such as /docs and /design-system stay top-level. Keep legacy top-level lab routes working through redirects when a lab moves; migrate existing exceptions when that surface is next changed rather than duplicating the page.

Prerequisites

  • Bun (fast JavaScript runtime and package manager)
  • No external dependencies required

Commands

# Build all provider formats
bun run build

# Clean dist folder
bun run clean

# Rebuild from scratch
bun run rebuild

What Gets Generated

source/                          -> dist/
  skills/{name}/SKILL.md           {provider}/{configDir}/skills/{name}/SKILL.md

Each provider gets its own output directory.

Build System Details

The build system uses a factory pattern under scripts/:

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:

    '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:

    '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

  • createTransformer(config): Factory that returns a transformer function from a provider config
  • parseFrontmatter(): Extracts YAML frontmatter and body from SKILL.md files
  • readSourceFiles(): Reads skill/SKILL.src.md plus its reference/ and scripts/ siblings
  • replacePlaceholders(): Substitutes {{model}}, {{config_file}}, etc. per provider
  • generateYamlFrontmatter(): Serializes objects to YAML frontmatter (auto-quotes values starting with [ or {)

Testing

bun run test                  # Default suite — unit + static fixtures (no API keys needed)
bun run test:live-e2e         # Opt-in — full-cycle live-mode E2E across framework fixtures (~2 min, needs `npx playwright install chromium` once)
bun run test:skill-behavior   # Opt-in — LLM-backed checks that the SKILL.md Setup flow actually drives the agent (~5 min, costs cents, needs `.env`)

The skill-behavior suite runs three providers (claude-haiku-4-5, gpt-5.4-mini, gemini-3.1-flash-lite — the cheapest tier of each, every run) with the source skill/SKILL.src.md inlined as the system prompt and a workspace-scoped bash/read/write/list tool set. It then asserts on the tool-call trace, not on free-form output. Use it whenever you edit skill/SKILL.src.md's Setup section, skill/scripts/context.mjs, or any Setup-touching reference (teach.md, document.md, brand.md, product.md, sub-command refs). Per-scenario assertions and the current baseline (21-22/24) live in tests/skill-behavior/README.md. Provider keys live in repo-root .env (gitignored); missing keys skip cleanly.

Best Practices

Skill Writing

  1. Focused scope: One clear domain per skill
  2. Clear descriptions: Make purpose obvious
  3. Clear instructions: LLM should understand exactly what to do
  4. Include examples: Where they clarify intent
  5. State constraints: What NOT to do as clearly as what to do
  6. Test across providers: Verify it works in multiple contexts. For Setup-related edits to skill/, bun run test:skill-behavior automates this across three providers.

Reference Documentation

Repository Structure

impeccable/
  skill/                           # Edit these! Source of truth
    SKILL.src.md                   # Frontmatter, shared design laws, command router
    reference/                     # One <command>.md per command + domain references
    scripts/                       # Skill runtime scripts (hooks, context.mjs, etc.)
    agents/                        # Nested subagent definitions
  cli/                             # Standalone `impeccable` CLI (npm package)
  site/                            # impeccable.style (Astro)
  extension/                       # Chrome extension
  functions/                       # Cloudflare Pages Functions
  plugin/                          # Committed Claude Code plugin build output
  dist/                            # Generated provider 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
  docs/
    HARNESSES.md                   # Provider capabilities reference
    STYLE.md                       # Editorial style guide
    adr-live-variant-mode.md       # Live mode architecture decision record
    DEVELOP.md                     # This file
  README.md                        # User documentation

Troubleshooting

Build fails with YAML parsing errors

  • Check frontmatter indentation (YAML is indent-sensitive)
  • Ensure --- delimiters are on their own lines
  • Values starting with [ or { are auto-quoted; other special YAML chars may need manual quoting

Output doesn't match expectations

  • 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 HARNESSES.md for provider-specific details

Questions?

Open an issue first. If a maintainer approves the direction, offer to follow up with a PR. Regular contributors pbakaus and abdulwahabone may open PRs directly.