Skip to content
TilloTech Docs

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.

FieldDescription
timestampTimestamp generated by Effect.
levelEffect log level. Review lifecycle events use INFO.
fiberIdentifier for the Effect fiber that emitted the entry.
messageReview 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

EventEvent-specific annotations
run_startedOptional run mode.
context_loadedOptional file/comment counts plus discussion source and review-thread counts.
diff_filteredOptional included and excluded file counts and excludedReasons.
risk_classifiedRequired riskTier; optional signals.
change_analyzedRequired affected-behavior count, recommended reviewer list, and uncertainty count.
reviewer_startedRequired opencode; optional reviewer role and selected reason.
opencode_progressRequired 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_completedOptional duration, finding and quarantine counts, status, reason, retry, usage, cost, and OpenCode metadata.
editor_completedRequired accepted, duplicate, rejected-unmappable, and severity-adjusted counts; optional existing-discussion suppress count and grouped severity/category/source counts (countsBySeverity, countsByCategory, countsBySource).
blocking_decisionRequired policy, file, line, severity, would-block and did-block flags; optional bypass reason.
finding_producedRequired info, warning, or error severity; optional path. This is the provider-neutral result-contract event, distinct from canonical editor severity.
publish_attemptedRequired target and publication mode.
run_completedRequired 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_failedRequired classified failure object.

OpenCode metadata

The optional opencode object accepts:

FieldDescription
sdkClientModeembedded or external.
serverLabelRuntime server identity such as an owned-per-run label.
sessionId, agentIdOpenCode session and agent identifiers.
configDirLabel, configDirHashTrusted configuration identity and SHA-256 content hash.
rawArtifactPathDiagnostic artifact reference when one exists.
fallbackUsed, retryCountRoute fallback and retry metadata.
pollCount, eventCount, lastStatusRuntime progress counters and final observed status.
structuredOutputsuccess 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.

FieldDescription
schema_version, kind, revisionLiteral 1, session_summary, and a monotonic session revision.
session_id, parent_session_idOpaque OpenCode session relationships.
role, agent, provider, modelAttribution to editor, specialist, verifier, or bounded other activity.
duration_ms, model_duration_msSession wall time and completed model-call time.
tool_duration_ms, model_calls, tool_callsAggregate tool/model counts and tool time.
errors, cost_usd, tokens, toolsError 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.retryable and retry.maxAttempts;
  • terminalCiOutcomes.comment and terminalCiOutcomes.check; and
  • exitCode.

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

text
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.