Skip to content

HARP-GATEWAY Specification

Version: 0.2 Draft (Standards-Grade) Status: Draft Specification (Gateway Semantics)


HARP-GATEWAY (HARP-GW) defines the HARP Gateway: an intermediary service that provides store-and-forward, correlated routing, and delivery for HARP exchanges between:

  • Enforcer (HE): submits an Artifact and awaits a Decision.
  • Approver (MA): receives Approval Requests and submits Decisions.
  • Gateway (GW): brokers the exchange and routes Decisions back to the correct Enforcer.

This specification defines abstract gateway semantics (independent of transport). An HTTP binding (REST + SSE + WebSocket) is defined in HARP-GATEWAY-HTTP.


Normative language follows RFC 2119.

This document depends on:

  • HARP-CORE v0.2
  • HARP-TRANSPORT v0.2

The Gateway SHALL be treated as untrusted and zero-knowledge: it MUST NOT require access to plaintext artifact contents. The Gateway MUST operate using ciphertext payloads and minimal metadata required for routing and lifecycle management.

The Gateway MUST correlate all exchange activities using a stable requestId.

The Gateway MUST provide a durable Exchange record for each requestId, supporting disconnected clients (Approver or Enforcer).

All gateway-facing and gateway-emitted messages MUST be framed as a HARP Envelope. (See HTTP binding for wire representation.)


An Exchange is a correlated interaction identified by requestId that relates:

  • an Artifact submission (from Enforcer),
  • one or more Approval Requests (to Approver(s)),
  • a Decision submission (from an Approver),
  • Decision delivery (to the Enforcer).
  • requestId (string): REQUIRED. Unique within the scope of the Gateway’s retention window.
  • tenantId (string/UUID): OPTIONAL/RECOMMENDED if multi-tenant.
  • createdAt (RFC3339 datetime): REQUIRED.
  • expiresAt (RFC3339 datetime): REQUIRED.

Once an Exchange enters state Decided, the decision outcome for that requestId MUST be immutable.

The Gateway uses messages (enveloped) in two directions:

  • Upstream submissions: Artifact, Decision, Ack
  • Downstream deliveries: Approval Request, Decision Delivery, Error

Each message MUST include:

  • msgId (string, unique): REQUIRED for gateway-emitted messages; RECOMMENDED for submitted messages.
  • requestId: REQUIRED (correlation)
  • createdAt: REQUIRED
  • expiresAt: REQUIRED or derivable from Exchange

The Gateway MUST provide at least one durable inbox mechanism:

  • Approver Inbox: lists pending Approval Requests.
  • Enforcer Inbox: lists pending Decision Deliveries (if Enforcer was offline).

Inbox items MUST be retrievable until they are acknowledged, expire, or exceed retention policy.

Withdrawn exchanges MUST be removed from the active Approver Inbox.


An Exchange MUST be in exactly one of the following states:

  • PendingApproval: Artifact accepted; awaiting Decision.
  • Decided: Decision accepted; awaiting delivery/ack (optional).
  • Delivered: Decision delivered and acknowledged by Enforcer (optional but RECOMMENDED).
  • Expired: Exchange expired without an accepted decision.
  • Withdrawn: Exchange withdrawn by Enforcer before a Decision was submitted.
  • Cancelled: Exchange cancelled by policy or administrative action (OPTIONAL).
  • Artifact accepted ⇒ state becomes PendingApproval.
  • Decision accepted ⇒ state becomes Decided.
  • Decision delivered and acknowledged ⇒ state MAY become Delivered.
  • Enforcer withdraws ⇒ state becomes Withdrawn (only from PendingApproval).
  • Time > expiresAt and state is not Decided ⇒ state MUST become Expired.
  • Withdrawn MUST prevent accepting new Decisions.
  • If Cancelled is implemented, cancellation MUST prevent accepting new decisions.

The Gateway MUST treat an Artifact submission as idempotent under the key:

  • (requestId, artifactHash)

Rules:

  • If an identical (requestId, artifactHash) is resubmitted, the Gateway MUST NOT create duplicate approval requests and MUST return a success response.
  • If requestId is reused with a different artifactHash, the Gateway MUST reject with a conflict error (AlreadyExistsConflict).

The Gateway MUST treat a Decision submission as idempotent under at least one of:

  • (requestId, signerKeyId, nonce) (RECOMMENDED), or
  • (requestId, decisionHash)

Rules:

  • Duplicate decisions under the idempotency key MUST be accepted as no-ops.
  • If an Exchange is already Decided and a different Decision is submitted, the Gateway MUST reject with a conflict error (AlreadyDecidedConflict).

When accepting an Artifact for requestId, the Gateway MUST bind the Exchange to an Enforcer Delivery Address, derived from:

  • the authenticated Enforcer identity (enforcerId), and
  • the current active connection/channel (if any).

If multiple active channels exist for the same enforcerId, the Gateway MUST define deterministic selection. The HTTP binding defines a default rule: “most recent active channel”.

The Gateway MUST support delivery of Approval Requests to one or more eligible Approvers.

