Skip to main content
The Harbormaster approval queue is the human-in-the-loop gate for agent actions that match a policy rule. Enqueue is internal-only — it fires from harbormaster.Gate when an agent hits a rule-matching action — so the public surface is the read + decide flow operators use to triage, approve, or deny pending requests. See the Harbormaster guide.
All endpoints require authentication and are workspace-scoped. Decision endpoints additionally require OWNER or ADMIN role.

Endpoints


Queue

Read the approval queue and inspect individual requests.

List approvals

Query parameters: Response: 200 OK
The rows[] objects are serialized with their Go field names (PascalCase) — the harbormaster.Request struct carries no JSON tags. The rows, status, and count envelope keys are lowercase. TimeoutSecs is an in-memory-only field that is never read back from the row, so it always serializes as 0 here (the effective deadline is TimeoutAt). DecidedAt and TimeoutAt are pointers — they serialize as null when unset rather than being omitted. For ?status=all, the status envelope key echoes back as an empty string (""), not "all" — the handler maps all to “no status filter” internally.

Get approval

Auth: Requires an authenticated request with workspace context. The optional X-Workspace-ID header selects the workspace when it is not already present in the request context. Response: 200 OK — the full approval request object, with the same fields and Go field-name JSON serialization as a rows[] item from List. Returns the full request object (same schema as list rows). Errors:

Decisions

Approve or deny a pending request, and manage the auto-tuning model that learns from those decisions.

Decide

Auth: OWNER or ADMIN only. 403 for any other role. Request body:
Response: 200 OK
Errors:
The decision and its side effects are one transaction. For kind=ephemeral_hire rows the decision also flips the staged agent (approve → IDLE, deny → ghosted) and resolves the blocking inbox waitpoint. All three writes commit together or not at all.If the staged agent can no longer take that transition — it was deleted, already activated through POST /api/v1/agents/{agentId}/approve-hire, or ghosted by the TTL sweeper — the whole decision is rolled back and you get 409 staged hire is no longer decidable. The queue row stays pending and is still decidable (or will time out on its own); it is never left approved/denied against an agent that never moved.A kind=ephemeral_hire row that times out ghosts the staged agent in the same sweep, so the lapsed hire is no longer approvable through either surface until crewship rehire reopens the cycle — see Ephemeral agents.

Cancel

Withdraw a still-pending request, moving it to the cancelled status. Unlike decide, this records no approve/deny outcome — it marks the gated action moot (mission aborted, agent retired, duplicate request). Auth: OWNER or ADMIN only. 403 for any other role. Request body: optional. A bare POST cancels with no reason; a present-but-malformed body is a 400.
Response: 200 OK
Errors:

Reset auto-tuning

Harbormaster observes operator decisions over time and auto-tunes its rule confidences (a denied request that would have auto-approved next time is a calibration signal). This endpoint resets that learned state to defaults — useful after a major change in policy or after a misconfiguration polluted the auto-tuning model. Auth: OWNER or ADMIN only. Request body: requires a non-empty tool field — the reset is scoped to a single tool’s auto-tuning state.
Response: 200 OK
rows_deleted is the number of auto-tuning rows wiped for that tool. Idempotent — calling twice in a row returns rows_deleted: 0 on the second call. Errors: 400 bad JSON or missing tool; 401 not authenticated; 403 wrong role; 500 DB error. This does not affect already-decided approval rows, journal history, or the rule definitions themselves — only the per-rule confidence that drives auto-mode (async/sync/required) selection.

Journal side-effects

Every write emits a journal entry: See Crew Journal for payload shapes.