TypestateSign in

Who does what, from the first question to Live

You decide what your product must do. Your agent writes it, over MCP. Typestate checks every step, writes the code with a program, runs your examples in Sandbox and keeps Live behind a change that you approve.

Choose a plan

  • YouYou answer questions and approve each change before it goes Live.
  • Your agentClaude, ChatGPT, Cursor or any agent that speaks MCP. It asks, writes and answers.
  • TypestateIt stores your data, checks and builds each action, and runs it in Sandbox and Live.
  1. You and your agent agree on the plan

    1. 1Your agentYouYour agent asks before it builds
    2. You say yes to the plan
  2. Your agent builds, and Typestate checks every step

    1. 2Your agentYour agent writes the steps
    2. 3TypestateTypestate checks the calls
    3. 4TypestateTypestate writes the code
    4. 5TypestateYour agentTypestate compares steps and sentences
  3. Typestate runs your examples, then the action goes Live

    1. 6Your agentTypestateExamples prove the action in Sandbox
    2. 7Your agentTypestateYouA change lists what goes Live
    3. You approve the change before it goes Live
    4. 8TypestateLive answers your customers
    5. Live

Each action goes through 8 stages on its way to Live. You act at the 2 orange moments: you say yes to the plan, and you approve the change.

The bike shop below is invented. The refusal, the fixed words and the code are what Typestate printed for its steps.

Part 1 of 3

You and your agent agree on the plan

YouYour agent

1 of 8

Your agentYou

Your agent asks before it builds

Before the first record type or action of a new feature, your agent asks who uses it, what done means, the rules, and what must never happen. It asks a few questions at a time, restates the plan in your words, and waits for your yes.

Typestate gives every agent this instruction when it connects. A small edit to an action that exists needs fewer questions.

Back to the 8 stages

Your agentWho books a repair slot: anybody with the link, or only customers who signed in?

YouAnybody. They give a name and an email.

Your agentTwo people want Saturday at 10:00. What happens to the second one?

YouThey are refused. One bike per slot.

Your agentAnd when somebody cancels?

YouThen the slot is free again.

Your agentThe plan: a record type Booking, and an action Book A Slot that refuses a slot somebody holds. Shall I build it?

YouYes.

Part 2 of 3

Your agent builds, and Typestate checks every step

Your agentTypestate

2 of 8

Your agent

Each action is steps: a sentence and the calls that do it

Your agent defines the record type first. A Booking has a slot, a name, an email and a state.

Then it writes the action Book A Slot as 3 steps. Each step holds one sentence in your words and the typed calls that do it: read, write, if, stop, answer and a few more. The sentence says what you want, and the calls say exactly what Typestate does.

Back to the 8 stages

Booking

  • slotdate and time
  • nametext
  • emailtext
  • statetext

Book A Slot

  1. 1

    Refuse with "That slot is taken." when somebody already booked that slot.

    The calls, as your agent sends them
    [
      {
        "kind": "read",
        "record": "Booking",
        "count": true,
        "where": {
          "slot": {
            "input": "slot"
          },
          "state": "booked"
        },
        "as": "taken"
      },
      {
        "kind": "if",
        "condition": {
          "value": {
            "name": "taken"
          },
          "at_least": 1
        },
        "then": [
          {
            "kind": "stop",
            "refuse": {
              "words": "That slot is taken.",
              "status": 409
            }
          }
        ]
      }
    ]
  2. 2

    Store the booking with the name and email the customer gives.

    The calls, as your agent sends them
    {
      "kind": "write",
      "create": true,
      "record": "Booking",
      "set": {
        "slot": {
          "input": "slot"
        },
        "name": {
          "input": "name"
        },
        "email": {
          "input": "email"
        },
        "state": "booked"
      },
      "as": "booking"
    }
  3. 3

    Answer the booking's id and slot.

    The calls, as your agent sends them
    {
      "kind": "answer",
      "fields": {
        "id": {
          "name": "booking.id"
        },
        "slot": {
          "name": "booking.slot"
        }
      }
    }

3 of 8

Typestate

Typestate checks the calls before it builds anything

Every record type and field must exist, and every value must have the right type. A refusal must be quoted in its sentence, so the words your customer reads are words you can read in the step.

When a check fails, Typestate refuses the action and says which step and why. The first version of step 1 failed this way, and your agent fixed the sentence.

Back to the 8 stages

Step 1 refuses with "That slot is taken.", and its sentence does not quote these words.

First version

Refuse when somebody already booked that slot.

Fixed

Refuse with "That slot is taken." when somebody already booked that slot.

4 of 8

Typestate

Typestate writes each step back in fixed words, then writes the code

A program, and no model, turns the calls of each step into English from a fixed set of phrases. You read what a step does without reading code.

The same program writes the TypeScript. The same steps always give the same code, and nobody edits it. To change the code, your agent changes the steps.

Back to the 8 stages

Your sentenceWhat Typestate reads in the calls
1

Refuse with "That slot is taken." when somebody already booked that slot.

Counts the Bookings whose slot is the given slot and state is "booked", as taken. When the value named taken is at least 1: Stops and refuses with "That slot is taken." (status 409).

2

Store the booking with the name and email the customer gives.

