--- title: Quickstart description: Install gorp and wire up your first client/server replica. --- ## Installation ```sh npm install @assistant-ui/gorp ``` ## Define your state and commands A gorp app has two types: the shape of the synced **state**, and the **commands** the client can send. Both live in shared code so client and server stay in lockstep. ```ts type State = { count: number; }; type Command = | { type: "inc" } | { type: "set"; value: number }; ``` ## Define a mutator The mutator responds to commands by writing to state. Its signature is the same for `GorpClient` and `GorpServer`, so a single function can run on both sides. ```ts const initialState: State = { count: 0 }; const mutator = (state: State, cmd: Command) => { switch (cmd.type) { case "inc": state.count += 1; break; case "set": state.count = cmd.value; break; } }; ``` It must be deterministic in `(state, command, seq)` — `GorpClient` re-runs it on every replay to rebuild the optimistic view. ## Set up the server `GorpServer` owns the authoritative state. Writes inside the mutator are batched per microtask and emitted as deep-patch ops to every subscriber. ```ts import { GorpServer, GorpSessions } from "@assistant-ui/gorp"; const server = new GorpServer({ initialState, mutator, }); const sessions = new GorpSessions(server); ``` ## Set up the client `GorpClient` is a replica plus an optimistic view layered on top of the last server-confirmed state. The config also takes a `send` callback — gorp invokes it whenever a command needs to go over the wire. ```ts import { GorpClient } from "@assistant-ui/gorp"; const transport = createTransport(); const client = new GorpClient({ initialState, mutator, send: (cmd) => transport.send(cmd), }); transport.onMessage((msg) => client.apply(msg)); ``` ## Use it ```ts client.send({ type: "inc" }); client.state.count; // 1, immediately (optimistic) ``` The server's first envelope is always a full snapshot, so a fresh client catches up without an explicit handshake. After that, only patches flow. On reconnect, call `client.resync()` to re-emit pending commands via the new connection. `GorpSessions` dedups them against the session high-water.