Configuration schema
The canonical JSON Schema is published at:
https://harnery.com/schemas/config.schema.jsonReference it in your config file’s $schema field to get editor autocomplete and validation in VS Code, Cursor, Zed, JetBrains, and anywhere else that respects $schema.
Locations
Section titled “Locations”Settings resolve from these sources, lowest precedence first (later wins):
~/.config/harnery/config.jsonc: the user-global file, a base for every project on the machine (honorsXDG_CONFIG_HOME; falls back to~/.config)<project>/.harnery/config.jsonc: the project settings file, which overrides the user-global file field by field (a project that sets onlyweb.portkeeps a user-globalweb.bind)- CLI flags + environment variables: per-invocation overrides (see each field’s env note)
The config reader (src/core/config.ts) merges the two files and owns binName, hooksSetupHint, tools, workflow, skills, presence, coord, artifacts, backup, and sync; the web layer reads files. One deliberate exception: the binName pin that harn init guards against re-stamping is read from the project file only. A user-global binName is a display fallback, never a project pin.
Top-level fields
Section titled “Top-level fields”| Field | Type | Default | Description |
|---|---|---|---|
$schema |
string | none | URL to the JSON Schema (used by editors for autocomplete/validation) |
project_name |
string | repo basename | Display name surfaced in log lines and to peers |
binName |
string | harn |
Host CLI bin name used in agent-facing prompts (see below) |
coord |
object | see below | Coord-layer settings |
artifacts |
object | see below | Working-artifact retention |
tools |
object | see below | Managed-tool provisioning consent (tools.ripgrep.autoInstall) |
workflow |
object | see below | Workflow-engine defaults |
skills |
object | see below | Shipped-skill suppression (skills.exclude) |
instructions |
object | see below | Host-owned addendum spliced into AGENTS.md (instructions.hostAddendumFile) |
presence |
object | see below | Cross-machine presence transports |
files |
object | see below | Web file-viewer path policy (additive deny/allow globs) |
web |
object | see below | Standalone Next.js dashboard |
backup |
object | see below | restic-backed snapshots |
sync |
object | see below | rclone-backed cross-machine sync |
binName
Section titled “binName”The host CLI’s bin name. Harnery’s coord binaries (agent-hook, agent-coord) and the web UI run as Harnery itself, so they can’t see the name of a consumer CLI that composes Harnery (e.g. myapp). They read it back from this field for every agent-facing string: end-of-turn nudges, council prompts, worktree-conflict hints. harn init stamps it automatically for a consumer (any bin name other than the harn default). Resolution precedence: HARNERY_BIN env → this field → "harn".
| Field | Type | Default | Description |
|---|---|---|---|
freshness_seconds |
number | 600 |
Heartbeat age (seconds) above which the sweeper prunes an agent (10 min) |
Resolution: HARNERY_AGENT_COORD_FRESHNESS env (canonical; HARNERY_AGENT_FRESHNESS is a legacy alias) → this config.jsonc key → 600.
artifacts
Section titled “artifacts”| Field | Type | Default | Description |
|---|---|---|---|
default_retention_days |
number | 3 |
Retention used by harn artifacts create when --days is absent |
Resolution: HARNERY_ARTIFACT_RETENTION_DAYS env → this config.jsonc key →
3. See harn artifacts for cleanup behavior.
workflow
Section titled “workflow”| Field | Type | Default | Description |
|---|---|---|---|
subscriptionOnly |
bool | false (engine) / true (stamped by harn init) |
Pin workflow run to subscription billing: API-key vars are scrubbed from every child env, so children can only authenticate via the adapter CLI’s stored login |
harn init stamps { "subscriptionOnly": true } into any project without a committed workflow key; an existing workflow key of any shape is never touched (set false for key-only CI hosts). Env override per process: HARNERY_WORKFLOW_SUBSCRIPTION_ONLY=1|0. See run → billing safeguards.
| Field | Type | Default | Description |
|---|---|---|---|
ripgrep.autoInstall |
bool | false |
Let harn grep download the pinned, checksum-verified ripgrep into the harnery tools dir on first miss (falls back to GNU grep on any failure). A repo commits this once and every clone self-heals |
Env override per process: HARNERY_TOOLS_AUTOINSTALL=1|0.
skills
Section titled “skills”| Field | Type | Default | Description |
|---|---|---|---|
exclude |
string[] | [] |
Shipped harnery skills this repo suppresses, e.g. ["harn-decide", "harn-council"] when the host keeps its own richer versions. The injected AGENTS.md block points at --help instead of an excluded skill |
instructions
Section titled “instructions”| Field | Type | Default | Description |
|---|---|---|---|
hostAddendumFile |
string | none | Repo-relative path to a markdown file holding this project’s own coordination policy. init splices its contents into a second managed region in AGENTS.md, init --check reports drift against it, and deinit (or deleting this key) removes the region. Harnery never parses the content |
The path must be repo-relative and resolve inside the project, and the file must exist and be non-empty; anything else fails the run before the first write. Delete the key and re-run init to take the region back out.
{ "instructions": { "hostAddendumFile": ".agents/host-instructions.md" } }presence
Section titled “presence”| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Cross-machine presence over git refs (refs/harnery/presence/<machine> on origin). On by default when an origin remote exists; every operation is fail-silent |
relay |
string | unset | Optional live upgrade: a wss:// relay URL (public reference: wss://relay.harnery.com; self-host via harn relay serve or relay/worker/). When set, hooks keep a per-machine daemon connected for seconds-latency presence; git refs stay on as the floor |
Env overrides per process: HARNERY_PRESENCE=1|0 (whole feature), HARNERY_PRESENCE_RELAY=<url|0> (relay only), HARNERY_PRESENCE_FETCH_INTERVAL=<secs> (git-refs fetch throttle). A committed .harnery/presence-salt file rotates the relay room (it is NOT a secret; see decision record 0016). Full behavior: harn presence.
| Field | Type | Default | Description |
|---|---|---|---|
port |
number | 9000 |
Listen port for harn web up |
bind |
string | 127.0.0.1 |
Bind address. Localhost-only by default |
Override via flags: harn web up --port 4000.
backup
Section titled “backup”| Field | Type | Default | Description |
|---|---|---|---|
repo |
string | ~/.cache/harnery/restic-repo |
restic repository path or URL |
password_file |
string | ~/.config/harnery/restic-password |
File containing the restic repo password |
keep_daily |
number | 7 |
Daily snapshots to keep on harn backup prune |
keep_weekly |
number | 4 |
Weekly snapshots to keep |
keep_monthly |
number | 6 |
Monthly snapshots to keep |
Env overrides: HARNERY_RESTIC_REPO, HARNERY_RESTIC_PASSWORD_FILE.
| Field | Type | Default | Description |
|---|---|---|---|
remote |
string | none | rclone remote name (e.g. gdrive) |
prefix |
string | harnery |
Subpath under the remote root |
Env overrides: HARNERY_SYNC_REMOTE, HARNERY_SYNC_PREFIX.
Sync subset is fixed: identities/, journal/archived/, councils/. Heartbeats and event logs are intentionally machine-local and won’t sync.
Web file-viewer path-serving policy (the universal file viewer in harn web). The shipped secret denylist is a non-removable floor baked into code; these knobs are additive only: they extend the floor, never shrink it.
| Field | Type | Default | Description |
|---|---|---|---|
deny_globs |
string[] | [] |
Extra **/-anchored deny patterns on top of the shipped floor (treated as hard-tier: never overridable) |
allow_overrides |
string[] | [] |
Rescue globs consulted only when a deny came from a soft-tier floor pattern; naming a hard secret family is dropped at load |
How each section is resolved
Section titled “How each section is resolved”Every section above is read from config.jsonc (both the user-global and project files, merged project-over-user). Env vars and CLI flags override the config value per invocation:
| Section | Config keys | Env override | Other |
|---|---|---|---|
coord |
freshness_seconds |
HARNERY_AGENT_COORD_FRESHNESS (alias HARNERY_AGENT_FRESHNESS) |
(none) |
artifacts |
default_retention_days |
HARNERY_ARTIFACT_RETENTION_DAYS |
artifacts create --days |
backup |
repo, password_file, keep_* |
HARNERY_RESTIC_REPO, HARNERY_RESTIC_PASSWORD_FILE |
--keep-* flags override the prune policy per run |
sync |
remote, prefix |
HARNERY_SYNC_REMOTE, HARNERY_SYNC_PREFIX |
~/.config/harnery/sync.json (written by harn sync init) is a lower-precedence fallback than the sync config section |
files |
deny_globs, allow_overrides |
(none) | read by the web layer, not the core reader |
Full precedence for a sync remote, highest first: HARNERY_SYNC_REMOTE env → project sync.remote → user-global sync.remote → ~/.config/harnery/sync.json.
Example config
Section titled “Example config”{ "$schema": "https://harnery.com/schemas/config.schema.json", "project_name": "my-monorepo", "binName": "mycli",
"coord": { "freshness_seconds": 900 },
"artifacts": { "default_retention_days": 3 },
"web": { "port": 9000 },
"tools": { "ripgrep": { "autoInstall": true } },
"workflow": { "subscriptionOnly": true },
"presence": { "relay": "wss://relay.harnery.com" },
"sync": { "remote": "gdrive", "prefix": "harnery/my-monorepo" }}Schema status
Section titled “Schema status”The schema lives at schemas/config.schema.json in the Harnery repo. v1 covers the fields above; future fields land additively with semver minor bumps. Breaking schema changes require a major bump and a migration note.