Skip to content

Harnesses & adapters

A harness is a target AI coding agent. Each one loads skills from its own path with its own schema. adept sync renders every canonical skill into every enabled harness, and adept sync-from adopts harness-side edits back into canonical.

Enable and inspect harnesses:

Terminal window
adept harness add claude-code # enable a harness
adept harness remove cursor # disable a harness
adept harness list # registered harnesses + enabled state

Enabled harness ids are recorded in .adeptability/config.json under harnesses[].

Five harnesses ship dedicated renderers that get the details right — correct frontmatter, activation translation, sidecar handling, and size budgets:

Harness id Output Global
Claude Code claude-code .claude/skills/<id>/SKILL.md (full sidecars, allowed-tools) ~/.claude/skills/<id>/SKILL.md
Cursor cursor .cursor/rules/<id>.mdc (activation → alwaysApply/globs/description) not global-capable
OpenCode opencode .opencode/skill/<id>/SKILL.md (full sidecars) ~/.config/opencode/skill/<id>/SKILL.md
Codex codex AGENTS.md (aggregated, 32 KiB cap, lowest-priority dropped first) ~/.codex/AGENTS.md
GitHub Copilot copilot .github/instructions/<bucket>.instructions.md (aggregated per-glob) not global-capable

See the Harness Comparison for exactly what each renderer emits and why it differs, and Scopes for what --global changes and why Cursor and Copilot are excluded.

Beyond the five specialized renderers, adept ships built-in generic per-skill adapters for 50+ more agents — each writing SKILL.md into that agent’s convention. A sample:

amp, cline, continue, gemini-cli, github-copilot (agent-skills mode), goose, junie, kilo, openhands, qwen-code, roo, warp, windsurf, zencoder, and many more that write into a shared .agents/skills/<id>/SKILL.md.

Run adept harness list for the authoritative, live registry — it always reflects the version you have installed.

You can teach adept about a new harness by dropping a YAML adapter file into $ADEPT_LIBRARY/adapters/ (or a library’s adapters/ dir). It’s loaded at startup. Example:

id: jetbrains-junie
name: JetBrains Junie
kind: per-skill
output: ".junie/guidelines/{id}.md"
needs-directory: false
size-budget-bytes: 0
frontmatter:
include:
- description
- tags
rename:
description: summary
body:
prefix: |
> Auto-generated by adeptability. Do not edit by hand.
detect:
- ".junie/"
- ".junie/guidelines/"

Adapter files are validated against an embedded schema on load. Key fields:

  • kindper-skill (one file per skill), aggregator-single, or aggregator-per-glob.
  • output — the on-disk path template; {id} expands to the skill id.
  • frontmatter.include / frontmatter.rename — which canonical fields to emit, and any key renames.
  • body.prefix / body.suffix / body.replace — body transforms (with {{.Project.Name}} templating).
  • detect — path globs used to auto-adopt existing files on adept init.
  • import.rename — optional reverse-render hints; the default sync-from flow auto-derives the inverse of frontmatter.rename, so this is only needed for non-bijective renames.

See examples/adapters/jetbrains-junie.yaml in the repo for the fully annotated version.

Two optional keys give a config-driven adapter a home-level target, same as the built-in renderers:

id: jetbrains-junie
name: JetBrains Junie
kind: per-skill
output: ".junie/guidelines/{id}.md"
global-output: ".junie/guidelines/{id}.md" # path relative to the global render root ($HOME)
global-base-dir: ".junie" # detection root when scoped globally

Leave both out and the adapter simply isn’t global-capable: adept --global harness add <id> fails with harness has no global config location, same as the built-in Cursor and Copilot adapters. See Scopes for the full global-scope model.