~ $ harness-sync

One config, every LLM harness.

A CLI tool that syncs skills, agents, MCP servers, endpoints, and instructions from a single canonical tree into each harness's native format.

# import from whatever you already use
$ harness-sync detect
  ✓ claude-code  → ~/.claude/
  ✓ kilo         → ~/.config/kilo/
  ✓ crush        → ~/.config/crush/
  × goose          not found
  × opencode       not found

$ harness-sync init
  imported 12 skills, 4 agents, 6 mcp servers from claude-code

$ harness-sync apply --dry-run
  plan: write 14 files to claude-code, 11 to kilo, 9 to crush
  (dry-run, nothing written)
install github

The problem

You run claude-code, kilo, crush, opencode, goose, cagent, zed — each keeps its own copy of the same config.

without harness-sync

  • same skill markdown, duplicated seven ways
  • same agent definitions, rewritten per harness
  • same MCP registry, seven different key names (mcpServers, mcp, context_servers…)
  • same gateway URL, hand-copied into seven files
  • edit once, forget the others, things break

with harness-sync

  • one canonical tree under git version control
  • per-harness adapters render native config formats
  • 3-way merge via git merge-file
  • secrets via ${VAR} env-var substitution, never stored
  • git rollback on every apply

What it does

Supported harnesses

Each adapter grounded against real config files and upstream docs.

harness manages note
claude-code mcp · skills · instructions provider config managed by Anthropic directly
crush mcp · skills · providers · models full gateway rendering with provider map
kilo mcp · skills · providers · models small model + provider map config
opencode mcp · skills · providers · models · instructions JSONC config with instructions merging
goose mcp · skills · providers · models YAML with extensions map
cagent mcp · providers · models · instructions starter YAML with per-agent model
zed mcp · providers · models context servers in settings.json

Install

one-liner (recommended)

$ curl -fsSL https://raw.githubusercontent.com/\
    lukaszraczylo/harness-sync/main/install.sh | bash

Picks the right release for OS/arch, verifies SHA-256, drops binary in ~/.local/bin.

homebrew

$ brew install lukaszraczylo/taps/harness-sync

from source

$ git clone https://github.com/lukaszraczylo/harness-sync
$ make build && make install

Requires Go 1.24+ and git on $PATH.

Usage

# 1. see what's installed
$ harness-sync detect

# 2. import from detected harnesses into canonical tree
$ harness-sync init

# 3. render canonical tree to all harness configs
$ harness-sync apply
$ harness-sync apply --dry-run        # preview without writing
$ harness-sync diff                  # same as apply --dry-run
$ harness-sync profile list           # list profiles
$ harness-sync profile use work       # switch active profile
$ harness-sync rollback 2             # git revert last 2 applies
$ harness-sync update                 # pull latest release

flags

flageffect
--dry-runshow plan, write nothing
--forceoverwrite without merge
--yesskip confirmation prompt
--from a,bpick source adapters for init
--no-prompttake all detected sources

Architecture

Single Go binary. ~7,400 LOC. 174 passing tests. 18 packages.

harness-sync architecture

canonical tree

~/.config/harness-sync/  (git)
├── profiles/<name>.yaml
├── skills/<name>/SKILL.md
├── agents/<name>.md
├── mcp.yaml
└── instructions/global.md

merge model

base   ← state/  (last render)
ours   ← rendered (what we'd write now)
theirs ← on disk  (what's actually there)

disjoint → clean merge, write file
overlap  → .rej file, exit non-zero