Runs

View as Markdown

A Run is one execution of a Runtime, from start until it stops or fails. It is the record of that execution.

Every trace, event, recording, and usage entry for the execution is keyed by the Run ID. A Run response exposes that identifier as id; Run-scoped methods take it as runId. Use runtimeId to identify the Runtime that produced the Run.

The runtime controls the Run lifecycle:

  1. Creating an ephemeral runtime normally opens a Run immediately.
  2. Starting a stopped runtime opens a Run and returns its runId.
  3. Browser connections, Tools, ToolCalls, and Agent turns contribute to that Run.
  4. Stopping the runtime ends the Run.
1const runtime = await bctrl.runtimes.create({
2 profile: true,
3 name: "audited-session",
4});
5
6const started = await bctrl.runtimes.start(runtime.id);
7const run = await bctrl.runs.get(started.runId);
8
9console.log(run.id, run.status, run.runtimeId);
10
11await bctrl.runtimes.stop(runtime.id);

Find Runs

List Runs for a Space or read one by ID:

1const page = await bctrl.runs.list({
2 spaceId: "default",
3});
4
5for await (const run of bctrl.runs.iter({ spaceId: "default" })) {
6 console.log(run.id, run.status, run.startedAt);
7}
8
9const one = await bctrl.runs.get(runId);

Run status is active, stopped, or failed. A failed Run includes a failure code and message when the platform has one.

Run fields

FieldTypeAlways presentDescription
idRunIdYesUnique Run identifier.
spaceIdstringYesSpace that owns the Run.
runtimeIdRuntimeIdYesRuntime that produced the Run.
runtimeType"browser" | "desktop" | "spreadsheet"YesRuntime category recorded for the Run. The SDK currently creates browser Runtimes.
status"active" | "stopped" | "failed"YesCurrent Run state.
createdAtstringYesCreation timestamp in ISO 8601 format.
startedAtstringYesStart timestamp in ISO 8601 format.
finishedAtstring | nullYesCompletion timestamp, if finished.
durationSecondsnumber | nullYesRun duration, if available.
failureRunFailure | nullYesFailure code and message, if failed.
recording{ enabled: boolean }YesWhether recording was enabled.
counts{ events: number; files: number; spans: number }YesRelated resource counts.
usageRunUsageNoUsage totals when available.
1type Run = {
2 id: string;
3 spaceId: string;
4 runtimeId: string;
5 runtimeType: "browser" | "desktop" | "spreadsheet";
6 status: "active" | "stopped" | "failed";
7 createdAt: string;
8 startedAt: string;
9 finishedAt: string | null;
10 durationSeconds: number | null;
11 failure: RunFailure | null;
12 recording: { enabled: boolean };
13 counts: { events: number; files: number; spans: number };
14 usage?: RunUsage;
15};

Runtime and Run are different

The Runtime is the durable automation resource. The Run is one session of that Runtime. An ephemeral Runtime normally has one Run; a profile-backed Runtime can have many Runs over its lifetime.

Use the Run ID when you need to inspect the trace, read raw events, follow live activity, review an audit record, or connect files and artifacts to one execution.

Trace and events

BCTRL exposes two complementary views of a Run:

SurfaceWhat it containsBest for
TraceHierarchical spans with a kind, status, timing, and parentUnderstanding causal work such as a ToolCall inside an Agent turn
EventsRaw point-in-time facts from the control plane, runtime, browser, or connectionDebugging low-level runtime behavior
Run streamA resumable SSE stream of trace and event framesBuilding live progress or monitoring

Read the trace

1const tracePage = await bctrl.runs.trace.list(runId, {
2 kind: ["tool", "browser"],
3 status: ["succeeded", "failed"],
4});
5
6for await (const span of bctrl.runs.trace.iter(runId)) {
7 console.log(span.kind, span.name, span.status, span.parentId);
8}

Trace spans can have these kinds:

runtime, agent, tool, llm, browser, network, file, and system.

parentId connects nested spans into a causal tree. Use resourceType and resourceId to connect a span back to a runtime, ToolCall, Agent turn, file, or other platform resource.

Read raw events

1const eventsPage = await bctrl.runs.events.list(runId);
2
3for await (const event of bctrl.runs.events.iter(runId)) {
4 console.log(event.timestamp, event.source, event.type, event.data);
5}

Events include a source such as control-plane, browser-host, runtime-agent, gateway, cdp, or webdriver. They may reference the trace span that caused the event through spanId.

Trace and event fields

SurfaceImportant fields
Trace spanid, kind, name, status, parentId, resourceType, resourceId, startedAt, finishedAt, durationMs, data
Run eventid, runId, timestamp, source, type, spanId, pageId, data

Trace kind is one of runtime, agent, tool, llm, browser, network, file, or system. Event source identifies where the fact came from.

1type TraceSpan = {
2 id: string;
3 runId: string;
4 kind: "runtime" | "agent" | "tool" | "llm" | "browser" | "network" | "file" | "system";
5 name: string;
6 status: "queued" | "running" | "requires_input" | "suspended" | "succeeded" | "failed" | "cancelled" | "timed_out";
7 parentId: string | null;
8 resourceId: string | null;
9 resourceType: "run" | "runtime" | "tool_call" | "agent_turn" | "message" | "file" | "artifact" | "connection" | null;
10 startedAt: string | null;
11 finishedAt: string | null;
12 durationMs: number | null;
13 data: Record<string, unknown>;
14};
15
16type RunEvent = {
17 id: string;
18 runId: string;
19 timestamp: string;
20 source: "control-plane" | "browser-host" | "runtime-agent" | "gateway" | "cdp" | "webdriver";
21 type: string;
22 spanId: string | null;
23 pageId: string | null;
24 data: Record<string, unknown>;
25};

Stream a Run

The unified stream emits normalized frames as the Run changes:

1for await (const item of bctrl.runs.stream(runId, {
2 include: ["trace", "events"],
3})) {
4 switch (item.type) {
5 case "span.started":
6 case "span.updated":
7 case "span.completed":
8 console.log(item.type, item.span.name, item.span.status);
9 break;
10 case "runtime.event":
11 console.log(item.event.type, item.event.data);
12 break;
13 case "run.ended":
14 console.log("Run ended:", item.status);
15 break;
16 }
17}

For a reconnect, pass the last received stream ID as after so the server can continue from that point. The stream ends when the Run ends.

Use trace to answer “what work caused this result?”, events to answer “what did the runtime report?”, and the stream to answer “what is happening now?”.

See Connect with CDP for attaching a browser client to the active Run.