Harbourmaster review behavior
This reference defines how Harbourmaster filters input, selects reviewers, scopes agent access, verifies publication, and classifies failures.
Run modes
| Mode | GitHub writes | Behavior |
|---|---|---|
silent | No | Runs analysis without publication. |
check-only | No | Produces a check-style result and telemetry. |
comment | Yes, when trusted and permitted | Publishes one pull request review. This is the default. |
blocking | Yes, when trusted and permitted | Publishes 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
| Tier | Classification | Specialist selection |
|---|---|---|
low | Every changed file is documentation-like. | Special-case routing |
medium | Ordinary code or configuration change without a higher-risk signal. | All specialists |
high | At least one sensitive path and no full-review signal. | All specialists |
full | Degraded 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 identifier | Role | Default tier | Primary scope |
|---|---|---|---|
harbourmaster-code-quality-reviewer | Code quality | deep | Changed behavior, logic, contracts, data, concurrency, and tests |
harbourmaster-security-reviewer | Security | deep | Auth, secrets, permissions, security, and sensitive data |
harbourmaster-performance-reviewer | Performance | deep | Latency, throughput, memory, I/O, and complexity |
harbourmaster-documentation-reviewer | Documentation | fast | Documentation, README, and user-facing guidance |
harbourmaster-release-management-reviewer | Release management | deep | CI, configuration, migrations, dependencies, publishing, and rollout |
harbourmaster-compliance-reviewer | Compliance | fast | Explicit policy, legal, regulatory, and mandatory standards |
harbourmaster-agentsmd-reviewer | AGENTS.md | fast | AGENTS.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:
| Field | Contents |
|---|---|
body | Markdown review summary without the trusted marker or inline issue text. |
newFindings | New verified inline comments, each containing path, line, and body. |
previousFindings | One 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
| Class | Retryable | Maximum attempts | Exit code |
|---|---|---|---|
configuration | No | 1 | 10 |
github_auth | No | 1 | 20 |
github_rate_limit | Yes | 3 | 20 |
github_publish | Yes | 3 | 50 |
opencode_install | No | 1 | 30 |
opencode_config | No | 1 | 10 |
opencode_server_startup | Yes | 3 | 30 |
opencode_sdk_runtime | Yes | 3 | 30 |
opencode_session_timeout | Yes | 3 | 30 |
model_auth | No | 1 | 20 |
model_rate_limit | Yes | 3 | 20 |
model_timeout | Yes | 3 | 20 |
model_context_limit | No | 1 | 40 |
model_malformed_output | Yes | 2 | 40 |
diff_unavailable | Yes | 3 | 20 |
policy_skipped | No | 1 | 0 |
internal_error | Yes | 3 | 30 |
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.