@zephyrcloudio/harness-protocol

The validated, versioned HTTP and SSE contract shared by the Server and Client.

Import endpoint metadata, Effect schemas, limits, and transport error values from the package root:

import { V1, TurnResponse, decodeProtocol } from '@zephyrcloudio/harness-protocol';

The protocol does not perform network requests. Decode all external values, respect MAX_WIRE_BYTES, apply the shared byte-safe Session system-prompt schema, and treat SSE values as observations rather than commands. A caught-up Session event stream repeats its current session.cursor at least every SESSION_EVENT_HEARTBEAT_MILLIS (15 seconds), and a quiet Turn event stream sends turn.heartbeat at least every TURN_EVENT_HEARTBEAT_MILLIS (15 seconds), so clients can treat a longer silence as a lost connection. A turn.heartbeat carries no new state: every durable event through its revision has already been sent.

The Fetch Server adds Ze-Harness-Version: <protocol>/<release> to responses, including SSE and API errors. For example, 1/0.6.0 advertises protocol 1 and release 0.6.0. The header is exposed through Access-Control-Expose-Headers without changing origin authorization. SERVER_VERSION_HEADER, ServerVersion, and parseServerVersionHeader define this advisory metadata. It is not an admission or compatibility gate: clients can warn without retrying an already accepted mutation. Old servers may omit it.

The v1 contract includes revision-checked Session configuration replacement, durable permission replies (once, always, or reject), and listing or removing saved Session grants. Replies target a PermissionRequestId, not a Tool call ID.

Sessions fork with POST /v1/servers/:server/sessions/:sessionId/forks/:forkedSessionId: settled history before an optional turnId is copied into the caller-selected identity, the targeted Turn stays behind for resending, and an absent body forks the whole settled history. A through boundary instead copies the named message inclusively (a Turn message selects its whole Turn; a conversation entry selects itself), and visibility restricts the copy to what the forking actor may observe. The fork inherits the parent workdir, default model, system prompt, and permission rules, and records forkedFrom lineage (parent Session plus the boundary) queryable on the Session; saved grants, overlay state, and unsettled work stay behind, and exact retries are idempotent.

Sessions carry an immutable working directory (workdir, server root by default): relative file paths resolve inside it, shell commands run inside it, and file and shell permission resources are judged against it. Creation may send a clientWorkdir absolute path instead; the server resolves it against its root (an explicit workdir always wins) and rejects hints outside the root. List a server's Sessions with GET /v1/servers/:server/sessions (oldest first, deleted identities excluded) and delete a server — every Session plus shared credentials, with files kept — with DELETE /v1/servers/:server.

Watch a whole server with GET /v1/servers/:server/events?afterServerCursor=N. Omit the cursor to start live from the current one, which the first server.cursor announces; pass one to replay every stamped row after it. The stream is the control-plane feed over the durable ServerActivityCursor: one monotonic counter per server database that stamps every Session creation and title change, every Turn change, and every Session deletion. Each ServerStreamEvent carries the serverCursor it was observed at and reuses the Session stream's Turn event shapes (session.turn.snapshot, .tool.activity, .started, .usage, .tool.requested, .approval.requested, .approval.resolved, .tool.completed, .question.asked, .question.replied, .question.rejected) with their per-Session envelope intact; the live text, refusal, and reasoning deltas stay on the per-Session stream. Session-scoped events are session.created (the Session snapshot, sent the first time a stream sees a Session and therefore repeatable after a resume), session.title, and session.deleted (sessionId, deletedAt). A Session's first event on a stream is always session.created: a Turn event for a Session the stream has not announced yet is preceded by one stamped one serverCursor before the Turn's, so a resume between the two replays the Turn and may repeat that session.created. A caught-up stream repeats server.cursor at least every SERVER_EVENT_HEARTBEAT_MILLIS (15 seconds), and a page whose rows produced no event still advances with server.cursor.

Sub-agents spawn through the task tool, not the API: each call runs one prompt to completion on a child Session pinned to the named agent, or continues task_id, and settles to a result envelope. The child inherits the parent workdir and default model and records spawnedFrom lineage; deleting a parent deletes its spawned children while forks stay independent. Read children with GET /v1/servers/:server/sessions/:sessionId/children, report host support with GET /v1/capabilities, and detach blocking foreground chains with POST /v1/servers/:server/sessions/:sessionId/background (true when any chain detached; each result arrives as a queued parent turn).

