Guide

Agents

The same eleven tools over MCP, the Pi extension and the OMP extension. What they read, what they run, what they write.

Eleven tools, three surfaces

MCP server, Pi extension and OMP extension all call the same executors in src/tool-operations.ts, with the same schemas from src/tool-schemas.ts. They answer identically and a fix lands once.

ToolKindDoes
harnesses_detectreadInstalled harnesses, their versions and how each one runs
harnesses_inforeadFull metadata for one id, or a batch of up to 20 ids
harnesses_modelsexecModels a harness can use now, optionally filtered
harnesses_runexecOne prompt through another harness
harnesses_mcp_listreadMCP servers in every config, normalized
harnesses_mcp_addwriteAdd or replace one MCP server
harnesses_mcp_removewriteRemove one MCP server
harnesses_mcp_syncwriteReset user scope configs to ~/.config/agntn/mcp.jsonc
harnesses_agents_syncwriteLink global instructions files to the master bundle, or check
harnesses_prompts_syncwriteSync canonical Markdown prompts into harness destinations, or check
harnesses_skills_syncwriteLink harness skills directories to the XDG data skills folder, or check

harnesses_info with a list keeps the input order and returns an error entry beside the successful ones for an unknown id, so one typo doesn't fail the batch.

Its text shows every path once, under resolved, expanded for the machine the tool runs on and filtered to its platform. The ~ templates with their platform tags are what harnesses info prints. An agent doesn't need both.

MCP

shell
harnesses mcp
claude mcp add harnesses --scope user -- npx -y @agntn/harnesses mcp

Or in a client's config, or on the master list that mcp-servers sync distributes:

json
{
  "mcpServers": {
    "harnesses": { "command": "npx", "args": ["-y", "@agntn/harnesses", "mcp"] }
  }
}

The server speaks MCP over stdio and validates every call against the published JSON Schema. Read tools are annotated read-only and idempotent; harnesses_run is marked destructive and open world, because it is.

Running another harness from an agent

harnesses_run takes id, prompt, and tools as a required boolean. The model has to choose. tools: false is the advisor without tools, tools: true the full agent, readOnly: true beside it demands a native read-only sandbox. A mode the target harness cannot provide comes back as a tool error with the retry that would work; it never widens access on its own. timeoutSeconds defaults to 600.

Not sure which modes a harness has? harnesses_detect tells you before the first call. Each row carries advisor, readOnly and agent. Codex says no to advisor right there. No refused run, no retry, no wasted turn.

effort is optional and lasts one run. harnesses_info says which harnesses take it, in effortSelection. Handy when a global config says xhigh and all you wanted was a yes or no. Elsewhere it comes back as a tool error, never as a run that quietly ignored it.

Cancellation follows the host's request signal, the one MCP, Pi and OMP hand to a tool when the user interrupts. It is not a JSON argument, because a model would forget to pass it.

The answer comes back as plain text: a short TOON block with the id, the invocation, exit code and timeout state, then stdout: and the output on the lines below, capped at 8000 characters per stream, terminal control sequences stripped. A failed run adds stderr: the same way, and a run that printed nothing on stdout shows its stderr instead. The output is not quoted into a TOON string, so a markdown answer with code blocks reads as markdown.

Pi and OMP

shell
pi install npm:@agntn/harnesses

Both extensions are declared in package.json. Results render as a collapsed preview in the terminal, with the full text once you expand the row. harnesses_run output from a long review is where that matters.

A second harness's answer is a hypothesis. When Claude asks Codex to review a patch through harnesses_run, what comes back is text to check against the code, not a verdict to paste. The tool returns it as text on purpose.