Adds a Booking: sets email to the given email, name to the given name, slot to the given slot, state to "booked", as booking.

3

Answer the booking's id and slot.

Answers with id = the booking's id, slot = the booking's slot.

Show the code Typestate wrote

You can read this code and not change it. Typestate wrote it from the steps, with a program and no model.

import { defineFlow, Refusal, type Json } from "@typestate/sdk";

type Input = { email: string; name: string; slot: string };

export default defineFlow<Input>(async (ctx, input): Promise<Json> => {
  ctx.step?.("1.1");
  const taken = await ctx.db.Booking.count({ slot: input.slot, state: "booked" });
  ctx.step?.("1.2");
  if ((taken >= 1)) {
    ctx.step?.("1.2.then");
    ctx.step?.("1.2.then.1");
    throw new Refusal("That slot is taken.", 409);
  } else {
    ctx.step?.("1.2.else");
  }
  ctx.step?.("2.1");
  const booking = await ctx.db.Booking.create(
    { email: input.email, name: input.name, slot: input.slot, state: "booked" },
    {
      onlyWhile: {
        terms: [{ record: "Booking", where: { slot: input.slot, state: "booked" } }],
        below: 1,
        refusal: "That slot is taken.",
        status: 409,
      },
    },
  );
  ctx.step?.("3.1");
  return { id: booking.id ?? null, slot: booking.slot ?? null };
});

Look at step 2 in the code. The write counts the bookings again in the same moment it stores the new one, so two people who book 10:00 in the same second cannot both get it.

5 of 8

TypestateYour agent

Typestate reads each step against its sentence, and asks

A model reads each sentence beside its fixed words. When the two say different things, Typestate asks your agent a question on the action. The build goes on, and Sandbox runs it.

Your agent answers each question once. It changes the calls, or it keeps them with one line of reason. A kept question goes to Live with the reason, and you can read it on the change later.

Choose a plan

Back to the 8 stages

QuestionStep 1

The sentence refuses when somebody already booked that slot.

The calls count only bookings whose state is "booked", so a cancelled booking does not hold the slot.

keep_units  reason: "The owner said a cancelled booking frees the slot."

A model writes the words of a question, so they differ from one run to the next.

Part 3 of 3

Typestate runs your examples, then the action goes Live

YouYour agentTypestate

6 of 8

Your agentTypestate

Examples in your terms prove the action in Sandbox

Your agent writes at least one example for each action: what is true before, what the action is asked, and what should happen. A model checks that each example agrees with the steps it speaks for.

Typestate runs every example against the real code in Sandbox, at an address of its own such as repairs--leipzig-bikes.typestate.dev, with a database of its own. Live waits until every example passes.

Back to the 8 stages

A free slot is booked

What is true before
No bookings
What the action is asked
Ana books Saturday 10:00
What should happen
A Booking for Saturday 10:00 is made, and nothing else

A held slot is refused

What is true before
Ben holds Saturday 10:00
What the action is asked
Ana books Saturday 10:00
What should happen
Refused with "That slot is taken." (409)

A cancelled slot is free

What is true before
Ben cancelled Saturday 10:00
What the action is asked
Ana books Saturday 10:00
What should happen
A Booking for Saturday 10:00 is made

run_examples

- A free slot is booked (passed). Judge: agrees with its sentences
- A held slot is refused (passed). Judge: agrees with its sentences
- A cancelled slot is free (passed). Judge: agrees with its sentences

Examples run from Starter, the first plan with Live. On Free, your agent writes them and Typestate keeps them.

7 of 8

Your agentTypestateYou

A change collects what Live is behind on

When Sandbox is right, your agent makes a change. It lists every action, record type and web endpoint that differs from Live, with each change to stored data, and Typestate keeps a fingerprint of what is in it. An edit after that makes the change out of date.

Your agent shows you the change and records your approval. A change with an open question, or one that takes payments, you approve yourself in the cockpit.

Back to the 8 stages

Bookings for repair slots

  • ActionBook A Slotadded
  • Record typeBookingadded
  • Web endpointPOST /bookingsadded

Kept by your agent, read when you can

Step 1 of Book A Slot. Your agent kept it and gave this reason: The owner said a cancelled booking frees the slot.

No open questionsApprove and go Live

8 of 8

Typestate

Live answers your customers, and the code stays on view

Approving starts the deploy. Live has its own address, such as repairs--leipzig-bikes.typestate.live, and its own database, and it runs on Cloudflare close to whoever calls it.

Typestate records every run with each step it took and how long the step took. The code stays on the action's Code tab, read only, as evidence of what runs.

Back to the 8 stages

Request

POST /bookings
{ "slot": "2026-10-17T10:00",
  "name": "Ana", "email": "ana@example.com" }

Steps

1 Counted the bookings of the slot4 ms
2 Stored the booking11 ms
3 Answered1 ms

Answer

{ "id": "0b5e2c1a-7d4f-4e39-9a51-3c8e2f6b1d07",
  "slot": "2026-10-17T10:00" }

The times are an example.

Start in Sandbox

Free gives your agent Sandbox: it builds, and you try every action at its Sandbox address. Starter runs your examples and opens Live.

Starter: EUR 15 a month (EUR 17.85 incl. VAT).

Choose a plan