Skip to content

Harness Adapters

A harness is the coding environment Tuff emits into, such as .agents/ or .claude/. A harness adapter is Tuff’s agent-specific implementation layer for that environment.

The adapter decides where files are emitted, how native settings are updated, and where tool registration lives.

Tuff currently ships five adapters:

Adapter Target id Main output root
Open Agents open-agents .agents/
Claude claude .claude/
Codex codex .agents/
Cursor cursor .cursor/
OpenCode opencode .opencode/

opencode takes policies and MCP servers, both written to .opencode/opencode.json. OpenCode reads skills from the .agents/ layout, so install those with open-agents.

open-agents remains the generic shared .agents/ adapter. Codex now has a dedicated adapter even though it currently emits the same directory family, because its hook coverage and native behavior are tracked independently.

Legacy aliases are also accepted:

  • claude-code resolves to claude

The same capability can be emitted differently depending on the agent.

A capability that is already installed can be emitted for a harness it was not installed for. Point tuff add at the directory it already occupies and name the new agent:

Terminal window
tuff add .agents/skills/release-checklist -a claude

This records a new target and emits the capability into that harness’s layout. The recorded source, version, and description are left alone, because adding a harness says nothing about where the capability came from. A target that is already recorded is not re-emitted; use tuff update for that.

Agent Emitted path
open-agents .agents/skills/<id>/...
claude .claude/skills/<id>/...
Agent Emitted path MCP registration
open-agents .agents/tools/<id>/... .agents/mcp.json
claude .claude/tools/<id>/... .mcp.json
codex .agents/tools/<id>/... [mcp_servers.<id>] in .codex/config.toml
cursor .cursor/tools/<id>/... .cursor/mcp.json
opencode not supported mcp in .opencode/opencode.json (MCP servers only)

Tuff writes the tool files and also registers the tool in the agent’s MCP config so the harness can discover it.

Hooks are where the adapter differences are most visible:

Agent Emitted path Format
open-agents .agents/hooks/<id>/run.sh plus .agents/hook.json Native JSON (development format)
claude .claude/hooks/<id>/... plus .claude/settings.json Native Claude JSON
codex .agents/hooks/<id>/run.sh plus .codex/hooks.json Codex hooks JSON, grouped
cursor .cursor/hooks/<id>/run.sh plus .cursor/hooks.json Cursor Hooks JSON

For Claude, tuff add hook ... --hook-file settings.json reads a hooks-only native fragment, copies runtime files when needed, and merges the fragment into .claude/settings.json.

All four adapters currently support:

  • skill
  • tool
  • hook

Manifest-style Tuff-standard hook event support is adapter-specific, and each adapter declares it as a compatibility matrix: for every canonical event, the native event it renders to and whether coverage is full, partial with a caveat, or unsupported. The matrices for all four adapters are published in the Hooks Specification, generated from the same code tuff add runs. Native hook fragments supplied with --hook-file keep their harness event names and are merged as-is.

If you try to install a manifest-style hook with an unsupported event, Tuff blocks the install and shows which events that adapter accepts. Run tuff hooks matrix to inspect the registered adapter compatibility matrix, or tuff hooks check-portability <id> --target <adapter> to check an installed hook before switching adapters.

Terminal window
tuff harness list
tuff harness add open-agents
tuff harness add claude
tuff harness add codex
tuff harness add cursor
tuff hooks matrix