> 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.

# Files

> Store, transfer, and inspect durable files across Spaces, Runtimes, and Runs.

A **File** is durable storage owned by a Space. It can be uploaded by your
application, produced by a Runtime, or exported from a Run. The File resource
is the durable record; a Runtime workspace is only the live machine disk used
while automation is running.

## Three file surfaces

| Surface           | Use it for                                        | SDK entry point                       |
| ----------------- | ------------------------------------------------- | ------------------------------------- |
| Durable Files     | Upload, list, download, rename, and delete files  | `bctrl.files`                         |
| Runtime workspace | Move a durable File into or out of a live Runtime | File Tools                            |
| Run files         | Inspect files attached to one Run or export them  | `bctrl.runs.files` and Run File Tools |

Files produced by a Runtime can be collected into durable storage and remain
available after the Run ends. Files staged into a Runtime are copies for that
Runtime workspace; staging does not move or delete the durable File.

## Upload a File

The Space can be omitted to use the caller’s default Space:

```ts
const file = await bctrl.files.upload({
  file: new Blob(["name,email\nada@acme.com"]),
  name: "contacts.csv",
  path: "imports/2026/contacts.csv",
  metadata: { source: "crm" },
});

console.log(file.id, file.path, file.source);
```

`file` is a `Blob`. `name`, `path`, and `metadata` are optional. Use
`spaceId` when uploading to a Space other than the caller’s default:

```ts
await bctrl.files.upload({
  spaceId: "space_production",
  file,
  path: "incoming/report.pdf",
});
```

Paths are relative to the Space’s storage namespace. Use a path prefix to
organize files; absolute paths and `.`/`..` path segments are not allowed.

## List and browse Files

```ts
const page = await bctrl.files.list({
  prefix: "imports/2026/",
  source: "upload",
});

for await (const file of bctrl.files.iter({ type: "download" })) {
  console.log(file.name, file.sizeBytes, file.contentType);
}
```

`list()` returns one cursor page. `iter()` follows all pages automatically.
Available filters are:

| Filter         | Type                    | Description                                                   |
| -------------- | ----------------------- | ------------------------------------------------------------- |
| `spaceId`      | `string`                | Space to search; defaults to the caller’s default Space       |
| `source`       | `"upload" \| "runtime"` | Files uploaded by an application or produced by a Runtime     |
| `path`         | `string`                | Exact file path                                               |
| `prefix`       | `string`                | Path prefix                                                   |
| `q`            | `string`                | Name search                                                   |
| `runId`        | `string`                | Files associated with one Run                                 |
| `runtimeId`    | `string`                | Files associated with one Runtime                             |
| `type`         | `string \| string[]`    | Artifact kind, such as `recording`, `screenshot`, or `export` |
| `createdAfter` | `string`                | Files created after an ISO 8601 timestamp                     |
| `include`      | `"folders"`             | Include immediate child-folder summaries                      |

To render a folder tree, request folder summaries:

```ts
const { data, folders } = await bctrl.files.list({
  prefix: "imports/",
  include: "folders",
});

for (const folder of folders ?? []) {
  console.log(folder.path, folder.fileCount, folder.totalBytes);
}

for (const file of data) {
  console.log(file.path);
}
```

With `include: "folders"`, `data` contains files directly under the requested
prefix and `folders` contains immediate child-folder rollups.

## Read, download, update, and delete

```ts
const file = await bctrl.files.get(fileId);

const response = await bctrl.files.content(file.id);
const bytes = await response.arrayBuffer();

await bctrl.files.update(file.id, {
  name: "contacts-reviewed.csv",
  metadata: { reviewed: true },
});

await bctrl.files.delete(file.id);
```

The File resource also includes `downloadUrl` when you want to download through
the returned URL instead of `files.content()`.

## File fields

| Field         | Type                    | Always present | Description                                 |
| ------------- | ----------------------- | -------------- | ------------------------------------------- |
| `id`          | `string`                | Yes            | Unique File identifier.                     |
| `source`      | `"upload" \| "runtime"` | Yes            | How the File entered durable storage.       |
| `name`        | `string`                | Yes            | Display filename.                           |
| `path`        | `string`                | Yes            | Path within the Space.                      |
| `contentType` | `string`                | Yes            | MIME type.                                  |
| `sizeBytes`   | `number`                | Yes            | File size.                                  |
| `spaceId`     | `string`                | Yes            | Space that owns the File.                   |
| `downloadUrl` | `string`                | Yes            | Download endpoint.                          |
| `runId`       | `string`                | No             | Run that produced the File, when known.     |
| `runtimeId`   | `string`                | No             | Runtime that produced the File, when known. |
| `type`        | `string`                | No             | Artifact kind for produced Files.           |
| `metadata`    | `JsonObject \| null`    | Yes            | Caller-owned metadata.                      |
| `createdAt`   | `string`                | Yes            | Creation timestamp.                         |
| `expiresAt`   | `string`                | No             | Expiration timestamp, when applicable.      |

## Runtime workspace files

Use the built-in File Tools to transfer files through a live Runtime workspace:

```ts
await bctrl.tools.call("runtime.files.stage", {
  fileId: file.id,
  path: "contacts.csv",
}, { runtimeId });

const collected = await bctrl.tools.call("runtime.files.collect", {
  path: "result.json",
}, { runtimeId });

console.log(collected.fileId);
```

See [Stage Runtime file](/sdk/tools/runtime/runtime-files-stage) and
[Collect Runtime file](/sdk/tools/runtime/runtime-files-collect) for the Tool
fields and path rules. Runtime workspace paths are relative to the workspace;
use `path`, not an absolute host path or the old `runtimePath` name.

## Run files

List durable Files attached to one Run:

```ts
const runFiles = await bctrl.runs.files.list(runId);
for (const file of runFiles.data) {
  console.log(file.fileId, file.name, file.size);
}
```

Use [`run.files.export`](/sdk/tools/run/run-files-export) when you want to
combine selected Run files into one durable archive File.

## Next

* [Spaces](/sdk/spaces) — configure the storage namespace available to a Space
* [Runtimes](/sdk/runtimes) — run automation that can produce workspace files
* [Runs](/sdk/runs) — inspect the execution that produced a File