Agent Harness Kit

Local MCP server that tracks specs, tasks, handoffs and health-gated completion for coding agents

By Enmanuel Magallanes Pinargote (individual) TypeScript Local · stdio Developer toolsProductivity

50 popularity score ★ 184 ↓ 397/wk

Connect your client

Local (npm)

Add in one click

Opens the app, which asks before it adds the server.

Or add it by command or config

FirstTerminal
npm install -g @cardor/agent-harness-kit
ahk init
Claude CodeTerminal
claude mcp add agent-harness-kit -- ahk serve
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "agent-harness-kit": {
      "command": "ahk",
      "args": [
        "serve"
      ]
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "agent-harness-kit": {
      "command": "ahk",
      "args": [
        "serve"
      ]
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "agent-harness-kit": {
      "type": "stdio",
      "command": "ahk",
      "args": [
        "serve"
      ]
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.agent-harness-kit]
command = "ahk"
args = ["serve"]
Gemini CLITerminal
gemini mcp add --scope user agent-harness-kit ahk -- serve

What it does

Agent Harness Kit (AHK) is a command-line tool, `ahk`, that gives AI coding agents in one project a shared way of working. You run `ahk init` once, and it writes the native MCP config plus agent and skill files for six coding clients, among them Claude Code and Codex CLI. After that each client starts `ahk serve`, a local stdio MCP server that holds the record of the work.

Specs and use cases stay as Markdown under `docs/`. Tasks, logged actions and handoffs between the five roles (lead, explorer, consultant, builder, reviewer) go into a SQLite database, either `.harness/harness.db` in the project or a per-user store. Claiming a task runs your own health script first. If that fails the task is blocked, and code fixes then need a recorded repair authorisation. Marking it done reruns the script and only closes the task on a pass.

OpenCode V2 is a separate provider from the older `opencode` one. New projects pick it in `ahk init`, and existing ones move with `ahk migrate --to opencode-v2`, which backs up the v1 files first.

The server registers 69 tools. 37 of them live in `src/core/mcp-tools.ts` and handle specs, tasks and handoffs along with health runs. The other 32 are `ahk.*` tools generated in `src/core/maintenance-tools.ts` from a list of CLI operations, from init and build to exports, the dashboard and sounds. Sync, the migrations and reset are split into a plan tool and an apply tool. Model changes are not: `ahk.models.apply_defaults` overwrites the saved model choice of all five roles in one call and regenerates their files, keeping backups. Codex roles get models from the live catalog. Claude Code, Cursor and OpenCode V2 roles get `inherit`. Paging is capped in code. `specs.list` returns 50 documents unless asked for up to 100, and `specs.get` returns 8000 characters of a body per call, 12000 at most.

The makers are clear that the instructions AHK writes for agents are not a security boundary. The model and its permissions come from your coding client.

What it needs

RuntimeNode.js 22.14+
Runs onmacOS, Windows, Linux
Also
  • Claude Code, Codex CLI, Cursor, Grok Build or OpenCode installed
  • A build toolchain if the better-sqlite3 driver has to compile

Node.js 22.14.0 or newer on the 22.x line, or 23.6.0 or newer (earlier 23.x releases are excluded). Install the package globally with npm, pnpm or Bun, then run `ahk init` in the project. Your client has to start the server inside that project folder.

Limits

  • Not covered Works on the folder it is started in. Without a config file it runs in setup mode and offers only setup through ahk.init.
  • Limit A health pass proves only what your health script runs. A script that always succeeds makes the gate meaningless.
  • Limit Applying model defaults for Codex needs its live model catalog. Providers with no default policy get an unsupported answer.
  • Not covered No Jira or issue tracker connector: ticket text has to be pasted into the conversation.
  • Limit ahk.export writes JSON only. Asking for SQL returns an unsupported answer (maintenance-tools.ts).
  • Size cap Storage migration refuses to inspect a SQLite snapshot larger than 1 GiB (mcp-tools.md).
  • Limit OpenCode v1 and V2 share the opencode executable and .opencode paths, so choosing one does not isolate it from the other.
  • Limit Going back from OpenCode V2 to v1 needs the documented recovery steps. Customised v1 agents stop the migration.
  • Platform Sounds play on macOS and Linux. Windows skips them.
  • Platform better-sqlite3 has reported install failures on Windows with npm and on Linux with pnpm.

Who it suits

Suits a developer or team on Claude Code, Codex CLI, Cursor, Grok Build or OpenCode (v1 or V2) who wants specs, tracked tasks, role handoffs and a test-gated "done" kept in one local place. It runs on your machine with no sign-in. It is as much a workflow framework as a tool server: it writes agent and skill files and expects you to follow its roles and approval steps. If you only need an assistant to read or edit files, a plain file-system server is lighter. It is not published by any of the clients it supports.

Tools 38 of 69

17 only read, 21 change things. A ? marks an optional parameter.

specs.list
List use cases and specs without their bodies, 50 per page by default and up to 100, plus diagnostics for invalid filesspecKind?: enumstatus?: stringquery?: stringoffset?: integerlimit?: integer
specs.get
Read one spec body by slug, 8000 characters by default and up to 12000 per callslug: stringoffset?: integerlimit?: integer
specs.search
Search spec metadata and body text, returning short excerptsquery: stringspecKind?: enumstatus?: stringoffset?: integerlimit?: integer
specs.related
List the specs linked to one spec, without their bodiesslug: stringrelationships?: array
specs.create changes
Create a use case or spec file with a date prefix in its filenameslug: stringtitle: stringdescription: stringspecKind: enumstatus?: stringsourceSpec?: stringsourceUseCases?: arraycontent: string
specs.update_metadata changes
Change validated frontmatter fields of a specslug: stringtitle?: stringdescription?: stringstatus?: stringsourceSpec?: stringsourceUseCases?: array
specs.update_content changes
Replace the body of a spec and keep its frontmatterslug: stringcontent: string
specs.transition changes
Move a spec to another status, checking that its sources are approvedslug: stringstatus: string
specs.link changes
Link two specs with a named relationshipslug: stringtargetSlug: stringrelationship: enum
specs.unlink changes
Remove a link between two specsslug: stringtargetSlug: stringrelationship: enum
specs.validate
Check frontmatter, links and source references across the use-case and spec folders
health.run changes
Run the health script again for a task and store the resulttaskId: number
actions.start changes
Open a logged action on a task for one roletaskId: numberagent: string
actions.write changes
Add a named section of evidence to an open actionactionId: numbersectionType: stringcontent: string
actions.complete changes
Close an action with a short summaryactionId: numbersummary: string
actions.get
Read the actions recorded on a tasktaskId: number
actions.list
List a task's actions newest first, 20 per page by defaulttaskId: numberagent?: stringstatus?: enumcursor?: stringlimit?: integer
actions.get_by_id
Read one action and the index of its sectionsactionId: number
actions.sections.list
List the sections of one action, filtered by type if askedactionId: numbertypes?: arraycursor?: stringlimit?: integer
actions.sections.get
Read the text of one section over a chosen character rangesectionId: numberoffset?: integerlength?: integer
actions.handoff.write changes
Write a structured handoff addressed to the next roleactionId: numberrecipient: enumgoal: stringcompleted: arraydecisions: arrayfiles: arrayverification: arrayblockers: arraynextStep: string
actions.handoff.get
Read the newest handoff for a role, the builder unless another is namedtaskId: numberrecipient?: enum
tasks.get
List tasks by status, leaving archived ones out unless askedstatus?: enumincludeArchived?: booleanarchivedOnly?: boolean
tasks.claim changes
Claim a task after a health run, which puts it in blocked mode on failureid: numberagent: string
tasks.repair.begin changes
Record a scoped, audited permission to fix a failed health gatetaskId: numberactor: stringreason: stringscope: string
tasks.update changes
Change a task's status, where done reruns health and closes only on a passid: anystatus: enum
docs.search
Search the project documentationquery: string
tasks.acceptance.update changes
Mark one acceptance criterion as metcriterionId: number
tasks.acceptance.get
Read the acceptance criteria of a tasktaskId: number
tasks.add changes
Create a task with title, optional slug, description and acceptance criteriatitle: stringslug?: stringdescription?: stringacceptance?: array
tasks.edit changes
Change the title, description or criteria of a task by id or slugid: anytitle?: stringdescription?: stringacceptance?: array
tasks.archive changes
Archive a taskid: number
tasks.unarchive changes
Bring an archived task backid: number
permissions.check
Check that an agent definition file exists for every role
deps.snapshot changes
Save the current package.json dependencies to .harness/deps-lock.json
deps.check
Compare package.json with the saved dependency snapshot
ahk.doctor
Check the installed version, agent files and skill sync, with optional database history diagnosticsdb?: boolean
ahk.models.apply_defaults changes
Set all five roles to the current provider's default models and regenerate their files, backing up the old onesprovider?: enum

Similar servers