Metadata toolkit for AI coding harnesses. One registry of paths, formats, and detection rules for every major CLI.
pnpm add @agntn/harnessesimport { getHarness, detectHarness, detectProjectHarnesses } from "@agntn/harnesses";
const claude = getHarness("claude");
console.log(claude.skills); // [{ path: ".claude/skills/", scope: "project", ... }, ...]
console.log(claude.hooks); // [{ path: ".claude/hooks/", scope: "project", ... }, ...]
// Resolve to absolute paths for current platform
const paths = claude.resolve({ platform: "linux", homeDir: "/home/dev" });
console.log(paths.config); // [{ path: "/home/dev/.claude/settings.json", ... }, ...]
// Detect which agent is running (env vars first, then project markers)
const active = detectHarness();
if (active) {
console.log(`Running inside ${active.name}`);
}
// Find all agents configured in a project directory
const harnesses = detectProjectHarnesses("/path/to/project");Session schemas are typed per agent, so you get structure when parsing JSONL/SQLite/JSON files:
import type { ClaudeSessionEntry, CodexThread, GeminiConversationRecord } from "@agntn/harnesses";| Agent | ID | Detection | Skills | Hooks | Sessions |
|---|---|---|---|---|---|
| Claude Code | claude |
env + project | .claude/skills/ |
.claude/hooks/ |
JSONL |
| Codex CLI | codex |
project | .agents/skills/ |
- | SQLite + JSONL |
| Gemini CLI | gemini |
env + project | .gemini/skills/ |
- | JSON |
| Grok CLI | grok |
env + project | .grok/skills/ |
.grok/hooks/ |
TOML + JSONL |
| OpenCode | opencode |
project | .opencode/skills/ |
- | SQLite |
| Cursor | cursor |
env + project | .cursor/skills/ |
- | - |
| GitHub Copilot | github-copilot |
env + project | .github/skills/ |
- | - |
| Mastra Code | mastracode |
project | .mastracode/skills/ |
.mastracode/hooks.json |
SQLite |
| OMP (oh-my-pi) | omp |
env + project | .omp/skills/ |
- | JSONL + SQLite |
| Pi Coding Agent | pi |
env + project | .pi/skills/ |
- | JSON + JSONL |
| Freebuff | freebuff |
project | .agents/skills/ |
- | JSON + JSONL |
Each agent is a concrete subclass of the abstract Harness class. Custom subclasses can be added with registerHarness. Every harness exposes config paths, session locations, instruction files, skills dirs, hooks, commands, persistence formats, capabilities (MCP, vision, tools, streaming), detection rules, and a normalized non-interactive invocation (harness.invoke(prompt)) where the CLI has a headless mode. All paths carry scope (user/project/system/data), level (official/community/inferred), and optional platforms tags.
harnesses list # all known harnesses
harnesses detect # which ones are installed + versions
harnesses info claude # full metadata for a harness
harnesses paths claude # resolved paths for current platform
harnesses info codex --json # machine-readable output
harnesses run codex "fix lint" # one prompt through a harness's headless mode
harnesses mcp # run the MCP server over stdiounagent covers similar ground but makes different tradeoffs.
harnesses is deep and narrow. Each harness gets verified, platform-specific paths with scope, evidence level, and platform tags. Session formats are typed per harness. Eleven harnesses, each fully mapped.
unagent is wide and shallow. 40+ agents detected by env vars, but each definition is just configDir + rulesFile + skillsDir. No platform-specific paths, no session schemas. In exchange, it ships runtime primitives harnesses doesn't touch yet: skill install/uninstall, vector stores, browser automation, sandboxes, queues, workflows.
harnesses tells you where coding harnesses live and what format their data uses. unagent tells you which agent is running and gives you tools to do things with skills. They could use each other.