# `@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:

```ts
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`

---

Generated from [`packages/protocol/README.md`](https://github.com/ZephyrCloudIO/ze-harness/blob/main/packages/protocol/README.md).
