Agents
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.
| Tool | Kind | Does |
|---|---|---|
harnesses_detect | read | Installed harnesses, their versions and how each one runs |
harnesses_info | read | Full metadata for one id, or a batch of up to 20 ids |
harnesses_models | exec | Models a harness can use now, optionally filtered |
harnesses_run | exec | One prompt through another harness |
harnesses_mcp_list | read | MCP servers in every config, normalized |
harnesses_mcp_add | write | Add or replace one MCP server |
harnesses_mcp_remove | write | Remove one MCP server |
harnesses_mcp_sync | write | Reset user scope configs to ~/.config/agntn/mcp.jsonc |
harnesses_agents_sync | write | Link global instructions files to the master bundle, or check |
harnesses_prompts_sync | write | Sync canonical Markdown prompts into harness destinations, or check |
harnesses_skills_sync | write | Link 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
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:
{
"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
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.
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.