# harness-compound

> Harness Compound

- Skill: `intense-visions/harness-compound` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add intense-visions/harness-compound`
- Raw SKILL.md: https://api.skillmd.com/api/skills/intense-visions/harness-compound/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Intense-Visions (https://skillmd.com/u/intense-visions)
- Updated: 2026-08-19
- Page: https://skillmd.com/skills/intense-visions/harness-compound

---

# Harness Compound

> 5-phase post-mortem capture. When a problem is solved, distill it into a structured doc at `docs/solutions/<track>/<category>/<slug>.md` so the next person (or agent) finds the playbook before re-deriving it.

## When to Use

- Manually, after solving a non-trivial problem (a bug fix that took >1 commit, a debugging session, an architectural decision worth preserving)
- When the orchestrator's step 6b mechanical triggers fire (deferred until Phase 7 wires it)
- When the weekly `compound-candidates` scanner surfaces a candidate (deferred until Phase 5)
- NOT for trivial fixes (typos, lint, one-line obvious)
- NOT for facts that belong in `docs/knowledge/` (use `harness-knowledge-pipeline`; the boundary is: knowledge-pipeline extracts structural facts FROM CODE; compound captures post-mortem playbooks WRITTEN AFTER A FIX)
- NOT for ephemeral session notes (`.harness/learnings.md` still exists for that)

## Process

### Iron Law

**One problem, one canonical doc.** Phase 3 (overlap-check) is mandatory. If overlap is high, UPDATE the existing doc (bump `last_updated`, append to relevant section). Do not create a duplicate.

---

### Phase 1: IDENTIFY

Extract the problem and the solution from available context:

1. Read recent conversation, the active debug session at `.harness/debug/active/*.md` if present, and recent `git log --oneline -20`.
2. Distill into a 1-2 sentence problem statement and 1-2 sentence solution statement.
3. Note the affected `module` (package name or area, e.g. `orchestrator`, `cli/validate`).

**Output:** `{ problem, solution, module, candidateTags }`.

---

### Phase 2: CLASSIFY

Read `docs/solutions/references/schema.yaml` for the authoritative track/category enum and `docs/solutions/references/category-mapping.md` for examples of which problems land in which category.

1. Choose `track`:
   - `bug-track` — a thing was broken; you fixed it. Concrete failure, concrete cause.
   - `knowledge-track` — a pattern, convention, or decision worth preserving as guidance, not a fix.
2. Choose `category` from the enum for that track. If nothing fits, **stop and escalate** — adding categories requires a PR (Decision 8).

**Output:** `{ track, category }`.

---

### Phase 3: OVERLAP-CHECK

1. List every existing `docs/solutions/<track>/<category>/*.md`.
2. For each, read the `# <Title>` heading and the first 200 chars of the `## Problem` (bug-track) or `## Context` (knowledge-track) section.
3. Compute overlap heuristically: shared `module`, shared `problem_type`, similar problem statement (Jaccard on bag-of-words >= 0.5 is a reasonable threshold; the agent uses judgment).
4. If high overlap with one existing doc:
   - Open the existing doc.
   - Update relevant sections (append a new bullet under `## Solution` or `## Guidance` describing the new instance, bump `last_updated`).
   - Skip Phase 4 and most of Phase 5 (only the write-with-lock step runs).
5. If no overlap, proceed to Phase 4.

---

### Phase 4: ASSEMBLE

1. Copy `docs/solutions/assets/resolution-template.md` to a working buffer.
2. Fill the frontmatter:

   ```yaml
   ---
   module: <from Phase 1>
   tags: [<from Phase 1 candidateTags, lowercase, hyphenated>]
   problem_type: <short noun phrase, e.g. 'race-condition'>
   last_updated: '<YYYY-MM-DD, today>'
   track: <bug-track | knowledge-track>
   category: <from Phase 2>
   ---
   ```

3. Replace the `# <Title>` placeholder with a concise problem statement.
4. For `bug-track`: fill `## Problem`, `## Root cause`, `## Solution`, `## Prevention`. Delete the knowledge-track sections (`## Context`, `## Guidance`, `## Applicability`).
5. For `knowledge-track`: fill `## Context`, `## Guidance`, `## Applicability`. Delete the bug-track sections.
6. Cite commit SHAs and `file:line` where helpful.

---

### Phase 5: WRITE (lock-protected)

1. Compute slug: kebab-case from the title; if a file with that slug already exists in the target directory, append `-2`, `-3`, etc.
2. **Acquire the per-category lock via the harness MCP server.** Call `acquire_compound_lock({ path: process.cwd(), category: '<category>' })`. On success it returns `{ acquired: true, token, lockPath }` — hold the `token` while you write the doc, then call `release_compound_lock({ token })` when finished. The MCP server holds the file handle and registers process-exit cleanup, so an abandoned agent does not leave a dangling lock-with-stale-PID. Lock path: `.harness/locks/compound-<category>.lock`. Fallback for environments without the MCP server (only works when `@harness-engineering/core` is resolvable from the project): `node -e "import('@harness-engineering/core').then(({ acquireCompoundLock }) => { const h = acquireCompoundLock('<category>'); /* write the doc here */ h.release(); })"`.
   - On `{ acquired: false, error: 'CompoundLockHeldError', holderPid }` (or `CompoundLockHeldError` when invoked directly): report "compound lock for category `<category>` is held by pid `<holderPid>` — wait for it to release or run `/harness:compound` for a different category" and stop. **Do not retry automatically.** A second invocation on the same problem after release will go through Phase 3 and find the doc the first invocation produced.
