Skip to main content

Install

:::tip Paste this to your agent

Read https://stump-wtf.github.io/harness/llms.txt and
https://stump-wtf.github.io/harness/guides/install. Install Harness on this
machine with the method that page recommends for my OS, then run `harness
doctor` and show me its output. Done means doctor reports the config and
daemon checks as ok, not that the install command exited 0.

:::

Harness is one Go binary, harness, that is both the daemon and the client. Pick one of the two methods below, then verify with harness doctor.

Homebrew (macOS and Linux)​

brew install stump-wtf/tap/harness

This installs the latest tagged release and reports its version. Installing by the fully qualified name is a one-liner and the only form that works out of the box: since Homebrew 6.0.0 non-official taps require explicit trust, and a fully qualified name trusts just that one formula rather than the tap and everything it may ever contain. The older brew tap stump-wtf/tap + brew install harness form now fails, because the short name needs the tap loaded and the tap is untrusted.

The formula compiles from source, so Homebrew pulls in Go as a build dependency and there is no Gatekeeper prompt on macOS.

To update later:

brew update && brew upgrade stump-wtf/tap/harness

Opting in to the latest main​

--HEAD builds the tip of main instead of the tagged release, and is worth using only when a guide needs a feature that has not shipped yet:

brew install --HEAD stump-wtf/tap/harness

A --HEAD build reports the version it was built from, so it is no longer indistinguishable from an unreleased build. To update one:

brew upgrade --fetch-HEAD stump-wtf/tap/harness

Running the daemon as a service​

The formula ships a brew services definition, which is the easiest way to keep the daemon running without hand-authoring a launchd plist:

brew services start harness

brew services starts the daemon in your GUI login session, so agents it launches inherit your login Keychain and a claude-code harness needs no env_file. One caveat: a service does not read your shell profile, and agent CLIs are looked up on the daemon's PATH, so an agent installed outside Homebrew (~/.local/bin, an npm or bun global prefix, mise or asdf shims) will not be found and the harness fails at spawn. See the service guide for how to fix that on each platform. On Linux, use the systemd --user unit instead; the same guide covers it.

From source​

You need Go 1.26 or newer. An older Go (1.21+) downloads the right toolchain automatically the first time you build.

git clone https://github.com/stump-wtf/harness.git
cd harness
go install ./cmd/harness

That puts harness in $(go env GOPATH)/bin, usually ~/go/bin; make sure that is on your PATH. Alternatively, make install builds with version metadata baked in and installs to ~/.local/bin.

Or install by module path​

Since v0.4.0 the module declares itself as github.com/stump-wtf/harness, so the one-liner works:

go install github.com/stump-wtf/harness/cmd/harness@latest

:::note Versions before v0.4.0

Up to and including v0.3.0 the module declared a private path, so installing by module path failed with a version constraints conflict — the GitHub mirror is a byte copy, and its go.mod carried the original path. Pin @v0.4.0 or later, or clone and build as above.

Note that go install alone reports harness dev for its version: the version string is injected at link time, which go install does not do. Use make install, a release binary, or the Homebrew formula if you want harness --version to report a real version.

:::

Verify​

harness --version
harness doctor

On a fresh install, doctor fails two checks, and both are expected. It prints a hint for each, plus a SETTING table showing where every setting came from:

CHECK STATUS DETAIL
config error not found at /home/you/.config/harness/harness.toml
→ create one (see `harness daemon -h`) or pass --config PATH
daemon error unreachable at /run/user/1000/harness.sock
→ start it with: harness daemon
summary 0 passed · 0 warning(s) · 2 failed

SETTING SOURCE VALUE
socket default /run/user/1000/harness.sock
config default /home/you/.config/harness/harness.toml
…

The binary works. There is simply no config and no daemon yet. The next two guides add both, after which every check should read ok.

To take it for a spin before setting up a service, run the daemon in one terminal and the dashboard in another:

harness daemon # terminal 1: the supervisor, in the foreground
harness # terminal 2: the dashboard (q to quit)

Where things live​

WhatDefault path
Config~/.config/harness/harness.toml (honors $XDG_CONFIG_HOME)
State and intent~/.local/state/harness/state.json (honors $XDG_STATE_HOME)
Run history (the run ledger)~/.local/state/harness/ledger/YYYY-MM-DD.jsonl
Per-harness logs~/.local/state/harness/logs/NAME.log; rotated backups are NAME-STAMP.log.zst
Per-run logs of scheduled harnesses~/.local/state/harness/jobs/NAME/RUN_ID.log, then RUN_ID.log.zst once the run closes
Control socket (Linux)$XDG_RUNTIME_DIR/harness.sock, usually /run/user/UID/harness.sock
Control socket (macOS, no $XDG_RUNTIME_DIR)~/.local/state/harness/harness.sock

The client finds the daemon through that socket, so both must agree on it. The service guide covers the one case where they don't.

Next: run the daemon as a service.