@cardor/agent-harness-kit
v1.10.3
Published
CLI scaffolding for multi-agent harness systems
Maintainers
Readme
@cardor/agent-harness-kit
A provider-agnostic scaffolding kit for running structured multi-agent workflows in your codebase.
Instead of letting AI agents roam freely through your project with no memory, no coordination, and no audit trail, agent-harness-kit gives them a shared structure: a task backlog, a defined workflow, a persistent log of every action taken, and a health gate that must be green before any work begins.
You stay in control. The agents stay on track.
Visit the website to view a full explanation, examples, and other tools!
npx ahk initTable of Contents
- @cardor/agent-harness-kit
Why this exists
If you don't know what is Agent Harness, you can check this blog post: Introducing Agent Harness.
Most AI coding tools give you a single agent with a chat window. That works for small tasks. It breaks down when:
- You want multiple specialized agents working in sequence (plan → explore → build → review)
- You need to track what changed, what was tried, and what was blocked — across sessions
- You switch between AI providers (Claude Code today, OpenCode tomorrow) and don't want to re-setup everything
- You want a health check that agents must pass before touching code
agent-harness-kit solves all of this with a thin layer of scaffolding and a local MCP server that any MCP-compatible AI tool can connect to.
How it works
ahk init
└── creates config, agent definitions, task backlog, health check
AI tool opens your project
└── reads .claude/mcp.json, opencode.json, or .codex/config.toml
└── spawns: npx ahk serve (stdio MCP server)
Agent starts working
└── tasks.get() → picks a task from the backlog
└── tasks.claim(id) → atomically claims it (no double-work)
└── actions.start() → registers its action
└── actions.write() → logs sections: result, files, blockers…
└── actions.complete() → closes the action
Lead → Explorer → Builder → Reviewer
└── each role has its own agent definition with clear responsibilities
└── the harness DB records the full historyEverything is stored locally in a SQLite database (.harness/harness.db). No cloud, no external services, no API keys required beyond what your AI tool already uses.
Features
- Provider-agnostic — works with Claude Code, OpenCode, Codex CLI, or any MCP-compatible AI tool. Switch providers without losing your task history or reconfiguring your workflow.
- Structured 5-agent workflow — Lead, Explorer, Consultant, Builder, and Reviewer each have defined responsibilities and can only act within their role.
- Atomic task claiming — agents use
tasks.claim()which uses a SQLite transaction to prevent two agents from picking up the same task at the same time. - Full audit trail — every action, file touched, tool used, and section written is stored in SQLite and queryable.
- Health gate — agents must run
health.shand get a green exit before starting or closing any task. You define what "healthy" means. - Markdown fallback —
current.mdis always regenerated so agents can understand the session state even without the MCP server. - Docs search — agents can call
docs.search(query)to find relevant content in your project's docs folder before writing code. - Multi-database support — SQLite by default (uses
better-sqlite3on Node ≥ 22 orbun:sqliteon Bun). Switch to PostgreSQL or MySQL with a single config line — same schema, same MCP tools, same workflow. - Incremental scaffold —
ahk initpreserves files you've already customized (agent definitions you've edited are kept).ahk buildalways regenerates agent files from the latest templates so they stay up to date. - Global installation —
ahk initcan scaffold the harness into your home directory (~/.claudeor~/.config/opencode) to share it across all projects. - Input validation — CLI prompts validate all inputs (name length, path format, task title, etc.) and retry with the error message instead of silently accepting bad values.
Requirements
- Node.js ≥ 22.5 or Bun (any recent version)
- npm ≥ 9
Installation
# Install in your project as a dev dependency (recommended)
npm install --save-dev @cardor/agent-harness-kitThen run the interactive setup inside your project:
npx ahk initLocal install recommended. The generated
agent-harness-kit.config.tsusesimport type, which is erased at compile time, soahkno longer needs to resolve the package from your project'snode_modulesat runtime. If it detects a global-only install (npm install -g @cardor/agent-harness-kit), it prints a non-blocking warning recommendingnpm install --save-dev @cardor/agent-harness-kit(or thepnpm/yarn/bunequivalent) — the command still runs and exits normally either way. This is only about keeping the CLI version pinned and reproducible across your team and CI, not a functional requirement.This check also works with Yarn Berry (PnP) projects, which never create a
node_modulesfolder —ahkdetects.pnp.cjs/.pnp.loader.mjsand falls back to checking that the package is declared inpackage.jsoninstead of requiring anode_modulesentry.
MCP command per package manager
ahk init and ahk build detect which package manager your project uses and generate the MCP server launch command (.mcp.json, opencode.json, or .codex/config.toml) accordingly, instead of hardcoding npx:
| Package manager | Detected via | Generated command |
| -------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------- |
| npm | packageManager field, package-lock.json, or fallback | npx --no ahk serve --port <port> |
| pnpm | packageManager field or pnpm-lock.yaml | pnpm exec ahk serve --port <port> |
| yarn classic (v1) | packageManager field (major 1) or yarn.lock without .yarnrc.yml | yarn run ahk serve --port <port> |
| yarn berry (v2+, PnP or node-modules) | packageManager field (major ≥ 2) or yarn.lock + .yarnrc.yml | yarn run ahk serve --port <port> |
| bun | packageManager field or bun.lockb/bun.lock | bunx --no-install ahk serve --port <port> |
Detection order: the packageManager field in your package.json (e.g. "packageManager": "[email protected]") takes priority when present; otherwise ahk falls back to lockfile heuristics; if nothing is detected, it defaults to npm.
Existing projects: if you initialized your project before this change, your .mcp.json/opencode.json/.codex/config.toml may still have a hardcoded npx command. No migration step is needed — ahk build always regenerates (merges) these files from scratch on every run, so the command self-corrects the next time you run ahk build (or ahk build --sync), including if you've since switched package managers.
Commands
ahk init
Interactive scaffold. Asks for your project name, description, AI provider, docs path, storage scope, task adapter, and an optional first task. Creates all harness files in the current directory.
For Claude Code and Codex CLI (not OpenCode), you'll also be asked whether to personalize the model per agent (lead/explorer/consultant/builder/reviewer):
- Claude Code: pick from
inherit(default),haiku,sonnet,opus,fableper agent. - Codex CLI: free-text model name per agent — Codex does not validate this value; leaving it blank or under 3 characters means no override is written to that agent's TOML file.
Storage scope — where the harness DB (and its current.md fallback) physically lives:
local(default) —.harness/harness.db, inside the project.global—~/.harness/dbs/<projectId>/harness.db, outside the project tree (useful to keep the DB out of version control entirely, or to centralize storage for many projects).<projectId>is a UUID generated once at init and persisted inagent-harness-kit.config.ts— it's never regenerated on subsequent runs.
Regardless of scope, .harness/storage-state.json is always written to the project — it records the actual current storage state (scope, projectId, dbType, migratedAt), separate from the desired state declared in the config file.
Agent and skill files always live in the project tree, regardless of storage scope — --storage-scope only affects where the harness DB lives.
ahk init
# Skip prompts with flags
ahk init --name "my-app" --provider claude-code --docs ./docs --tasks local --storage-scope local
ahk init --name "my-app" --provider codex-cli --docs ./docs --tasks local --storage-scope globalRun this once per project. If the project is already initialized, the command prints an 'already initialized' message with suggested next-step commands (ahk build, ahk build --sync, ahk reset, ahk serve) and exits without overwriting anything.
The config file extension is chosen automatically: .ts if a tsconfig.json is present, .mjs for ESM-only projects ("type": "module" in package.json), or .mjs otherwise.
ahk build
Regenerates AGENTS.md and provider-specific files from your agent-harness-kit.config.ts. Use this after changing config values.
ahk build
ahk build --watch # watch mode: rebuilds automatically on config changes
ahk build --sync # sync tools: frontmatter in agent files to match current permission constants (claude-code only; no-op for opencode/codex-cli)ahk dashboard
Opens a local web dashboard to visualize everything stored in the harness database — tasks, agent actions, file operations, tool usage, and live timelines. Updates in real time via WebSocket as agents work.
ahk dashboard # opens http://localhost:4242 in your browser
ahk dashboard --port 8080 # custom port
ahk dashboard --no-open # start server without opening browserIf the requested port (default 4242) is already in use, ahk dashboard automatically tries up to 10 sequential ports (e.g. 4242 → 4243 → … → 4251). The actual port opened is printed to the console. If all 10 ports are exhausted, the command exits with a clear error message showing which port range was attempted.
The dashboard includes:
| View | What it shows | | --------------- | --------------------------------------------------------------------------- | | Overview | Status counts, active tasks with acceptance progress, recent agent activity | | Tasks | Full task list, filterable by status, with acceptance progress bars | | Task detail | Acceptance criteria, action timeline per agent, files touched, tools used | | Agents | Per-role breakdown: actions, tasks worked, files touched, completion rate | | Tools | Top tools bar chart + full log of recent tool calls with args and results | | Files | Most-touched files with operation breakdown + recent file operation log |

