Skip to content

Cloud Client Package

@open-cowork/cloud-client is the typed Cloud HTTP/SSE client used by Open Cowork first-party clients. It is a supported workspace/source package for the current repo, not an independently versioned public npm SDK yet. Desktop cloud workspaces, Cloud Web, Gateway, and downstream builds from this repo should use this package instead of importing Cloud control-plane internals.

Contract

  • The client talks to Open Cowork Cloud product APIs over HTTP and SSE.
  • It does not import Electron, Desktop main-process modules, control-plane stores, Postgres modules, or @opencode-ai/sdk.
  • It may depend on @open-cowork/shared, which is the shared workspace/source package for Open Cowork product and wire types.
  • OpenCode still owns execution. The client only creates sessions, sends product commands, reads projections, subscribes to events, and manages product surfaces such as workflows, artifacts, BYOK metadata, and channel deliveries.
  • While Open Cowork is pre-1.0 and the package ships with the repo, typed API changes can happen in ordinary repo releases. Treat it as a source-level contract until an explicit standalone SDK publishing policy is announced. Breaking changes after 1.0.0 require a major version.
  • Modules outside the documented entry points are internal. Do not import Desktop Cloud server files, control-plane stores, runtime adapters, or source files from first-party clients or downstream deployments.

Entry Points

import { createHttpSseCloudTransportAdapter } from '@open-cowork/cloud-client'
import type { CloudTransportAdapter } from '@open-cowork/cloud-client/adapter'
import type { SessionListPage } from '@open-cowork/cloud-client/domains/sessions'

The package exports only compiled dist entry points:

  • @open-cowork/cloud-client
  • @open-cowork/cloud-client/adapter
  • @open-cowork/cloud-client/domains/artifacts
  • @open-cowork/cloud-client/domains/billing
  • @open-cowork/cloud-client/domains/byok
  • @open-cowork/cloud-client/domains/capabilities
  • @open-cowork/cloud-client/domains/channels
  • @open-cowork/cloud-client/domains/config
  • @open-cowork/cloud-client/domains/identity
  • @open-cowork/cloud-client/domains/sessions
  • @open-cowork/cloud-client/domains/settings
  • @open-cowork/cloud-client/domains/threads
  • @open-cowork/cloud-client/domains/transport
  • @open-cowork/cloud-client/domains/workflows

Desktop Bearer Client

import { createHttpSseCloudTransportAdapter } from '@open-cowork/cloud-client'

const client = createHttpSseCloudTransportAdapter({
  baseUrl: 'https://cowork.example.com',
  headers: { authorization: `Bearer ${oidcAccessToken}` },
  requestTimeoutMs: 30_000,
})

const session = await client.createSession({ profileName: 'default' })
await client.promptSession(session.session.sessionId, { text: 'Run the release checks' })

Desktop should create this client in the main process. The renderer should receive workspace views and status, not refresh tokens, provider keys, or raw cloud credentials.

Gateway Service-Token Client

import { createHttpSseCloudTransportAdapter } from '@open-cowork/cloud-client'

const gatewayClient = createHttpSseCloudTransportAdapter({
  baseUrl: 'https://cowork.example.com',
  headers: { authorization: `Bearer ${gatewayServiceToken}` },
  requestTimeoutMs: 30_000,
})

gatewayClient.subscribeChannelDeliveries?.({
  claimedBy: 'gateway-shard-a',
  onDelivery(delivery) {
    deliverToChannel(delivery)
  },
})

The service token authenticates the gateway process. The channel actor still needs to be resolved through Cloud identity/RBAC APIs before the gateway can prompt, approve, answer questions, or mutate channel state.

Browser Client

const client = createHttpSseCloudTransportAdapter({
  baseUrl: window.location.origin,
  credentials: 'include',
  csrfToken: bootstrap.csrfToken,
})

Browser clients use cookie auth and CSRF for mutating requests. Operator-only APIs should remain behind operator auth or private networking and must not be called from ordinary browser workbench code.

Auth Modes

Mode Caller Transport
Cookie Cloud Web browser credentials: 'include' plus CSRF token
Bearer Desktop main process Authorization: Bearer <OIDC access token>
Service token Gateway daemon or automation Authorization: Bearer <scoped API token>
Operator Deployment/operator tooling only Operator token or private network gate

Timeouts And Cancellation

requestTimeoutMs defaults to 30 seconds and is clamped to 100ms..120000ms. 0 disables HTTP timeouts and should only be used in tests or explicitly controlled deployments. Use signal to cancel in-flight HTTP requests and SSE subscriptions:

const controller = new AbortController()
const client = createHttpSseCloudTransportAdapter({
  baseUrl: 'https://cowork.example.com',
  headers: { authorization: `Bearer ${token}` },
  signal: controller.signal,
})

controller.abort()

SSE subscriptions are long-lived streams and are not governed by requestTimeoutMs.

The client does not retry automatically. Callers should choose retries per operation because mutating Cloud commands are durable and may be idempotency aware on the server.

SSE Authentication

Bearer-token clients use fetch-based SSE so the Authorization header is sent with stream requests. Cookie-authenticated browser clients use EventSource when no custom headers are configured.

SSE subscription URLs accept an afterSequence cursor. Clients should persist the highest processed sequence, resume with afterSequence after reconnect or process restart, and close subscriptions when the workspace/session/channel binding is no longer active.

import {
  createHttpSseCloudTransportAdapter,
  isCloudTransportError,
} from '@open-cowork/cloud-client'

const subscription = client.subscribeSessionEvents('session-id', {
  afterSequence: lastSeenSequence,
  onEvent(event) {
    lastSeenSequence = Math.max(lastSeenSequence, event.sequence)
  },
  onError(error) {
    if (isCloudTransportError(error) && error.kind === 'unauthorized') {
      requestReauth()
    }
  },
})

subscription.close()

Reconnect and backoff policy belong to the caller because Desktop, Web, and Gateway have different UI and delivery semantics.

Error Taxonomy

The client exports CloudTransportError, CloudTransportErrorKind, and isCloudTransportError. Clients should branch on typed fields instead of parsing strings.

Kind Meaning
unauthorized HTTP 401, expired or missing auth
forbidden HTTP 403, membership or policy denial
payment_required HTTP 402, subscription or entitlement gate
not_found HTTP 404
conflict HTTP 409, stale projection or command conflict
rate_limited HTTP 429, retryAfter may be set
server HTTP 5xx
http Other non-2xx HTTP status
timeout Client request timeout
abort Caller cancellation
parse Invalid JSON response or SSE payload
sse EventSource/fetch-SSE startup or stream failure
network Fetch/network failure before an HTTP response
request Invalid client request construction

Release Checklist

  • Build shared first: pnpm --filter @open-cowork/shared build.
  • Build the client package: pnpm --filter @open-cowork/cloud-client build.
  • Run transport and package-boundary tests.
  • Confirm package exports only the documented entry points.
  • Update README and this page when auth, timeout, SSE, or error behavior changes.
  • Keep examples free of private deployment URLs, org ids, tokens, provider keys, and project-specific values.
  • Pre-1.0 typed breaks must be called out in release notes. Do not add publishConfig, mark the package publishable, or present it as a standalone published SDK until package publication, versioning, provenance, and support ownership are explicit.