Web UI
harn web up boots a Next.js dashboard that reads .harnery/ directly from disk. There is no server-side database or API key to manage. Core coordination remains daemonless. The dashboard may start optional local services, including the resource observer, for features that need stable sampling between requests. The intended audience is the operator sitting in front of the monorepo.
What you see
Section titled “What you see”- Dashboard (
/): every active and stale agent as a card with name, age, platform, last-tool, model, task, and turn summary. File claims table at the bottom. - Per-agent page (
/agents/<id>): full heartbeat detail, claimed files, parsed journal entries newest-first, last 60 events emitted by this agent. - Councils (
/councils+/councils/<id>): active / closed / archived council manifests with members, rounds, and per-round contributions rendered inline. - Workflows (
/workflows+/workflows/<run-id>): live and terminal workflow runs, proof packets, policy decisions, and validated workspace allocation, verification, integration, conflict, and cleanup state. - Events (
/events): validated V3 rows with type-filter chips and per-instance drill-through. - Logs (
/logs): a moving two-minute view of every registered structured-log family, with severity filters, pause controls, and record details.
Realtime
Section titled “Realtime”Each page renders server-side from the latest .harnery/ state. A tiny client
component subscribes to /api/stream (Server-Sent Events) and calls
router.refresh() on any change. The server-side stream watches disposable
caches, councils, journals, and the active V3 segment, then debounces a 250 ms
burst. A two-second file-size poll backs up filesystem notifications because a
directory watch can miss an append to an existing file on Linux and WSL. The
poll fires only on actual growth.
The Logs page uses its own bounded /api/log-flow snapshot every two seconds
while the tab is visible and the flow is not paused. Log traffic stays off the
global refresh stream, so a busy family does not rerender unrelated pages.
If the connection drops, the client backs off exponentially (1 s → 30 s) and reconnects.
Write actions
Section titled “Write actions”The dashboard is mostly read-focused, but exposes three operator escape hatches:
- Release claim: drop a file claim from any heartbeat. Useful when a session ended mid-Edit and a peer is now blocked on a path the original agent no longer cares about. Hits
POST /api/actions/release-claim. - Ping agent: write a
handoffentry to a peer’s journal, prefixedfrom web-ui:. HitsPOST /api/actions/ping. - End session: request an authoritative V3 terminal and remove the cache only
after finalization succeeds. Hits
POST /api/actions/end-sessionand requires confirmation.
Authority-bearing actions use the same V3 recorder as CLI and hook producers. Presentation-only state remains a disposable local cache.
Production mode
Section titled “Production mode”By default harn web up runs next dev with HMR. For a long-running operator panel:
harn web build # next buildharn web start # next startOr use --prod on up once a build exists:
harn web up --prodNetwork exposure
Section titled “Network exposure”Localhost-only by design. To reach the dashboard from a different machine, use harn tunnel (IP-gated Cloudflare quick tunnel); see harn tunnel for the full setup.
Implementation notes
Section titled “Implementation notes”- All read paths live in
harnery/web/lib/coord-reader.ts. Single source of truth for the JSON shapes returned by/api/*. - The webpack
extensionAliasinnext.config.tsteaches the bundler that.tsre-exports can import.js-suffixed paths (Harnery’s source uses the ESM-spec convention; bun handles it natively, but webpack needs the hint). - The reader caches its
.harnery/root after the first resolve to avoid repeated walks. SetHARNERY_COORD_ROOTto override (and to test against a fixture).