Skip to content

harn web

harn web <subcommand> [options]

Standalone Next.js dashboard for .harnery/ state. See concepts / web UI for the feature tour.

harn web up [--port 4276] [--coord-root <dir>] [--prod] [--no-fetch] [--max-old-space <mb>]
harn web build [--no-fetch]
harn web start [--port 4276] [--coord-root <dir>] [--no-fetch] [--max-old-space <mb>]
harn web performance [--coord-root <dir>] [--since 1h] [--limit 20] [--json]

Boot the dashboard. Dev mode by default (HMR, no build needed). With --prod, runs next start (requires a prior web build).

Terminal window
harn web up
# → http://localhost:4276
harn web up --port 4000 --coord-root /path/to/some/repo
# → http://localhost:4000, reading .harnery/ from /path/to/some/repo

Produce the production bundle:

Terminal window
harn web build

Runs next build against harnery/web/. Output lands in harnery/web/.next/.

Start the production server (requires prior build):

Terminal window
harn web build && harn web start

up and start pin a V8 old-space ceiling of 2048 MB by default.

Without it, Next picks its own ceiling at roughly half of system RAM. On a large machine that is a limit a dashboard will never reach, so V8 never feels enough pressure to run a major GC, and a server left up for days settles at a multi-gigabyte working set that is mostly collectable garbage. On one 32 GB machine a dev server sat at 7.9 GB after three days; the same server under the default ceiling held at 1.7 GB, and the production build held at 0.4 GB.

Raise it, lower it, or opt out entirely:

Terminal window
harn web up --max-old-space 4096 # roomier ceiling
HARNERY_WEB_MAX_OLD_SPACE=1024 harn web up
harn web up --max-old-space 0 # opt out; Next sizes it again

Precedence is flag, then HARNERY_WEB_MAX_OLD_SPACE, then the default. A ceiling you set yourself in NODE_OPTIONS is always left alone.

For a dashboard that stays up, prefer build + start over up: the production server carries no bundler state, no source maps, and no HMR machinery, which is most of the difference.

harn web up and harn web start record request timing, event-loop delays, memory samples, and long garbage-collection pauses to .harnery/logs/web-performance.jsonl. The recorder runs below Next.js, so it covers pages, route handlers, React Server Component refreshes, and requests that spend most of their time in framework compilation.

Query strings, headers, request bodies, and response bodies are never logged. Framework static assets are excluded. The active log rotates at 5 MB and keeps three backups, which bounds the default footprint at about 20 MB.

Run the summary when the dashboard feels slow:

Terminal window
harn web performance
harn web performance --since 30m --limit 10

The report ranks routes by maximum and p95 duration, lists individual slow requests, and lists the largest event-loop delays with the requests that overlapped them. It also reports current and peak heap, RSS, external memory, array-buffer memory, garbage-collection counts, total collection time, and the longest pauses. A large request duration with little event-loop delay points toward asynchronous I/O or framework compilation. A large event-loop delay with no matching garbage-collection pause points toward synchronous filesystem or CPU work, or a descheduled process. It is evidence about overlap, not proof that one listed request caused the delay.

The server also prints a short warning when a request crosses 1,000 ms or the event loop is delayed by at least 250 ms. These environment variables tune the recorder without changing the log schema:

Environment variable Default Effect
HARNERY_WEB_SLOW_REQUEST_MS 1000 Slow-request warning threshold
HARNERY_WEB_EVENT_LOOP_DELAY_MS 250 Event-loop delay warning threshold
HARNERY_WEB_MEMORY_SAMPLE_MS 30000 Memory and garbage-collection summary interval
HARNERY_WEB_GC_PAUSE_MS 100 Long garbage-collection warning threshold
HARNERY_WEB_PERFORMANCE_LOG_MAX_BYTES 5242880 Bytes per log generation
HARNERY_WEB_PERFORMANCE_LOG_BACKUPS 3 Rotated generations to retain

Restart the webserver after changing a recorder setting. Diagnostics begin on the first request handled by the restarted process.

Dashboard startup also ensures the optional local resource observer is running on supported machines. The observer supplies the /resources page with process CPU deltas and agent process-tree attribution. A failed observer launch is logged as a warning and never prevents the dashboard from starting.

The npm package omits the dashboard to keep the CLI lean. When web/ is absent (a plain npm i -g harnery), the first harn web up fetches it:

  1. Clones the harnery repo at the matching version tag (v<your version>) into ~/.cache/harnery/web/<ref>/.
  2. Installs the web app’s deps there (just web/; no root install, no browser downloads).
  3. Boots it. Later runs reuse the cache, so only the first launch pays the cost.
Flag / env Effect
--no-fetch Skip the fetch; print manual clone steps instead. Works on build / start too.
HARNERY_WEB_REF=<ref> Fetch a specific git ref instead of the version tag (e.g. next, a branch).

The fetched dashboard matches your installed harnery version, so it stays in sync with the coord schema the CLI writes.

Localhost-only by default. For cross-device access (phone, second laptop), pair with harn tunnel:

Terminal window
harn web up &
harn tunnel up --target 127.0.0.1:4276

harn tunnel runs an IP-gated reverse-proxy in front of a Cloudflare quick tunnel; see harn tunnel for the allowlist + setup story.

The dashboard resolves .harnery/ from, in order:

  1. --coord-root <dir> flag
  2. HARNERY_COORD_ROOT env var
  3. Walk up from cwd looking for a .harnery/ directory (up to 8 levels)