Skip to main content

Adding Harness Support

This guide is for developers building AI clients, IDEs, agent frameworks, or other tools who want to support the Agent Harnesses standard.

What clients must implement

A compliant client must support the four-phase loading model:
  1. Load — at session start, inject the full HARNESS.md body into the agent’s context
  2. Discovery — expose tools so the agent can read skill and reference descriptions to find what is relevant to a task
  3. Activation — expose tools so the agent can read the full content of a skill or reference when its description matches the task
  4. Execution — expose tools so the agent can run scripts bundled within skills
Clients may implement additional features (caching, skill search, UI affordances) but these four behaviors are the baseline.

Loading model in detail

Load

At session start, read HARNESS.md frontmatter to get name and description for routing or presenting the harness to the user, then inject the full body into the agent’s context:
harness = parse_frontmatter_and_body("HARNESS.md")
present_to_user(harness.name, harness.description)
inject_into_context(harness.body)
HARNESS.md is the agent’s map of the harness — it establishes the agent’s role and tells it what skills and references are available.

Discovery

When a task arrives, the agent reads skill and reference descriptions to decide what is relevant. Expose a tool so the agent can request descriptions on demand rather than having the client inject everything upfront.

Activation

When the agent determines a skill or reference is relevant, your client reads the requested content and returns it. Expose these tools to the agent:
load_skill(path: str) -> str
    If path points to a grouping directory, returns its SKILLS.md.
    If path points to a leaf skill directory, returns its SKILL.md and lists available scripts.

load_reference(path: str) -> str
    If path points to a grouping directory, returns its REFERENCES.md.
    If path points to a file, returns the full file content.
Using paths rather than names keeps the interface uniform across flat and grouped harnesses and handles arbitrary nesting without client changes.

Handling subdirectories

Skills and references may be organized into named grouping subdirectories. Each grouping directory contains a SKILLS.md or REFERENCES.md summary file that describes its contents.
skills/
├── data-access/
│   ├── SKILLS.md          ← summary for this group
│   ├── query-database/
│   │   └── SKILL.md
│   └── read-spreadsheet/
│       └── SKILL.md
└── reporting/
    ├── SKILLS.md
    └── generate-report/
        └── SKILL.md
The agent navigates this hierarchy progressively: it reads HARNESS.md to learn about groups, loads a SKILLS.md to learn what is in a group, then loads individual SKILL.md files only when a task requires them. Your client’s load_skill tool handles all three levels via the same path-based interface. The same pattern applies to references/ with REFERENCES.md. Groups may be nested arbitrarily; each level gets its own summary file.

Reference file types

References may be any file type — markdown, images, code, data files, or anything else. Your load_reference tool should return the raw file content and let the agent handle interpretation. When indexing references for presentation or search, only markdown files (.md) may carry a description frontmatter field. Non-markdown files have no structured metadata.

Script execution

When an agent invokes a script bundled inside a skill, your client is responsible for executing it. The expected interface:
  • Scripts receive input via command-line arguments or stdin
  • Scripts write results to stdout
  • Non-zero exit code indicates failure; stderr contains the error message
Clients should sandbox script execution appropriately for their environment and expose a run_script(skill: str, script: str, args: list[str]) -> str tool to the agent.

Validation

Use the harnesses-ref CLI to validate a harness before loading it:
pip install harnesses-ref
harnesses-ref validate ./my-harness
The validator checks structural correctness including HARNESS.md frontmatter, skill validity, and the presence of SKILLS.md/REFERENCES.md in grouping subdirectories. Clients may run this check at install time and surface errors to the user.

Minimal example

A minimal Python implementation of harness loading:
from pathlib import Path

def load_harness(harness_path: Path) -> dict:
    harness_md = (harness_path / "HARNESS.md").read_text()
    frontmatter, body = parse_frontmatter_and_body(harness_md)

    skills = []
    for skill_md in harness_path.glob("skills/**/SKILL.md"):
        fm, _ = parse_frontmatter_and_body(skill_md.read_text())
        skills.append({
            "name": fm["name"],
            "description": fm["description"],
            "path": skill_md.parent,
        })

    references = []
    for ref in (harness_path / "references").rglob("*"):
        if ref.is_dir() or ref.name in ("REFERENCES.md",):
            continue  # skip grouping summaries; they are loaded on demand
        description = ""
        if ref.suffix == ".md":
            fm, _ = parse_frontmatter_and_body(ref.read_text())
            description = fm.get("description", "")
        references.append({
            "filename": ref.name,
            "description": description,
            "path": ref,
        })

    return {
        "name": frontmatter["name"],
        "description": frontmatter["description"],
        "body": body,
        "skills": skills,
        "references": references,
    }

def load_skill(harness_path: Path, skill_path: str) -> str:
    target = harness_path / "skills" / skill_path
    if (target / "SKILLS.md").exists():
        return (target / "SKILLS.md").read_text()
    skill_md = target / "SKILL.md"
    scripts = list(target.glob("scripts/*"))
    result = skill_md.read_text()
    if scripts:
        result += "\n\nAvailable scripts: " + ", ".join(s.name for s in scripts)
    return result

def load_reference(harness_path: Path, ref_path: str) -> str:
    target = harness_path / "references" / ref_path
    if target.is_dir() and (target / "REFERENCES.md").exists():
        return (target / "REFERENCES.md").read_text()
    return target.read_bytes().decode(errors="replace")