Approver selection MAY be:

  • explicitly addressed (recipient approverId in the message),
  • tenant-wide (any approver with the right entitlement), or
  • policy-based (e.g., role-based, rotation).

The selection algorithm is out of scope; the observable requirements are:

  • Approval Requests MUST be persisted to Approver Inbox(es).
  • Approval Requests MUST be deliverable over real-time channels when available.

When the Artifact submission includes a metadata object in the envelope body, the Gateway MUST apply the following forwarding rules:

  • Routing-sensitive keys (e.g., routingToken): MUST be stripped from Approval Request envelopes forwarded to Approvers.
  • Display-safe keys (e.g., workspaceName, repoName): SHOULD be forwarded to Approvers for human-friendly context.
  • Missing metadata MUST NOT cause submission rejection; the metadata field is OPTIONAL.

Note: Artifact-level metadata (inside the encrypted artifact, part of artifactHash) and gateway envelope body.metadata (cleartext, subject to forwarding) are different layers. See HARP-CORE Appendix A for clarification.

The following well-known metadata keys are defined for interoperability:

KeySemanticsForwarding
routingTokenOpaque token binding Enforcer to Approver for delivery routing.MUST strip (routing-sensitive)
workspaceNameHuman-readable workspace/organization name.SHOULD forward (display-safe)
repoNameHuman-readable repository or project name.SHOULD forward (display-safe)
enforcerLabelHuman-readable label for the Enforcer instance.SHOULD forward (display-safe)
requestLabelHuman-friendly label describing the review trigger (e.g., "Pre Tool Use", "Terminal Command").SHOULD forward (display-safe)
tenantHintOpaque tenant identifier for multi-tenant routing.MAY strip or forward per policy

Implementations MAY define additional keys. Unknown keys SHOULD be treated as display-safe unless listed as routing-sensitive by policy.

The Gateway MAY maintain best-effort presence information for connected Enforcers.

Presence records are informational only and MUST NOT be used for authorization or routing decisions.

A presence record SHOULD include:

  • enforcerDeviceId (string): REQUIRED.
  • status (string): online | offline.
  • lastSeenAt (RFC3339 datetime): REQUIRED.
  • transport (string): e.g., websocket, poll.
  • workspaceName (string): OPTIONAL.
  • enforcerLabel (string): OPTIONAL.
  • capabilities (object): OPTIONAL.

Presence data SHOULD be scoped to the authenticated tenant. TTL-based expiry is RECOMMENDED for automatic offline detection.

Pairing establishes a trust relationship between an Enforcer and an Approver, producing a routingToken for subsequent exchanges.

The pairing lifecycle consists of:

  1. Initiate: Enforcer requests a pairing session. Gateway returns a short-lived, single-use pairing code and nonce.
  2. Resolve: Approver presents the pairing code. Gateway returns the Enforcer’s identity and public key.
  3. Complete: Approver confirms pairing. Gateway generates a routingToken and binds the Enforcer-Approver pair.

Requirements:

  • Pairing codes MUST be short-lived (RECOMMENDED ≤ 10 minutes).
  • Pairing codes MUST be single-use; reuse MUST be rejected.
  • Pairing codes SHOULD have sufficient entropy to resist brute-force (RECOMMENDED ≥ 6 alphanumeric characters).
  • Completing a pairing that is already completed MUST return a conflict error.
  • Out-of-band verification (e.g., visual confirmation of Enforcer label) is RECOMMENDED.

7. Delivery Guarantees and Acknowledgements

Section titled “7. Delivery Guarantees and Acknowledgements”
  • Approval Requests: at-least-once delivery to Approver(s).
  • Decision Deliveries: at-least-once delivery to Enforcer.

The Gateway MUST support acknowledgement of gateway-emitted messages using an Ack mechanism.

An Ack MUST include:

  • msgId
  • requestId
  • status in { received, processed }
  • ackAt (RFC3339 datetime)

Upon valid Ack, the Gateway MUST stop redelivering the acknowledged message.

If an inbox item is not acknowledged, the Gateway MAY redeliver it over SSE/WS and MUST continue to expose it via inbox listing until expiry/retention.


The Gateway MUST produce structured errors that include:

  • code (string)
  • message (string)
  • requestId (if applicable)
  • details (object, optional)

Conflict errors MUST be distinguishable from validation errors.


  • The Gateway MUST authenticate Enforcers and Approvers.
  • The Gateway MUST authorize operations per tenant and role/entitlement.
  • The Gateway MUST NOT require plaintext to route; it SHALL handle ciphertext and minimal metadata.
  • Decisions MUST be delivered without modification; the Enforcer remains responsible for signature verification.

An implementation conforms to HARP-GW v0.2 if it implements:

  • Exchange lifecycle and state machine (Section 4)
  • Idempotency/conflict rules (Section 5)
  • Routing semantics and durable inboxes (Sections 3.3 and 6)
  • At-least-once delivery + Ack mechanism (Section 7)
  • Envelope-mandatory message framing (Section 2.4)

Transport conformance is defined in HARP-GATEWAY-HTTP.