🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@getremoteapp/wire

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@getremoteapp/wire

Shared message wire types and Zod schemas for Remote clients and services

latest
npmnpm
Version
0.1.0
Version published
Maintainers
1
Created
Source

@getremoteapp/wire

Canonical wire specification package for Remote clients and services.

This package defines shared wire contracts as TypeScript types + Zod schemas. It is intentionally small and focused on protocol-level data only.

Quick Examples (Legacy vs New)

Both legacy and new formats are transported inside encrypted session messages.

Legacy format examples (decrypted payload):

{
  "role": "user",
  "content": {
    "type": "text",
    "text": "fix the failing test"
  },
  "meta": {
    "sentFrom": "mobile"
  }
}
{
  "role": "agent",
  "content": {
    "type": "output",
    "data": {
      "type": "message",
      "message": "I found the issue in api/session.ts"
    }
  },
  "meta": {
    "sentFrom": "cli"
  }
}

New session protocol format example (decrypted payload):

{
  "role": "session",
  "content": {
    "id": "msg_01",
    "time": 1739347230000,
    "role": "agent",
    "turn": "turn_01",
    "ev": {
      "t": "text",
      "text": "I found the issue in api/session.ts"
    }
  },
  "meta": {
    "sentFrom": "cli"
  }
}

Modern session protocol user envelope (decrypted payload):

{
  "role": "session",
  "content": {
    "id": "msg_legacy_user_01",
    "time": 1739347231000,
    "role": "user",
    "ev": {
      "t": "text",
      "text": "fix the failing test"
    }
  },
  "meta": {
    "sentFrom": "cli"
  }
}

Protocol invariant:

  • outer role = "session" marks modern session-protocol payloads.
  • inside content, envelope role is only "user" or "agent".

Session protocol send rollout (ENABLE_SESSION_PROTOCOL_SEND):

  • sender emits modern session-protocol user payloads (role = "session" with content.role = "user").
  • default (disabled): app consumes legacy user payloads (role = "user", content.type = "text") and drops modern user payloads.
  • enabled: app consumes modern user payloads and drops legacy user payloads.
  • truthy values: 1, true, yes (case-insensitive).

Wire-level encrypted container (same for legacy and new):

{
  "id": "msg-db-row-id",
  "seq": 101,
  "localId": null,
  "content": {
    "t": "encrypted",
    "c": "BASE64_ENCRYPTED_PAYLOAD"
  },
  "createdAt": 1739347230000,
  "updatedAt": 1739347230000
}

Purpose

@getremoteapp/wire centralizes definitions for:

  • encrypted message/update payloads
  • session protocol envelope and event stream
  • helper for creating valid session envelopes

The goal is to keep CLI/app/server/agent on the same wire contract and avoid schema drift.

Package Identity

  • Name: @getremoteapp/wire
  • Workspace path: packages/remote-wire
  • Entry: src/index.ts
  • Runtime deps: zod, @paralleldrive/cuid2

Public Exports

src/index.ts exports everything from:

  • src/messages.ts
  • src/legacyProtocol.ts
  • src/sessionProtocol.ts

messages.ts exports

Schemas + inferred types:

  • SessionMessageContentSchema
  • SessionMessage
  • SessionMessageSchema
  • MessageMetaSchema
  • MessageMeta
  • SessionProtocolMessageSchema
  • SessionProtocolMessage
  • MessageContentSchema
  • MessageContent
  • VersionedEncryptedValueSchema
  • VersionedEncryptedValue
  • VersionedNullableEncryptedValueSchema
  • VersionedNullableEncryptedValue
  • UpdateNewMessageBodySchema
  • UpdateNewMessageBody
  • UpdateSessionBodySchema
  • UpdateSessionBody
  • VersionedMachineEncryptedValueSchema
  • VersionedMachineEncryptedValue
  • UpdateMachineBodySchema
  • UpdateMachineBody
  • CoreUpdateBodySchema
  • CoreUpdateBody
  • CoreUpdateContainerSchema
  • CoreUpdateContainer

