Harbourmaster telemetry
Harbourmaster emits one logfmt record per line using Effect's built-in
Logger.logFmt format. This matches OpenCode's compact key=value logs. Review
metadata is redacted before it is added as log annotations.
Effect logfmt fields
Harbourmaster does not define a separate telemetry wire schema or schema version. Effect owns the log format.
| Field | Description |
|---|---|
timestamp | Timestamp generated by Effect. |
level | Effect log level. Review lifecycle events use INFO. |
fiber | Identifier for the Effect fiber that emitted the entry. |
message | Review event name, such as run_started. |
Effect writes annotations as additional fields on the same line. Common fields
include run, repo, pullNumber, headSha, workflowRunId, agent,
model, provider, modelTier, riskTier, and opencode. Strings containing
spaces are quoted. Arrays and nested objects are encoded as quoted JSON values.
Event names
| Event | Event-specific annotations |
|---|---|
run_started | Optional run mode. |
context_loaded | Optional file/comment counts plus discussion source and review-thread counts. |
diff_filtered | Optional included and excluded file counts and excludedReasons. |
risk_classified | Required riskTier; optional signals. |
change_analyzed | Required affected-behavior count, recommended reviewer list, and uncertainty count. |
reviewer_started | Required opencode; optional reviewer role and selected reason. |
opencode_progress | Required phase; optional duration, event count, last status, output stream, stdout line, and structured details. Telemetry uses phase: telemetry_record with the validated record in details; the former stderr_line and server_log phases are not emitted. |
reviewer_completed | Optional duration, finding and quarantine counts, status, reason, retry, usage, cost, and OpenCode metadata. |
editor_completed | Required accepted, duplicate, rejected-unmappable, and severity-adjusted counts; optional existing-discussion suppress count and grouped severity/category/source counts (countsBySeverity, countsByCategory, countsBySource). |
blocking_decision | Required policy, file, line, severity, would-block and did-block flags; optional bypass reason. |
finding_produced | Required info, warning, or error severity; optional path. This is the provider-neutral result-contract event, distinct from canonical editor severity. |
publish_attempted | Required target and publication mode. |
run_completed | Required exit code; optional duration, findings, calls, retries, degradation, unavailable usage, cost, previous-finding considered/preserved/completed/replied counts, lifecycle warnings, receipt verification, and cost warning. |
run_failed | Required classified failure object. |
OpenCode metadata
The optional opencode object accepts:
| Field | Description |
|---|---|
sdkClientMode | embedded or external. |
serverLabel | Runtime server identity such as an owned-per-run label. |
sessionId, agentId | OpenCode session and agent identifiers. |
configDirLabel, configDirHash | Trusted configuration identity and SHA-256 content hash. |
rawArtifactPath | Diagnostic artifact reference when one exists. |
fallbackUsed, retryCount | Route fallback and retry metadata. |
pollCount, eventCount, lastStatus | Runtime progress counters and final observed status. |
structuredOutput | success or error for the accepted structured-output boundary. |
Specialists and the adversarial verifier return bounded intermediate text. The editor response is the structured-output boundary whose accepted value can become canonical findings.
Retry, usage, and cost
The retry object can contain attempts, retries, fallbackUsed, and an
array of classified failureClasses.
The usage object can contain inputTokens, outputTokens, totalTokens, and
unavailable. Valid plugin records aggregate editor, specialist, and verifier
usage. Missing child-session records are represented with unavailable: true;
usage is not inferred from the editor alone. Coverage requires at least one
editor record, at least as many specialist records as the editor reports
completed, and at least one verifier record when any specialist completed. Runs
without completed specialists need only the editor record. estimatedCostUsd is
emitted only when provider cost or complete token usage and configured model
rates permit calculation. A cost_usd value from the telemetry plugin is used
directly and takes precedence over token-rate estimates from
costPer1kTokensUsd. A configured warning_budget_usd produces a warning but
does not stop execution.
OpenCode telemetry plugin
Harbourmaster's bundled harbourmaster-telemetry plugin observes the official
OpenCode plugin hooks for sessions, chat messages, tools, and errors. It uses
the OpenCode SDK message and event types to aggregate completed activity in
memory. The plugin does not poll OpenCode and does not subscribe to text-delta
or other high-volume streaming events.
On session idle, error, or deletion, the plugin sends a cumulative
session_summary record through client.app.log. The inner record schema is
version 1 and is independent of Harbourmaster's outer Effect logfmt record.
Later revisions for the same session replace earlier revisions.
| Field | Description |
|---|---|
schema_version, kind, revision | Literal 1, session_summary, and a monotonic session revision. |
session_id, parent_session_id | Opaque OpenCode session relationships. |
role, agent, provider, model | Attribution to editor, specialist, verifier, or bounded other activity. |
duration_ms, model_duration_ms | Session wall time and completed model-call time. |
tool_duration_ms, model_calls, tool_calls | Aggregate tool/model counts and tool time. |
errors, cost_usd, tokens, tools | Error count, provider cost, token counters, and tool-name counts. |
Harbourmaster accepts only strict, versioned records bearing the
harbourmaster.telemetry service marker. Arbitrary OpenCode server log lines
are ignored. Server spawn, readiness, timeout, abort, and exit measurements
remain adapter-owned lifecycle telemetry.
The plugin is observational and failure-isolated: logging errors are swallowed, pending log writes and observed sessions/tool calls are capped, identifiers and input buffers are bounded, and telemetry cannot change reviewer output or publication policy. Records never include prompts, message text, reasoning, tool arguments, tool results, file contents, or error messages.
Editor and policy fields
editor_completed contains existingDiscussionSuppressedCount when the editor
reports findings already covered by visible pull request discussion. This count
is model-reported and has no publication authority.
Each blocking_decision describes a critical finding considered by policy. Its
optional reason is policy-nonblocking, fork, untrusted, or unmappable.
would_block records severity intent; did_block records the deterministic
policy result.
Failure object
The failure annotation on a run_failed entry contains:
class: one of the failure classes in the review behavior reference;message: redacted failure description;retry.retryableandretry.maxAttempts;terminalCiOutcomes.commentandterminalCiOutcomes.check; andexitCode.
Redaction
Annotations recursively redact secret-like keys and values, including GitHub tokens, API keys, bearer credentials, passwords, private keys, and prompt or message fragments before Effect serializes the log entry.
Example
timestamp=2026-07-16T10:00:00.000Z level=INFO fiber=#0 message=run_completed run=github-987654321 repo=team/service pullNumber=42 headSha=abc123 workflowRunId=987654321 riskTier=medium durationMs=48123 findingCount=2 modelCalls=5 retries=0 degradedCount=0 usageUnavailableCount=1 exitCode=0
Dashboard status derivation
The pilot dashboard groups entries by the run field. A completed run is
success or partial when degradation is present. Terminal failures become
timeout, config_failure, provider_failure, or failed according to
failure class. A run without a terminal event remains running.