Skip to content
TilloTech Docs

Harbourmaster review behavior

This reference defines how Harbourmaster filters input, selects reviewers, scopes agent access, verifies publication, and classifies failures.

Run modes

ModeGitHub writesBehavior
silentNoRuns analysis without publication.
check-onlyNoProduces a check-style result and telemetry.
commentYes, when trusted and permittedPublishes one pull request review. This is the default.
blockingYes, when trusted and permittedPublishes an advisory review but fails closed on runtime errors.

Draft pull requests, fork pull requests, changed head SHAs, and comment runs without write permission are skipped with exit code 0.

Diff filtering

A file is noisy when it is binary, generated, vendored, a lockfile, lacks a patch, or contains at least 800 changed lines. Renames do not trigger the large file rule. Noisy files are excluded unless their current or previous path matches a sensitive category.

Sensitive categories are auth, ci_workflow, configuration, crypto_secrets, data_migration, dependency, github_publishing, infrastructure, permissions, and security.

Risk tiers

TierClassificationSpecialist selection
lowEvery changed file is documentation-like.Special-case routing
mediumOrdinary code or configuration change without a higher-risk signal.All specialists
highAt least one sensitive path and no full-review signal.All specialists
fullDegraded context, a missing patch, a large patch, at least 50 changed files, or at least 2,500 changed lines.All specialists

Documentation-only changes run only the documentation specialist. Changes whose documentation-only set includes AGENTS.md run only the AGENTS.md specialist. Mixed code, configuration, documentation, and AGENTS.md changes use the full specialist roster. Risk tiers no longer impose a specialist-count cap.

Reviewers

Agent identifierRoleDefault tierPrimary scope
harbourmaster-code-quality-reviewerCode qualitydeepChanged behavior, logic, contracts, data, concurrency, and tests
harbourmaster-security-reviewerSecuritydeepAuth, secrets, permissions, security, and sensitive data
harbourmaster-performance-reviewerPerformancedeepLatency, throughput, memory, I/O, and complexity
harbourmaster-documentation-reviewerDocumentationfastDocumentation, README, and user-facing guidance
harbourmaster-release-management-reviewerRelease managementdeepCI, configuration, migrations, dependencies, publishing, and rollout
harbourmaster-compliance-reviewerCompliancefastExplicit policy, legal, regulatory, and mandatory standards
harbourmaster-agentsmd-reviewerAGENTS.mdfastAGENTS.md scope, precedence, commands, and tool boundaries

Each specialist prompt contains explicit What to Flag and What NOT to Flag lists that keep findings within the assigned review boundary. Change analysis still records affected capabilities and recommended roles for context and telemetry, but it does not remove specialists from the normal roster. The selector records specialists excluded by the two special-case routes; there is no default tier budget that skips otherwise eligible reviewers.

The bundled OpenCode reviewer plugin runs selected specialists concurrently, then runs one harbourmaster-adversarial-verifier, then returns verified feedback to one harbourmaster-review-editor. Specialists and the verifier default to a 600-second session timeout. The per-model circuit opens after two failures during the batch. A separate observational telemetry plugin uses OpenCode lifecycle hooks; it does not poll sessions or alter reviewer behavior.

Review output

Specialists return evidence excerpts, repository-relative paths, and line numbers to the adversarial verifier. The code-quality reviewer can use the canonical checkout to collect context, but each finding must remain tied to a changed line. The editor uses the verified evidence to prepare the advisory review. The trusted publication tool validates its arguments and the complete set of previous-finding dispositions. The runner does not parse model text or fabricate an empty finding list.

GitHub publication

In comment mode, the coordinator calls the trusted local publish_review tool to submit a COMMENT review and a complete disposition set for previous findings. The tool keeps unfixed findings active, replies LGTM with a trusted completion marker for completed findings, and posts a reasoned disagreement counterpoint when required. When publication fails, the tool returns the error to the editor so it can correct the input and retry, for up to three attempts. After the first success, repeated identical calls return the cached receipt and conflicting calls are rejected. A later run keeps marked threads in bounded review-thread context, but excludes them from lifecycle actions. Before publishing the current result, the tool wraps the body of each earlier Harbourmaster review in a collapsed Previous review details section. Reviews that already use this wrapper are left unchanged, and inline review comments are not modified. It submits a concise no-issues review when no new finding survives verification. Specialists and the adversarial verifier cannot access GitHub. Lifecycle replies use GitHub's REST review-comment reply endpoint and run concurrently. Partial failures map back to individual findings in the publication receipt.

