Skip to content

harn init

harn init [--adapter claude-code|cursor|codex] [--instructions-only] [--dry-run] [--check] [--project-root <path>]

One command to make a project harnery-ready. It does the setup steps that are otherwise easy to miss, and that fail silently when missed:

  1. Creates the .harnery/ coord root. Without it, findCoordRoot returns null and every hook no-ops forever. init also drops a .harnery/.gitignore (*) so machine-local runtime state (heartbeats, the event stream) never gets committed.
  2. Excludes .harnery/ from editor indexing. Git-aware tools already skip runtime state thanks to .harnery/.gitignore, but Cursor’s codebase indexer and the VS Code/Cursor file watcher do not read gitignore. init appends a managed .harnery/ entry to .cursorindexingignore and merges "files.watcherExclude": {"**/.harnery/**": true} into .vscode/settings.json, creating either file when absent. A settings file it cannot merge safely (comments, malformed JSON) is left byte-identical and reported as a manual step. Without the exclusions, a busy coord root (tens of thousands of ledger events plus working artifacts) turns every editor start into an indexing storm over machine-local state.
  3. Wires the agent-hook entries into the chosen adapter’s settings file (see the adapter-specific counts below).
  4. Injects the agent-facing guidance so a fresh consumer’s agent actually knows the coord surfaces exist (design: ADR 0008):
    • A machine-owned instructions block spliced into AGENTS.md (a hash-versioned <!-- harnery:begin instructions --> region; everything outside the markers is untouched). Every command in it renders in your bin name.
    • Four generic skills installed for every supported adapter: harn-decide, harn-council, harn-end, and harn-team. Claude Code receives them in .claude/skills/; Cursor and Codex share the vendor-neutral .agents/skills/ root. Suppress one with skills.exclude in .harnery/config.jsonc when you maintain a richer version. The block is exclusion-aware: it only points at skills it actually wrote and uses the corresponding CLI command when one is excluded.
    • A CLAUDE.md @AGENTS.md import shim when CLAUDE.md is absent (Claude Code reads CLAUDE.md, not AGENTS.md). A CLAUDE.md that already imports AGENTS.md, or already carries the block, is left alone.
    • Your own coordination policy, if you name a file in instructions.hostAddendumFile. See below.
  5. Installs the git-hook managed regions. The coordination content of pre-commit, post-commit, and post-checkout is machine-owned on the same lifecycle as the instructions block: a hash-versioned # harnery:begin git-hook-<event> region that invokes agent-coord git-hook <event>. All actual behavior (the commit conflict verdict, claim pruning after commits and checkouts) lives in the package, so upgrading harnery upgrades your hooks with no file edits. init honors core.hooksPath; a hook file you already own keeps every host line and gets the region inserted after the shebang, a missing hook file is created whole (and deinit deletes only those). Never hand-copy coordination logic into a hook file: a copy sits outside the upgrade path and decays until it blocks commits it should allow.
Skill Use it for
harn-decide Search decision precedent, file a decision without blocking, or resolve one with evidence
harn-council Create, route, and contribute to guarded multi-agent council rounds
harn-end Finish a completed session with an authoritative V3 terminal event
harn-team Choose between a bounded run, durable work, and a governed role team; build the governor artifacts and drive the goal

All Harnery-owned skill names carry the harn- prefix, even when an embedding CLI uses another binary name. init does not create unprefixed aliases.

Harnery’s block is deliberately generic: it ships to every consumer, so it carries engine mechanics and no house rules. A project with real coordination policy of its own (commit conventions, escalation targets, a triage rubric) used to have nowhere machine-managed to put it, and hand-maintained it beside the block where nothing kept the two in step.

Name a file instead:

.harnery/config.jsonc
{ "instructions": { "hostAddendumFile": ".agents/host-instructions.md" } }

init splices that file’s contents into a second managed region (<!-- harnery:begin host-addendum -->) right after its own block. From then on your policy gets the same treatment harnery’s does: refreshed when the file changes, reported by init --check, removed by deinit or by deleting the config key and re-running init.

Harnery never parses or renders what the file says. It is your content, placed and versioned by harnery, which is what lets one generic mechanism serve consumers whose policies have nothing in common.

The path must be repo-relative and inside the project, and the file must exist and be non-empty. Anything else fails the run before the first write, so a mistyped path leaves your AGENTS.md exactly as it found it rather than silently dropping a section you believe is still there.

When you run init through a host CLI that composes Harnery under its own bin name (e.g. mycli init), it also stamps binName into .harnery/config.jsonc so Harnery’s coord binaries and web UI tell agents to run your command (mycli agents status, …) rather than the harn default. The stamp is comment-preserving and idempotent. Standalone harn needs no stamp; it’s the resolver’s default. See the config reference.