Compatibility aliases:

  • ApiMessageSchema -> SessionMessageSchema
  • ApiMessage -> SessionMessage
  • ApiUpdateNewMessageSchema -> UpdateNewMessageBodySchema
  • ApiUpdateNewMessage -> UpdateNewMessageBody
  • ApiUpdateSessionStateSchema -> UpdateSessionBodySchema
  • ApiUpdateSessionState -> UpdateSessionBody
  • ApiUpdateMachineStateSchema -> UpdateMachineBodySchema
  • ApiUpdateMachineState -> UpdateMachineBody
  • UpdateBodySchema -> UpdateNewMessageBodySchema
  • UpdateBody -> UpdateNewMessageBody
  • UpdateSchema -> CoreUpdateContainerSchema
  • Update -> CoreUpdateContainer

legacyProtocol.ts exports

Schemas + inferred types:

  • UserMessageSchema
  • UserMessage
  • AgentMessageSchema
  • AgentMessage
  • LegacyMessageContentSchema
  • LegacyMessageContent

sessionProtocol.ts exports

Schemas + inferred types:

  • sessionRoleSchema
  • SessionRole
  • sessionTextEventSchema
  • sessionServiceMessageEventSchema
  • sessionToolCallStartEventSchema
  • sessionToolCallEndEventSchema
  • sessionFileEventSchema
  • sessionTurnStartEventSchema
  • sessionStartEventSchema
  • sessionTurnEndStatusSchema
  • SessionTurnEndStatus
  • sessionTurnEndEventSchema
  • sessionStopEventSchema
  • sessionEventSchema
  • SessionEvent
  • sessionEnvelopeSchema
  • SessionEnvelope
  • CreateEnvelopeOptions
  • createEnvelope(...)

Wire Type Specifications

Common Primitive Rules

These are schema-level requirements, not just recommendations.

  • id, sid, machineId, call, name, title, description, ref: string
  • seq, createdAt, updatedAt, size, width, height, version, activeAt: number
  • All nullable fields are explicitly marked with .nullable().
  • All optional fields are explicitly marked with .optional().
  • .nullish() means undefined | null | <type>.

Message/Update Specs (messages.ts)

SessionMessageContentSchema

{
  t: 'encrypted';
  c: string;
}

Meaning:

  • t is a strict discriminator with value 'encrypted'.
  • c is encrypted payload bytes encoded as a string (typically base64 in current usage).

SessionMessageSchema

{
  id: string;
  seq: number;
  localId?: string | null;
  content: SessionMessageContent;
  createdAt: number;
  updatedAt: number;
}

Notes:

  • localId is .nullish() for compatibility with different producers.
  • createdAt and updatedAt are required in this shared schema.

MessageMetaSchema

{
  sentFrom?: string;
  permissionMode?: 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan' | 'read-only' | 'safe-yolo' | 'yolo';
  model?: string | null;
  fallbackModel?: string | null;
  customSystemPrompt?: string | null;
  appendSystemPrompt?: string | null;
  allowedTools?: string[] | null;
  disallowedTools?: string[] | null;
  displayText?: string;
}

Legacy Decrypted Payload Specs (legacyProtocol.ts)

UserMessageSchema (legacy decrypted payload)

{
  role: 'user';
  content: {
    type: 'text';
    text: string;
  };
  localKey?: string;
  meta?: MessageMeta;
}

AgentMessageSchema (legacy decrypted payload)

{
  role: 'agent';
  content: {
    type: string;
    [key: string]: unknown;
  };
  meta?: MessageMeta;
}

LegacyMessageContentSchema

Discriminated union on role:

  • 'user' -> UserMessageSchema
  • 'agent' -> AgentMessageSchema

Top-Level Decrypted Payload Specs (messages.ts)

SessionProtocolMessageSchema (modern decrypted payload wrapper)

{
  role: 'session';
  content: SessionEnvelope;
  meta?: MessageMeta;
}

MessageContentSchema

