Files
pbakaus_impeccable/docs/DEVELOP.md
T
6ebc24ad66 Add DeepSeek Harness as a supported skills provider (#746)
* 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>
2026-09-06 14:46:05 -07:00

230 lines
10 KiB
Markdown

# 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](HARNESSES.md).
## Source Format
### Skill (`skill/SKILL.src.md`)
```yaml
---
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](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
- `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
```bash
# 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`:
```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
- `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
```bash
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
- [Agent Skills Specification](https://agentskills.io/specification) - Open standard
- [HARNESSES.md](HARNESSES.md) - Provider capabilities matrix
- [Cursor Skills](https://cursor.com/docs/context/skills)
- [Claude Code Skills](https://code.claude.com/docs/en/skills)
- [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
- [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)
- [Qoder Skills](https://docs.qoder.com/extensions/skills)
- [Mistral Vibe Skills](https://docs.mistral.ai/vibe/code/cli/skills)
- [Grok Build Skills, Plugins & Marketplaces](https://docs.x.ai/build/features/skills-plugins-marketplaces)
- [Grok Build Hooks](https://docs.x.ai/build/features/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 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](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.