init also pins workflow.subscriptionOnly: true into .harnery/config.jsonc so run children can only authenticate via the adapter CLI’s logged-in (subscription) auth, so API-key vars are scrubbed from child envs, making accidental per-token billing structurally impossible in the repo. The pin is written only when no workflow key exists; a committed workflow key of any shape (including subscriptionOnly: false for key-only CI hosts) is a deliberate choice and is never touched. Per-process escape hatch: HARNERY_WORKFLOW_SUBSCRIPTION_ONLY=0.

Terminal window
harn init # wire the current project for Claude Code
harn init --dry-run # preview every change without writing

Refresh instructions without runtime wiring

Section titled “Refresh instructions without runtime wiring”

Use --instructions-only when a project consumes Harnery’s managed agent guidance but must not enable local coordination runtime wiring:

Terminal window
harn init --adapter codex --instructions-only

This mode refreshes only the managed regions in AGENTS.md, the harn-* skills for the selected adapter, and the Claude import shim when applicable. It does not create .harnery/, stamp configuration defaults, initialize or refresh Event Ledger V3, read or write adapter settings, or install managed Git hooks. The adapter flag still selects the skills directory.

Both modifiers keep the same scope:

Terminal window
harn init --adapter codex --instructions-only --dry-run
harn init --adapter codex --instructions-only --check

The scoped check reports only instruction and skill drift. Its exit contract remains 0 for fresh, 2 for drift, and 1 for an unreadable or invalid instruction source. Use the ordinary harn init --check when runtime wiring must be current too. See ADR 0106.

Safe to re-run. init merges into an existing settings file. It preserves non-Harnery hooks, rewrites stale Harnery commands, moves entries filed under the wrong event, collapses duplicates, and removes entries retired from the adapter’s native lifecycle. Mixed Claude Code and Codex groups keep their unrelated command handlers. If the settings file isn’t valid JSON, init refuses to overwrite it.

harn init
root: /path/to/project
· .harnery/ already exists
· all 10 claude-code hooks already wired in .claude/settings.json

Run harn init after updating Harnery. Existing commands pick up the new code immediately. Init migrates Harnery-owned entries when a release adds, renames, or retires a hook event or changes the command form. It replaces the V3 epoch only when the schema or adapter capability contract changed. A build-only update keeps the current epoch and its live sessions. harn doctor and harn init --check report any drift.

The same is true of the instructions block and skills. You commit those files, while the installed Harnery version owns their templates, so a package upgrade shows up as drift until you re-run init.

--check is read-only. It validates adapter hook presence, command freshness, duplicates, misplaced or retired entries, the instructions block, installed skills, managed Git-hook regions, and the active V3 runtime profile. It’s the exit-code contract you wire into a pre-commit hook or CI:

Exit Meaning
0 Fresh: every init-managed surface is current
2 Drift: a hook or managed artifact is missing, stale, duplicated, misplaced, or incompatible
1 Error: a file couldn’t be read
harn init --check: drift found (re-run `init` to refresh)
✗ skill harn-council: stale (re-run init)

A skill you excluded via skills.exclude is not required, so --check never flags it missing.

Defaults to the git top-level (falls back to the current directory). Override with --project-root <path>.

All three adapters are fully auto-wired. Pass --adapter:

--adapter Settings file Notes
claude-code (default) .claude/settings.json 13 events; nested { hooks: [{ type, command }] } entries
cursor .cursor/hooks.json 13 events; flat { command } entries + "version": 1
codex .codex/hooks.json 11 native events; nested { hooks: [{ type, command }] } entries; strict description + hooks top-level schema

Each writes only its own file, so you can wire several adapters in one project by running init once per adapter. The canonical file path + event→subcommand map + entry shape for every adapter lives in src/core/hooks/adapter/events.ts (ADAPTER_SPECS).

Writing .codex/hooks.json does not authorize its commands. Codex stores approval separately for each hook path and command hash, so a project can be trusted while all 11 Harnery hooks remain unable to run.

After harn init --adapter codex, review the commands before starting work:

  • Terminal UI: run /hooks.
  • Codex Desktop: open Settings > Hooks for the project.

Start a fresh task after approval. An already-open task cannot replay the SessionStart event it missed while the hooks were untrusted. harn init prints this reminder every time it wires or verifies the Codex adapter, and harn doctor checks execution authorization separately from manifest wiring.

Harnery never approves a command, writes Codex’s trusted hashes, or uses the hook-trust bypass flag.