---
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<State, Command>({
  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<State, Command>({
  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.