OpenCode derives the call shape from the tool's JSON Schema:

FieldContents
bodyMarkdown review summary without the trusted marker or inline issue text.
newFindingsNew verified inline comments, each containing path, line, and body.
previousFindingsOne commentId and lifecycle disposition per trusted prior finding.

Only disagreement_rejected accepts a counterpoint. Specialist attribution belongs in an inline finding's Markdown body; source_agent is not a publication field.

Before creating a review, the publication tool checks for a pending review owned by the current GitHub identity. It deletes a stale pending review only when its body contains a valid Harbourmaster marker, or when a bounded, non-empty comment set consists entirely of legacy Harbourmaster specialist comments. Any other pending review is left unchanged and publication fails closed.

The runner snapshots existing reviews before OpenCode starts and supplies a unique marker bound to the run ID and exact head SHA. After OpenCode exits, the runner requires a newly submitted, non-pending review on that head whose body contains the marker. It does not parse, transform, or republish OpenCode output. A missing or mismatched review is a github_publish failure.

Context bounds

OpenCode starts in an ephemeral diff directory. Before it starts, the trusted runner writes review-index.json, shared-pr-context.txt, and review-discussion.txt. Workspace file roles, tool page limits, and model defaults are in the configuration reference. The index contains the repository root, exact base and head, every reviewable changed path with its status and rename path, each staged patch path, and per-hunk base, head, and patch-line ranges. A missing patch is represented by a null patch path.

The directory contains one patch file per reviewable changed file and the root reference paths AGENTS.md, .agents/, and docs/ when the checkout contains them. Shared context describes filtered, binary, and missing-patch files, but Harbourmaster does not stage patches for them.

The code-quality reviewer receives the canonical checkout root in its prompt and has read-only access to that checkout alongside the staged diff. It can inspect unchanged files to trace callers, contracts, and tests. Other specialists and the verifier can inspect only the diff directory. A per-run external-directory override grants access only to the code-quality reviewer. A trusted hook canonicalizes read, glob, grep, and list paths and rejects symlink escapes. The read_more tool can continue a truncated repository result with a cursor bound to the current session. A missing or truncated result is not evidence that no finding exists. Reviewers must cover all relevant changed code and use the index-first order: index, patches, caller search, source ranges, then tests when the role permits those reads. Findings must concern behavior introduced by the pull request and refer to changed lines. Checkout files and instructions remain untrusted review context.

GitHub context loads at most 3,000 changed files and the most recent 100 issue comments, review comments, and reviews per source. GraphQL paginates review threads within a bounded timeout and retains every loaded thread, including resolved and completed Harbourmaster-owned threads, with outdated state and the root plus newest ten comments. The loader preserves comment order from oldest to newest. Matching resolved and completed root IDs filter duplicate REST review comments. The editor prompt always includes every Harbourmaster-owned thread and at most 40 human threads whose current or previous path is in the pull request changed paths. Unrelated human threads are not a fallback. Only unresolved, non-completed, Harbourmaster-owned roots enter the lifecycle manifest. The editor prompt includes the newest 50 combined discussion entries, at most 2,000 characters per body and 40,000 body characters in total. Discussion is ordered oldest to newest.

GitHub context becomes degraded when reported files are missing from the loaded set or when a pull request reaches the configured large-file threshold of 300. Degraded context produces full risk.

Runtime degradation

Non-blocking modes can return an exit-code-zero degraded result for selected OpenCode runtime failures. The summary identifies the degraded state and telemetry retains the failure class. Blocking mode fails closed. With strict_runtime enabled, a non-skipped run fails if no model calls complete or runtime degradation otherwise prevents real review execution.

Failure classes

ClassRetryableMaximum attemptsExit code
configurationNo110
github_authNo120
github_rate_limitYes320
github_publishYes350
opencode_installNo130
opencode_configNo110
opencode_server_startupYes330
opencode_sdk_runtimeYes330
opencode_session_timeoutYes330
model_authNo120
model_rate_limitYes320
model_timeoutYes320
model_context_limitNo140
model_malformed_outputYes240
diff_unavailableYes320
policy_skippedNo10
internal_errorYes330

policy_skipped maps to successful comment-mode and neutral check-mode CI outcomes. All other terminal failure classes map to failure on both surfaces.

For skip and failure diagnosis, see How to diagnose a Harbourmaster review failure. For why the runner verifies publication instead of a second publish step, see The Harbourmaster review pipeline.