harness-sharev0.3.0
Compile, export, import, and sync harness configurations across Claude Code, Cursor, and GitHub Copilot
Install
Add the marketplace once, then install the plugin:
/plugin marketplace add harnessprotocol/harness-kit/plugin install harness-share@harness-kitSecurity & permissions
Caution2 warnings, 5 infoDeclared capabilities
Scan observations
- infoskills/harness-export/README.md:23
External URL detected: https://harnessprotocol.io/schema/v1/harness.schema.json
Verify this URL is necessary and trustworthy. Consider if this data should be fetched at install time or runtime.
- infoskills/harness-export/README.md:55
External URL detected: https://raw.githubusercontent.com/harnessprotocol/harness-kit/main/harness-restore.sh
Verify this URL is necessary and trustworthy. Consider if this data should be fetched at install time or runtime.
- warningskills/harness-export/README.md:55
Suspicious pattern detected: Piped bash execution
Review this code carefully. This pattern can be dangerous if not properly controlled.
- infoskills/harness-export/SKILL.md:171
External URL detected: https://harnessprotocol.io/schema/v1/harness.schema.json
Verify this URL is necessary and trustworthy. Consider if this data should be fetched at install time or runtime.
- infoskills/harness-import/README.md:53
External URL detected: https://raw.githubusercontent.com/harnessprotocol/harness-kit/main/harness-restore.sh
Verify this URL is necessary and trustworthy. Consider if this data should be fetched at install time or runtime.
- warningskills/harness-import/README.md:53
Suspicious pattern detected: Piped bash execution
Review this code carefully. This pattern can be dangerous if not properly controlled.
- infoskills/harness-validate/SKILL.md:52
External URL detected: https://raw.githubusercontent.com/harnessprotocol/harness-protocol/spec/v1-foundation/schema/draft/harness.schema.json
Verify this URL is necessary and trustworthy. Consider if this data should be fetched at install time or runtime.
Scanned at build time from source. How trust signals work →
Skills5
harness-compileskills/harness-compile/SKILL.md
Compile a Harness Configuration
You are compiling a harness.yaml file into native configuration files for one or more AI coding tools. Each target tool gets its own idiomatic output: instruction files, MCP server configs, skill files, and permission settings.
This skill implements the Harness Protocol compiler mapping defined at harnessprotocol.io. The output is deterministic — the same harness.yaml always produces the same files.
Workflow Order (MANDATORY)
Follow these steps in order. Do not skip any step.
Step 1: Find harness.yaml
Check for the harness file in this order:
- A path provided by the user after
/harness-compile(e.g.,/harness-compile ~/dotfiles/harness.yaml) ./harness.yamlin the current directory
If no file is found at either location, tell the user:
"No
harness.yamlfound. Specify a path:/harness-compile path/to/harness.yaml"
Read and parse the file. Extract metadata.name (use default if absent). Extract version to confirm v1 format. Note the instructions.import-mode value (default: merge if not specified).
If version is absent, is the integer 1 (legacy format), or is any value other than the string "1", stop and tell the user: "This harness.yaml uses an unsupported format. Run /harness-validate to check the file and see upgrade instructions."
Also check for any flags the user passed:
--target <claude-code|cursor|copilot|all>— restricts which targets are compiled--dry-run— preview output without writing any files--clean— remove orphaned marker blocks in addition to current update--verbose— show skipped slots and extra detail in the compilation report
Step 2: Platform detection
If --target was provided, skip interactive detection and use those targets directly. all means compile for all three: claude-code, cursor, copilot.
Otherwise, scan the working directory for platform indicators:
Claude Code is present if any of these exist: CLAUDE.md, .claude/, .mcp.json
Cursor is present if any of these exist: .cursor/, .cursor/rules/, .cursor/mcp.json, .cursor/skills/
Copilot is present if any of these exist: .github/, .vscode/mcp.json, .github/skills/
Never assume a platform is present. Detect each independently. If .github/ is the only Copilot indicator, ask the user: "I found a .github/ directory but no other Copilot indicators. Are you using GitHub Copilot in this project?"
Present the detected platforms as a multi-select and ask the user to confirm or adjust:
"I detected these targets in your project: [x] Claude Code (found: CLAUDE.md, .claude/) [x] Cursor (found: .cursor/) [ ] Copilot (not detected)
Which targets should I compile for? (Confirm, add, or remove any.)"
Wait for confirmation before proceeding. If no platforms are detected, ask:
"No AI tool config directories found. Which targets should I compile for? (claude-code, cursor, copilot)"
Step 3: Compile instructions
For each confirmed target, write the instruction slots using this mapping:
| Harness slot | Claude Code | Copilot | Cursor |
|---|---|---|---|
instructions.operational | CLAUDE.md | .github/copilot-instructions.md | .cursor/rules/harness.mdc |
instructions.behavioral | AGENT.md | .github/instructions/behavioral.instructions.md | .cursor/rules/behavioral.mdc |
instructions.identity | SOUL.md | (omit — not supported) | (omit — not supported) |
Section markers (exact format — do not deviate):
Every generated block must be wrapped in markers. The {name} value is metadata.name from harness.yaml, or default if absent. The {slot} value is operational, behavioral, or identity.
<!-- BEGIN harness:{name}:{slot} -->
...generated content...
<!-- END harness:{name}:{slot} -->
Example with metadata.name: data-engineer and slot operational:
<!-- BEGIN harness:data-engineer:operational -->
## Commands
- Build: `dbt run`
<!-- END harness:data-engineer:operational -->
Import-mode behavior:
merge(default): If the target file already exists and contains matching markers, update only the content between those markers. If no markers exist yet, append the marker block at the end of the file (creating the file if it does not exist).replace: Warn the user that existing content will be overwritten and require explicit confirmation before proceeding:"Warning: import-mode 'replace' will overwrite
CLAUDE.md. Existing content (42 lines) will be replaced with generated content. Your manual customizations outside the markers will be lost.Proceed? [y/N]" After confirmation, write the generated content wrapped in markers as the entire file. Skip the confirmation prompt on re-compilation if the file already contains only harness marker blocks.
skip: Do not write or modify this slot's file at all. Leave it untouched.
Cursor .mdc frontmatter (mandatory):
Cursor rules files require YAML frontmatter. Always prepend this block before the instruction content for .cursor/rules/harness.mdc (operational slot):
---
description: Harness operational instructions
globs: **/*
alwaysApply: true
---
For .cursor/rules/behavioral.mdc (behavioral slot):
---
description: Harness behavioral preferences
globs: **/*
alwaysApply: true
---
The frontmatter goes before the <!-- BEGIN ... --> marker block.
Copilot .instructions.md frontmatter:
Copilot instructions files require YAML frontmatter. Always prepend this block:
---
applyTo: "**"
---
The frontmatter goes before the <!-- BEGIN ... --> marker block.
Directory creation: Create parent directories before writing if they don't exist (.cursor/rules/, .github/instructions/).
Step 4: Compile MCP servers
If the harness has a mcp-servers: section, write MCP JSON config files for each confirmed target.
| Target | File path |
|---|---|
| Claude Code | .mcp.json |
| Cursor | .cursor/mcp.json |
| Copilot / VS Code | .vscode/mcp.json |
All three files use identical JSON structure. Translate from harness YAML:
- YAML key
transport→ JSON keytype - Omit any harness-specific YAML keys that have no MCP JSON equivalent
{
"mcpServers": {
"postgres": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-server-postgres", "--connection-string", "${DB_CONNECTION_STRING}"]
}
}
}
Note the casing: mcpServers (camelCase) — not mcp-servers, not mcp_servers.
Merging: If the target MCP file already exists, merge: add new servers defined in the harness, but do not overwrite existing server configurations. Servers already present in the file take precedence.
If a server name in harness.yaml already exists in the target config file, do not overwrite but print a warning (substitute the actual target file path and server name):
Warning: <target-config-file> already defines server '<server-name>'. Existing config kept.
To update it, edit <target-config-file> directly or remove the entry and re-run.
For example: Warning: .cursor/mcp.json already defines server 'postgres'. Existing config kept.
Create parent directories if they don't exist.
Step 5: Compile skills
This step only runs if both conditions are true:
- The harness has a
plugins:section - At least one plugin has a SKILL.md discoverable via the source lookup below
For each plugin in plugins:, locate its SKILL.md by checking these locations in order:
~/.claude/skills/<name>/SKILL.md— Claude Code global install.cursor/skills/<name>/SKILL.md— project-local Cursor.agents/skills/<name>/SKILL.md— agentskills.io shared location
Use the first SKILL.md found. If no SKILL.md is found in any of these locations, skip that plugin and note it in the compilation report as: <name>: skipped (no SKILL.md found in ~/.claude/skills/, .cursor/skills/, or .agents/skills/).
For each plugin that has a SKILL.md, copy it to each confirmed target's skill directory:
| Target | Skill directory |
|---|---|
| Claude Code | (skip — uses plugin install system, not file copy) |
| Cursor | .cursor/skills/<name>/SKILL.md or .agents/skills/<name>/SKILL.md |
| Copilot | .github/skills/<name>/SKILL.md or .agents/skills/<name>/SKILL.md |
Ask the user which location to write to if multiple are applicable, or write to the platform-specific location by default (.cursor/skills/<name>/ for Cursor, .github/skills/<name>/ for Copilot).
Frontmatter adaptation when copying to Cursor/Copilot:
- If the source SKILL.md frontmatter has a
dependenciesfield, rename it tocompatibility - Enforce that the
namefield matches the folder name: lowercase letters and hyphens only, max 64 characters. Truncate and slugify if needed. - If
descriptionexceeds 1024 characters, truncate at the last word boundary before 1024 characters and append….
Create parent directories before writing.
Step 6: Compile permissions
Claude Code:
If the harness has a permissions: section, write or update .claude/settings.json with the permissions data:
{
"permissions": {
"allow": ["Read", "Glob", "Grep", "Write", "Edit"],
"deny": ["mcp__postgres__drop_*"],
"additionalDirectories": ["sql/", "migrations/"]
}
}
The keys map as follows:
permissions.tools.allow→permissions.allowpermissions.tools.deny→permissions.denypermissions.paths→permissions.additionalDirectories
If .claude/settings.json already exists, merge: update or add the permissions key without touching other keys in the file.
Cursor and Copilot:
These tools do not support machine-enforceable permissions via a JSON config. Instead, append a human-readable permission description inside markers to the operational instructions file for that target (e.g., appended to the marker block in .cursor/rules/harness.mdc or .github/copilot-instructions.md):
## Tool Permissions
This harness specifies the following tool permissions:
- **Allowed**: Read, Glob, Grep, Write, Edit, Bash
- **Denied**: Any tool matching `mcp__*__drop_*` or `mcp__*__delete_*`
Please configure your tool's permission settings to match these constraints.
Print a warning for each non-Claude-Code target that has a deny list:
Warning: permissions.tools.deny is not machine-enforceable for target 'cursor'.
Denied tools: mcp__*__drop_*
Instructions have been updated to describe the intended permissions,
but manual tool configuration is required.
Step 7: Handle flags
--dry-run:
Do not write any files. Instead, for each file that would be written, print its path and full content:
[DRY RUN] Would write: CLAUDE.md
----------------------------------------
<!-- BEGIN harness:data-engineer:operational -->
## Commands
- Build: `dbt run`
<!-- END harness:data-engineer:operational -->
----------------------------------------
[DRY RUN] Would write: .mcp.json
----------------------------------------
{
"mcpServers": {
"postgres": { ... }
}
}
----------------------------------------
End with:
"Dry run complete. No files were written. Remove --dry-run to apply."
--clean:
In addition to normal compilation, scan all target files for orphaned marker blocks — markers whose {name} no longer matches metadata.name in the current harness.yaml.
Example: if a file contains <!-- BEGIN harness:old-harness:operational --> but the current harness name is data-engineer, that block is orphaned.
Before deleting any orphaned blocks, the agent must:
- List every orphaned block found: profile name, slot, file, and line numbers
- Show the user exactly what will be deleted
- Ask for confirmation: "Remove these N orphaned blocks? [y/N]"
- Only proceed with deletion if the user confirms
This confirmation is required every time. --clean is a destructive operation with no recovery path — never skip this step.
Step 8: Print compilation report
After all files are written (or previewed in dry-run mode), print a compilation report:
Compiled harness: data-engineer (v1.2.0)
Targets: claude-code, cursor
CLAUDE.md operational merge 48 lines added
AGENT.md behavioral merge 12 lines added
.mcp.json mcp-servers —— 2 servers
.claude/settings.json permissions —— 4 allowed, 1 denied
.cursor/rules/harness.mdc operational merge 48 lines added
.cursor/rules/behavioral.mdc behavioral merge 12 lines added
.cursor/mcp.json mcp-servers —— 2 servers
Warnings:
permissions.tools.deny is not machine-enforceable for target 'cursor'.
Format rules:
- Group by target: claude-code entries first, then cursor, then copilot
- Within each target group, list files in slot order: operational, behavioral, identity, mcp-servers, permissions, skills
- Skipped slots are omitted unless
--verboseis passed - Show line counts for instruction files where calculable
- Show server counts for MCP files
- Show allowed/denied counts for permissions
Common Mistakes
| Mistake | Fix |
|---|---|
| Using wrong marker format | Markers must be exact: <!-- BEGIN harness:{name}:{slot} --> — any deviation breaks re-compilation merge logic |
Using mcp_servers or mcp-servers in JSON | JSON key must be mcpServers (camelCase) |
Omitting Cursor .mdc frontmatter | Always add frontmatter to .mdc files — it is mandatory for Cursor to recognize the file |
Omitting Copilot .instructions.md frontmatter | Always add applyTo: "**" frontmatter to Copilot instructions files |
| Overwriting existing MCP server configs on merge | Merge means add new servers only; existing server definitions win |
| Silently skipping MCP server key collisions | Always warn when a server name already exists in the target file — never skip silently |
Expecting import-mode to be per-slot | import-mode is a single scalar under instructions: that applies to all slots. Per-slot override is not supported in v1 |
| Writing SOUL.md for non-Claude-Code targets | identity slot is Claude Code-only — omit it for cursor and copilot |
| Assuming platforms are present | Always detect independently; never assume a platform exists |
Applying --clean without the flag | Only remove orphaned markers when --clean is explicitly passed |
Skipping replace confirmation | Always confirm with the user before overwriting existing file content |
| Skipping parent directory creation | Always create parent dirs (.cursor/rules/, .github/instructions/, .vscode/) before writing |
Using {name} as literal string in markers | {name} must be replaced with the actual metadata.name value, or default if absent |
harness-exportskills/harness-export/SKILL.md
Export Your Harness Configuration
You are helping the user capture their current harness-kit setup into a harness.yaml file they can share with teammates or commit to their dotfiles repo.
This file follows the Harness Protocol v1 format — the open spec at harnessprotocol.io. It is backward-compatible with harness-import (which handles both old and new formats).
Workflow Order (MANDATORY)
Follow these steps in order. Do not skip any step.
Step 1: Detect installed skills
Scan all four skill directories. Each subdirectory inside these directories is an installed skill:
~/.claude/skills/— Claude Code global skills.cursor/skills/— Cursor project-local skills.github/skills/— Copilot project-local skills.agents/skills/— agentskills.io standard shared location
ls ~/.claude/skills/ 2>/dev/null
ls .cursor/skills/ 2>/dev/null
ls .github/skills/ 2>/dev/null
ls .agents/skills/ 2>/dev/null
Collect the directory names from each location. Deduplicate by skill name across locations — if the same skill name appears in multiple directories, count it once. Track which platforms each skill was found in.
Show the user the combined result:
Found skills across AI tools:
Claude Code (~/.claude/skills/): research, explain, orient
Cursor (.cursor/skills/): research, explain
Copilot (.github/skills/): research
Shared (.agents/skills/): (none)
Unique skills: research, explain, orient
Use this deduplicated list as your list of installed plugin names for the steps that follow.
If all four directories are empty or missing, tell the user: "No installed skills found in any supported location. Nothing to export." and stop.
Step 2: Ask about sources and metadata
Tell the user what skills you found, then ask:
"I found these installed skills: [list]. A couple of quick questions:
For each plugin, which repo is it from? Format:
owner/repo— for exampleharnessprotocol/harness-kit. If a plugin is from harness-kit, just say so and I'll fill it in.What name and description should I give this harness profile? (optional — press enter to skip)
Do you have any MCP servers, env variables, or CLAUDE.md instructions you'd like to include? (optional)
Note: MCP server detection is automatic — Step 2.6 will scan
.mcp.json,.cursor/mcp.json, and.vscode/mcp.jsonand ask you separately. You only need to answer about MCP here if you have MCP servers in a non-standard location not covered by those files.If you've only added harness-kit plugins, just say so."
Wait for the user's response before proceeding.
Step 2.5: Detect cross-platform instruction content
Check whether any cross-platform instruction files exist and contain harness-generated marker blocks:
grep -l "<!-- BEGIN harness:" .cursor/rules/harness.mdc .github/copilot-instructions.md 2>/dev/null
Claude Code instruction files (CLAUDE.md, AGENT.md, SOUL.md) are intentionally excluded — they are managed by the user directly and are not cross-platform sources for export.
If any matching files are found, tell the user what was found and ask. List all slots found in each file — a file may contain multiple harness marker blocks:
"I also found harness-generated instruction content in these files:
.cursor/rules/harness.mdc(containsmy-harness:operationalandmy-harness:behavioralblocks).github/copilot-instructions.md(containsmy-harness:operationalblock)Would you like me to include the
operationalandbehavioralinstruction content in the export?"
(List only the files that actually exist and contain marker blocks — substitute the real profile name from the markers in place of my-harness.)
If the user says yes:
- Extract the content between each
<!-- BEGIN harness:{name}:{slot} -->and<!-- END harness:{name}:{slot} -->marker from those files. - If the same profile + slot block appears in multiple files with identical content, use it once.
- If the same profile + slot block appears in multiple files with different content, show the user both versions and ask which to use.
- Store the extracted content to include as the
instructions:section in harness.yaml (Step 4).
If the user says no, skip — do not include instruction content from cross-platform files.
If no harness marker blocks are found in any cross-platform file, skip this step silently.
Step 2.6: Detect cross-platform MCP servers
Scan these three files for MCP server definitions:
cat .mcp.json 2>/dev/null
cat .cursor/mcp.json 2>/dev/null
cat .vscode/mcp.json 2>/dev/null
Each file uses the same JSON structure with a top-level mcpServers key. Merge all mcpServers entries across all files found. Deduplicate by server name:
- If the same server name appears in multiple files with the same config, note that it is shared and count it once.
- If the same server name appears in multiple files with different configs, show the user both configs and ask which to keep.
Show the user a summary:
Found MCP servers:
postgres (in .mcp.json and .cursor/mcp.json — same config)
filesystem (in .mcp.json only)
"Would you like to include these in the export? (all / pick / none)"
If the user selects all or pick (and picks at least one), store the chosen servers to write to the mcp-servers: section in harness.yaml (Step 4). Convert from JSON format back to harness YAML format: JSON key type → YAML key transport.
If the user selects none, or if no MCP config files are found, skip this step.
Step 3: Build the plugin entries
For each installed skill, determine its source repo:
Known harness-kit plugins (source: harnessprotocol/harness-kit):
| Plugin | Description |
|---|---|
| explain | Layered explanations of files, functions, directories, or concepts |
| research | Process any source into a structured, compounding knowledge base |
| lineage | Column-level lineage tracing through SQL, Kafka, Spark, and JDBC |
| orient | Topic-focused session orientation across graph, knowledge, and research |
| capture | Capture session information into a staging file for later reflection |
| review | Code review for a branch, PR, or path — severity labels and cross-file analysis |
| docgen | Generate or update README, API docs, architecture overview, or changelog |
| harness-export | Export your installed plugins to a shareable harness.yaml |
| harness-import | Import a harness.yaml and interactively select plugins to install |
| harness-validate | Validate a harness.yaml file against the Harness Protocol v1 JSON Schema |
| harness-compile | Compile harness.yaml to native config files for Claude Code, Cursor, and Copilot |
| harness-sync | Sync AI tool configuration across Claude Code, Cursor, and Copilot |
| open-pr | Pre-flight checks and PR creation: run tests, open a PR, code review, and check CI |
| merge-pr | PR merge workflow: verify CI and review status, sync with base, confirm, squash merge, and clean up |
| pr-sweep | Cross-repo PR sweep: triage all open PRs, run code reviews, merge what's ready, fix quick CI blockers, and report |
For any installed skill not in this table, ask the user:
"I see
[name]installed but don't recognize it. Whatowner/repois it from, and what does it do in one sentence?"
Step 4: Write harness.yaml
Write harness.yaml to the current directory (or a path the user specifies). Use the Harness Protocol v1 format:
$schema: https://harnessprotocol.io/schema/v1/harness.schema.json
version: "1"
# Profile identity (optional but recommended)
metadata:
name: my-harness
description: My personal harness configuration.
plugins:
- name: explain
source: harnessprotocol/harness-kit
description: Layered explanations of files, functions, directories, or concepts
# additional plugins follow the same structure
With MCP servers (include only if user provided them):
mcp-servers:
postgres:
transport: stdio
command: uvx
args:
- mcp-server-postgres
- ${DB_CONNECTION_STRING}
With env declarations (include only if user has env vars):
env:
- name: DB_CONNECTION_STRING
description: PostgreSQL connection string.
required: true
sensitive: true
With instructions (include only if user wants to bundle CLAUDE.md/AGENT.md content):
instructions:
operational: |
Your operational instructions here.
import-mode: merge
Rules:
versionmust be the string"1"(quoted), not the integer1sourceisowner/repo— nomarketplace:key, nomarketplaces:section- Only include
mcp-servers,env,instructions, andpermissionssections if the user provided content for them - If instruction content was collected in Step 2.5, include it as the
instructions:section - If MCP servers were collected in Step 2.6, include them as the
mcp-servers:section (using YAMLtransport:key, not JSONtype:) - Omit
metadataif the user skipped the name/description questions - Do NOT include
harness-exportorharness-importin the output unless the user explicitly asks
Step 5: Confirm and suggest next steps
Tell the user where the file was written:
"Saved to
harness.yaml. To compile it to Cursor and Copilot config files, run/harness-compile.To share with teammates: commit it to your dotfiles repo. They can import it with
/harness-importinside Claude Code, or with the shell fallback:curl -fsSL https://raw.githubusercontent.com/harnessprotocol/harness-kit/main/harness-restore.sh | bash -s -- harness.yaml ```"
Common Mistakes
| Mistake | Fix |
|---|---|
Using version: 1 (integer) | Must be version: "1" (string) — this is what distinguishes the protocol format |
Using marketplace: harness-kit | Protocol format uses source: harnessprotocol/harness-kit — no marketplaces: section |
Including harness-export and harness-import in the output | Only include plugins the user actually uses |
| Writing to a path without confirming | Write to ./harness.yaml by default. If user specified a path in the invocation, use that |
Adding mcp-servers: / env: / instructions: as empty sections | Only include these sections when the user has actual content to put in them |
harness-importskills/harness-import/SKILL.md
Import a Harness Configuration
You are helping the user install plugins from a harness.yaml file — either all of them or a subset they choose.
This skill handles both format versions:
- v1 protocol format (
version: "1"string) — usessource: owner/repoper plugin, may includemcp-servers,env, andinstructionssections - Legacy format (
version: 1integer) — usesmarketplace: keyper plugin with amarketplaces:section
Workflow Order (MANDATORY)
Follow these steps in order. Do not skip any step.
Step 1: Find and read the config
Check for harness.yaml in this order:
- A path provided by the user after
/harness-import(e.g.,/harness-import ~/dotfiles/harness.yaml) ./harness.yamlin the current directory
If no file is found at either location, tell the user:
"No
harness.yamlfound. Get one from a teammate or generate your own with/harness-export."
Read and parse the file. Detect which format version it uses:
version: "1"(string) → Protocol v1 formatversion: 1(integer) → Legacy format
Step 2: Show what's available
Display the plugin list clearly before asking anything:
Plugins in this config:
1. explain (harnessprotocol/harness-kit) — Layered explanations of files, functions, directories, or concepts
2. research (harnessprotocol/harness-kit) — Process any source into a structured, compounding knowledge base
3. superpowers (obra/superpowers-marketplace) — Structured dev workflows — TDD, systematic debugging, subagent delegation
For legacy format, resolve the source by looking up plugins[].marketplace → marketplaces[key].
Then, if the file contains any of the following sections, mention them briefly:
mcp-servers:— "This config also declares MCP servers. I'll ask about those after plugins."env:— "This config declares environment variables. I'll surface those after plugins."instructions:— "This config includes harness instructions. I'll offer to apply those after plugins."
Then ask:
"Would you like to install all of these, pick a subset, or get more details on any before deciding?"
Step 3: Handle the user's choice
"All" — mark all plugins as selected, skip to Step 5.
"Details" — for each plugin the user asks about, explain what it does based on its description. You can supplement with your knowledge of harness-kit plugins. Then return to this question.
"Pick" or "subset" — proceed to Step 4.
Step 4: Individual selection
Walk through each plugin one at a time:
"explain — Layered explanations of files, functions, directories, or concepts. Include? (yes/no)"
Wait for the answer before moving to the next plugin. Collect the selection list.
After all plugins: "Got it — you've selected: [list]. Ready to generate the install commands?"
Step 5: Generate install commands
Output the complete Claude Code command sequence. Marketplace adds come first, plugin installs second.
For protocol v1 format (source: owner/repo), derive marketplace info from the source field:
Run these in Claude Code:
/plugin marketplace add harnessprotocol/harness-kit
/plugin marketplace add obra/superpowers-marketplace
/plugin install explain@harness-kit
/plugin install superpowers@obra
The marketplace short name to use in /plugin install commands is the repo name (last segment of owner/repo). Example: harnessprotocol/harness-kit → short name harness-kit.
For legacy format (marketplace: key + marketplaces: section), resolve as before:
marketplace: harness-kit+marketplaces.harness-kit: harnessprotocol/harness-kit→/plugin marketplace add harnessprotocol/harness-kit
Only include marketplaces for plugins actually selected.
Close with:
"Paste these into Claude Code and run them in order. Restart Claude Code after the installs complete."
Step 5.5: Offer cross-platform setup
After generating the Claude Code install commands, scan the current directory for other AI tool indicators.
Cursor is present if any of these exist: .cursor/, .cursor/rules/, .cursor/mcp.json, .cursor/skills/
GitHub Copilot is present if any of these exist: .github/, .github/skills/, .vscode/mcp.json
If .github/ is the only Copilot indicator present, ask the user: "I found a .github/ directory but no other Copilot indicators. Are you using GitHub Copilot in this project?" Only include Copilot in the multi-select menu if the user confirms.
If neither platform is detected, skip this step silently — do not ask.
If one or more platforms are detected, show them and ask which to include:
"I detected the following other AI tools in this project: Cursor, GitHub Copilot. Which would you like to set up?
- Both
- Cursor only
- Copilot only
- Neither (skip)"
For each confirmed platform, copy installed skill SKILL.md files:
- Only copy skills that have an installed SKILL.md at
~/.claude/skills/<name>/SKILL.md - Only copy skill files for the plugins the user selected in Steps 3–4. Do not copy all installed skills — only the selected subset.
- Cursor: copy to
.cursor/skills/<name>/SKILL.md - Copilot: copy to
.github/skills/<name>/SKILL.md
Frontmatter adaptation when copying:
- If the source SKILL.md frontmatter has a
dependenciesfield, rename it tocompatibility - Enforce that the
namefield is lowercase letters and hyphens only, max 64 characters. Truncate and slugify if needed. - If
descriptionexceeds 1024 characters, truncate at the last word boundary before 1024 characters and append…
Create parent directories before writing (.cursor/skills/<name>/, .github/skills/<name>/, .github/instructions/).
Record which platforms were confirmed — Steps 6 and 8 will use this.
Step 6: Handle MCP servers (if present)
If the config has a mcp-servers: section, walk through each server:
"This config declares an MCP server: postgres (stdio,
uvx mcp-server-postgres). Would you like me to add this to your.mcp.json?"
If yes, write or update .mcp.json in the current directory with the server definition.
If platforms were confirmed in Step 5.5, also write to platform-specific MCP configs:
- Cursor confirmed: also write
.cursor/mcp.json - Copilot confirmed: also write
.vscode/mcp.json
All three files use the same mcpServers JSON structure:
{
"mcpServers": {
"postgres": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-server-postgres", "--connection-string", "${DB_CONNECTION_STRING}"]
}
}
}
Note the casing: mcpServers (camelCase) — not mcp-servers, not mcp_servers.
Merge behavior (applies to all target files): If the target file already exists, add new servers but do not overwrite existing server configurations. If a server name already exists in the target file, warn:
Warning: <target-config-file> already defines server '<server-name>'. Existing config kept.
To update it, edit <target-config-file> directly or remove the entry and re-run.
For example: Warning: .cursor/mcp.json already defines server 'postgres'. Existing config kept.
Create parent directories before writing (.cursor/, .vscode/).
If the server command contains ${VAR} references, note which env vars are needed (the env: section will cover them in Step 7).
Step 7: Surface env declarations (if present)
If the config has an env: section, display them clearly:
Environment variables required by this harness:
DB_CONNECTION_STRING (required, sensitive) — PostgreSQL connection string for the project database.
ANALYTICS_API_KEY (optional, sensitive) — API key for the analytics MCP server.
Tell the user:
"These environment variables need to be set before using the MCP servers or skills that depend on them. Set them in your shell profile,
.envfile, or secret manager."
Do NOT ask for the values — sensitive vars must never be stored in the harness file or conversation.
Step 8: Offer to apply instructions (if present)
If the config has an instructions: section and import-mode: merge (or if import-mode is absent, default to merge), offer:
"This config includes harness instructions (operational guidance for the AI). Would you like me to append them to your
CLAUDE.mdorAGENT.md?"
If yes, append to the file the user specifies. If import-mode: replace is set, warn:
"This config requests full replacement of existing instructions. That will overwrite your current CLAUDE.md/AGENT.md. Are you sure?"
If Cursor or Copilot was confirmed in Step 5.5, also compile instructions to those platforms using the same import-mode from harness.yaml. Use metadata.name from the harness.yaml as {name} (or default if absent). Wrap all generated content in section markers (exact format — do not deviate):
<!-- BEGIN harness:{name}:{slot} -->
...generated content...
<!-- END harness:{name}:{slot} -->
Cursor operational — write .cursor/rules/harness.mdc with mandatory frontmatter before the marker block:
---
description: Harness operational instructions
globs: **/*
alwaysApply: true
---
Cursor behavioral — if instructions.behavioral is present in harness.yaml, write .cursor/rules/behavioral.mdc with mandatory frontmatter before the marker block:
---
description: Harness behavioral preferences
globs: **/*
alwaysApply: true
---
Then content from instructions.behavioral in section markers <!-- BEGIN harness:{name}:behavioral --> / <!-- END harness:{name}:behavioral -->.
GitHub Copilot operational — write .github/copilot-instructions.md with mandatory frontmatter before the marker block:
---
applyTo: "**"
---
GitHub Copilot behavioral — if instructions.behavioral is present in harness.yaml, write .github/instructions/behavioral.instructions.md with mandatory frontmatter before the marker block:
---
applyTo: "**"
---
Then content from instructions.behavioral in section markers <!-- BEGIN harness:{name}:behavioral --> / <!-- END harness:{name}:behavioral -->.
Identity slot: Omit for both Cursor and Copilot — the identity slot is Claude Code-only.
Apply the same import-mode behavior for all Cursor and Copilot files:
merge(default): If the file exists and contains matching markers, update the content between them. If no markers exist yet, append the marker block at the end (creating the file if it does not exist).replace: Before overwriting any Cursor or Copilot instruction file, warn the user and require confirmation, the same as for CLAUDE.md:"This config requests full replacement of existing [file]. That will overwrite your current [file] content. Are you sure?" Never apply
replacewithout confirmation.skip: Do not write or modify the file.
Create parent directories before writing (.cursor/rules/, .github/, .github/instructions/).
Step 9: Offer shell fallback
After all the above, add:
"If you'd rather install without Claude Code, use the shell script:
curl -fsSL https://raw.githubusercontent.com/harnessprotocol/harness-kit/main/harness-restore.sh | bash -s -- harness.yamlThis installs skill files directly (no scripts or hooks — those require the marketplace install)."
Step 9.5: Cross-platform compilation report
If cross-platform setup was performed (at least one platform confirmed in Step 5.5), print a summary after all steps complete:
Cross-platform setup complete:
Cursor:
Skills: explain, research (.cursor/skills/)
MCP: postgres (.cursor/mcp.json)
Instructions: harness.mdc (operational), behavioral.mdc (behavioral)
GitHub Copilot:
Skills: explain, research (.github/skills/)
MCP: (none declared in harness.yaml)
Instructions: copilot-instructions.md (operational), behavioral.instructions.md (behavioral)
Omit any row where nothing was written for that category (e.g., omit MCP: if the harness has no mcp-servers: section). Omit a platform block entirely if that platform was not confirmed or nothing was written for it. If cross-platform setup was skipped (Step 5.5 produced no confirmations), do not print this report.
Common Mistakes
| Mistake | Fix |
|---|---|
| Including marketplaces for plugins the user didn't select | Only add marketplace add lines for marketplaces that have at least one selected plugin |
Forgetting to explain the @name convention | The @name in /plugin install must match the marketplace short name (repo name), not the owner |
| Skipping the marketplace add commands | They must come before the plugin installs, or the installs will fail |
Ignoring mcp-servers, env, instructions sections | Always check for these sections and handle them in the appropriate steps |
| Prompting the user for sensitive env var values | Never ask for secret values — just tell the user which vars to set and where |
| Asking about cross-platform setup when no other platforms are detected | Only prompt for cross-platform setup if Cursor or Copilot indicators are found; skip silently otherwise |
| Copying skill SKILL.md files that aren't installed | Only copy skills that have a SKILL.md at ~/.claude/skills/<name>/SKILL.md |
Using mcp_servers or mcp-servers in MCP JSON files | JSON key must be mcpServers (camelCase) in all target files |
| Silently skipping MCP server key collisions in Cursor/Copilot configs | Always warn when a server name already exists in the target file — never skip silently |
Omitting Cursor .mdc frontmatter | Always add description, globs, alwaysApply frontmatter — it is mandatory for Cursor to recognize the file |
Omitting Copilot copilot-instructions.md frontmatter | Always add applyTo: "**" frontmatter to Copilot instructions files |
| Using wrong section marker format | Markers must be exact: <!-- BEGIN harness:{name}:{slot} --> — any deviation breaks merge logic |
| Skipping parent directory creation | Always create parent dirs (.cursor/skills/<name>/, .github/skills/<name>/, .cursor/rules/, .vscode/) before writing |
| Printing the cross-platform report when nothing was set up | Only print Step 9.5 report if at least one platform was confirmed in Step 5.5 |
harness-syncskills/harness-sync/SKILL.md
Sync Harness Configurations Across Platforms
You are syncing AI tool configurations across Claude Code, Cursor, and GitHub Copilot. You will inventory what is installed and configured on each platform, report any divergence, and execute the sync direction the user chooses.
This skill depends on harness-compile: the push path reuses harness-compile's compilation logic to write the selected source platform's content to all target platforms.
Workflow Order (MANDATORY)
Follow these steps in order. Do not skip any step.
Step 1: Detect platforms
Check for any --target <platform> flag the user passed. If present, restrict the entire workflow to that platform only. Valid values: claude-code, cursor, copilot. For sync, --target <platform> means "treat this platform as the only target for push output." It does not restrict which platforms are scanned in Step 2 — all detected platforms are still inventoried so divergence can be identified.
Otherwise, scan the working directory for platform indicators:
Claude Code is present if any of these exist: CLAUDE.md, .claude/, .mcp.json
Cursor is present if any of these exist: .cursor/, .cursor/rules/, .cursor/mcp.json, .cursor/skills/
Copilot is present if any of these exist: .github/, .vscode/mcp.json, .github/skills/
Never assume a platform is present. Detect each independently. If .github/ is the only Copilot indicator, ask the user:
"I found a
.github/directory but no other Copilot indicators. Are you using GitHub Copilot in this project?"
Also check global skill directories:
~/.claude/skills/— Claude Code global skill installs~/.cursor/skills/— Cursor global skills (if the directory exists)
If no platforms are detected, tell the user:
"No AI tool config directories found. Which platforms are you using? (claude-code, cursor, copilot)"
Step 2: Inventory current state
For each detected platform, catalog three things:
Installed skills:
- Claude Code:
~/.claude/skills/(global) and any project-local skill symlinks - Cursor:
.cursor/skills/(project-local),~/.cursor/skills/(global if the directory exists) - Copilot:
.github/skills/(project-local) - Shared:
.agents/skills/(agentskills.io shared — available to both Cursor and Copilot)
Distinguish global vs. project-local installs with a (global) or (local) tag. Label skills found in .agents/skills/ as (shared) in the inventory display.
Instruction files: Read each platform's instruction files and identify:
- Harness marker blocks: lines matching
<!-- BEGIN harness:and<!-- END harness: --> - Manual content: any content outside marker blocks
Report marker blocks by their {name}:{slot} identifier.
MCP server configs: Parse JSON from:
- Claude Code:
.mcp.json - Cursor:
.cursor/mcp.json - Copilot / VS Code:
.vscode/mcp.json
List each server by name and transport type.
Present a unified inventory:
Current state:
Claude Code:
Skills: research (global), explain (global), orient (global)
MCP: postgres (stdio), filesystem (stdio)
Harness blocks in CLAUDE.md: [my-harness:operational], [my-harness:behavioral]
Cursor:
Skills: research (local), explain (local)
MCP: postgres (stdio)
Harness blocks in .cursor/rules/harness.mdc: [my-harness:operational]
Copilot:
Skills: (none)
MCP: (none)
Harness blocks in .github/copilot-instructions.md: (none)
If a platform has no instruction file for a slot, show (none) for that slot's harness blocks.
Step 3: Detect divergence
Compare across all detected platforms:
Skills divergence: For each unique skill name found anywhere, note which platforms have it and which don't.
MCP divergence: For each unique MCP server name found anywhere, note which platforms have it and which don't. If a server exists on multiple platforms but with different configurations (different command, args, or type), flag it as a configuration conflict.
Instructions divergence: For each unique harness block identifier (e.g., my-harness:operational) found anywhere, compare the content between platforms. If the content differs between any two platforms, flag it.
Present a divergence report:
Divergence detected:
Skills:
✓ research — all platforms
✓ explain — all platforms
✗ orient — Claude Code only (missing from Cursor, Copilot)
MCP:
△ postgres — Claude Code, Cursor (missing from Copilot)
✗ filesystem — Claude Code only
Instructions:
CLAUDE.md ↔ .cursor/rules/harness.mdc: content differs (my-harness:operational block)
.github/copilot-instructions.md: no harness blocks (Claude Code has my-harness:operational, my-harness:behavioral)
If no divergence is found across any dimension, tell the user:
"All platforms are in sync. Nothing to do."
And stop here.
Step 4: Propose sync direction
Ask the user:
"How would you like to sync?
- Push from Claude Code → other platforms
- Push from Cursor → other platforms
- Pull changes from Cursor/Copilot into harness.yaml, then recompile
- Show me the diff first
Which would you like?"
Wait for the user's answer before proceeding.
Note: Copilot cannot be a push source. To incorporate changes made directly in Copilot config files into harness.yaml, use option 3 (pull).
Option 1 or 2 (push): Note the source platform. Ask which targets to push to:
"Push to which platforms? (all detected platforms, or list specific ones)"
Wait for target confirmation before proceeding to Step 5.
Option 3 (pull): Note that the user wants to pull external changes back into harness.yaml and proceed to Step 5.
Option 4 (diff): Show a detailed diff of each divergent section:
- For skills: list which skills are missing from which platforms
- For MCP: list which servers are missing or differ between platforms, showing the full server config side by side if configs differ
- For instructions: show the full content of each divergent harness block from each platform, labelled by platform and file path
After showing all diffs, return to this question.
Step 5: Conflict detection
Before executing any sync, check for conflicts: a conflict exists when the same harness block identifier (e.g., my-harness:operational) has different content on two or more platforms that the user is treating as peers (i.e., neither is designated the authoritative source).
For push operations: The source platform is authoritative. There are no conflicts — the source wins. Skip to Step 6.
For pull operations: Two kinds of conflicts must be resolved before writing to harness.yaml:
First, if multiple external platforms are selected as pull sources (e.g., both Cursor and Copilot), compare those platforms against each other. If the same harness block exists on both with different content, that is a cross-platform conflict that must be surfaced before either is merged into harness.yaml:
Cross-platform conflict: my-harness:operational
Cursor (.cursor/rules/harness.mdc):
[content A]
Copilot (.github/copilot-instructions.md):
[content B]
These platforms disagree. Which should I pull from?
1. Use Cursor version
2. Use Copilot version
3. Edit manually first, then re-run /harness-sync
4. Skip this block
Resolve all cross-platform conflicts first, then proceed to compare the surviving version against harness.yaml.
Second, any harness block that exists on the pull source and in harness.yaml with different content is a conflict.
For each conflict, show both versions side by side and ask for resolution:
Conflict: my-harness:operational
Claude Code (CLAUDE.md):
[full content of the block from CLAUDE.md]
Cursor (.cursor/rules/harness.mdc):
[full content of the block from .cursor/rules/harness.mdc]
How would you like to resolve this?
1. Use Claude Code version (overwrite Cursor)
2. Use Cursor version (overwrite Claude Code)
3. Edit manually first, then re-run /harness-sync
4. Skip this conflict for now
Never silently overwrite. Always show both versions. Always wait for the user's resolution choice before proceeding. Resolve all conflicts before moving to Step 6.
If the user chooses option 3 (edit manually), stop and tell them:
"Make your edits, then run
/harness-syncagain to pick up where we left off."
If the user chooses option 4 (skip), note the skipped conflict and continue resolving remaining conflicts. Skipped conflicts will not be synced.
Step 6: Execute
Push path:
Use harness-compile logic to write the source platform's content to all confirmed target platforms. Only update items that are divergent — do not touch content that is already in sync across platforms.
When reading skill SKILL.md files for the push source, locate them as follows:
- Push source = Claude Code: read from
~/.claude/skills/<name>/SKILL.md - Push source = Cursor: check
.cursor/skills/<name>/SKILL.mdfirst; if not found, fall back to~/.cursor/skills/<name>/SKILL.md - Skills in
.agents/skills/<name>/SKILL.mdare available to both platforms and may be used as a source if neither platform-specific path yields a SKILL.md
For each divergent item:
- Skills: copy the skill's SKILL.md (located via the lookup above) to each target platform's skill directory (
.cursor/skills/<name>/SKILL.mdfor Cursor,.github/skills/<name>/SKILL.mdfor Copilot). Apply frontmatter adaptation rules from harness-compile (renamedependenciestocompatibility, enforce name constraints, truncate description if over 1024 characters). - MCP servers: add missing servers to target MCP config files using the source platform's server definition. Do not overwrite existing server entries in the target — if a server name already exists in the target file, print a warning and skip it.
- Instructions: write the source platform's harness block content into each target platform's instruction file, following the slot mapping and marker format from harness-compile. Follow import-mode rules: if the target file already contains markers for that block, update between the markers; if no markers exist yet, append the block.
Create parent directories before writing if they don't exist.
Pull path:
- Read all content that exists outside harness marker blocks in the source platform's instruction files (Cursor or Copilot). This is native content the user added directly.
- Read all MCP servers that exist in source platform config files but are not in harness.yaml.
Skill files are not pulled. Skills in harness.yaml are plugin source references (source: owner/repo), not file content. If Cursor has a skill in .cursor/skills/ that is not in harness.yaml, it cannot be automatically added — the plugins: section requires knowing the plugin's source repo. Tell the user:
"I found skills in
.cursor/skills/not in your harness.yaml: [list]. To add these, run/harness-exportand specify their source repos when prompted."
- Summarize what would be added to harness.yaml:
Changes to write to harness.yaml:
instructions.operational: 14 lines of content from .cursor/rules/harness.mdc (outside harness blocks)
mcp-servers: add "redis" server from .cursor/mcp.json
- Warn the user:
"This will modify your harness.yaml — your source of truth file. The changes above will be merged in."
"Proceed? [y/N]"
- If the user confirms, write the updated harness.yaml with the pulled content merged in.
- After writing harness.yaml, immediately run harness-compile logic to recompile all platforms from the updated harness.yaml, applying the new content consistently everywhere.
Step 7: Verify
Re-run the Step 2 inventory scan across all platforms that were modified. Compare the results to confirm platforms are now in sync.
Report the outcome:
Sync complete:
Added: .cursor/skills/orient/SKILL.md
Updated: .cursor/mcp.json (added filesystem server)
Updated: .cursor/rules/harness.mdc (my-harness:operational block)
Skipped: .github/ (Copilot not detected)
All platforms are now in sync.
If any divergence remains (e.g., a skipped conflict, a server that already existed in the target), report it:
Remaining divergence:
my-harness:operational block was skipped (conflict unresolved)
Run /harness-sync again to address it.
Common Mistakes
| Mistake | Fix |
|---|---|
| Silently overwriting divergent content | Always show the conflict and ask — never write without the user's explicit choice |
Treating .github/ alone as Copilot confirmation | Ask the user if .github/ is the only indicator — it may exist for CI only |
| Conflating global and project-local skills | Always label skills as (global) or (local) in the inventory — they are not equivalent |
| Skipping conflict detection on push | Push makes the source authoritative — but still check whether the user confirmed the target list before writing |
| Overwriting existing MCP server entries in targets | On push, add missing servers only — warn and skip if a server name already exists in the target |
| Running pull without warning about harness.yaml modification | Always warn that pull modifies harness.yaml before writing |
| Forgetting to recompile after pull | Pull must update harness.yaml and then run harness-compile logic — the two steps are always paired |
| Skipping Step 7 verification | Always re-scan after sync to confirm platforms are in sync and report any remaining divergence |
| Reporting all items in the sync report, not just changed ones | Only report files that were actually added, updated, or skipped — do not list unchanged files |
| Applying frontmatter adaptation only for new skills | Frontmatter rules (rename dependencies, enforce name constraints, truncate description) apply on every copy to Cursor/Copilot, including updates |
| Showing only one version in a conflict | Always show both versions side by side with platform labels — never show just one |
| Skipping cross-platform comparison on pull | When multiple platforms are pull sources, compare them against each other before merging into harness.yaml |
| Expecting Copilot to be a push source | Copilot is a pull-only platform. Use option 3 to bring Copilot changes back into harness.yaml |
harness-validateskills/harness-validate/SKILL.md
Validate a Harness Configuration
You are helping the user validate a harness.yaml file against the Harness Protocol v1 JSON Schema.
Workflow Order (MANDATORY)
Follow these steps in order. Do not skip any step.
Step 1: Find the file
Check for the harness file in this order:
- A path provided by the user after
/harness-validate(e.g.,/harness-validate ~/dotfiles/harness.yaml) ./harness.yamlin the current directory
If no file is found at either location, tell the user:
"No
harness.yamlfound. Specify a path:/harness-validate path/to/harness.yaml"
Read the file contents.
Step 2: Run validation
Install the validation tools if not present and run validation:
python3 -m venv /tmp/hk-validate-venv 2>/dev/null || true
/tmp/hk-validate-venv/bin/pip install jsonschema pyyaml -q 2>/dev/null || \
(python3 -m venv /tmp/hk-validate-venv && /tmp/hk-validate-venv/bin/pip install jsonschema pyyaml -q)
Then run this validation script:
import json, sys, yaml
try:
from jsonschema import validate, ValidationError, SchemaError
from jsonschema.validators import validator_for
except ImportError:
print("ERROR: jsonschema not installed")
sys.exit(1)
SCHEMA_URL = "https://raw.githubusercontent.com/harnessprotocol/harness-protocol/spec/v1-foundation/schema/draft/harness.schema.json"
HARNESS_FILE = "harness.yaml" # replace with actual path
# Fetch the schema
import urllib.request
try:
with urllib.request.urlopen(SCHEMA_URL, timeout=5) as resp:
schema = json.loads(resp.read())
except Exception as e:
print(f"WARN: Could not fetch remote schema ({e}). Falling back to basic checks.")
schema = None
# Load the harness file
try:
with open(HARNESS_FILE) as f:
doc = yaml.safe_load(f)
except yaml.YAMLError as e:
print(f"FAIL: YAML parse error — {e}")
sys.exit(1)
if schema is None:
# Basic offline checks
errors = []
if "version" not in doc:
errors.append("Missing required field: version")
elif doc["version"] not in ("1", 1):
errors.append(f"version must be \"1\" (string) or 1 (legacy integer), got: {doc['version']!r}")
if "metadata" not in doc:
errors.append("Missing required field: metadata")
elif "name" not in doc.get("metadata", {}):
errors.append("metadata.name is required")
if errors:
for e in errors:
print(f"FAIL: {e}")
else:
print("PASS (basic checks only — schema fetch failed)")
sys.exit(0)
# Full schema validation
try:
validate(instance=doc, schema=schema)
print("PASS")
except ValidationError as e:
path = " → ".join(str(p) for p in e.absolute_path) or "(root)"
print(f"FAIL: {path}: {e.message}")
except SchemaError as e:
print(f"ERROR: Schema itself is invalid — {e.message}")
Run the script with /tmp/hk-validate-venv/bin/python3 and capture the output.
Step 3: Report results
On PASS:
"Your
harness.yamlis valid — passes Harness Protocol v1 schema validation."
If the file uses version: 1 (integer, legacy format), add:
"Note: this is in the legacy format (
version: 1integer). Run/harness-exportto regenerate in Harness Protocol v1 format (version: \"1\"string)."
On FAIL (validation errors):
Display errors with clear field paths and fix suggestions:
✗ harness.yaml failed validation:
plugins → 0 → source: 'marketplace' is not a valid property
Fix: Use source: owner/repo instead of marketplace: key.
Example: source: harnessprotocol/harness-kit
env → 0: 'default' is not allowed when sensitive is true
Fix: Remove the default value — sensitive vars must be set by the user,
never baked into the harness file.
(root): version must be "1" (string), got 1 (integer)
Fix: Change version: 1 to version: "1" (add quotes).
Common errors and their fixes:
| Error | Fix |
|---|---|
version must be string "1" | Change version: 1 to version: "1" |
source is not a valid property | Replace marketplace: key with source: owner/repo |
default not allowed when sensitive: true | Remove the default value |
metadata.name is required | Add a metadata.name field |
| Unknown additional property | Check for typos in field names |
After listing errors:
"Fix these issues and run
/harness-validateagain to confirm."
On YAML parse error:
"Your
harness.yamlhas a YAML syntax error:[error details]Common causes: wrong indentation, missing quotes around special characters (like
:in strings), or a tab used instead of spaces."
Common Mistakes
| Mistake | Fix |
|---|---|
| Reporting only the first error | Show all errors, not just the first one |
| Giving up if schema fetch fails | Fall back to basic checks and tell the user the schema was unavailable |
Suggesting marketplace: as a fix | Always recommend source: owner/repo — that's the v1 format |