mirror of
https://github.com/lukaszraczylo/harness-sync.git
synced 2026-10-12 00:45:22 +00:00
321 lines
24 KiB
HTML
321 lines
24 KiB
HTML
<!doctype html>
|
||
<html lang="en" class="scroll-smooth">
|
||
<head>
|
||
<meta charset="UTF-8"/>
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
||
<title>harness-sync · one config, every harness</title>
|
||
<meta name="description" content="One canonical source of truth for skills, agents, MCP servers, LLM endpoints, and global instructions across every LLM harness on your machine."/>
|
||
<link rel="canonical" href="https://harness-sync.raczylo.com"/>
|
||
<meta property="og:type" content="website"/>
|
||
<meta property="og:url" content="https://harness-sync.raczylo.com"/>
|
||
<meta property="og:title" content="harness-sync · one config, every harness"/>
|
||
<meta property="og:description" content="One canonical source of truth for skills, agents, MCP servers, LLM endpoints, and global instructions across every LLM harness on your machine."/>
|
||
<meta property="og:image" content="https://harness-sync.raczylo.com/assets/banner.svg"/>
|
||
<meta name="twitter:card" content="summary_large_image"/>
|
||
<meta name="twitter:title" content="harness-sync · one config, every harness"/>
|
||
<meta name="twitter:description" content="One canonical source of truth for skills, agents, MCP servers, LLM endpoints, and global instructions across every LLM harness on your machine."/>
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<script>tailwind.config={darkMode:'class'}</script>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"/>
|
||
<style>
|
||
body{font-family:system-ui,sans-serif}
|
||
code,pre,.mono{font-family:"JetBrains Mono",ui-monospace,monospace}
|
||
.terminal{background:#0d1117;color:#c9d1d9;border:1px solid #21262d;border-radius:8px;overflow:hidden}
|
||
.terminal-bar{background:#161b22;border-bottom:1px solid #21262d;padding:10px 14px;display:flex;gap:6px}
|
||
.terminal-dot{width:11px;height:11px;border-radius:50%}
|
||
.terminal pre{padding:18px 20px;margin:0;white-space:pre-wrap;font-size:13px;line-height:1.7;overflow-x:auto}
|
||
.terminal .g{color:#7ee787}.terminal .c{color:#79c0ff}.terminal .y{color:#d29922}.terminal .r{color:#ff7b72}.terminal .w{color:#c9d1d9}.terminal .d{color:#6e7681}
|
||
section + section{border-top:1px solid theme('colors.neutral.200')}
|
||
.dark section + section{border-top:1px solid theme('colors.neutral.800')}
|
||
@media(max-width:768px){.terminal pre{font-size:12px;padding:14px}}
|
||
</style>
|
||
<script>
|
||
if(localStorage.theme==="dark"||(!("theme" in localStorage)&&window.matchMedia("(prefers-color-scheme:dark)").matches))document.documentElement.classList.add("dark");else document.documentElement.classList.remove("dark");
|
||
</script>
|
||
</head>
|
||
<body class="bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100">
|
||
|
||
<!-- Nav -->
|
||
<nav class="sticky top-0 z-50 bg-white/90 dark:bg-neutral-950/90 backdrop-blur border-b border-neutral-200 dark:border-neutral-800">
|
||
<div class="max-w-3xl mx-auto px-5 flex items-center justify-between h-14">
|
||
<a href="#" class="mono text-sm font-medium tracking-tight"><span class="text-emerald-600 dark:text-emerald-400">$</span> harness-sync</a>
|
||
<div class="hidden md:flex items-center gap-6 text-sm text-neutral-500 dark:text-neutral-400">
|
||
<a href="#problem" class="hover:text-neutral-900 dark:hover:text-neutral-100">problem</a>
|
||
<a href="#features" class="hover:text-neutral-900 dark:hover:text-neutral-100">features</a>
|
||
<a href="#harnesses" class="hover:text-neutral-900 dark:hover:text-neutral-100">harnesses</a>
|
||
<a href="#install" class="hover:text-neutral-900 dark:hover:text-neutral-100">install</a>
|
||
<a href="#usage" class="hover:text-neutral-900 dark:hover:text-neutral-100">usage</a>
|
||
<a href="#architecture" class="hover:text-neutral-900 dark:hover:text-neutral-100">architecture</a>
|
||
</div>
|
||
<div class="flex items-center gap-3">
|
||
<button id="theme-toggle" class="text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 p-1" aria-label="Toggle theme">
|
||
<svg id="theme-moon" class="w-4 h-4 dark:hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/></svg>
|
||
<svg id="theme-sun" class="w-4 h-4 hidden dark:block" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/></svg>
|
||
</button>
|
||
<a href="https://github.com/lukaszraczylo/harness-sync" class="text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 p-1" aria-label="GitHub">
|
||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
||
</button>
|
||
<button id="mobile-toggle" class="md:hidden text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 p-1" aria-label="Menu">
|
||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div id="mobile-menu" class="hidden md:hidden border-t border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-950">
|
||
<div class="px-5 py-3 flex flex-col gap-2 text-sm">
|
||
<a href="#problem" class="text-neutral-500 dark:text-neutral-400 py-1">problem</a>
|
||
<a href="#features" class="text-neutral-500 dark:text-neutral-400 py-1">features</a>
|
||
<a href="#harnesses" class="text-neutral-500 dark:text-neutral-400 py-1">harnesses</a>
|
||
<a href="#install" class="text-neutral-500 dark:text-neutral-400 py-1">install</a>
|
||
<a href="#usage" class="text-neutral-500 dark:text-neutral-400 py-1">usage</a>
|
||
<a href="#architecture" class="text-neutral-500 dark:text-neutral-400 py-1">architecture</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- Hero -->
|
||
<header class="max-w-3xl mx-auto px-5 pt-16 pb-12 md:pt-24 md:pb-16">
|
||
<p class="mono text-sm text-emerald-600 dark:text-emerald-400 mb-4">~ $ harness-sync</p>
|
||
<h1 class="text-3xl md:text-4xl font-semibold tracking-tight leading-tight mb-4">One config, every <span class="text-neutral-400 dark:text-neutral-500">LLM</span> harness.</h1>
|
||
<p class="text-lg text-neutral-600 dark:text-neutral-400 mb-8 max-w-xl leading-relaxed">A CLI tool that syncs skills, agents, MCP servers, endpoints, and instructions from a single canonical tree into each harness's native format.</p>
|
||
<div class="terminal mb-8">
|
||
<div class="terminal-bar">
|
||
<span class="terminal-dot" style="background:#ff5f57"></span>
|
||
<span class="terminal-dot" style="background:#febc2e"></span>
|
||
<span class="terminal-dot" style="background:#28c840"></span>
|
||
</div>
|
||
<pre><span class="d"># import from whatever you already use</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> detect
|
||
<span class="w"> ✓ claude-code → ~/.claude/</span>
|
||
<span class="w"> ✓ kilo → ~/.config/kilo/</span>
|
||
<span class="w"> ✓ crush → ~/.config/crush/</span>
|
||
<span class="d"> × goose not found</span>
|
||
<span class="d"> × opencode not found</span>
|
||
|
||
<span class="g">$</span> <span class="c">harness-sync</span> init
|
||
<span class="w"> imported 12 skills, 4 agents, 6 mcp servers from claude-code</span>
|
||
|
||
<span class="g">$</span> <span class="c">harness-sync</span> apply --dry-run
|
||
<span class="w"> plan: write 14 files to claude-code, 11 to kilo, 9 to crush</span>
|
||
<span class="y"> (dry-run, nothing written)</span>
|
||
</pre>
|
||
</div>
|
||
<div class="flex items-center gap-3">
|
||
<a href="#install" class="inline-block bg-neutral-900 dark:bg-neutral-100 text-white dark:text-neutral-900 px-5 py-2.5 text-sm font-medium rounded">install</a>
|
||
<a href="https://github.com/lukaszraczylo/harness-sync" class="inline-block border border-neutral-300 dark:border-neutral-700 px-5 py-2.5 text-sm font-medium rounded hover:bg-neutral-50 dark:hover:bg-neutral-900">github</a>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Problem -->
|
||
<section id="problem" class="max-w-3xl mx-auto px-5 py-12 md:py-16">
|
||
<h2 class="text-2xl font-semibold tracking-tight mb-3">The problem</h2>
|
||
<p class="text-neutral-600 dark:text-neutral-400 mb-8 leading-relaxed">You run <code class="mono text-sm bg-neutral-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded">claude-code</code>, <code class="mono text-sm bg-neutral-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded">kilo</code>, <code class="mono text-sm bg-neutral-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded">crush</code>, <code class="mono text-sm bg-neutral-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded">opencode</code>, <code class="mono text-sm bg-neutral-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded">goose</code>, <code class="mono text-sm bg-neutral-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded">cagent</code>, <code class="mono text-sm bg-neutral-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded">zed</code> — each keeps its own copy of the same config.</p>
|
||
<div class="grid md:grid-cols-2 gap-6">
|
||
<div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-3">without harness-sync</h3>
|
||
<ul class="space-y-2 text-sm text-neutral-700 dark:text-neutral-300">
|
||
<li class="flex gap-2"><span class="text-red-500 shrink-0">✕</span><span>same skill markdown, duplicated seven ways</span></li>
|
||
<li class="flex gap-2"><span class="text-red-500 shrink-0">✕</span><span>same agent definitions, rewritten per harness</span></li>
|
||
<li class="flex gap-2"><span class="text-red-500 shrink-0">✕</span><span>same MCP registry, seven different key names (<code class="mono text-xs">mcpServers</code>, <code class="mono text-xs">mcp</code>, <code class="mono text-xs">context_servers</code>…)</span></li>
|
||
<li class="flex gap-2"><span class="text-red-500 shrink-0">✕</span><span>same gateway URL, hand-copied into seven files</span></li>
|
||
<li class="flex gap-2"><span class="text-red-500 shrink-0">✕</span><span>edit once, forget the others, things break</span></li>
|
||
</ul>
|
||
</div>
|
||
<div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-3">with harness-sync</h3>
|
||
<ul class="space-y-2 text-sm text-neutral-700 dark:text-neutral-300">
|
||
<li class="flex gap-2"><span class="text-emerald-600 dark:text-emerald-400 shrink-0">→</span><span>one canonical tree under git version control</span></li>
|
||
<li class="flex gap-2"><span class="text-emerald-600 dark:text-emerald-400 shrink-0">→</span><span>per-harness adapters render native config formats</span></li>
|
||
<li class="flex gap-2"><span class="text-emerald-600 dark:text-emerald-400 shrink-0">→</span><span>3-way merge via <code class="mono text-xs">git merge-file</code></span></li>
|
||
<li class="flex gap-2"><span class="text-emerald-600 dark:text-emerald-400 shrink-0">→</span><span>secrets via <code class="mono text-xs">${VAR}</code> env-var substitution, never stored</span></li>
|
||
<li class="flex gap-2"><span class="text-emerald-600 dark:text-emerald-400 shrink-0">→</span><span>git rollback on every apply</span></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Features -->
|
||
<section id="features" class="max-w-3xl mx-auto px-5 py-12 md:py-16">
|
||
<h2 class="text-2xl font-semibold tracking-tight mb-6">What it does</h2>
|
||
<ul class="space-y-4 text-sm text-neutral-700 dark:text-neutral-300">
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Canonical tree.</strong> Profiles, skills, agents, mcp servers, and instructions in a single git-managed directory.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Native adapters.</strong> Each harness gets its correct keys and file types — no lowest-common-denominator config.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">3-way merge.</strong> <code class="mono text-xs">git merge-file</code> semantics — disjoint changes merge cleanly, conflicts produce <code class="mono text-xs">.rej</code> files.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Profiles.</strong> Bundle gateway URL, model allowlist, and upstream keys — switch with one command.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Secret safety.</strong> Env-var substitution at render time. Secrets never written to disk or canonical tree.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Auto-detection.</strong> Detects installed harnesses. Only touches what's relevant on your machine.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Dry-run preview.</strong> Diff every target file before writing anything to disk.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Git rollback.</strong> Revert the last <em>n</em> applies. Full version history in local git.</div></li>
|
||
<li class="flex gap-3"><span class="text-emerald-600 dark:text-emerald-400 shrink-0 mt-0.5">→</span><div><strong class="font-medium text-neutral-900 dark:text-neutral-100">Non-destructive overlay.</strong> Only managed keys are written. Your hooks, permissions, and editor settings survive.</div></li>
|
||
</ul>
|
||
</section>
|
||
|
||
<!-- Harnesses -->
|
||
<section id="harnesses" class="max-w-3xl mx-auto px-5 py-12 md:py-16">
|
||
<h2 class="text-2xl font-semibold tracking-tight mb-3">Supported harnesses</h2>
|
||
<p class="text-neutral-600 dark:text-neutral-400 mb-8 text-sm">Each adapter grounded against real config files and upstream docs.</p>
|
||
<div class="overflow-x-auto">
|
||
<table class="w-full text-sm">
|
||
<thead class="border-b border-neutral-200 dark:border-neutral-800 text-left">
|
||
<tr class="text-neutral-500 dark:text-neutral-400 mono text-xs uppercase tracking-wide">
|
||
<th class="pb-2 pr-4 font-medium">harness</th>
|
||
<th class="pb-2 pr-4 font-medium">manages</th>
|
||
<th class="pb-2 font-medium">note</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="text-neutral-700 dark:text-neutral-300">
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60">
|
||
<td class="py-2.5 pr-4 mono font-medium">claude-code</td>
|
||
<td class="py-2.5 pr-4">mcp · skills · instructions</td>
|
||
<td class="py-2.5 text-neutral-500 dark:text-neutral-500">provider config managed by Anthropic directly</td>
|
||
</tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60">
|
||
<td class="py-2.5 pr-4 mono font-medium">crush</td>
|
||
<td class="py-2.5 pr-4">mcp · skills · providers · models</td>
|
||
<td class="py-2.5 text-neutral-500 dark:text-neutral-500">full gateway rendering with provider map</td>
|
||
</tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60">
|
||
<td class="py-2.5 pr-4 mono font-medium">kilo</td>
|
||
<td class="py-2.5 pr-4">mcp · skills · providers · models</td>
|
||
<td class="py-2.5 text-neutral-500 dark:text-neutral-500">small model + provider map config</td>
|
||
</tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60">
|
||
<td class="py-2.5 pr-4 mono font-medium">opencode</td>
|
||
<td class="py-2.5 pr-4">mcp · skills · providers · models · instructions</td>
|
||
<td class="py-2.5 text-neutral-500 dark:text-neutral-500">JSONC config with instructions merging</td>
|
||
</tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60">
|
||
<td class="py-2.5 pr-4 mono font-medium">goose</td>
|
||
<td class="py-2.5 pr-4">mcp · skills · providers · models</td>
|
||
<td class="py-2.5 text-neutral-500 dark:text-neutral-500">YAML with extensions map</td>
|
||
</tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60">
|
||
<td class="py-2.5 pr-4 mono font-medium">cagent</td>
|
||
<td class="py-2.5 pr-4">mcp · providers · models · instructions</td>
|
||
<td class="py-2.5 text-neutral-500 dark:text-neutral-500">starter YAML with per-agent model</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-2.5 pr-4 mono font-medium">zed</td>
|
||
<td class="py-2.5 pr-4">mcp · providers · models</td>
|
||
<td class="py-2.5 text-neutral-500 dark:text-neutral-500">context servers in settings.json</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Install -->
|
||
<section id="install" class="max-w-3xl mx-auto px-5 py-12 md:py-16">
|
||
<h2 class="text-2xl font-semibold tracking-tight mb-6">Install</h2>
|
||
<div class="space-y-6">
|
||
<div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-2">one-liner (recommended)</h3>
|
||
<div class="terminal"><pre><span class="g">$</span> curl -fsSL https://raw.githubusercontent.com/<span class="w">\</span>
|
||
lukaszraczylo/harness-sync/main/install.sh | bash</pre></div>
|
||
<p class="text-xs text-neutral-500 dark:text-neutral-500 mt-2">Picks the right release for OS/arch, verifies SHA-256, drops binary in <code class="mono">~/.local/bin</code>.</p>
|
||
</div>
|
||
<div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-2">homebrew</h3>
|
||
<div class="terminal"><pre><span class="g">$</span> brew install lukaszraczylo/taps/harness-sync</pre></div>
|
||
</div>
|
||
<div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-2">from source</h3>
|
||
<div class="terminal"><pre><span class="g">$</span> git clone https://github.com/lukaszraczylo/harness-sync
|
||
<span class="g">$</span> make build && make install</pre></div>
|
||
<p class="text-xs text-neutral-500 dark:text-neutral-500 mt-2">Requires Go 1.24+ and <code class="mono">git</code> on <code class="mono">$PATH</code>.</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Usage -->
|
||
<section id="usage" class="max-w-3xl mx-auto px-5 py-12 md:py-16">
|
||
<h2 class="text-2xl font-semibold tracking-tight mb-6">Usage</h2>
|
||
<div class="terminal mb-8"><pre><span class="d"># 1. see what's installed</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> detect
|
||
|
||
<span class="d"># 2. import from detected harnesses into canonical tree</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> init
|
||
|
||
<span class="d"># 3. render canonical tree to all harness configs</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> apply
|
||
<span class="g">$</span> <span class="c">harness-sync</span> apply --dry-run <span class="d"># preview without writing</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> diff <span class="d"># same as apply --dry-run</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> profile list <span class="d"># list profiles</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> profile use work <span class="d"># switch active profile</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> rollback 2 <span class="d"># git revert last 2 applies</span>
|
||
<span class="g">$</span> <span class="c">harness-sync</span> update <span class="d"># pull latest release</span>
|
||
</pre></div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-3">flags</h3>
|
||
<div class="overflow-x-auto">
|
||
<table class="w-full text-sm">
|
||
<thead class="border-b border-neutral-200 dark:border-neutral-800 text-left">
|
||
<tr class="text-neutral-500 dark:text-neutral-400 mono text-xs uppercase tracking-wide"><th class="pb-2 pr-4 font-medium">flag</th><th class="pb-2 font-medium">effect</th></tr>
|
||
</thead>
|
||
<tbody class="text-neutral-700 dark:text-neutral-300">
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60"><td class="py-2 pr-4 mono">--dry-run</td><td class="py-2">show plan, write nothing</td></tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60"><td class="py-2 pr-4 mono">--force</td><td class="py-2">overwrite without merge</td></tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60"><td class="py-2 pr-4 mono">--yes</td><td class="py-2">skip confirmation prompt</td></tr>
|
||
<tr class="border-b border-neutral-100 dark:border-neutral-800/60"><td class="py-2 pr-4 mono">--from a,b</td><td class="py-2">pick source adapters for init</td></tr>
|
||
<tr><td class="py-2 pr-4 mono">--no-prompt</td><td class="py-2">take all detected sources</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Architecture -->
|
||
<section id="architecture" class="max-w-3xl mx-auto px-5 py-12 md:py-16">
|
||
<h2 class="text-2xl font-semibold tracking-tight mb-3">Architecture</h2>
|
||
<p class="text-neutral-600 dark:text-neutral-400 mb-8 text-sm">Single Go binary. ~7,400 LOC. 174 passing tests. 18 packages.</p>
|
||
<div class="flex justify-center mb-8">
|
||
<img src="assets/architecture.svg" alt="harness-sync architecture" class="w-full max-w-2xl"/>
|
||
</div>
|
||
<div class="grid md:grid-cols-2 gap-6">
|
||
<div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-3">canonical tree</h3>
|
||
<div class="terminal"><pre><span class="c">~/.config/harness-sync/</span> <span class="d">(git)</span>
|
||
├── profiles/<span class="y"><name>.yaml</span>
|
||
├── skills/<span class="y"><name>/SKILL.md</span>
|
||
├── agents/<span class="y"><name>.md</span>
|
||
├── mcp.yaml
|
||
└── instructions/<span class="y">global.md</span></pre></div>
|
||
</div>
|
||
<div>
|
||
<h3 class="mono text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-3">merge model</h3>
|
||
<div class="terminal"><pre><span class="d">base </span> ← state/ <span class="d">(last render)</span>
|
||
<span class="g">ours </span> ← rendered <span class="d">(what we'd write now)</span>
|
||
<span class="c">theirs</span> ← on disk <span class="d">(what's actually there)</span>
|
||
|
||
<span class="d">disjoint</span> → clean merge, write file
|
||
<span class="y">overlap </span> → .rej file, exit non-zero</pre></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Footer -->
|
||
<footer class="border-t border-neutral-200 dark:border-neutral-800">
|
||
<div class="max-w-3xl mx-auto px-5 py-8 flex flex-col md:flex-row justify-between items-center gap-3 text-sm text-neutral-500 dark:text-neutral-500">
|
||
<div class="mono">
|
||
<span class="text-emerald-600 dark:text-emerald-400">$</span> harness-sync — one config, every harness
|
||
</div>
|
||
<div class="flex items-center gap-5">
|
||
<a href="https://github.com/lukaszraczylo/harness-sync" class="hover:text-neutral-900 dark:hover:text-neutral-100">github</a>
|
||
<a href="https://github.com/sponsors/lukaszraczylo" class="hover:text-neutral-900 dark:hover:text-neutral-100">sponsor</a>
|
||
<span>MIT</span>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
document.getElementById('theme-toggle').addEventListener('click',()=>{
|
||
const d=document.documentElement.classList;
|
||
if(d.contains('dark')){d.remove('dark');localStorage.theme='light'}
|
||
else{d.add('dark');localStorage.theme='dark'}
|
||
});
|
||
const mt=document.getElementById('mobile-toggle'),mm=document.getElementById('mobile-menu');
|
||
mt.addEventListener('click',()=>mm.classList.toggle('hidden'));
|
||
mm.querySelectorAll('a').forEach(l=>l.addEventListener('click',()=>mm.classList.add('hidden')));
|
||
</script>
|
||
</body>
|
||
</html>
|