Metadata-Version: 2.4
Name: oneharness
Version: 0.1.1
Summary: Maintain a single .1harness/ config directory and transpile to multiple AI coding agent formats
License-Expression: MIT
Requires-Python: >=3.10
Requires-Dist: click>=8.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# OneHarness

Maintain a single `.1harness/` directory as the source of truth for your AI coding agent configurations, then transpile them into multiple target formats.

**One config. Every tool.**

## The Problem

Each AI coding tool has its own config directory, file format, and feature set:

| Tool | Skills | Instructions | MCP | Config location |
|------|--------|-------------|-----|-----------------|
| Claude Code | `.claude/skills/` | `CLAUDE.md` | `.claude/settings.json` | `.claude/` |
| OpenCode | `.opencode/skills/` | `AGENTS.md` | `.opencode/config.yaml` | `.opencode/` |
| GitHub Copilot | `.github/skills/` | `.github/copilot-instructions.md` | `.vscode/mcp.json` | `.github/`, `.vscode/` |

When you update a skill or MCP server config, you have to replicate the change across every tool manually. OneHarness eliminates that.

## How It Works

```
.1harness/                    # You maintain this (committed to git)
  config.yaml                 # Which tools to target
  AGENTS.md                   # Main instructions
  skills/
    code-review/SKILL.md      # Your skills
  instructions/
    coding-standards.md       # Your instructions
  mcp/
    servers.yaml              # Your MCP servers

        oneharness sync
        ────────────────>

.claude/                      # Generated (gitignored)
  skills/code-review/SKILL.md
  settings.json               # MCP servers merged in
CLAUDE.md                     # Instructions concatenated

.opencode/                    # Generated (gitignored)
  skills/code-review/SKILL.md
AGENTS.md                     # Instructions concatenated

.github/                      # Generated (gitignored)
  skills/code-review/SKILL.md
  copilot-instructions.md     # Instructions concatenated
.vscode/
  mcp.json                    # MCP servers merged in
```

## Install

```bash
# Zero-install (recommended) - runs directly without installing
uvx oneharness

# Or install permanently
uv pip install oneharness
# or
uv add oneharness
```

## Quick Start

```bash
# 1. Initialize - select which tools to target
oneharness init

# 2. Add your content to .1harness/
#    - Put skills in .1harness/skills/<name>/SKILL.md
#    - Put instructions in .1harness/instructions/*.md
#    - Put MCP configs in .1harness/mcp/*.yaml
#    - Edit .1harness/AGENTS.md for main instructions

# 3. Sync to all target tools
oneharness sync
```

### Global / Home Config Quick Start

Use this when you want personal defaults available across projects.

```bash
# 1. Initialize your home-level config
oneharness init --global

# 2. Add your personal defaults
#    - ~/.config/1harness/AGENTS.md
#    - ~/.config/1harness/skills/<name>/SKILL.md
#    - ~/.config/1harness/instructions/*.md
#    - ~/.config/1harness/mcp/*.yaml

# 3. Sync home config into each tool's home directory
oneharness sync --global
```

Project and global configs are independent. OneHarness syncs both levels separately; the target tool decides how they combine.

## Commands

### `oneharness init`

Interactive setup. Prompts you to select target tools, scaffolds `.1harness/`, writes `config.yaml`, and optionally runs an initial sync.

```bash
oneharness init            # Project only (default)
oneharness init --global   # Global config (~/.config/1harness/)
oneharness init --all      # Both
```

### `oneharness sync`

Transpiles `.1harness/` content into each target tool's config directory.

```bash
oneharness sync            # Incremental sync (default)
oneharness sync --clean    # Wipe target dirs first, then sync fresh
oneharness sync --global   # Sync global config only
oneharness sync --all      # Sync both global and project
```

- Only touches files it owns (tracked in `sync.lock`)
- Manually added files in target dirs are preserved
- Incremental: skips unchanged files via SHA-256 hashing
- Reports 4-level diagnostics: `info`, `lossy`, `skipped`, `blocked`

### `oneharness status`

Shows sync state per adapter: file count, last sync time, capability resolutions, lossy transform count.

### `oneharness clean`

Interactive removal of generated config directories. Reads ownership from `sync.lock` so it removes exactly what OneHarness created.

```bash
oneharness clean                    # Interactive select
oneharness clean --target claude-code  # Clean specific adapter
```

### `oneharness doctor`

Read-only audit. Checks config validity, adapter availability, hash mismatches, missing files, and whether target tools are installed.

## Config

`.1harness/config.yaml` (committed to git):

`config.yaml` is generated automatically by `oneharness init`, but it is intended to remain human-editable. You can enable or disable adapters, add version constraints, change fallback behavior, and edit instruction entries manually.

```yaml
schema_version: 1
adapters:
  claude-code:
    enabled: true
    version: ">=1.0.0"    # Optional version constraint
  opencode:
    enabled: true
  copilot-vscode:
    enabled: true
instructions:
  - path: "instructions/coding-standards.md"
    scope: project
    apply_to: ["*.py", "*.ts"]    # Optional file targeting
  - path: "AGENTS.md"
    scope: global
fallback:
  on_lossy: warn      # warn | error | ignore
  on_skipped: warn
  on_blocked: error
```

## Scope Levels

OneHarness supports two independent config levels:

| Level | Location | Syncs to |
|-------|----------|----------|
| Project | `./.1harness/` | Tool project dirs (`.claude/`, `.opencode/`, etc.) |
| Global | `~/.config/1harness/` | Tool home dirs (`~/.claude/`, `~/.opencode/`, etc.) |

Each level syncs independently. OneHarness does **not** merge between levels -- the target tools handle that.

All commands default to `--project`. Use `--global` or `--all` to include other levels.

## Supported Adapters (v1)

| Adapter | Skills | Instructions | Agents | MCP | Hooks | Commands | Prompts |
|---------|--------|-------------|--------|-----|-------|----------|---------|
| Claude Code | yes | yes | yes | yes | partial | yes | yes |
| OpenCode | yes | yes | yes | yes | no | no | no |
| Copilot VS Code | yes | yes | yes | yes | yes | partial | yes |

**partial** = some sub-features supported; unsupported parts emit `lossy` diagnostics.

## Diagnostics

Every sync reports diagnostics at four levels:

| Level | Meaning |
|-------|---------|
| `info` | File synced successfully |
| `lossy` | Content was simplified or partially dropped during transform |
| `skipped` | Feature not supported by target adapter, omitted |
| `blocked` | Fatal error, file could not be synced |

Configure how each level is treated via `fallback` in `config.yaml`.

## Files

OneHarness adds only two files to your `.1harness/`:

- **`config.yaml`** -- Adapter selection and settings. Commit this.
- **`sync.lock`** -- Sync state with hashes and ownership. Gitignored.

Everything else in `.1harness/` is your content. Adapter manifests and all CLI logic ship inside the Python package.

## Requirements

- Python 3.10+
- [uv](https://docs.astral.sh/uv/) (recommended for `uvx` zero-install usage)
