0.0.10 • Published 2d ago
@av-pi-studio/protocol
Licence
—
Version
0.0.10
Deps
0
Vulns
0
Weekly
0
@av-pi-studio/protocol
Shared wire schemas, binary frame codecs, and capability flags for Pi-Studio. This package is the single source of truth for everything that crosses the WebSocket between the daemon and any client (CLI, web, mobile, desktop).
It is a zero-runtime-workspace-dependency library — the only external dependency is zod —
so it can be imported by browser and React Native clients as freely as by the Node.js daemon.
Install
npm install @av-pi-studio/protocol
What's in here
- JSON wire schemas (
messages.ts) — every message type that can appear on the WebSocket, as Zod schemas plus their inferred TypeScript types: thehello/statushandshake, RPC requests/responses, broadcasts (agent_update,agent_stream, …), and the top-level envelope union that wraps them all. - Binary frame codecs (
binary-frames/) — encode/decode functions for the two binary wire formats: terminal I/O ([opcode][slot][payload]) and chunked file transfer. Both useUint8Array, neverBuffer, so they run unchanged in a browser. - Client capability flags (
client-capabilities.ts) —CLIENT_CAPS(what a client can advertise inhello.capabilities) andSERVER_FEATURES(what the daemon advertises inserver_info.features), plus asupports()helper. - Endpoint parsing (
endpoint.ts) — turns a daemon target string (host:port,ws://…,relay://…) into a structuredEndpointDescriptor. - Provider manifest types (
provider-manifest.ts) — UI-facing scaffolding for describing providers/modes (labels, color tiers, capability flags).
Usage
import {
helloSchema,
agentStreamEventSchema,
encodeTerminalFrame,
decodeTerminalFrame,
parseEndpoint,
rpcName,
} from "@av-pi-studio/protocol";
// Validate + parse an inbound message
const hello = helloSchema.parse(rawJson);
// Build a canonical dotted RPC name
const name = rpcName("agent", "permission", "respond", "request");
// → "agent.permission.respond.request"
// Parse a daemon connection target
const endpoint = parseEndpoint("workstation.local:6767");
// → { kind: "direct", host: "workstation.local", port: 6767, ssl: false, raw: "…" }
Every exported schema has a paired TypeScript type (XSchema / X), inferred with z.infer<> —
import whichever you need.
Design rules
These are enforced by convention and by the package's own tests, not by tooling:
- Append-only. Fields are only ever added, and only as optional. Nothing is ever removed, narrowed, or given a new discriminant value. This is what lets an older daemon load data written by a newer one (and vice versa) without a migration step.
- Schema passthrough. Most schemas use Zod's
.passthrough(), so unknown fields from a newer protocol version survive a round-trip through an older decoder instead of being stripped or rejected. - Zero workspace imports. This package never imports from another
@av-pi-studio/*package — it has to stay usable standalone by any future client, including ones that don't otherwise depend on the rest of the monorepo. - Cross-platform binary codecs. The binary frame encode/decode functions only use
Uint8Array— no Node-only APIs — so they work identically in Node, the browser, and React Native. - Dotted RPC names. New RPCs are named via
rpcName(domain, sub, op, dir)→"domain.provider.operation.direction"(e.g.agent.permission.respond.request). Legacy flat names are still accepted on the wire via aliases, but never generated by new code.
Adding a new wire message type
- Define the Zod schema (and its inferred type) in
messages.tsor a new sibling file. - Add it to the
sessionMessageSchemadiscriminated union. - Export it from
index.ts. - Add a round-trip test (
messages.envelopes.test.tsor a new*.test.ts). - Register the corresponding handler in the daemon's
HandlerRegistry(@av-pi-studio/server).
Development
npm run build # tsc -b
npm test -- --project packages/protocol
Tests are Vitest and live alongside their source files as *.test.ts.