MidstreamDocs
Start here

Scene, Capture, Instance, Deploy

The four words Midstream uses for the four things it makes, and how they nest.

Midstream has four nouns, and they form a strict hierarchy: each one is a materialization of the one above it. Learning them takes about five minutes and makes the rest of this knowledgebase read straight through.

The four words

WordWhat it is
SceneThe moment in a user flow that you mark in a test. A scene is an idea — "the cart with items in it" — and exists independently of any branch or commit. This is the word you will use most.
CaptureA scene as it stood on one commit. CI ran your test at commit a1b2c3d and captured the moment. One scene has many captures; every capture belongs to exactly one scene.
InstanceA live, interactive copy of a capture that someone can open and use. One capture can back many instances — each reviewer gets their own.
DeployOne attempt to stand an instance up: clone, install, start, run the test to the scene. A deploy has a status and its own logs.

Any sentence you write with these words should read as naturally as this:

Mark a scene in your test. Each branch that runs CI produces a capture. Share it and each person gets their own live instance. If a deploy fails, read that deploy's logs.

One scene, end to end

Here is a single scene, followed from the test file to a reviewer's browser.

You mark the scene

In tests/cart.spec.ts:

import { test, expect } from "@playwright/test";
import { midstreamScene } from "@midstream/sdk/playwright";

test.describe("Cart", () => {
  test("shows the items a shopper has added", async ({ page }) => {
    await page.goto("/products/espresso-beans");
    await page.getByRole("button", { name: "Add to cart" }).click();
    await page.goto("/cart");
    await expect(
      page.getByRole("heading", { name: "Your cart" }),
    ).toBeVisible();

    await midstreamScene(page, "cart-with-items");
  });
});

The scene is cart-with-items. That slug is its identity: as long as the slug stays the same, everything Midstream records about this moment accumulates under one scene. Rename the slug and you have started a different scene.

Nothing exists yet. On your laptop this line does nothing.

CI makes the first capture

You push to add-cart-badge, and your test suite runs in CI. When the test reaches the scene call, the SDK records a capture of cart-with-items at that commit:

  • a screenshot of the page,
  • an accessibility snapshot of the page — the structure and text, which is what Midstream compares to tell whether a scene actually changed,
  • the test file (tests/cart.spec.ts) and the chain of titles that led here (Cartshows the items a shopper has added),
  • the commit, and the branch CI reported.

The capture holds no session data. No cookies, no local storage — those are captured later, when someone opens the scene.

Your pull request now gets a Midstream check and a link into Midstream's view of that pull request, listing cart-with-items among the scenes the change touches.

The same scene, a second capture

A teammate is fixing something else in the cart on fix-cart-totals. Their CI run captures cart-with-items too. Same scene, second capture.

That is the point of the split. The scene is what you both mean; a capture is what each branch made of it. Nothing collides, and either capture can be opened on its own.

A reviewer opens an instance

A reviewer clicks the scene in the pull-request view. Midstream resolves it to their instance of that capture — creating it if this is their first look — and sends them to the address it lives at, a subdomain of midstream.studio.

An instance belongs to one person. Two reviewers of the same pull request are clicking around two separate copies of your app, so one filling in a form does not disturb the other. An instance keeps its identity over time: it is the same instance tomorrow, even though the container underneath it was thrown away and rebuilt in between.

Standing it up is a deploy

Behind the loading page, one deploy is running:

  1. Clone your repository at that capture's commit.
  2. Run your install command.
  3. Run your start command and wait for your app to answer.
  4. Run tests/cart.spec.ts, narrowed to that test, up to the scene call.
  5. At the scene call, take the browser session as it stands — the current URL, cookies, local storage, session storage — and hand it to the reviewer's browser.

Then the reviewer is in the cart, with items in it, on the branch under review.

The first deploy of an instance does all five steps and takes minutes. Later ones skip the work that is already done, so they are quick. A deploy is a routine, forgettable event — a word deliberately chosen to be undramatic. It matters only when one fails, and then you read that deploy's logs.

How they nest

  • One scene has many captures — one for each commit whose CI run reached the scene call.
  • One capture backs many instances — normally one per person who opens it, plus one per set of parameter values if the scene takes parameters.
  • One instance goes through many deploys over its life — the first one, and another every time it has to be rebuilt.

The set of a scene's instances has no name of its own. It is a relationship, not a thing you reason about, so just say "the scene's instances".

Where you meet these words in code

The same four words run all the way down, so what you read here is what you type and what you see on the wire:

WhereWhat it looks like
Your test filemidstreamScene(page, "cart-with-one-item")
API paths/api/v1/captures, /api/v1/instances, /api/v1/instances/{id}/deploys
Webhook eventscapture.created, instance.ready, instance.deploy-failed
Your pull requestsA check named Midstream Scenes, counting the scenes the change touches

Two words we do not use as nouns, in this knowledgebase or in the app: "checkpoint" and "demo". Nothing in Midstream is "a demo" — a scene is part of your real product, which is the whole argument for looking at one.