Skip to content

diagnostics

harn diagnostics lists current findings and turns a bounded set of local supervisor inputs into a frozen, portable bundle. Use it to inspect a finding now, preserve it for later, check whether a finding-engine change reproduces the same result, or expose regressions and recoveries between two captures.

Terminal window
harn diagnostics list
harn diagnostics show <artifact-ref>
harn diagnostics explain [--bundle <artifact-ref>] [--json]
harn diagnostics capture [--finding <id> | --from <timestamp> --to <timestamp>]
harn diagnostics replay <artifact-ref>
harn diagnostics compare <before-artifact-ref> <after-artifact-ref> [--json]

list returns active and recently resolved findings together with saved diagnostic bundles. A stopped or idle supervisor produces an explicit expired capability instead of presenting its last file as current. A missing findings file remains unsupported. show resolves an exact finding ID first, then an exact managed bundle reference.

explain gives an agent or tool one compact answer before it starts more local work. The live command reads the current findings projection. --bundle reads the advice frozen in a validated diagnostic bundle and never falls back to live state.

{
"schema_version": 2,
"observer_only": true,
"assessment": {
"state": "critical",
"scope": "guest",
"limiting_resource": "memory",
"recommended_action": "avoid-new-heavy-work"
}
}

The complete response includes the assessment’s evidence per dimension, its reason codes with the measured value and the threshold each was compared against, its contributors with attribution confidence, its per-workload guidance, and the hysteresis state this sample carries forward. --json selects structured output in host CLIs; standalone harn already emits JSON.

State is set only by contention evidence, and attribution findings are carried as contributors that can never change it. The dimensions and their thresholds are documented on the resources page. Entry needs a streak of hot samples and exit needs a dwell of clear samples, which is why the advice carries prior_hysteresis: a frozen bundle replays a transition without needing the observer’s memory.

Live advice requires the observer’s published assessment and a current supervisor heartbeat. If the daemon has exited or its heartbeat is stale, the assessment is unknown, every dimension reads unavailable, and no owner is named. A gap in the evidence is never reported as health. Frozen bundle advice remains an explicit historical result tied to the bundle capture time.

Resolved and informational findings do not restrict fan-out. Pressure is calculated before the contributing-findings list is bounded, so truncation cannot hide a critical result. A degraded source stays explicit and never becomes a healthy result.

Advice is not enforcement. Harnery does not pause, deny, start, stop, restart, or reprioritize work. The caller decides how to use the recommendation.

The finding schema groups short reopenings into one incident episode. A finding that resolves and returns within five minutes keeps its ID, increments occurrence_count, and retains the highest observed value. A return after that gap opens a new episode with a new ID.

Resource findings carry process ownership only when the sampler can walk the process tree to a live service anchor or a start-token-validated agent anchor. Anything else stays explicitly unattributed. Agent memory-growth findings also carry the most recent bounded activity projection. Growth during declared work remains a warning; growth while the agent is idle, waiting for input, blocked, or done is critical. Missing or stale activity evidence produces an unknown relationship instead of a guessed one.

Service findings state why liveness is stale. The current reasons distinguish a missing local process, an expired remote heartbeat, and a service-reported error. Findings are still observations. They do not stop processes, restart services, or change an agent’s lifecycle.

Related timeline events with the same source kind, source identity, and capability are stored as one cluster. The entry records its occurrence count, first observation, last observation, and latest resolvable source reference. The timeline reports a separate compaction count, so repeated activity remains measurable without taking the space reserved for distinct evidence.

Without a selector, capture records the most recent 15 minutes. --finding uses that finding’s opened and last-observed timestamps. --from and --to must appear together and accept ISO timestamps. --days overrides the managed artifact retention period for one capture.

Each capture creates and then releases a managed artifact. It contains this fixed file set:

diagnostic-manifest.json
inputs/observations.json
inputs/thresholds.json
expected.json
summary.json

The managed artifact manifest sits beside these files. The diagnostic manifest records file sizes and SHA-256 digests, the exact source capabilities, the engine version, and a digest of the captured thresholds. The machine ID is a pseudonymous hash. It is stable for one configured machine label, but the label itself is not stored.

Capture sanitizes data before calculating a digest or writing a file. It removes credential-shaped values, home-directory paths, prompts, transcripts, tool payloads, and environment blocks. Missing or unreadable sources stay visible as unsupported or error capabilities instead of disappearing from the result. The frozen inputs include the bounded activity projection and the finding-policy values used for episode gaps and freshness checks. New captures also include the bounded completed-hook projection and up to 20 recent shadow-admission records. Admission capture keeps only the run ID, terminal time, observer state, pressure, recommendation, freshness, service state, and wait time. It excludes workflow names, objectives, transcripts, child output, commands, and tool data.

show validates the bundle before returning its manifest and summary. The reader accepts only a managed artifact inside the repository’s artifact root. It rejects symlinks, non-regular files, path escapes, extra files, oversized payloads, unknown manifest fields, unsupported schemas, and digest mismatches.

replay reads only the frozen observations and frozen thresholds. It does not read the current supervisor cache, resource sampler, event ledger, or process table. The pure finding evaluator rebuilds findings, timelines, explanations, and pressure advice, then compares their canonical digest with expected.json. A missing captured source produces a deterministic degraded capability; it does not trigger a live fallback.

The output uses versioned JSON envelopes. replay.matched is true only when the rebuilt output matches the frozen expected output exactly.

compare validates both managed bundles independently and reads no live supervisor state. It matches findings by stable fingerprint rather than episode ID, because a signal can resolve and later reopen under a new ID. The result classifies each fingerprint as added, resolved, or persistent and then labels its effect as a regression, worsening, change, improvement, recovery, or no change.

Persistent signals compare severity, open or resolved state, recurrence count, peak value when units match, attributed owner, and workload relationship. The result also compares pressure advice and source capabilities. Completed-hook summaries expose invocation, degraded, faulted, slow, high-memory, and retry counts. Shadow-admission summaries expose pressure counts, unavailable samples, and maximum observation wait.

The default output is a compact readable report. --json returns comparison schema 1, including a deterministic comparison_digest. Repeating the same two inputs produces the same ordered rows and digest.

Threshold, engine-build, machine, capture-order, duplicate-fingerprint, and source-capability differences are explicit warnings. A bundle created before hook-health or shadow-admission capture remains valid; comparison marks the missing optional source unavailable rather than turning it into a zero or a healthy result.

The comparison page at /diagnostics/compare lists managed candidates from their bounded headers, then fully validates the selected pair before it renders the frozen contract. This avoids a repository-wide artifact inventory on every page load without weakening digest or schema checks. Every signal row stays in the document so browser Find sees the complete result.

Comparison is observer-only. It does not tune thresholds, deny or delay work, signal processes, restart hooks, or notify people.

Diagnostic bundle and expected-output schemas are version 3. The input schema remains version 2, the nested timeline schema is version 2, the advice schema is version 2, and the finding schema is version 3. Harnery is pre-1.0, so this is a direct cutover: earlier bundle, expected-output, timeline, advice, and finding schemas are rejected rather than read through a compatibility path.

Every pressure threshold is included in the threshold_digest. Tuning any one of them therefore invalidates a frozen replay instead of silently changing the result it expects.

Diagnostic bundles are local support artifacts, not durable records. A bundle that needs permanent retention must move into a tracked project location before its managed retention expires.