It also defines model discovery and provider connection endpoints:

  • Model discovery: GET /v1/runtime/models, GET /v1/runtime/models/events, GET /v1/servers/:server/sessions/:sessionId/models, and GET /v1/servers/:server/sessions/:sessionId/models/events.
  • Provider management: GET /v1/runtime/providers, GET /v1/runtime/providers/:providerId, POST /v1/runtime/providers/:providerId/connect/key, PATCH /v1/runtime/providers/:providerId/connections/:connectionId, and DELETE /v1/runtime/providers/:providerId/connections/:connectionId.
  • Revisions are single-shot current-revision checks over SSE: each .../models/events call emits the present revision once and closes. Clients re-fetch the corresponding GET .../models snapshot for fresh data. Secrets are never exposed over protocol routes.

Public TypeScript exports

  • AddSessionPluginRequest
  • AddSessionPluginRequestValue
  • AppendConversationReceiptResponse
  • AppendConversationRequest
  • AppendConversationRequestValue
  • Authorization
  • CancelContextCompactionRequest
  • CancelMcpCredentialRequest
  • CancelTurnRequest
  • CapabilitiesResponse
  • CapabilitiesResponseValue
  • CLIENT_ID_HEADER
  • ClientWorkdir
  • ClientWorkdirValue
  • CompleteMcpCredentialCallbackRequest
  • CompleteMcpCredentialCallbackRequestValue
  • ConflictError
  • ConflictErrors
  • ConnectProviderKeyRequest
  • ConnectProviderKeyResponse
  • ContextCompactionReceiptResponse
  • ContextCompactionResponse
  • CreateSessionRequest
  • CreateSessionRequestValue
  • DAEMON_LOG_PAGE_MAX
  • DaemonLogEntry
  • DaemonLogLevel
  • DaemonLogLevelValue
  • DaemonLogQuery
  • DaemonLogResponse
  • DaemonLogResponseValue
  • decodeProtocol
  • DeleteProviderConnectionResponse
  • DeleteSessionRequest
  • DescendantApprovalsResponse
  • DescendantQuestionsResponse
  • EndpointErrors
  • ForbiddenError
  • ForgetMcpCredentialRequest
  • ForkSessionRequest
  • HARNESS_PROTOCOL_VERSION
  • HarnessApi
  • HealthResponse
  • HealthResponseValue
  • InternalServerError
  • makeHarnessOpenApi
  • MAX_WIRE_BYTES
  • MCP_CREDENTIAL_AUTHORIZATION_REQUIRED_REASONS
  • MCP_CREDENTIAL_CALLBACK_DENIED_REASONS
  • MCP_CREDENTIAL_REVOCATION_STATUSES
  • McpCatalogPrompt
  • McpCatalogResource
  • McpCatalogResourceTemplate
  • McpCatalogResponse
  • McpCatalogServer
  • McpCatalogSnapshot
  • McpCatalogSnapshotValue
  • McpCatalogTool
  • McpCredentialChallenge
  • McpCredentialChallengeValue
  • McpCredentialForgetResponse
  • McpCredentialForgetResponseValue
  • McpCredentialStartResponse
  • McpCredentialStartResponseValue
  • McpCredentialStatus
  • McpCredentialStatusResponse
  • McpCredentialStatusValue
  • McpPromptArguments
  • McpPromptName
  • McpResourceContents
  • McpResourceReadResponse
  • McpResourceReadResult
  • McpResourceReadResultValue
  • McpServerCatalog
  • McpServerName
  • ModelRevisionEvent
  • NotFoundError
  • parseServerVersionHeader
  • PermissionReplyRequest
  • PermissionReplyResponse
  • PluginJournalCursor
  • PluginJournalQuery
  • PluginJournalResponse
  • PluginJournalResponseValue
  • ProviderModelRefreshOutcome
  • ProviderModelRefreshOutcomeValue
  • PublicPromptAdmission
  • QuestionReplyRequest
  • QuestionReplyResponse
  • ReadMcpResourceRequest
  • RefreshProviderModelsRequest
  • RefreshProviderModelsResponse
  • RefreshProviderModelsResponseValue
  • RefreshSessionPluginRequest
  • RefreshSessionPluginRequestValue
  • ReloadSessionPluginRequest
  • RemoveSessionPluginRequest
  • ReplaceSessionConfigurationRequest
  • REQUEST_ID_HEADER
  • RuntimeApi
  • RuntimePlugin
  • RuntimePluginsResponse
  • RuntimePluginValue
  • RuntimeProviderResponse
  • RuntimeProvidersResponse
  • RuntimeReloadRequest
  • RuntimeReloadResponse
  • RuntimeSkillsResponse
  • SafeFailure
  • SafeProviderSummary
  • SavedPermissionResponse
  • SavedPermissionsResponse
  • SchemaError
  • SERVER_EVENT_HEARTBEAT_MILLIS
  • SERVER_VERSION_HEADER
  • ServerCursorEvent
  • ServerDeletedResponse
  • ServerDeletedResponseValue
  • ServerSessionCreatedEvent
  • ServerSessionDeletedEvent
  • ServerSessionTitleEvent
  • ServerStreamEvent
  • ServerStreamEventValue
  • ServerTurnApprovalRequestedEvent
  • ServerTurnApprovalResolvedEvent
  • ServerTurnQuestionAskedEvent
  • ServerTurnQuestionRejectedEvent
  • ServerTurnQuestionRepliedEvent
  • ServerTurnSnapshotEvent
  • ServerTurnStartedEvent
  • ServerTurnToolActivityEvent
  • ServerTurnToolCompletedEvent
  • ServerTurnToolRequestedEvent
  • ServerTurnUsageEvent
  • ServerVersion
  • SESSION_COMPACTION_PAGE_MAX
  • SESSION_EVENT_HEARTBEAT_MILLIS
  • SESSION_JOURNAL_PAGE_MAX
  • SESSION_TURN_PAGE_MAX
  • SessionAgentEntry
  • SessionAgentEntryValue
  • SessionAgentsResponse
  • SessionAgentsResponseValue
  • SessionBackgroundResponse
  • SessionCompactionHistoryBoundary
  • SessionCompactionHistoryBoundaryValue
  • SessionCompactionPosition
  • SessionCompactionPositionValue
  • SessionCompactionsContinuationQuery
  • SessionCompactionsFirstQuery
  • SessionCompactionsQuery
  • SessionCompactionsResponse
  • SessionCompactionsResponseValue
  • SessionCompactionState
  • SessionConfigurationResponse
  • SessionCursorEvent
  • SessionDeletedResponse
  • SessionDeletedResponseValue
  • SessionHistoryBoundary
  • SessionHistoryBoundaryValue
  • SessionListQuery
  • SessionListResponse
  • SessionPluginActivation
  • SessionPluginActivationValue
  • SessionPluginRevision
  • SessionPluginRevisionValue
  • SessionPluginsResponse
  • SessionPluginsStatus
  • SessionPluginsStatusValue
  • SessionResponse
  • SessionsApi
  • SessionSkillsResponse
  • SessionStreamEvent
  • SessionStreamEventValue
  • SessionTurnApprovalRequestedEvent
  • SessionTurnApprovalResolvedEvent
  • SessionTurnQuestionAskedEvent
  • SessionTurnQuestionRejectedEvent
  • SessionTurnQuestionRepliedEvent
  • SessionTurnReasoningDeltaEvent
  • SessionTurnRefusalDeltaEvent
  • SessionTurnsContinuationQuery
  • SessionTurnsFirstQuery
  • SessionTurnSnapshotEvent
  • SessionTurnsQuery
  • SessionTurnsResponse
  • SessionTurnsResponseValue
  • SessionTurnStartedEvent
  • SessionTurnState
  • SessionTurnTextDeltaEvent
  • SessionTurnToolActivityEvent
  • SessionTurnToolCompletedEvent
  • SessionTurnToolRequestedEvent
  • SessionTurnUsageEvent
  • SkillListEntry
  • SkillListEntryValue
  • StartMcpCredentialRequest
  • StartMcpCredentialRequestValue
  • SteerConflictError
  • SubmitContextCompactionRequest
  • SubmitContextCompactionRequestValue
  • SubmitMcpPromptRequest
  • SubmitMcpPromptRequestValue
  • SubmitPromptReceiptResponse
  • SubmitPromptRequest
  • SubmitPromptRequestValue
  • SystemApi
  • toSafeProviderSummary
  • TURN_EVENT_HEARTBEAT_MILLIS
  • TurnApprovalRequestedEvent
  • TurnApprovalResolvedEvent
  • TurnHeartbeatEvent
  • TurnHeartbeatEventValue
  • TurnNotActiveError
  • TurnNotSteerableError
  • TurnQuestionAskedEvent
  • TurnQuestionRejectedEvent
  • TurnQuestionRepliedEvent
  • TurnReasoningDeltaEvent
  • TurnRefusalDeltaEvent
  • TurnResponse
  • TurnSnapshot
  • TurnSnapshotEvent
  • TurnSnapshotEventValue
  • TurnSnapshotValue
  • TurnStartedEvent
  • TurnStreamEvent
  • TurnStreamEventValue
  • TurnTerminalEvent
  • TurnTextDeltaEvent
  • TurnToolActivityEvent
  • TurnToolCompletedEvent
  • TurnToolRequestedEvent
  • TurnUsageEvent
  • UnauthorizedError
  • UnavailableError
  • UpdateProviderConnectionRequest
  • ValidationError
  • WatchServerQuery
  • WatchSessionQuery
  • WatchTurnQuery