Discriminated union on top-level role:

  • 'user' -> UserMessageSchema (legacy)
  • 'agent' -> AgentMessageSchema (legacy)
  • 'session' -> SessionProtocolMessageSchema (modern)

Message/Update Specs (messages.ts) Continued

VersionedEncryptedValueSchema

{
  version: number;
  value: string;
}

Used for encrypted, version-tracked blobs that cannot be null when present.

VersionedNullableEncryptedValueSchema

{
  version: number;
  value: string | null;
}

Used where payload presence can be intentionally reset to null while still versioning.

VersionedMachineEncryptedValueSchema

{
  version: number;
  value: string;
}

Machine update variant. Equivalent shape to VersionedEncryptedValueSchema.

UpdateNewMessageBodySchema

{
  t: 'new-message';
  sid: string;
  message: SessionMessage;
}

UpdateSessionBodySchema

{
  t: 'update-session';
  id: string;
  metadata?: VersionedEncryptedValue | null;
  agentState?: VersionedNullableEncryptedValue | null;
}

Important distinction:

  • metadata.value is string when metadata block exists.
  • agentState.value may be string or null when block exists.

UpdateMachineBodySchema

{
  t: 'update-machine';
  machineId: string;
  metadata?: VersionedMachineEncryptedValue | null;
  daemonState?: VersionedMachineEncryptedValue | null;
  active?: boolean;
  activeAt?: number;
}

CoreUpdateBodySchema

Discriminated union on t with exactly 3 variants:

  • 'new-message'
  • 'update-session'
  • 'update-machine'

CoreUpdateContainerSchema

{
  id: string;
  seq: number;
  body: CoreUpdateBody;
  createdAt: number;
}

Session Protocol Specs (sessionProtocol.ts)

Role

sessionRoleSchema

'user' | 'agent'

Role meaning:

  • 'user': user-originated envelope.
  • 'agent': agent-originated envelope.

Event Variants

sessionEventSchema is a discriminated union on t with 9 variants.

1) Text event

{
  t: 'text';
  text: string;
  thinking?: boolean;
}

2) Service event

{
  t: 'service';
  text: string;
}

3) Tool-call-start event

{
  t: 'tool-call-start';
  call: string;
  name: string;
  title: string;
  description: string;
  args: Record<string, unknown>;
}

4) Tool-call-end event

{
  t: 'tool-call-end';
  call: string;
}

5) File event

{
  t: 'file';
  ref: string;
  name: string;
  size: number;
  image?: {
    width: number;
    height: number;
    thumbhash: string;
  };
}

6) Turn-start event

{
  t: 'turn-start';
}

7) Start event

{
  t: 'start';
  title?: string;
}

8) Turn-end event

{
  t: 'turn-end';
  status: 'completed' | 'failed' | 'cancelled';
}

9) Stop event

{
  t: 'stop';
}

Envelope

sessionEnvelopeSchema

{
  id: string;
  time: number;
  role: 'user' | 'agent';
  turn?: string;
  subagent?: string; // must pass cuid2 validation when present
  ev: SessionEvent;
}

Additional validation (superRefine):

  • If ev.t === 'service', then role MUST be 'agent'.
  • If ev.t === 'start' or ev.t === 'stop', then role MUST be 'agent'.
  • If subagent is present, it MUST satisfy isCuid(...).

Helper Function Contract

createEnvelope(role, ev, opts?)

Input:

  • role: SessionRole
  • ev: SessionEvent
  • opts?: { id?: string; time?: number; turn?: string; subagent?: string }

Behavior:

  • If opts.id is absent, generates id using createId().
  • If opts.time is absent, sets time to Date.now().
  • Includes turn only when provided.
  • Includes subagent only when provided.

Output:

  • Returns a SessionEnvelope parsed by sessionEnvelopeSchema.
  • Throws on invalid combinations (for example role = 'user' with ev.t = 'service').

Normative JSON Examples

Update container with new-message

