Getting Started
Why this exists
Every coding agent keeps its state somewhere slightly different. Claude Code writes JSONL transcripts under a dash-encoded copy of your working directory, Codex keeps TOML with comments you'd like to survive an edit, OpenCode puts one SQLite database under XDG on every platform, Gemini CLI has a %PROGRAMDATA% path on Windows and nowhere else. Every tool that reads a session, adds an MCP server or looks for the right AGENTS.md needs that table, and a table kept in twelve heads is wrong in at least one of them.
So @agntn/harnesses writes it down once. Each harness is a class with the same fields, each path carries a scope and an evidence level, and the same object knows how to detect the harness, run a prompt through it headlessly, and edit its MCP list. Nothing is scanned or guessed at runtime. You get the table, expanded for your platform, and that's it.
Install
pnpm add @agntn/harnesses
Node 22 or newer. The package is ESM only.
First call
import { getHarness } from "@agntn/harnesses";
const claude = getHarness("claude");
claude.name; // "Anthropic Claude Code"
claude.skills; // [{ path: ".claude/skills/", scope: "project", level: "official" }, ...]
const paths = claude.resolve({ platform: "linux", homeDir: "/home/dev" });
paths.config[0]?.path; // "/home/dev/.claude/settings.json"
getHarness wants an exact id and throws on anything else. isHarnessId(value) narrows a string first, listHarnesses() gives you the ids, getAllHarnesses() the objects. Importing the package registers the twelve built-ins; registerHarness adds yours.
Which one am I in
import { detectHarness, detectProjectHarnesses } from "@agntn/harnesses";
const active = detectHarness();
active?.id; // "claude" when CLAUDE_CODE is set, null when nothing is unambiguous
detectProjectHarnesses("/srv/app").map((h) => h.id); // every harness with a marker in that directory
Environment variables win, because being inside a harness is unambiguous. Without one, a single project marker decides; two harnesses with markers in the same directory give null, not the first one. A CLAUDE.md next to an AGENTS.md is the common case, and picking one there would be a lie.
The shape
Every harness has these:
| Field | Type | What it holds |
|---|---|---|
id, name, binaries | HarnessId, string, string[] | Registry id, display name, executables searched on PATH |
config, sessions, instructions, skills, commands, hooks | PathCandidate[] | Templates with scope, level, optional platforms and note |
persistence | StorageDescriptor[] | Formats on disk: JSON, JSONL, TOML, SQLite, YAML, Protocol Buffers |
capabilities | HarnessCapabilities | mcp, vision, audio, video, tools, streaming |
detection | HarnessDetection | envVars and projectMarkers |
invocation | HarnessInvocation | null | Argument templates per mode, or null without a headless CLI |
modelListing | HarnessModelListing | null | Native model listing command, when the CLI has one |
mcpConfigs | McpConfigFile[] | Config files that hold MCP servers, with format, key and dialect |
agentsFile | string | null | The one user scope instructions file that syncAgentsFiles links |
And these methods: resolve(options), detectEnv(), detectProject(cwd), isInstalled(), version, invocationModes, buildInvocation(prompt, options), invocationError(options), invoke(prompt, options), buildModelListInvocation(search), listModels(options).
Evidence
level is official when the path comes from the CLI's documentation or source, community when it comes from a maintained outside source, inferred when someone reasoned it out from the others and hasn't verified it. platforms is set only where a path differs by OS. scope is user, project, system or data, and data is where transcripts and databases live as opposed to settings you edit.
A false in capabilities.audio or video means no native route into model context was verified, not that every provider and extension was disproved. The README lists the evidence for those two, harness by harness.
Next
- Registry and paths: resolve, platforms, what the notes are for.
- Running another harness: six modes, timeouts, cancellation, models.
- MCP servers: one master list, every dialect.
- Instructions files: one
AGENTS.mdbehind every harness's global file. - CLI: the
harnessescommand. - Agents: nine tools over MCP, Pi and OMP.
- Sessions: typed schemas for the transcript formats.
- Custom harnesses: extend
Harness, register it. - Explorer: every path, expanded in the page.