3. Re-run a quick Phase 3 overlap-check inside the lock (defends against TOCTOU when the first overlap-check returned "no overlap" but another invocation completed in the meantime; the re-check is cheap).
4. Write the file at `docs/solutions/<track>/<category>/<slug>.md`.
5. Validate frontmatter against `SolutionDocFrontmatterSchema` by running `harness validate` (which runs `validateSolutionsDir`).
6. Release the lock via `release_compound_lock({ token })` (or `handle.release()` on the fallback shell-out path).
7. Surface to chat: file path created (or updated), category, and a one-sentence summary.

## Harness Integration

- **`harness validate`** — Run after writing the doc; the solutions validator catches frontmatter errors before commit.
- **`harness check-deps`** — Not required (no new module imports introduced by writing a doc).
- **Harness MCP tools consumed by this skill** (canonical execution path — no project-local `@harness-engineering/core` required):
  - `acquire_compound_lock({ path, category })` — returns `{ acquired: true, token, lockPath }` on success or `{ acquired: false, error: 'CompoundLockHeldError', holderPid, lockPath }` on contention.
  - `release_compound_lock({ token })` — releases the lock; idempotent on repeat calls with the same token.
- **`@harness-engineering/core` lock primitive** (only directly relevant when the MCP server is unavailable) — `acquireCompoundLock(category, { cwd })` returns a release handle; throws `CompoundLockHeldError` on contention. See `packages/core/src/locks/compound-lock.ts`.
- **Schema authority** — `packages/core/src/solutions/schema.ts` is the single source of truth for tracks and categories. `docs/solutions/references/schema.yaml` mirrors it for human reading.
- **Boundary with `harness-knowledge-pipeline`** — Knowledge-pipeline extracts structural facts FROM CODE. Compound captures post-mortem playbooks WRITTEN AFTER A FIX. Compound's knowledge-track output is a _candidate input_ to the pipeline (Phase 7 of the spec wires this).
- **Boundary with `.harness/learnings.md`** — The file remains for ephemeral session notes. It is no longer the canonical sink for compounding knowledge — that's `docs/solutions/`.

## Success Criteria

- A new solution doc is written to `docs/solutions/<track>/<category>/<slug>.md` with valid frontmatter (passes `validateSolutionsDir`).
- Two concurrent invocations on the same category cannot both succeed: one writes, the other returns `CompoundLockHeldError`.
- A second invocation on the same problem updates the existing doc instead of creating a duplicate.
- The skill never invents a new category — unknown categories are escalated.
- PII is not written into the doc (the agent reads from local conversation/commits; no remote queries).

## Rationalizations to Reject

