> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://platform.bctrl.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://platform.bctrl.ai/_mcp/server.

# Views

> Give people a scoped way to watch or control automation.

A **View** is a human-facing surface for automation. It can show a live
Runtime, a completed Run, trace and event data, or a place for a person to
respond when automation needs help.

The **Run** remains the machine-readable record. The View is the interface a
person uses to observe or influence that execution. This pattern is commonly
called **live supervision** or **human-in-the-loop control**.

## Create a View

Create a hosted View for one Run:

```ts
const view = await bctrl.views.create({
  scope: { runId },
  bell: true,
  control: true,
  recordings: true,
  trace: true,
  events: false,
});

console.log(view.id);
console.log(view.url);
```

`scope` is required. `bell`, `control`, `recordings`, `trace`, and `events` are
the canonical capability fields. `bell`, `control`, `recordings`, and `trace`
default to `true`; `events` defaults to `false`. `presentation` defaults to
hosted (`{ mode: "hosted" }`). `expiresInSeconds` defaults to `28_800` (8 hours)
and accepts up to `2_592_000` (30 days).

## Choose a scope

The scope determines what automation the View can show:

| Scope                     | Use it for                                  |
| ------------------------- | ------------------------------------------- |
| `{ spaceId }`             | A Space-level workspace view                |
| `{ spaceId, runtimeIds }` | A Space view limited to selected Runtimes   |
| `{ runtimeId }`           | One durable Runtime and its current session |
| `{ runId }`               | One execution and its history               |

For a Space scope, `runtimeIds` is optional and may contain up to 50 unique
Runtime IDs. A View must use exactly one of `spaceId`, `runtimeId`, or `runId`.

## Choose capabilities

Each capability grants the View access to a surface. Omit a capability to use
its default:

| Capability   | Default | What it enables                                                   |
| ------------ | ------- | ----------------------------------------------------------------- |
| `bell`       | `true`  | In-View notification and action center                            |
| `control`    | `true`  | Live browser interaction and actions from the notification center |
| `recordings` | `true`  | Runtime recordings                                                |
| `trace`      | `true`  | Runtime traces                                                    |
| `events`     | `false` | Runtime event history                                             |

Create a supervised View when a person should be able to act:

```ts
const supervised = await bctrl.views.create({
  scope: { runtimeId },
  bell: true,
  control: true,
  recordings: false,
  trace: true,
  events: false,
});
```

The legacy `components` object is accepted as a deprecated compatibility input,
but new integrations should use the capability booleans above.

## Hosted and embedded Views

Hosted Views open at the returned URL:

```ts
const hosted = await bctrl.views.create({
  scope: { runId },
  presentation: { mode: "hosted" },
});

console.log(hosted.url);
```

Use an embedded View when you want to place the surface inside your own
application. `allowedOrigins` must contain exact HTTPS origins. HTTP is allowed
only for localhost development:

```ts
const embedded = await bctrl.views.create({
  scope: { runtimeId },
  bell: false,
  control: false,
  recordings: true,
  trace: true,
  events: false,
  presentation: {
    mode: "embedded",
    allowedOrigins: ["https://app.example.com"],
  },
});
```

The View token is returned only when the View is created. Treat it as a
short-lived bearer credential: do not log it or expose it outside the intended
viewer. Use `expiresInSeconds` to set a shorter lifetime. It defaults to 28,800
seconds (8 hours) and the maximum is 2,592,000 seconds (30 days).

## Live and recording sessions

When you need a short-lived session URL for a live browser or a recording, use
the token returned during creation:

```ts
const session = await bctrl.views.createSession(
  view.id,
  { runId, surface: "live" },
  view.token,
);

console.log(session.url, session.expiresAt);
```

`surface` is `"live"` or `"recording"`. A recording can be unavailable when
recording was disabled for the Run.

## View fields

| Field          | Type               | Always present | Description                                                          |
| -------------- | ------------------ | -------------- | -------------------------------------------------------------------- |
| `id`           | `string`           | Yes            | Public View identifier.                                              |
| `scope`        | `ViewScope`        | Yes            | Space, Runtime, or Run the View can access.                          |
| `components`   | `ViewComponents`   | Yes            | Surfaces enabled for this View.                                      |
| `presentation` | `ViewPresentation` | Yes            | Delivery mode: hosted or embedded.                                   |
| `branding`     | `ResolvedBranding` | Yes            | Account branding resolved for this View.                             |
| `createdAt`    | `string`           | Yes            | Creation timestamp.                                                  |
| `expiresAt`    | `string`           | Yes            | Time after which the View is no longer available.                    |
| `url`          | `string`           | No             | Returned only in the create response.                                |
| `token`        | `string`           | No             | Returned only in the create response; short-lived bearer credential. |

The response `components` field is the normalized, persisted capability map; it
is not the shape used by the canonical create request. It can contain `live`,
`inputs`, `recordings`, `trace`, and `events` entries.

| Response component | Shape                            | What it represents                                              |
| ------------------ | -------------------------------- | --------------------------------------------------------------- |
| `live`             | `{ control: "none" \| "input" }` | Live Runtime display and optional interaction                   |
| `inputs`           | `{ respond: boolean }`           | Visibility of Agent or Tool input requests and response actions |
| `recordings`       | `{}`                             | Run recording playback                                          |
| `trace`            | `{}`                             | Structured Run trace                                            |
| `events`           | `{}`                             | Raw Run events                                                  |

`token` and `url` are available on the create response. List and get return the
View resource without the token.

## Manage Views

```ts
for await (const item of bctrl.views.iter()) {
  console.log(item.id, item.expiresAt);
}

const current = await bctrl.views.get(view.id);
await bctrl.views.delete(view.id); // revoke access immediately
```

Views expire automatically. Delete a View when the viewer should lose access
before its expiration time.

## View, Run, and Conversation

| Resource         | Answers                             |
| ---------------- | ----------------------------------- |
| **View**         | What can a person see or control?   |
| **Run**          | What happened during one execution? |
| **Conversation** | What has the user and Agent said?   |

Use [Runs](/sdk/runs) for durable observability and [Conversations](/sdk/conversations)
for persistent Agent interaction. Use a View when that information or control
needs to be presented to a person.