A provider-agnostic scaffolding kit for running structured multi-agent workflows in your codebase.
$ npx -y skills add enmanuelmag/agent-harness-kit --agent claude-code
Repo: enmanuelmag/agent-harness-kit
What's inside
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 init
ahk initahk buildahk modelsahk dashboardahk statusahk healthahk doctorahk syncahk serveahk task addahk task listahk task done <id|slug>ahk resetahk migrateahk exportahk init
agent-harness-kit.config.{json|ts|mjs|cjs}health.sh.harness/feature_list.jsonIf 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:
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.
ahk init
โโโ creates config, agent definitions, task backlog, health check
AI tool opens your project
โโโ reads .claude/mcp.json, opencode.json, .codex/config.toml, or .grok/config.toml
โโโ spawns: ahk serve (stdio MCP server)
via your package manager (npx/pnpm exec/yarn run/bunx) when the
package is a local dependency, or the bare binary when it isn't
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 history
Everything 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.
Note: "Grok Build" here refers to xAI's official Grok Build CLI (
provider: 'grok-cli') โ it is unrelated to the unofficial, community-maintainedgrok-cli/grok-devnpm packages.
tasks.claim() which uses a SQLite transaction to prevent two agents from picking up the same task at the same time.health.sh and get a green exit before starting or closing any task. You define what "healthy" means.current.md is always regenerated so agents can understand the session state even without the MCP server.docs.search(query) to find relevant content in your project's docs folder before writing code.better-sqlite3 on Node โฅ 22 or bun:sqlite on Bun). Switch to PostgreSQL or MySQL with a single config line โ same schema, same MCP tools, same workflow.ahk init preserves files you've already customized (agent definitions you've edited are kept). A hand-written .harness/feature_list.json backlog is merged, never overwritten โ existing tasks survive and any first task you add during init is folded in (deduplicated by slug). ahk build also creates missing agent files and never touches existing ones. Use ahk build --force to regenerate them from the latest templates, discarding your edits (a backup is written first).ahk init can scaffold the harness into your home directory (~/.claude or ~/.config/opencode) to share it across all projects.# Install in your project as a dev dependency (recommended)
npm install --save-dev @cardor/agent-harness-kit
Then run the interactive setup inside your project:
npx ahk init
The config file format depends on whether the package is installed locally.
ahk initchecks that first, before anything else:
Local install Generated config Why Not installed (global-only CLI) agent-harness-kit.config.jsonYour project cannot resolve @cardor/agent-harness-kit, so a TypeScript config'simport typewould red-underline in your editor and failtsc --noEmiton a package that isn't there. JSON has no imports and no types โ nothing to resolve, zero editor errors.Installed ( npm install --save-dev @cardor/agent-harness-kit).ts,.mjsor.cjsThe package resolves, so you get the full typed config with editor autocompletion. Which of the three is picked is unchanged: .tswhen atsconfig.jsonis present, otherwise.mjs/.cjsbased onpackage.jsontype.The trade-off is autocompletion: a JSON config has no type information behind it, so your editor cannot suggest fields. Installing the package locally and switching to a
.tsconfig gets that back. There is no$schemakey in the generated JSON โ no JSON Schema forHarnessConfigis published yet, and pointing at a URL that doesn't resolve would only swap a type error for a fetch error.Existing projects are never converted. If a config of any extension already exists, it keeps working and keeps its format โ installing or removing the package locally will not silently rewrite it.
loadConfig()reads all five formats, andahk initstops when it finds any of them.A local install is still recommended even though it is no longer required: it pins the CLI version so behavior stays reproducible across your team and CI instead of drifting with whatever is installed globally on each machine. On a global-only install
ahkprints a non-blocking warning suggesting it โ the command runs and exits normally either way.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.
ahk init and ahk build detect which package manager your project uses and generate the MCP server launch command (.mcp.json, opencode.json, .codex/config.toml, or .grok/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> |
| any โ no local install | @cardor/agent-harness-kit is not a dependency of your project | ahk serve --port <port> |
Detection order: the packageManager field in your package.json (e.g. "packageManager": "pnpm@8.15.0") takes priority when present; otherwise ahk falls back to lockfile heuristics; if nothing is detected, it defaults to npm.
Global installs bypass the package manager entirely. Every command in the table above asks your package manager to resolve a locally installed ahk binary โ npx --no deliberately refuses to download one, and pnpm exec/yarn run/bunx --no-install have nothing to point at. If you installed the CLI globally and never added it to the project, all five of those commands fail. So ahk checks for a real local install first and, when there is none, generates the bare ahk serve --port <port> โ resolved from your PATH like any other global binary. The package-manager-specific commands are used only when a local install actually exists. If, on that global-install path, ahk is not resolvable on your PATH at generation time, ahk prints a non-blocking warning (the command still succeeds) pointing you at npm i -g @cardor/agent-harness-kit or a local install โ moving the "binary not found" failure earlier instead of surfacing it later when the MCP server is spawned.
Working inside the agent-harness-kit repository itself does not count as a local install for this decision: there is no real node_modules/@cardor/agent-harness-kit entry for a package manager to resolve, so self-dev generates the bare global ahk serve --port <port> form, same as any other project with no local install. This is a narrower check than the one deciding your config file format, above (ahk init's .ts/.mjs/.cjs vs. .json choice) โ that check still treats self-dev as satisfied, since it only cares whether the package is resolvable for type-checking purposes, not whether a package manager can mediate a spawned command.
Existing projects: if you initialized your project before this change, your .mcp.json/opencode.json/.codex/config.toml/.grok/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.
ahk initInteractive 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.
Claude Code only, init asks you to pick a model for each of the 5 core roles (lead, explorer, consultant, builder, reviewer) one at a time: inherit (default), haiku, sonnet, opus, or fable. Each choice is written straight into that role's generated .claude/agents/<role>.md frontmatter as a model: line at scaffold time โ it is never persisted to the config file. Picking inherit (the default) emits no model: line at all, leaving Claude Code to apply its own default. Agent files are user-owned once generated (see Agent files are yours below), so after init the model can be changed three ways: hand-editing the model: frontmatter line directly, running ahk models to re-prompt and regenerate just the 5 agent files, or running ahk build --force (which re-prompts too, then regenerates everything --force regenerates).
Codex CLI only, init asks you to pick a model and a reasoning effort for each of the 5 core roles, one role at a time: model choices are gpt-5.6-sol, gpt-5.6-terra (default), gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex-spark; effort choices are minimal, low, medium (default), high, xhigh. Not every model supports every effort level โ Codex applies its own per-model behavior for an unsupported combination, so pick deliberately rather than assuming universal compatibility. Both choices are written straight into that role's generated .codex/agents/<role>.toml as model = "..." / model_reasoning_effort = "..." lines at scaffold time โ never persisted to config.toml. Agent files are user-owned once generated, so after init the model/effort can only be changed by hand-editing the TOML directly (there is no Codex equivalent of ahk models yet) or running ahk build --force (which re-prompts, then regenerates everything --force regenerates).
Separately, .codex/config.toml always gets a project-wide top-level default โ model = "gpt-5.6-terra" and model_reasoning_effort = "medium" โ written once and preserved across every subsequent ahk build/ahk init --force: if you hand-edit either value in config.toml, your edit is never overwritten. Per-role model/model_reasoning_effort lines in .codex/agents/<role>.toml (above) act as overrides of this baseline for that one role.
OpenCode and Grok Build are unaffected by either prompt โ it never appears for those providers, since neither has a closed model enum to prompt against.
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 in agent-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 global
ahk init --name "my-app" --provider grok-cli --docs ./docs --tasks local --storage-scope local
Run 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 buildRegenerates 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 --force # DESTRUCTIVE: regenerate agent files, discarding your edits
ahk build --sync # kept for backwards compatibility โ now a no-op on every provider
ahk build creates agent files that are missing and never modifies ones that already exist. Edit .claude/agents/<role>.md (or .opencode/agents/<role>.md, .codex/agents/<role>.toml, or .grok/agents/<role>.md) freely โ change the role prompt, set a model: line, adjust the restriction fields. Rebuilding will not revert your work. ahk doctor does not report hand-edited files either; it checks existence only.
Everything else build writes โ MCP config and skills โ is derived from your config and is regenerated on every run.
AGENTS.md and CLAUDE.md โ derived, but your edits are safeAGENTS.md (all providers) and CLAUDE.md (Claude Code only) are generated from your config, so a config change should flow into them โ but they are also files people hand-edit. build reconciles both concerns with a provenance marker: every generated file ends with a comment holding a checksum of the exact bytes we wrote, e.g.
<!-- ahk:generated 3f7aโฆc1 -->
On each build the marker lets build tell its own untouched output apart from a human edit, byte-for-byte:
CLAUDE.md you customized before upgrading) โ left untouched, and build prints a loud notice naming the file and telling you to run --force if you actually want it regenerated.Because the checksum is over the exact bytes, any change โ even one space โ counts as an edit and is preserved. The behavior is identical with or without a terminal (there is no prompt), so it is safe in scripts and CI. Leave the marker comment in place; deleting it just makes build treat the file as hand-edited (preserve it) on the next run.
If you use OpenCode or Codex CLI, your agent files may be out of date right now. Those two providers have always preserved existing agent files on build, which means they have never picked up template improvements shipped in newer versions of this package. Claude Code, by contrast, used to overwrite them on every build โ that inconsistency was a bug, and it is now fixed in favour of preserving your edits. To pull in the current templates, run
ahk build --force(read the warning below first).
--forceBecause build no longer overwrites agent files on any provider, --force is the only way to regenerate them from the packaged templates. It is destructive:
ahk build --force
model: lines, and restriction tweaks are all lost..harness/backups/ โ agent files to agents-<timestamp>/, hand-edited AGENTS.md/CLAUDE.md to derived-<timestamp>/. If that backup cannot be written, the command aborts and no file is modified โ the same fail-safe as ahk migrate storage --force.ahk build --force runs the same per-role prompt as ahk init for the current provider โ the model prompt on Claude Code, or the model and reasoning-effort prompt on Codex CLI (see above) โ and injects the fresh choices into the regenerated frontmatter/TOML. OpenCode and Grok Build are unaffected โ no prompt appears for them, since neither has a closed model enum to prompt against.--force also regenerates a hand-edited AGENTS.md or CLAUDE.md (backing it up first) โ the only time you need it for those files, since an unedited one already re-generates on its own when config changes.
--watch never forces, even if you pass both flags: an automatic rebuild triggered by a file change must not destroy your edits in the background.
--sync used to rewrite the tools: frontmatter of agent files so it matched a canonical allowlist. Agent files no longer declare an allowlist at all โ they inherit every tool and declare only restrictions โ so there is nothing left to synchronise. Use ahk build --force to regenerate agent files.
ahk modelsClaude Code only. Re-runs ahk init's per-role model prompt and regenerates ONLY the 5 .claude/agents/*.md files with the chosen models โ nothing else (not AGENTS.md, CLAUDE.md, .mcp.json, .claude/settings.json, your config file, docs path, storage scope, or task adapter).
ahk models
inherit (default), haiku, sonnet, opus, or fable โ same prompt as ahk init..harness/backups/agents-<timestamp>/ โ the same fail-safe --force uses.agent-harness-kit.config is found, it prints a message pointing at ahk init and exits โ no prompt, no stack trace.ahk dashboardOpens 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 browser
--port must be an integer between 1 and 65535; an invalid value (e.g. ahk dashboard --port abc or --port 99999) is rejected at the CLI with a clear error naming the flag and the valid range, rather than silently failing.
If the requested port (default 4242) is already in use, ahk dashboard automatically tries up to 10 sequential ports (e.g. 4242 โ 4243 โ โฆ โ 4251), printing Port 4242 in use, using 4243. 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.
Port availability is checked against the same network interface the dashboard actually binds to, so an already-running ahk dashboard โ or any other server holding that port โ is reliably detected. The success banner is printed only after the server has genuinely bound; if the bind fails (for example, the port was claimed by another process in the moment between the check and the bind), the command reports an actionable error instead of crashing.
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 statusShows the current task table and any active agent actions in the terminal.
ahk status
ahk status --json # machine-readable output
ahk healthRuns health.sh and reports the result. Exit 0 = healthy, exit 1 = something is wrong.
ahk health
ahk doctorChecks the installed lib version, that every agent file is present, and that the harness skills are in sync.
ahk doctor
Reports three categories:
[โ] if up to date, [!] if an update is available, or [~] if the registry could not be reached.[!] with the file name if one is missing. The contents are never read, so editing an agent file by hand is a fully supported state and is never reported โ customise the body, the description, or the restrictions freely and ahk doctor stays green.ahk-ask, ahk-consultant, ahk-triage, and ahk-review skills exist and match the bundled source. Reports [!] if missing or outdated.Run ahk build to fix any reported issues.
ahk syncSyncs .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 in
ahk serveStarts 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)
--port must be an integer between 1 and 65535; an invalid value is rejected at the CLI with a clear error.
ahk task addInteractively adds a new task to the backlog (SQLite + feature_list.json).
ahk task add
ahk task listLists 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 output
ahk 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-flow
ahk resetClears 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-cli
ahk reset --provider grok-cli
What it can reset:
.db file (plus WAL and SHM files if present).harness/feature_list.json.claude/agents/, .opencode/agents/, .codex/agents/, or .grok/agents/After a reset, run ahk init to scaffold a fresh harness.
ahk migrateahk 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 providerMigrates 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
ahk migrate provider --to grok-cli
# Backward-compatible alias (identical behavior):
ahk migrate --to opencode
Migrating always regenerates the target provider's agent files from scratch, so โ same as ahk init and ahk build --force โ it also runs that target's per-role prompt first, before anything is written: the model prompt when migrating to Claude Code, or the model and reasoning-effort prompt when migrating to Codex CLI (see ahk init above for what each prompt asks). Migrating to OpenCode or Grok CLI shows no prompt at all, since neither has a closed model enum to prompt against.
ahk migrate storage โ โ ๏ธ sensitive, reads/writes real harness dataMigrates 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, storage.sqlitePath (local scope only), database.type/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 data
What 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):
setval on Postgres, sqlite_sequence update on SQLite; MySQL's AUTO_INCREMENT advances on its own) so that the next normal task/action created after migrating never collides with an imported id.storage-state.json intentionally never stores connection credentials, so there's nothing to reconnect to. Export manually with ahk export --json while still connected to the old database first.ahk exportExports 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 file
ahk initClaude Code (provider: 'claude-code'):
your-project/
โโโ agent-harness-kit.config.{json|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 agent
OpenCode (provider: 'opencode'):
your-project/
โโโ agent-harness-kit.config.{json|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.md
Codex CLI (provider: 'codex-cli'):
your-project/
โโโ agent-harness-kit.config.{json|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 lead
Grok Build (provider: 'grok-cli'):
your-project/
โโโ agent-harness-kit.config.{json|ts|mjs|cjs}
โโโ AGENTS.md
โโโ health.sh
โโโ .harness/
โโโ .grok/
โโโ config.toml โ MCP server registration
โโโ agents/
โโโ lead.md
โโโ explorer.md
โโโ builder.md
โโโ reviewer.md
| File | Purpose | Edit it? |
|---|---|---|
agent-harness-kit.config.{json|ts|mjs|cjs} | Defines project metadata, provider, storage paths, MCP port. JSON when the package isn't installed locally, otherwise .ts/.mjs/.cjs | 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 (ahk build --force regenerates) | 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 (ahk build --force regenerates) | 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 (ahk build --force regenerates) | Yes โ customize agent behavior |
.codex/config.toml | MCP server registration for Codex CLI. Merged by ahk build | Yes, carefully |
.grok/agents/*.md | Agent role definitions (Grok Build). Created once, never overwritten (ahk build --force regenerates) | Yes โ customize agent behavior |
.grok/config.toml | MCP server registration for Grok Build. Merged by ahk build | Yes, carefully |
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.
agent-harness-kit.config.{json|ts|mjs|cjs}Everything in the config file is yours to change. The example below is the TypeScript form, generated when the package is installed locally in your project:
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' | 'grok-cli'
// There is no `agents` key. Per-agent settings live in the generated agent
// file itself, which is yours to edit โ see "Agent files are yours" below.
// โโ Database โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// SQLite (default โ zero native deps, Node 22+ or Bun). Note: `database`
// never carries a file path โ where the .db file physically lives is a
// `storage` concern (see `storage.sqlitePath` below), not a `database` one.
database: { type: 'sqlite' },
// 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 โ scope: 'local' (default) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// DB and current.md live project-relative, in .harness/. `sqlitePath` and
// `markdownFallback.path` are only valid (and only exist on the type) when
// `scope: 'local'`.
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' },
scope: 'local',
projectId: '5f2c...', // UUID, generated once at init, never regenerated
// sqlitePath: '.harness/harness.db', // optional โ defaults to '.harness/harness.db' when omitted
},
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
The JSON form (agent-harness-kit.config.json, generated when the package is not installed locally) holds exactly the same values, minus the comments and the type annotation:
{
"project": {
"name": "My App",
"description": "What this project does",
"docsPath": "./docs"
},
"provider": "claude-code",
"database": { "type": "sqlite" },
"storage": {
"dir": ".harness",
"tasks": { "adapter": "local" },
"sections": {
"toolsUsed": true,
"filesModified": true,
"result": true,
"blockers": true,
"nextSteps": false
},
"markdownFallback": { "enabled": true, "path": ".harness/current.md" },
"scope": "local",
"projectId": "5f2c..."
},
"health": { "scriptPath": "./health.sh", "required": true },
"tools": {
"mcp": { "enabled": true, "port": 3742 },
"scripts": { "enabled": true, "outputDir": "./.harness/scripts" }
}
}
Every option documented below applies to both forms โ the same keys, the same defaults, the same runtime normalization. The only difference is that the JSON form has no type checking or autocompletion behind it, since there is no package to resolve them from. To switch a JSON config to TypeScript, install the package locally (npm install --save-dev @cardor/agent-harness-kit) and rename the file to agent-harness-kit.config.ts, wrapping the object as shown above. ahk will not convert it for you โ an existing config always keeps its format.
scope: 'global' โ DB and current.md live under ~/.harness/dbs/<projectId>/, outside the project tree. Under this scope, sqlitePath and markdownFallback.path don't exist on the type at all (a type error, not just a no-op) โ there's nothing local to declare a path for:
storage: {
dir: '.harness',
tasks: { adapter: 'local' },
sections: { toolsUsed: true, filesModified: true, result: true, blockers: true, nextSteps: false },
markdownFallback: { enabled: true }, // no `path` โ auto-managed under ~/.harness/dbs/<projectId>/
scope: 'global',
projectId: '5f2c...',
// sqlitePath is NOT a valid field here โ omit it entirely
},
StorageConfigis a discriminated union onscope(LocalStorageConfig | GlobalStorageConfig, seesrc/types.ts) โ this is what makes declaringsqlitePath/markdownFallback.pathunderscope: 'global'a compile-time error instead of a silently-ignored field. If you're loading a config file at runtime (vialoadConfig(), which usesjitiand does not type-check), an existingscope: 'global'config that still has these fields set gets normalized automatically with aconsole.warnrather than crashing โ seeapplyDefaults()insrc/core/config.ts.
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.shThis 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."
These files belong to you. ahk init and ahk build both create them when missing and never modify them once they exist. Customise them freely: rewrite the role prompt, add a model: line, adjust the restriction fields. Nothing in the normal workflow will revert your edits, and ahk doctor never reports a hand-edited file as drift โ it checks existence only.
The trade-off is that you do not automatically receive template improvements from new versions of this package. ahk build --force is the only way to pull them in, and it discards your customisations (writing a backup to .harness/backups/agents-<timestamp>/ first). Keep customisations in source control so you can diff against a forced regeneration.
There is no agents key in agent-harness-kit.config.ts. Per-agent settings live here, in the file itself โ set the model on the model: frontmatter line (model = "..." for Codex CLI) and write role instructions in the body. When no model line is present, the provider applies its own default.
Agent files do not declare a tool allowlist. Each agent inherits the full tool set of the session โ including Task and every MCP tool โ and the file declares only what the role is not allowed to do. Each provider expresses that restriction in its own syntax.
Claude Code (.claude/agents/*.md) uses a disallowedTools YAML block sequence:
---
name: explorer
description: Explorer agent โ reads and maps the codebase, never writes
disallowedTools:
- Write
- Edit
---
# Explorer Agent
You are the explorer agent for MyApp. Follow these rules:
- Map the modules relevant to the task and report where each concern lives
- Never modify files โ record every file you read
- Prefer the existing patterns in `src/lib/` when describing conventions
OpenCode (.opencode/agents/*.md) uses a permission mapping instead. OpenCode has no separate write permission โ its edit key is defined as "file modifications including write/patch", so a single edit: deny covers Write, Edit, and patch:
---
name: explorer
description: Explorer agent โ reads and maps the codebase, never writes
permission:
edit: deny
---
# Explorer Agent
You are the explorer agent for MyApp. Follow these rules:
- Map the modules relevant to the task and report where each concern lives
- Never modify files โ record every file you read
The legacy OpenCode
tools: { write: false }dict is deprecated upstream in favour ofpermissionand is no longer emitted.
For the builder, which has no restrictions, the key is omitted entirely โ no disallowedTools under Claude Code, no permission under OpenCode.
Codex CLI (.codex/agents/*.toml) uses TOML format:
name = "builder"
sandbox_mode = "danger-full-access"
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
"""
Deliberate security tradeoff (all 5 roles, not just builder). Codex CLI has no per-agent tool denylist. Earlier versions of this project used sandbox_mode as the OS-level enforcement mechanism ("read-only" for lead/explorer/consultant/reviewer, "workspace-write" for builder). As of a deliberate, user-chosen configuration decision (task #83), every role now runs with sandbox_mode = "danger-full-access" โ i.e. fully unsandboxed, with no OS-level write protection at all, for lead, explorer, consultant, builder, and reviewer alike.
This means the no-write restriction for lead/explorer/consultant/reviewer under Codex CLI is enforced entirely by prompt instruction, not by the operating system. Nothing technically blocks or rejects a write from a "read-only" role under Codex anymore โ the restriction is restated in prose inside developer_instructions (see CODEX_READ_ONLY_NOTICE in src/core/materializer/agent-restrictions.ts), and that prose is the only thing standing between a no-write role and it actually writing files. A violation won't fail loudly; it will silently corrupt the harness's audit trail and workflow guarantees. This tradeoff was explained to and knowingly chosen by the project's maintainer โ it is not an oversight, and it is not a general recommendation. If you fork this project, you may want to reintroduce "read-only"/"workspace-write" for stronger guarantees under Codex.
Grok Build (.grok/agents/*.md) uses markdown + YAML frontmatter, like Claude Code and OpenCode โ but its tools: field is an allowlist, the inverse shape of Claude's disallowedTools. A restricted role must enumerate every tool it IS allowed to use, since there is no way to say "everything except Write/Edit":
---
name: explorer
description: Explorer agent โ reads and maps the codebase, never writes
tools:
- Bash
- Read
- NotebookRead
- Grep
- Glob
- WebFetch
- WebSearch
- search_tool
- use_tool
---
# Explorer Agent
You are the explorer agent for MyApp. Follow these rules:
- Map the modules relevant to the task and report where each concern lives
- Never modify files โ record every file you read
For the builder, tools: is omitted entirely, same as every other provider โ the agent inherits every tool.
The equivalent constraint under Claude Code is expressed as disallowedTools: [Write, Edit], under OpenCode as permission: { edit: deny }, and under Grok Build as the tools: allowlist shown above.
.harness/feature_list.jsonThe human-editable task backlog. Add tasks here, then run ahk sync to load them into SQLite.
ahk init never clobbers this file: an existing backlog is merged into SQLite (deduplicated by slug) alongside any first task you add during init, then re-emitted โ so a hand-written backlog is preserved. On a fresh project the file is created (empty [] if you skip the first-task prompt). If the file contains invalid JSON, init leaves it untouched and warns you to fix it and run ahk sync.
[
{
"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.
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, files: [{ filePath, operation, notes? }, ...] | Batch-register one or more file touches, atomically. The only way to populate the Files dashboard. operation: read | created | modified | deleted. Batch-only โ files requires at least one entry; a single touch is still a one-element array |
actions.record_tool | actionId, calls: [{ toolName, argsJson?, resultSummary? }, ...] | Batch-register one or more tool calls, atomically. The only way to populate the Tools dashboard. Batch-only โ calls requires at least one entry; a single call is still a one-element array |
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 file presence, and harness skills sync status. Returns { lib: { current, latest, outdated }, agents: { missing, ok }, skills: { missing, outdated, ok } }. Agents are existence-checked only, so there is no outdated bucket for them; skills still has all three. 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. |
| 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. The only role that writes โ its write tools are enabled where every other role's are disabled. Records every file modified. |
| reviewer | Verifies all acceptance criteria are met. Approves or blocks. Runs health check before approving. |
Scope note. What a role may not do is enforced per tool, not per path. There is no per-agent path scoping and it is not configurable: the
allowedPaths/writablePathsfields were removed because they were only interpolated into prompt text and no provider ever enforced them โ they looked like a security control without being one. The restriction lives insrc/core/materializer/agent-restrictions.ts, which each provider translates natively:disallowedToolsin Claude Code,permission.editin OpenCode,sandbox_modein Codex CLI, and atools:allowlist in Grok Build. If a config still declares the removed fields they are stripped at load time with a warning. Codex CLI is the one exception to "enforced": by deliberate project configuration all 5 roles run withsandbox_mode = "danger-full-access"(see below), so under Codex specifically the restriction is enforced by prompt instruction only, not by the OS.The entire
agentsconfig key has since been removed too, for the same underlying reason: everything left in it was either dead or better expressed elsewhere.instructionsPath,contextandcustomwere written by the generator and never read by anything;modelwas the only field with an effect, and it now belongs in the agent file's frontmatter alongside the role prompt, since that file is user-owned. A config that still declaresagentsloads normally โ the key is ignored, with one aggregated warning pointing at the agent file.Breaking change for library consumers (compile time). The
AgentConfig,AgentsConfigandCustomAgentConfigtypes are no longer exported from the package, andHarnessConfigno longer has anagentsproperty. If you import those types, remove the import; if you construct aHarnessConfigin TypeScript, drop theagentsproperty. This is separate from the runtime tolerance above: existing config files keep loading, but code that references the removed types will not compile. TheAgentNametype is unrelated and unaffected.
Scope note. This table describes the intended division of labour between roles, not a restriction enforced by the agent files. Agent definitions no longer declare a tool allowlist, so every role inherits all MCP tools. The per-role
MCP_CLAUDE_PERMISSIONS_*arrays still exist, but they are only unioned together to populate the allow list in.claude/settings.local.jsonโ they are not applied per agent. Treat the table as the convention each role's prompt asks it to follow.
| 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 verifies only that a .claude/agents/*.md definition file exists for every role. Returns { in_sync: bool, agents: { lead, explorer, consultant, builder, reviewer } } where each agent is { ok: true } or { ok: false, reason: 'missing_file' }. Agent file contents are never inspected โ they are meant to be customised freely โ so this never reports drift, only absence. Run ahk build to restore a missing file.
| File | Commit? |
|---|---|
agent-harness-kit.config.{json|ts|mjs|cjs} | 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 |
.grok/agents/*.md | Yes |
.grok/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 | 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 MySQL
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 tests
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.sh
What the script does:
npm run build (full build including dashboard assets)npm link to register the package globally on your machinenpm link @cardor/agent-harness-kit inside the target projectahk binary with --versionAfter 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-kit
Tip: 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 โ :4242
Commit 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 22
Types: feat fix chore refactor docs test perf style build ci revert
See SECURITY.md for the vulnerability reporting process, supported versions, and coordinated-disclosure policy.
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.postgres and mysql2 packages. Configure with database: { type: 'postgres', connectionString: '...' }.actions.record_file + actions.record_tool โ dedicated MCP tools for populating the Files and Tools dashboard views.tasks.add via MCP โ agents can create new tasks on the fly without leaving the conversation.ahk init can install the harness to your home directory, shared across projects..codex/agents/*.toml files (sandbox_mode = "danger-full-access" for all roles, by deliberate project configuration โ see the Scope note above) and merges .codex/config.toml for MCP registration. Overrides the built-in default agent so the harness lead runs by default..grok/agents/*.md files with a tools: allowlist per role and merges .grok/config.toml for MCP registration.feature_list.json manually..claude/
agents/
builder.md
consultant.md
explorer.md
lead.md
reviewer.md
settings.json
.github/
workflows/
ci.yml
publish.yml
.gitignore
.husky/
commit-msg
pre-commit
.mcp.json
.npmrc
.opencode/
agents/
builder.md
explorer.md
lead.md
reviewer.md
.prettierignore
.prettierrc
agent-harness-kit.config.ts
AGENTS.md
assets/
ahk-dashboard.png
bin/
ahk.js
CLAUDE.md
commitlint.config.js
dashboard/
index.html
package.json
public/
logo-512.png
logo.png
src/
components/
shared/
agent-badge.tsx
empty-table-row.tsx
error-state.tsx
loading-state.tsx
operation-badge.tsx
page-header.tsx
status-badge.tsx
task-detail/
indx.tsx
hooks/
useStorage.ts
useTheme.ts
lib/
api.ts
main.tsx
routes/
__root.tsx
agents.tsx
files.tsx
index.tsx
tasks.$id.tsx
tasks.index.tsx
tools.tsx
routeTree.gen.ts
schema/
api.ts
styles/
global.css
tsconfig.json
vite.config.ts
docs/
architecture.md
components.md
implementation.md
index.md
README.md
eslint.config.js
health.sh
LICENSE
opencode.json
package.json
pnpm-lock.yaml
pnpm-workspace.yaml
README.md
scripts/
copy-assets.mjs
link-local.sh
publish.sh
SECURITY.md
skills-lock.json
src/
cli.ts
commands/
build.ts
claude-model-prompt.ts
codex-model-prompt.ts
dashboard.ts
doctor.ts
export.ts
health.ts
init-helpers.ts
init.ts
migrate-storage.ts
migrate.ts
models.ts
reset.ts
serve.ts
status.ts
sync.ts
task/
add.ts
done.ts
edit.ts
index.ts
list.ts
core/
config.ts
dashboard-server.ts
db.ts
doctor.ts
drivers/
migrate-actions.ts
mysql.ts
postgres.ts
sqlite.ts
types.ts
local-install-guard.ts
materializer/
agent-restrictions.ts
agent-templates/
builder.md
consultant.md
explorer.md
lead.md
reviewer.md
claude-code.ts
codex-cli.ts
detect-package-manager.ts
grok.ts
index.ts
mcp-merge.ts
opencode.ts
scaffold-utils.ts
skills/
ahk-ask/
SKILL.md
ahk-consultant/
SKILL.md
ahk-review/
SKILL.md
ahk-triage/
SKILL.md
templates.ts
mcp-server.ts
package-data.ts
path-probe.ts
permissions-check.ts
port-utils.ts
repositories/
ActionRepository.ts
StatsRepository.ts
TaskRepository.ts
server-types.ts
sqlite-adapter.ts
update-check.ts
dashboard-dist/
index.html
index.ts
schema/
init.ts
task.ts
tests/
agent-file-ownership.test.ts
cli-guard-integration.test.ts
cli-migrate.test.ts
config.test.ts
dashboard.test.ts
db.test.ts
derived-file-ownership.test.ts
detect-package-manager.test.ts
doctor.test.ts
health.test.ts
helpers/
mock-remote-driver.ts
init-feature-list.test.ts
init-helpers.test.ts
init-storage-scope-no-home-sync.test.ts
local-install-guard.test.ts
migrate-storage.test.ts
models.test.ts
path-probe.test.ts
port-utils.test.ts
slugify.test.ts
templates.test.ts
types-storage-config.test.ts
types.ts
utils/
file.ts
form.ts
tsconfig.json
tsup.config.tsFAQ
agent-harness-kit is a Claude Code plugin with 4 hand-picked skills for agent orchestration work, indexed on Flowy. Install it with the command on its page. It includes ahk-ask, ahk-consultant, ahk-review. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.