{
  "id": "upd-1",
  "seq": 100,
  "createdAt": 1739347200000,
  "body": {
    "t": "new-message",
    "sid": "session-1",
    "message": {
      "id": "msg-1",
      "seq": 55,
      "localId": null,
      "content": {
        "t": "encrypted",
        "c": "Zm9v"
      },
      "createdAt": 1739347199000,
      "updatedAt": 1739347199000
    }
  }
}

Decrypted new-message content example

message.content.c (ciphertext) decrypts into the payload below for a session-protocol message:

{
  "role": "session",
  "content": {
    "id": "env_01",
    "time": 1739347232000,
    "role": "agent",
    "turn": "turn_01",
    "ev": {
      "t": "text",
      "text": "I found 3 TODOs."
    }
  },
  "meta": {
    "sentFrom": "cli"
  }
}

For user text migration behavior:

  • clients emit only the modern payload (role = "session" with content.role = "user").
  • if ENABLE_SESSION_PROTOCOL_SEND is disabled, app keeps consuming legacy payloads and drops modern payloads.
  • if ENABLE_SESSION_PROTOCOL_SEND is enabled, app consumes modern payloads and drops legacy payloads.

Update container with update-session

{
  "id": "upd-2",
  "seq": 101,
  "createdAt": 1739347210000,
  "body": {
    "t": "update-session",
    "id": "session-1",
    "metadata": {
      "version": 8,
      "value": "BASE64..."
    },
    "agentState": {
      "version": 13,
      "value": null
    }
  }
}

Update container with update-machine

{
  "id": "upd-3",
  "seq": 102,
  "createdAt": 1739347220000,
  "body": {
    "t": "update-machine",
    "machineId": "machine-1",
    "metadata": {
      "version": 2,
      "value": "BASE64..."
    },
    "daemonState": {
      "version": 3,
      "value": "BASE64..."
    },
    "active": true,
    "activeAt": 1739347220000
  }
}

Session protocol envelope

{
  "id": "x8s1k2...",
  "role": "agent",
  "turn": "turn-42",
  "ev": {
    "t": "turn-start"
  }
}

Parsing/Validation Usage

import {
  CoreUpdateContainerSchema,
  sessionEnvelopeSchema,
} from '@getremoteapp/wire';

const maybeUpdate = CoreUpdateContainerSchema.safeParse(input);
if (!maybeUpdate.success) {
  // invalid update payload
}

const maybeEnvelope = sessionEnvelopeSchema.safeParse(envelopeInput);
if (!maybeEnvelope.success) {
  // invalid envelope/event payload
}

Build and Distribution Specification

package.json contract:

  • main: ./dist/index.cjs
  • module: ./dist/index.mjs
  • types: ./dist/index.d.cts
  • exports["."] provides both CJS and ESM entrypoints with type paths.

Build script:

  • shx rm -rf dist && npx tsc --noEmit && pkgroll

Tests:

  • vitest against src/*.test.ts

Publish gate:

  • prepublishOnly runs build + test

Published files:

  • dist
  • package.json
  • README.md

Monorepo Build Dependency Behavior

In this repository, consumer workspaces import @getremoteapp/wire through package exports that point at dist/*.

That means on a clean checkout:

  • Build wire first: yarn workspace @getremoteapp/wire build
  • Then build/typecheck dependents.

After publishing to npm, dependents consume prebuilt artifacts from the published tarball.

Change Policy

When modifying wire schemas:

  • Prefer additive changes to keep older consumers compatible.
  • Treat discriminator values (t) as protocol-level API and avoid breaking renames.
  • Document semantic changes in this README.
  • Bump package version before downstream releases that depend on new schema behavior.

Development Commands

# from repository root
yarn workspace @getremoteapp/wire build
yarn workspace @getremoteapp/wire test

Release Commands (maintainers)

# interactive release target selection from repo root
yarn release

# direct release invocation
yarn workspace @getremoteapp/wire release

This prepares release artifacts using the same release-it flow as other publishable libraries in the monorepo.

FAQs

Package last updated on 23 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts