create-harness-cli
v1.0.0
Published
Scaffold an AI coding-agent harness (conventions, verification gates, workflows) onto an existing project — for Cursor and Claude Code.
Maintainers
Readme
create-harness
Drop an AI coding-agent harness onto an existing project — one command.
Not an app scaffolder. create-harness installs conventions, verification gates, and workflows so Cursor and Claude Code produce consistent work in a repo you already have.
Published on npm as create-harness-cli (the create-harness name is taken).
Quick start
npx create-harness-cli
npx create-harness-cli ./my-app --dry-runRequires Node.js 20+.
Interactive vs explicit paths
- TTY (interactive): prompts walk you through every decision
- Non-TTY / automation: all required answers must be provided via
--flagsor--config <path.json>. Missing answers = immediate error (never hangs on stdin)
What you get
AGENTS.md— short source of truth for every agent (CLAUDE.mdimports it), includes design mode + coding style preferences- Cursor rules / Claude skills — architecture, data fetching, design system, testing, auth
- Workflows —
/spec→/impl→/verify→/ship,/qa, plus/ds-init,/ds-add,/ux-review,/ds-refwhen the design-system module is on - Blind QA agent —
/qa <goal>hands one user goal to aqa-testersubagent that knows nothing about the code (Claude Code: browser tools only, no file access, noCLAUDE.md). It uses the running app like a first-time user and reports blockers, confusion, missing feedback, accessibility signals, and console/network errors. Only confirmed bugs become tests — written while the bug still exists, so they start red - Design reference map (inspire/implement modes) — agent-maintained Figma link registry, prevents free redesign when
implementmode is set - Coding style config — componentDeclaration (function/arrow), export (default/named), styling (css-modules/tailwind) stored in config, enforced by agents
- Write-time checks — Cursor
preToolUse/ ClaudePreToolUseon every write tool and shell write: Storybook prerequisite, design reference, layout-first scaffold (implement mode), inline styles in pages, stories for new components - Commit gate — shared script wired to Cursor
beforeShellExecutionand ClaudePreToolUse(blocks failed checks, staged.env,--no-verify, force push; warns on structure drift — bloated pages, bloated atoms, look-alike components) - Reference code — axios instance,
ProtectedRoute, TanStack Query 3-layer example, Zustand store (compile-ready, not prose) - Lint enforcement — naming, public API boundaries, Atomic layer imports (early page raw JSX ban), color tokens via stylelint
- Brownfield baselines — existing violations (raw colors, raw page JSX) grandfathered as warnings; new code stays strict
Files you wrote are never overwritten. Conflicts land under .harness/incoming/. Every write is recorded in .harness/manifest.json.
Options
npx create-harness-cli [dir] [options]
--preset <name> preset (currently: react-fe)
--lang <lang> installation language en|ko (kr is alias for ko)
--agents <csv> cursor,claude (default: both)
--modules <csv> design-system,auth-http,data-fetching,lint
--ponytail optional YAGNI ladder rules from ponytail
--mode <mode> free|inspire|implement (default: free)
--component-declaration <type> function|arrow (default: function)
--component-export <type> default|named (default: default, not asked in interactive)
--styling <type> css|css-modules|tailwind (when not detected)
--figma-url <url> Figma file URL (optional)
--accept-disclaimer design reference liability disclaimer
--dry-run print the plan without writing
--config <path> load settings from JSON file (flags override config)Interactive runs also ask:
- Language: Korean or English
- Design mode: free (no design reference) / inspire (redesign allowed) / implement (match Figma closely)
- Coding style: component declaration, styling approach (componentExport defaults to 'default', not asked)
- Storybook intent:
off/pendingin.harness/config.json(use/ds-initlater to install and setready)
Note: --ponytail flag is available but no longer asked in interactive mode (power user feature only).
Config file format (--config)
JSON file matching CLI flags:
{
"lang": "ko",
"mode": "free",
"agents": ["cursor", "claude"],
"modules": ["design-system", "lint"],
"storybook": "pending",
"ponytail": false,
"componentDeclaration": "function",
"componentExport": "default",
"styling": "css-modules"
}Flags override config when both are present. You can also pass config via stdin: --config -
Modules
Core (rules, workflows, gates, docs) always installs. Code-generating modules default on only when they will compile and pass checks on the target:
| Module | Default on when | Skipped when |
|--------|-----------------|--------------|
| design-system | CSS / CSS Modules | Tailwind, CSS-in-JS |
| auth-http | axios + react-router + Vite | fetch-only, Next.js/CRA |
| data-fetching | TanStack Query + Zustand + axios | other stacks |
| lint | ESLint flat config + TypeScript | legacy .eslintrc, JS-only |
Use --modules to force inclusion. Dropping a module also drops the rules and workflows that depend on it.
Upgrading
Re-run the CLI in the same project with the same answers (flags or --config):
npx create-harness-cli@latest . --config harness.config.json- Harness files you never touched (hash matches
.harness/manifest.json) are replaced with the new version — shown as↻. - Files you edited are left alone; the new version goes to
.harness/incoming/<path>.incomingfor you to diff and merge. - Files that existed before the harness (e.g. your own
AGENTS.md) are never replaced.
From 0.x to 1.0
- Claude Code permission prompts come back. Before 0.7.0, the hook scripts returned an explicit
allow, which silently skipped your permission prompts for every shell command and write. They now stay silent on pass, so your normal permission settings apply again. .claude/settings.jsonhooks changed — writes viaEdit/MultiEditand shell writes are now checked. If you customized this file, merge thehooksblock from.harness/incoming/.claude/settings.json.incoming.- New files:
/qaworkflow,qa-testeragent (.claude/agents/or.cursor/agents/),.harness/gates/structure-check.mjs(design-system module). - Installs from before 1.0 upgrade cleanly only for files still matching their recorded hash; anything you edited lands in
incoming.
Stability (1.0+)
Semver applies to what you depend on. Breaking any of these means a new major version:
| Public (stable) | |
|---|---|
| CLI | flags and --config keys listed above |
| .harness/config.json | checks, storybook, mode, fidelity, style, lang, and the optional structure / qa keys |
| .harness/design-references.json | entry shape: id, kind, codePath, ref, status, lastReadOk |
| Installed locations | AGENTS.md, CLAUDE.md, .cursor/rules|commands|agents/, .claude/skills|agents/, .claude/settings.json, .harness/gates/, docs/ |
| Workflow names | /spec /impl /verify /ship /qa /ds-init /ds-add /ux-review /ds-ref |
| What blocks | the write-time and commit rules listed in the installed AGENTS.md. New blocking rules ship only in a major version — in minor versions, new checks arrive as warnings |
| Upgrade behavior | untouched harness files are replaced, edited files go to incoming |
Internal — may change in any minor version: function names and internals of .harness/gates/*.mjs, message wording, warning heuristics and their default thresholds, workflow prose, template wording.
Opinions (short)
- Docs suggest. Gates enforce. Prefer checks and lint errors over hoping the agent reads a paragraph.
- Design tokens + stylelint are the reliable way to stop UI drift; Atomic layer reverse-imports are ESLint errors.
- Storybook is on-demand (
/ds-init) — CLI asks intent only (off/pending), not installed up front. - Brownfield-friendly — existing violations go into baseline files (warning), new code stays strict (error).
- Design rationale lives in
DECISIONS.md.
Develop
npm run check
npm run dev -- <target> --dry-runtemplates/— files copied into target projects- everything else — this CLI
- roadmap:
TODO.md
Note on local paths: When running create-harness-cli with a local machine path (e.g. /Users/... on macOS), the executing context needs machine-targeted tools or a parent agent that can access that path. Cloud Agent sandbox executors may not see local machine paths directly.