These are common rationalizations that sound reasonable but lead to incorrect results. When you catch yourself thinking any of these, stop and follow the documented process instead.

| Rationalization                                                                                   | Why It Is Wrong                                                                                                                                                                                                                                                     |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "This problem is obviously new — I'll skip the Phase 3 overlap-check and write the doc directly." | Phase 3 is mandatory, no exceptions. "Obviously new" is exactly the assumption that produces duplicate docs and erodes the corpus's value. List the existing docs in the target category and compute overlap before writing.                                        |
| "No category fits perfectly — I'll invent one that describes this problem better."                | The track/category enum in `packages/core/src/solutions/schema.ts` is the single source of truth. Inventing a category requires a PR (Decision 8). Stop and escalate; a mislabeled doc is worse than a delayed one.                                                 |
| "The compound lock is held by another pid — I'll retry in a loop until it frees."                 | The contract is report-and-stop, never auto-retry. The holding invocation will produce the canonical doc, and a later re-run on the same problem goes through Phase 3 and finds it. Busy-looping defeats the per-category serialization the lock exists to provide. |
| "Overlap is high, but my instance is a little different, so a fresh doc is cleaner."              | Iron Law: one problem, one canonical doc. A near-duplicate splits the playbook across two files. Append a bullet under `## Solution`/`## Guidance` and bump `last_updated` instead of forking.                                                                      |
| "The doc is written and the frontmatter looks right — I'll skip `harness validate`."              | Frontmatter errors silently break the corpus (`validateSolutionsDir` is what catches them). Validation is a gate that must pass before exit; a doc that fails schema is not "done."                                                                                 |

## Examples

### Example: bug-track

Input: "Stalled lease cleanup in orchestrator caused stuck issues. Fix was to add a 5-minute lease TTL with a sweep at startup. Took 4 commits, debugged via `harness-debugging`."

- Phase 1: `module=orchestrator`, problem="stuck issues from stalled leases", solution="lease TTL + startup sweep".
- Phase 2: `track=bug-track`, `category=integration-issues` (lease coordination is integration-shaped).
- Phase 3: no overlap.
- Phase 4: fill Problem / Root cause / Solution / Prevention.
- Phase 5: write `docs/solutions/bug-track/integration-issues/stalled-lease-cleanup.md` under lock.

### Example: knowledge-track

Input: "We standardized on `Result<T, E>` returns for all I/O paths in `packages/core`. Document the convention and when not to use it."

- Phase 1: `module=core`, problem="when to use Result vs throwing", solution="convention doc".
- Phase 2: `track=knowledge-track`, `category=conventions`.
- Phase 3: no overlap.
- Phase 4: fill Context / Guidance / Applicability.
- Phase 5: write `docs/solutions/knowledge-track/conventions/result-type-for-io.md` under lock.

### Example: overlap-check updates existing doc

Input: "Hit the same stalled-lease bug today on a different code path."

- Phase 1, 2 produce the same `bug-track/integration-issues` target.
- Phase 3 finds `stalled-lease-cleanup.md` with high overlap.
- Append a bullet to `## Solution` describing the new instance, bump `last_updated`, do not create a new file.

## Gates

- **Phase 3 is mandatory.** No exceptions. Skipping overlap-check produces duplicate docs and erodes the value of the corpus.
- **No invented categories.** Unknown categories require a PR to `packages/core/src/solutions/schema.ts`. Escalate.
- **Lock must wrap Phase 5.** Without the lock, two concurrent invocations on the same category race on overlap-check and produce duplicates.
- **`harness validate` must pass before exit.** Frontmatter errors silently break the corpus.

## Escalation

- **Cannot decide track/category:** Escalate to the user. Show the candidate (track, category) pairs and the rationale for each. Wait for selection.
- **Lock held by another invocation:** Report and stop. Do not retry. The user re-runs after release.
- **`validateSolutionsDir` rejects the doc:** Show the validator error, fix the frontmatter, re-validate. Do not commit a doc that fails validation.
- **Problem does not fit any category:** Escalate. Adding a category requires a PR (Decision 8 of the feedback-loops spec).

