* Add DeepSeek Harness as a supported skills provider npx impeccable install now detects ~/.dsh (or $DSH_HOME when it sits under home) and installs into ~/.dsh/skills, the user-level skill root DeepSeek Harness scans, with project-level .dsh/skills on the same layout as other providers. Aliases: dsh, deepseek, deepseek-harness. Engine: PROVIDER_DIRS / aliases / display / input order / global hint, $DSH_HOME-aware user skills dir, provider id resolution from the skill dir, pin harness dirs, bundle path normalization for hashing. Build: dsh transformer target emitting the frontmatter DeepSeek Harness reads (user-invocable, license, compatibility, metadata; unknown keys are ignored there) with no emitHooks (DSH hooks are in-process plugins, not on-disk manifests) and no agentFormat (no documented on-disk subagent format); placeholders (AGENTS.md config file, ask_user_question tool, / command prefix), provider block tags, universal README entry. Docs: HARNESSES.md row and frontmatter column, CLI-CONTRACT constants, README/DEVELOP/AGENTS provider lists. Validation: cargo test --workspace; node scripts/run-tests.mjs core (138 pass); bun run build (19 providers, dist/dsh artifact verified); engine smoke against a fake HOME with a local bundle: install --providers=dsh --scope=global, auto-detected install, and update all resolve the .dsh provider. Generated provider output intentionally omitted per repo policy; the sync workflow regenerates tracked .dsh/skills after merge. Prepared with AI assistance (DeepSeek Harness coding agent). * Address review: DSH_HOME-only detection, generated-output pathspecs - Detect DeepSeek Harness through the resolved $DSH_HOME (fallback ~/.dsh) instead of gating on a fixed ~/.dsh path, so a DSH_HOME-only setup is offered by a provider-less install; generalize the two env-relocated config-dir hints (OpenCode, DSH) into one shared probe. - Add .dsh to the sync workflow's GENERATED_PATHS and CI's generated drift check so the tracked .dsh/skills payload is committed and validated. - Cover both behaviors: new install_detection_tests (DSH_HOME-only, default ~/.dsh, refused outside-home override) and a CLI-CONTRACT note on the resolved detection path. Validation: cargo test --workspace; node scripts/run-tests.mjs core (138 pass); engine smoke: DSH_HOME-only fake HOME installs globally into the resolved skills dir. Prepared with AI assistance (DeepSeek Harness coding agent). * Fix DeepSeek Harness home paths on Windows Use native relative-path containment, cover case and drive boundaries, and verify relocated global install/update without changing project skills. Add DSH output coverage and correct the install documentation. AI assistance: Codex, under pbakaus maintainer direction. * Document the CLI limit on external DSH homes Clarify that outside-home manual copies are not detected or updated by the CLI. AI assistance: Codex, under pbakaus maintainer direction. --------- Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
10 KiB
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 -- iftrue, the skill can be invoked as a slash commandargument-hint(optional): Hint shown during autocomplete (e.g.,[target],[area (feature, page...)])license(optional): License/attribution infocompatibility(optional): Environment requirements (1-500 chars)metadata(optional): Arbitrary key-value pairsallowed-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
-
Add a placeholder config to
PROVIDER_PLACEHOLDERSinscripts/lib/utils.js:'my-provider': { model: 'MyModel', config_file: 'CONFIG.md', ask_instruction: 'ask the user directly to clarify.', command_prefix: '/' } -
Add a provider config to
PROVIDERSinscripts/lib/transformers/providers.js:'my-provider': { provider: 'my-provider', configDir: '.my-provider', displayName: 'My Provider', frontmatterFields: ['user-invocable', 'argument-hint', 'license'], } -
Run
bun run build-- the provider is automatically picked up by the build loop. -
Update
HARNESSES.mdwith 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 configparseFrontmatter(): Extracts YAML frontmatter and body from SKILL.md filesreadSourceFiles(): Readsskill/SKILL.src.mdplus itsreference/andscripts/siblingsreplacePlaceholders(): Substitutes{{model}},{{config_file}}, etc. per providergenerateYamlFrontmatter(): 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
- Focused scope: One clear domain per skill
- Clear descriptions: Make purpose obvious
- Clear instructions: LLM should understand exactly what to do
- Include examples: Where they clarify intent
- State constraints: What NOT to do as clearly as what to do
- Test across providers: Verify it works in multiple contexts. For Setup-related edits to
skill/,bun run test:skill-behaviorautomates this across three providers.
Reference Documentation
- Agent Skills Specification - Open standard
- HARNESSES.md - Provider capabilities matrix
- Cursor Skills
- Claude Code Skills
- DeepSeek Harness
- Gemini CLI Skills
- Codex CLI Skills
- VS Code Copilot Skills
- Kiro Skills
- OpenCode Skills
- Pi Skills
- Qoder Skills
- Mistral Vibe Skills
- Grok Build Skills, Plugins & Marketplaces
- Grok Build Hooks
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 rebuildto 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.