ahk status
Shows the current task table and any active agent actions in the terminal.
ahk status
ahk status --json # machine-readable outputahk health
Runs health.sh and reports the result. Exit 0 = healthy, exit 1 = something is wrong.
ahk healthahk doctor
Checks that the installed lib version, agent files, and harness skills are all in sync.
ahk doctorReports three categories:
- lib version — compares installed version against the latest on npm. Shows
[✓]if up to date,[!]if an update is available, or[~]if the registry could not be reached. - agent files — reads each agent file on disk and compares against what
ahk buildwould generate. Reports[!]with the file name if outdated. - harness skills — checks that
ahk-ask,ahk-consultant,ahk-triage, andahk-reviewskills exist and match the bundled source. Reports[!]if missing or outdated.
Run ahk build to fix any reported issues.
ahk sync
Syncs .harness/feature_list.json ↔ SQLite. Tasks already in the DB are skipped by slug. Use this to seed the backlog from the JSON file without duplicating existing tasks.
ahk sync # both directions (default)
ahk sync --direction in # JSON → SQLite only
ahk sync --direction out # SQLite → JSON only
ahk sync --dry-run # preview changes without applying them
ahk sync --dry-run --direction inahk serve
Starts the MCP server on stdio. You never need to call this manually. After ahk init, the generated .claude/mcp.json (Claude Code) or opencode.json (OpenCode) tells the AI tool to spawn it automatically when you open the project.
ahk serve
ahk serve --port 3456 # store a port hint in config (stdio transport only)ahk task add
Interactively adds a new task to the backlog (SQLite + feature_list.json).
ahk task addahk task list
Lists all tasks. Optionally filter by status.
ahk task list
ahk task list --status pending
ahk task list --status in_progress
ahk task list --status done
ahk task list --status blocked
ahk task list --json # machine-readable outputahk task done <id|slug>
Marks a task as done. Runs the health check first if health is required — if it fails, the task is not closed.
ahk task done 3
ahk task done add-auth-flowahk reset
Clears harness data interactively. Only SQLite databases are managed by this command — remote Postgres/MySQL databases are intentionally skipped.
ahk reset # interactive — asks before deleting each item
ahk reset --force # skip all confirmation prompts
ahk reset --provider claude-code # also delete agent files for this provider
ahk reset --provider opencode
ahk reset --provider codex-cliWhat it can reset:
- The SQLite
.dbfile (plus WAL and SHM files if present) .harness/feature_list.json- Agent definition files in
.claude/agents/,.opencode/agents/, or.codex/agents/
After a reset, run ahk init to scaffold a fresh harness.
ahk migrate
ahk migrate has two subcommands: provider (migrate scaffold files to a different AI provider) and storage (migrate the harness database between storage backends). ahk migrate --to <provider> (no subcommand) is kept as a backward-compatible alias for ahk migrate provider --to <provider> — existing scripts/CI using the old form keep working unchanged.
ahk migrate provider
Migrates provider-specific files from one AI provider to another. Useful when switching from Claude Code to OpenCode or vice versa.
ahk migrate provider --to opencode
ahk migrate provider --to claude-code
ahk migrate provider --to codex-cli
# Backward-compatible alias (identical behavior):
ahk migrate --to opencodeahk migrate storage — ⚠️ sensitive, reads/writes real harness data
Migrates the harness database between storage backends: local↔global scope (moving .harness/harness.db in/out of ~/.harness/dbs/<projectId>/) and sqlite↔postgres/mysql (dumping and reloading all 6 tables — tasks, task_acceptance, actions, action_sections, action_files, action_tools — inside a single transaction). It is not interactive — agent-harness-kit.config.ts (storage.scope, database.type/path/connectionString) is the only source of truth for the desired target, compared against the real current state recorded in .harness/storage-state.json.
ahk migrate storage # migrate to whatever agent-harness-kit.config.ts declares
ahk migrate storage --dry-run # preview what would happen, without touching anything
ahk migrate storage --force # required whenever the destination already has dataWhat it does, case by case:
| Situation | Behavior |
|---|---|
| Config and real storage state already match | No-op — reports "nothing to migrate" |
| Only storage.scope differs (same DB engine) | Copies the .db file (+ WAL/SHM) and current.md directly to the new location, verifies the copy, then removes the original |
| Only database.type differs (sqlite → postgres/mysql) | Full export/import of all 6 tables inside one transaction; on failure, the destination is rolled back exactly as it was found |
| Destination already has data | Requires --force. Without it, the command aborts and touches nothing. With it, the destination's current content is backed up to .harness/backups/pre-migrate-<timestamp>.json before anything is overwritten — if the backup can't be written, the whole command aborts |
| Both source and destination have diverging data (not just empty vs. full) | Same as above (--force + backup required) — the command never attempts to auto-merge two independent histories |
| .harness/storage-state.json is missing | Never assumed to mean "safe, empty destination." Both the local and global sqlite candidate locations are inspected for real data first; if both have data, the command refuses to guess and asks for manual resolution |
Limitations (by design, matches the current scope):
- No connection pooling or incremental/partial migrations — always a full dump/load.
- After inserting rows with their original ids, the destination's internal id sequence is explicitly re-synced (
setvalon Postgres,sqlite_sequenceupdate on SQLite; MySQL'sAUTO_INCREMENTadvances on its own) so that the next normal task/action created after migrating never collides with an imported id. - Migrating away from a previously remote (postgres/mysql) database isn't supported automatically —
storage-state.jsonintentionally never stores connection credentials, so there's nothing to reconnect to. Export manually withahk export --jsonwhile still connected to the old database first. - The original sqlite file is not deleted after a sqlite→remote migration — remove it manually once you've verified the migrated data.
ahk export
Exports the full database as JSON or SQL. Useful for backups, external reporting, or migrating data.
ahk export --json # JSON to stdout
ahk export --json --output snapshot.json # JSON to file
ahk export --sql # SQL dump to stdout
ahk export --sql --output dump.sql # SQL dump to fileFiles created by ahk init
Claude Code (provider: 'claude-code'):
your-project/
├── agent-harness-kit.config.{ts|mjs|cjs}
├── AGENTS.md
├── CLAUDE.md
├── health.sh
├── .harness/
│ ├── harness.db ← gitignored (local scope only — absent when scope: 'global')
│ ├── current.md ← gitignored (local scope only — absent when scope: 'global')
│ ├── storage-state.json ← always present, reflects the REAL current storage scope/projectId
│ └── feature_list.json
└── .claude/
├── agents/
│ ├── lead.md
│ ├── explorer.md
│ ├── builder.md
│ └── reviewer.md
├── mcp.json ← MCP server registration
└── settings.json ← sets `agent: "lead"` as the default session agentOpenCode (provider: 'opencode'):
your-project/
├── agent-harness-kit.config.{ts|mjs|cjs}
├── AGENTS.md
├── health.sh
├── opencode.json ← MCP server + default_agent + compaction config
├── .harness/
└── .opencode/
└── agents/
├── lead.md
├── explorer.md
├── builder.md
└── reviewer.mdCodex CLI (provider: 'codex-cli'):
your-project/
├── agent-harness-kit.config.{ts|mjs|cjs}
├── AGENTS.md
├── health.sh
├── .harness/
└── .codex/
├── config.toml ← MCP server registration
└── agents/
├── lead.toml
├── explorer.toml
├── builder.toml
├── reviewer.toml
└── default.toml ← overrides Codex's built-in default agent → routes to leadWhat each file does
| File | Purpose | Edit it? |
| ----------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| agent-harness-kit.config.ts | Defines project metadata, provider, storage paths, MCP port | Yes — it's yours |
| AGENTS.md | Navigation map agents read first. Regenerated by ahk build | No — changes will be overwritten |
| health.sh | Shell script agents run before starting work. Must exit 0 | Yes — implement your checks here |
| .harness/feature_list.json | Task backlog in JSON. Humans edit this, ahk sync loads it into SQLite | Yes — add tasks here |
| .harness/harness.db | SQLite database (local scope only). Source of truth for tasks, actions, sections | No — managed by the harness |
| .harness/current.md | Auto-generated session snapshot for agents without MCP access (local scope only) | No — regenerated automatically |
| .harness/storage-state.json | Always project-local. Records the REAL current storage state (scope, projectId, dbType, migratedAt) — used by migration tooling | No — managed by the harness |
| .claude/agents/*.md | Agent role definitions (Claude Code). Created once, never overwritten | Yes — customize agent behavior |
| .claude/mcp.json | MCP server registration for Claude Code. Merged by ahk build | Yes, carefully — don't remove the agent-harness-kit entry |
| .claude/settings.json | Sets agent: "lead" so lead runs as the default session agent. Merged by ahk build | Yes, carefully |
| .opencode/agents/*.md | Agent role definitions (OpenCode). Created once, never overwritten | Yes — customize agent behavior |
| opencode.json | MCP server + default_agent + compaction config for OpenCode. Merged by ahk build | Yes, carefully |
| .codex/agents/*.toml | Agent role definitions (Codex CLI). Created once, never overwritten | Yes — customize agent behavior |
| .codex/config.toml | MCP server registration for Codex CLI. Merged by ahk build | Yes, carefully |
Tasks schema
The tasks table includes an updated_at timestamp column, set on creation and automatically updated on every status change. On first run after upgrading from an older version, existing rows are backfilled with COALESCE(completed_at, started_at, created_at). Tasks returned by tasks.get are ordered by status priority (pending → in_progress → blocked → done) then by updated_at descending.
What you can customize
agent-harness-kit.config.ts
Everything in the config file is yours to change:
import type { HarnessConfig } from '@cardor/agent-harness-kit'
const config: HarnessConfig = {
project: {
name: 'My App',
description: 'What this project does',
docsPath: './docs', // where agents search for documentation
},
provider: 'claude-code', // 'claude-code' | 'opencode' | 'codex-cli'
agents: {
lead: { instructionsPath: null, model: 'sonnet' }, // optional per-agent model override
explorer: { instructionsPath: null, allowedPaths: ['./docs', './src'], model: 'haiku' },
builder: { instructionsPath: null, writablePaths: ['./src', './tests'] },
reviewer: { instructionsPath: null },
consultant: { instructionsPath: null, model: 'haiku' },
custom: [], // define extra agents here
},
// ── Database ──────────────────────────────────────────────────────────────
// SQLite (default — zero native deps, Node 22+ or Bun)
database: { type: 'sqlite', path: '.harness/harness.db' },
// PostgreSQL — uncomment to use instead:
// database: { type: 'postgres', connectionString: process.env.DATABASE_URL },
// MySQL — uncomment to use instead:
// database: { type: 'mysql', connectionString: process.env.DATABASE_URL },
storage: {
dir: '.harness',
tasks: { adapter: 'local' }, // 'local' | 'jira' | 'linear' | 'mcp'
sections: {
toolsUsed: true, // log which tools agents used
filesModified: true, // log which files were touched
result: true, // log action results
blockers: true, // log blockers agents hit
nextSteps: false, // optional next steps field
},
markdownFallback: { enabled: true, path: '.harness/current.md' },
// 'local' (default) — DB lives in .harness/ (project-relative).
// 'global' — DB lives under ~/.harness/dbs/<projectId>/, outside the project.
scope: 'local', // 'local' | 'global'
projectId: '5f2c...', // UUID, generated once at init, never regenerated
},
health: {
scriptPath: './health.sh',
required: true, // set to false to skip health checks
},
tools: {
mcp: { enabled: true, port: 3742 },
scripts: { enabled: true, outputDir: './.harness/scripts' },
},
}
export default config
defineHarness()is still exported for anyone who prefers the value-import form (import { defineHarness } from '@cardor/agent-harness-kit'+export default defineHarness({ ... })) — it's an identity function kept for backward compatibility, andloadConfig()supports both shapes.
health.sh
This is the most important file to implement. Agents will not start or close tasks until this script exits 0. Examples:
#!/usr/bin/env bash
# Check the dev server is up
curl -sf http://localhost:3000/health > /dev/null || exit 1
# Run unit tests
npm test || exit 1
# Check DB connection
psql "$DATABASE_URL" -c "SELECT 1" > /dev/null 2>&1 || exit 1
echo "All checks passed."Agent definition files
Created by ahk init (which preserves existing files) and regenerated by ahk build from the latest templates. If you customise an agent file, re-running ahk build will overwrite your edits — keep customisations in source control.
Claude Code (.claude/agents/*.md) and OpenCode (.opencode/agents/*.md) use Markdown with YAML frontmatter:
---
name: builder
description: Builder agent — implements the plan produced by explorer and lead
tools:
read: true
write: true
edit: true
bash: true
permissionMode: acceptEdits
---
# Builder Agent
You are the builder agent for MyApp. Follow these rules:
- All API endpoints must be defined in `src/routes/`
- Never modify `src/core/` without lead approval
- Run `npm test` after every change and fix failures before completing
- Use the existing error handling pattern from `src/lib/errors.ts`Codex CLI (.codex/agents/*.toml) uses TOML format:
name = "builder"
sandbox_mode = "workspace-write"
description = """
Builder agent — implements the plan produced by explorer and lead.
"""
developer_instructions = """
# Builder Agent
You are the builder agent for MyApp. Follow these rules:
- All API endpoints must be defined in `src/routes/`
- Never modify `src/core/` without lead approval
- Run `npm test` after every change and fix failures before completing
"""The sandbox_mode field controls Codex's filesystem permissions per agent: "read-only" for lead, explorer, and reviewer; "workspace-write" for builder. The permissionMode field in Claude Code agent files enforces the same constraints at the session level (plan for read-only roles, acceptEdits for builder).
.harness/feature_list.json
The human-editable task backlog. Add tasks here, then run ahk sync to load them into SQLite.
[
{
"slug": "add-auth-flow",
"title": "Add JWT authentication flow",
"description": "Implement login, refresh token, and logout endpoints",
"acceptance": [
"POST /auth/login returns a signed JWT",
"POST /auth/refresh validates and rotates the token",
"All protected routes return 401 without a valid token",
"Tests cover happy path and token expiry"
]
}
]Good acceptance criteria make the difference — the reviewer agent uses them to decide whether to approve or block a task.
MCP tools (for agents)
The harness exposes these tools via MCP. Agents use them instead of reading files directly.
| Tool | Parameters | Description |
| ------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| tasks.get | status? | List tasks, optionally filtered by pending \| in_progress \| done \| blocked |
| tasks.claim | id, agent | Atomically claim a pending task. Returns task_already_claimed if another agent got it first |
| tasks.update | id, status | Change task status |
| tasks.add | title, slug?, description?, acceptance? | Create a new task directly from MCP (agents can queue work on the fly) |
| tasks.acceptance.update | criterionId | Mark an acceptance criterion as met. Criterion IDs come from tasks.acceptance_get |
| actions.start | taskId, agent | Start a new action, returns actionId |
| actions.write | actionId, sectionType, content | Record a text section: result \| tools_used \| blockers \| next_steps. Does not populate the Files dashboard — use actions.record_file for that |
| actions.complete | actionId, summary | Close an action with a one-line summary |
| actions.get | taskId | Full action history for a task (all agents, all sections) |
| actions.record_file | actionId, filePath, operation, notes? | Register a file touch. The only way to populate the Files dashboard. operation: read \| created \| modified \| deleted |
| actions.record_tool | actionId, toolName, argsJson?, resultSummary? | Register a tool call. The only way to populate the Tools dashboard |
| docs.search | query | Search the docsPath folder for content matching the query |
| tasks.acceptance_get | taskId | Returns all acceptance criteria for a task with their id, task_id, criterion text, and met status. Use the returned id values with tasks.acceptance.update |
| deps.snapshot | (none) | Snapshot current package.json dependencies to .harness/deps-lock.json |
| deps.check | (none) | Compare current package.json against .harness/deps-lock.json. Returns { significant, added, removed, majorBumps, advisory } |
| ahk.doctor | (none) | Check lib version, agent files, and harness skills sync status. Returns { lib: { current, latest, outdated }, agents: { missing, outdated, ok }, skills: { missing, outdated, ok } }. The lib version lookup (npm registry check) is cached in-memory with a 5-minute TTL — repeated calls within that window do not hit the network again. |
Agent roles
| Role | Responsibility |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| lead | Decomposes the task into a plan, assigns sub-agents. Does not write code or read source files. |
| explorer | Reads and maps the codebase. Never writes files. Records every file read. |
| consultant | Provides structured technical advisory after explorer. Runs conditionally. Never writes code. Writes advisory to harness via actions.write. |
| builder | Implements the plan. Only writes to writablePaths. Records every file modified. |
| reviewer | Verifies all acceptance criteria are met. Approves or blocks. Runs health check before approving. |
MCP tool permissions by role
Each agent role has a scoped set of MCP tools enforced through the agent definition files.
| Tool | lead | explorer | consultant | builder | reviewer |
| ----------------------------- | :--: | :------: | :--------: | :-----: | :------: |
| tasks.get | ✅ | ✅ | ✅ | ✅ | ✅ |
| tasks.claim | ✅ | ✅ | ✅ | ✅ | ✅ |
| tasks.add | ✅ | ❌ | ❌ | ✅ | ✅ |
| tasks.update | ✅ | ❌ | ❌ | ✅ | ✅ |
| tasks.edit | ✅ | ❌ | ❌ | ✅ | ✅ |
| tasks.archive / unarchive | ✅ | ❌ | ❌ | ✅ | ✅ |
| tasks.acceptance_get | ✅ | ✅ | ✅ | ✅ | ✅ |
| tasks.acceptance.update | ❌ | ❌ | ❌ | ❌ | ✅ |
| actions.* (all 6) | ✅ | ✅ | ✅ | ✅ | ✅ |
| docs.search | ✅ | ✅ | ✅ | ✅ | ✅ |
| permissions.check | ✅ | ✅ | ❌ | ✅ | ✅ |
| deps.snapshot | ❌ | ❌ | ✅ | ❌ | ❌ |
| deps.check | ❌ | ❌ | ✅ | ❌ | ❌ |
| ahk.doctor | ✅ | ✅ | ✅ | ✅ | ✅ |
explorer is read-only for task state — can query but cannot mutate status or mark criteria.
reviewer is the only role that can mark acceptance criteria as met (tasks.acceptance.update).
lead and builder have identical access, both excluding tasks.acceptance.update.
consultant is advisory-only — reads code, writes to harness, and can call deps tools. Never modifies the codebase.
permissions.check compares each .claude/agents/*.md tool list against the canonical constants in the package. Returns { in_sync: bool, agents: { lead, explorer, consultant, builder, reviewer } } with per-agent missing and extra arrays. Run ahk build --sync to fix any drift.
What to commit
| File | Commit? |
| ----------------------------- | ------------------- |
| agent-harness-kit.config.ts | Yes |
| AGENTS.md | Yes |
| CLAUDE.md | Yes |
| health.sh | Yes |
| .harness/feature_list.json | Yes |
| .claude/agents/*.md | Yes |
| .claude/mcp.json | Yes |
| .claude/settings.json | Yes |
| .opencode/agents/*.md | Yes |
| opencode.json | Yes |
| .codex/agents/*.toml | Yes |
| .codex/config.toml | Yes |
| .harness/harness.db | No (gitignored, local scope only) |
| .harness/current.md | No (gitignored, local scope only) |
| .harness/storage-state.json | Yes (metadata, not gitignored — always present regardless of scope) |
The rule: commit inputs (config, task definitions, agent instructions). Ignore outputs (DB, auto-generated snapshots). storage-state.json is metadata about where those outputs live, not an output itself — it's committed so the harness can detect storage drift.
Runtime compatibility
| Runtime | SQLite | PostgreSQL | MySQL |
| ---------------- | ------------------------------ | ------------------------- | ----------------------- |
| Node.js ≥ 22 | ✅ uses better-sqlite3 package | ✅ via postgres package | ✅ via mysql2 package |
| Bun (any recent) | ✅ uses bun:sqlite built-in | ✅ via postgres package | ✅ via mysql2 package |
| Node.js < 22 | ❌ blocked by engines.node (not by the SQLite driver) | ✅ | ✅ |
SQLite is included via the better-sqlite3 dependency (installed automatically). For PostgreSQL install postgres, for MySQL install mysql2:
npm install postgres # for PostgreSQL
npm install mysql2 # for MySQLContributing & local development
git clone <repo-url>
cd agent-harness-kit
npm install
npm run build:ui # build the dashboard SPA (dashboard/ → src/dashboard-dist/)
npm run build # build:ui + tsc + copy-assets
npm run dev # watch mode (CLI TypeScript only)
npm test # run testsTesting the local build in another project
Use the helper script to build the package and link it into any local project in one step:
# Build + link into a specific project
./scripts/link-local.sh /path/to/your-other-project
# Build + register globally only (then link manually wherever you need)
./scripts/link-local.shWhat the script does:
- Runs
npm run build(full build including dashboard assets) - Runs
npm linkto register the package globally on your machine - Runs
npm link @cardor/agent-harness-kitinside the target project - Smoke-tests the
ahkbinary with--version
After linking, npx ahk inside the target project will use your local build. To unlink when you're done:
# Inside the target project
npm unlink @cardor/agent-harness-kit
# Optionally remove the global registration
npm uninstall -g @cardor/agent-harness-kitTip: If you're iterating quickly, run
npm run buildin this repo after each change — the link picks up the newdist/immediately without re-running the script.
To work on the dashboard UI with hot reload:
# Terminal 1 — CLI server (no browser open)
cd your-test-project && ahk dashboard --no-open --port 4242
# Terminal 2 — Vite dev server with HMR
cd dashboard && npm run dev # http://localhost:5173, proxies /api and /ws → :4242Commit messages follow Conventional Commits with a required scope:
feat(cli): add export command
fix(db): prevent race condition in claimTask
chore(ci): update Node version to 22Types: feat fix chore refactor docs test perf style build ci revert
Roadmap
- ✅
ahk dashboard— local web UI with real-time WebSocket updates. Shows tasks, action timelines, file activity, tool usage, and per-agent breakdowns. - ✅
ahk reset— interactively clear the SQLite DB, feature list, and agent files to start a project fresh. - ✅ PostgreSQL + MySQL drivers — remote database support via
postgresandmysql2packages. Configure withdatabase: { type: 'postgres', connectionString: '...' }. - ✅
actions.record_file+actions.record_tool— dedicated MCP tools for populating the Files and Tools dashboard views. - ✅
tasks.addvia MCP — agents can create new tasks on the fly without leaving the conversation. - ✅ Global installation —
ahk initcan install the harness to your home directory, shared across projects. - ✅ Input validation — all CLI prompts validate and retry on bad values.
- ✅ Codex CLI provider — full support for OpenAI Codex CLI. Generates
.codex/agents/*.tomlfiles with propersandbox_modeper role and merges.codex/config.tomlfor MCP registration. Overrides the built-indefaultagent so the harness lead runs by default. - Graphify integration — connect the harness to Graphify to visualize agent workflows, task dependencies, and action timelines as interactive graphs.
- Open Telemetry integration — emit OpenTelemetry spans for all agent actions, file operations, and tool calls.
- Jira task adapter — pull tasks directly from Jira instead of maintaining
feature_list.jsonmanually. - Linear task adapter — same as Jira, for Linear.
- GitHub Issues adapter — same, for GitHub Issues.
- Remote MCP adapter — connect to a hosted MCP server instead of a local SQLite file. Enables shared task state across machines and team members without syncing a DB file.
