> ## Documentation Index
> Fetch the complete documentation index at: https://s2.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Studio

> S2 Studio is a browser-based data plane explorer built into the dashboard for reading and writing stream records interactively.

## Overview

Studio lets you:

* **Read** records from any stream, starting from a tail offset, sequence number, or timestamp
* **Stream** records live as they arrive
* **Append** records individually, line-by-line, or as a JSON array
* **Trim** records up to a sequence number to reclaim storage
* **Fence** a stream to enforce exclusive write access

***

## Opening Studio

Navigate to any basin in the dashboard, then click **Studio** in the stream list header. You can also switch basins and streams directly from within Studio using the selectors at the top.

<img src="https://mintcdn.com/streamstore/0pAUJuHAWw3coDj0/images/studio-1.png?fit=max&auto=format&n=0pAUJuHAWw3coDj0&q=85&s=78faed598ce2a2ce6741c0160f942bd6" width="3020" height="1532" data-path="images/studio-1.png" />

***

## Connection

By default, Studio connects to S2. You can override this to point at [s2-lite](/s2-lite) for local development.

Click the **connection badge** in the top-right header to open the connection settings.

<img src="https://mintcdn.com/streamstore/0pAUJuHAWw3coDj0/images/studio-3.png?fit=max&auto=format&n=0pAUJuHAWw3coDj0&q=85&s=cb4c409a1fd2f94fa5b2b2f8770aa2c4" width="994" height="760" data-path="images/studio-3.png" />

### Connecting to s2-lite

<Steps>
  <Step title="Start s2-lite with TLS">
    Run s2-lite with a self-signed certificate so the browser can connect over HTTPS:

    ```bash theme={null}
    s2 lite --local-root /tmp/s2-data --tls-self
    ```

    Lite listens on `https://localhost` (port 443) by default.
  </Step>

  <Step title="Set the connection endpoint">
    In the connection popover, click **Use Lite**. This pre-fills both endpoints with `https://localhost`.

    <img src="https://mintcdn.com/streamstore/0pAUJuHAWw3coDj0/images/studio-2.png?fit=max&auto=format&n=0pAUJuHAWw3coDj0&q=85&s=8ea9bc60ccd87392428b162e552c40f4" width="1198" height="920" data-path="images/studio-2.png" />
  </Step>

  <Step title="Trust the certificate">
    Since Lite uses a self-signed certificate, you need to trust it in your browser once.

    The popover will show a prompt — click **Open [https://localhost](https://localhost)** to open it in a new tab, then accept the browser security warning.

    <Note>
      After accepting the cert, come back to Studio and click **Save** to apply the connection. The page will reload and connect to your local Lite instance.
    </Note>
  </Step>
</Steps>

<Tip>
  s2-lite sends permissive CORS headers by default, allowing the dashboard to connect from any origin. Use `--no-cors` to disable this in stricter deployments.
</Tip>

***

## Read

The **Read** tab lets you fetch records from the selected stream.

<img src="https://mintcdn.com/streamstore/0pAUJuHAWw3coDj0/images/studio-4.png?fit=max&auto=format&n=0pAUJuHAWw3coDj0&q=85&s=51e991f06961f61119298b636d86fdb4" width="2502" height="1338" data-path="images/studio-4.png" />

| Field                      | Description                                                                                             |
| -------------------------- | ------------------------------------------------------------------------------------------------------- |
| **Start from**             | How to anchor the read position: tail offset, sequence number, or timestamp                             |
| **Tail offset**            | Number of records back from the stream tail (e.g. `10` = last 10 records)                               |
| **Sequence number**        | Absolute sequence number of the first record to read                                                    |
| **Timestamp**              | Start from the first record at or after this time                                                       |
| **Limit**                  | Maximum records to return per batch (up to 1000)                                                        |
| **Wait (s)**               | Seconds to hold a streaming connection open at the tail before stopping. `0` stops immediately at tail. |
| **Clamp to tail**          | If the start position is beyond the tail, clamp to tail instead of erroring                             |
| **Ignore command records** | Filter out fence and trim command records i.e. only data records are returned                           |

### Read Once vs Stream

* **Read Once** — fetches a single batch with the current settings
* **Stream** — opens a continuous session that delivers records as they arrive

***

## Append

The **Append** tab lets you write records to the selected stream.

<img src="https://mintcdn.com/streamstore/0pAUJuHAWw3coDj0/images/studio-5.png?fit=max&auto=format&n=0pAUJuHAWw3coDj0&q=85&s=9dc05548c24954f153c9767b0ee8876d" width="2506" height="1344" data-path="images/studio-5.png" />

### Input modes

| Mode             | Behavior                                                    |
| ---------------- | ----------------------------------------------------------- |
| **Single body**  | The entire payload is sent as one record                    |
| **One per line** | Each non-empty line becomes a separate record               |
| **JSON array**   | Parse payload as a JSON array of `{body, headers?}` objects |

You can also **load a file** directly into the editor — the input mode is auto-detected from the file extension (`.json` → JSON array, `.jsonl`/`.ndjson` → one per line, `.txt` → single body).

### Optional fields

| Field                     | Description                                                                              |
| ------------------------- | ---------------------------------------------------------------------------------------- |
| **Match Sequence Number** | Only append if the stream tail matches this sequence number.                             |
| **Fencing token**         | Required if the stream has a fencing token set. Must match exactly (max 36 bytes UTF-8). |

### Commands

| Command                | Description                                                                                                           |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **Trim through seq #** | Discard all records up to and including this sequence number.                                                         |
| **Fence**              | Set a new fencing token (max 36 bytes). Once set, all appends must supply this token to enforce single-writer access. |
