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

# Files

> Read, write, and manage files on a sandbox's filesystem

Every sandbox exposes a filesystem API under `/v1/sandbox/{sandbox_id}/fs`. All operations take a `sandbox_id` and, where they act on a path, a `path` query parameter.

> [!NOTE]
>
> Read and write bodies are **raw bytes** (`application/octet-stream`) — not tar archives, not multipart form data. Each call moves exactly one file's contents.

## Reading a file

```
GET /v1/sandbox/{sandbox_id}/fs/read
```

**path** `string` *required*

Path to the file.

Returns `200` with the raw file contents as `application/octet-stream`.

```shell cURL theme={null}
curl -s "https://api.bonya.ai/v1/sandbox/$SANDBOX_ID/fs/read?path=/workspace/hello.txt" \
  -H "Authorization: Bearer $BONYA_API_KEY" \
  -o ./hello.downloaded.txt
```

```shell CLI theme={null}
bonya fs read $SANDBOX_ID /workspace/hello.txt
```

```ts TypeScript theme={null}
const payload = await sandbox.readFile("/workspace/hello.txt");
```

```python Python theme={null}
payload = sandbox.read_file("/workspace/hello.txt")
```

```go Go theme={null}
payload, err := sandbox.ReadFile(ctx, "/workspace/hello.txt")
```

**MCP:** `fs_read` returns the file's contents as a UTF-8 string, since MCP tool calls carry inline text rather than binary bytes.

## Writing a file

```
PUT /v1/sandbox/{sandbox_id}/fs/write
```

**path** `string` *required*

Path to write to.

The request body is the raw file contents (`application/octet-stream`). Returns `204` on success — no response body.

```shell cURL theme={null}
curl -s -X PUT "https://api.bonya.ai/v1/sandbox/$SANDBOX_ID/fs/write?path=/workspace/hello.txt" \
  -H "Authorization: Bearer $BONYA_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @./hello.txt
```

```shell CLI theme={null}
bonya fs write $SANDBOX_ID /workspace/hello.txt ./hello.txt
```

```ts TypeScript theme={null}
await sandbox.writeFile("/workspace/hello.txt", "hello\n");
```

```python Python theme={null}
sandbox.write_file("/workspace/hello.txt", "hello\n")
```

```go Go theme={null}
sandbox.WriteFile(ctx, "/workspace/hello.txt", []byte("hello\n"))
```

**MCP:** `fs_write` takes UTF-8 text `content` and creates or overwrites the file, returning `{ ok: true, path, bytes }`.

## Uploading and downloading a local file

There's no dedicated REST endpoint for upload/download — the CLI and SDKs implement it as a local file streamed through the same raw-bytes `fs/read` and `fs/write` endpoints above.

```shell CLI theme={null}
bonya fs upload $SANDBOX_ID ./hello.txt /workspace/hello.txt
bonya fs download $SANDBOX_ID /workspace/hello.txt ./hello.downloaded.txt
```

```ts TypeScript theme={null}
await sandbox.uploadFile("./hello.txt", "/workspace/hello.txt");
await sandbox.downloadFile("/workspace/hello.txt", "./hello.downloaded.txt");
```

```python Python theme={null}
sandbox.upload_file("./hello.txt", "/workspace/hello.txt")
sandbox.download_file("/workspace/hello.txt", "./hello.downloaded.txt")
```

```go Go theme={null}
sandbox.UploadFile(ctx, "./hello.txt", "/workspace/hello.txt")
sandbox.DownloadFile(ctx, "/workspace/hello.txt", "./hello.downloaded.txt")
```

**MCP:** there's no `fs` upload/download tool — MCP tool calls carry inline UTF-8 text, not binary file transfers, so `fs_read`/`fs_write` are the only way to move file contents through MCP.

## Listing a directory

```
GET /v1/sandbox/{sandbox_id}/fs/list
```

**path** `string` *required*

Directory path to list.

Returns `FsListResponse`: `{ "files": [ ...FsFileInfo ] }`.

```shell cURL theme={null}
curl -s "https://api.bonya.ai/v1/sandbox/$SANDBOX_ID/fs/list?path=/workspace" \
  -H "Authorization: Bearer $BONYA_API_KEY"
```

```shell CLI theme={null}
bonya fs ls $SANDBOX_ID /workspace
```

```ts TypeScript theme={null}
const entries = await sandbox.listFiles("/workspace");
```

```python Python theme={null}
entries = sandbox.list_files("/workspace")
```

```go Go theme={null}
entries, err := sandbox.ListFiles(ctx, "/workspace")
```

**MCP:** `fs_list` returns `{ files: [{ path, name, kind, size, mode, modified_at_unix_nanos }, ...] }`.

## Getting file metadata

```
GET /v1/sandbox/{sandbox_id}/fs/stat
```

**path** `string` *required*

Path to stat.

Returns `FsStatResponse`: `{ "file": { ...FsFileInfo } }`.

```shell cURL theme={null}
curl -s "https://api.bonya.ai/v1/sandbox/$SANDBOX_ID/fs/stat?path=/workspace/hello.txt" \
  -H "Authorization: Bearer $BONYA_API_KEY"
```

```shell CLI theme={null}
bonya fs stat $SANDBOX_ID /workspace/hello.txt
```

```ts TypeScript theme={null}
const info = await sandbox.statFile("/workspace/hello.txt");
console.log(info.kind, info.size);
```

```python Python theme={null}
info = sandbox.stat_file("/workspace/hello.txt")
print(info.kind, info.size)
```

```go Go theme={null}
info, err := sandbox.StatFile(ctx, "/workspace/hello.txt")
fmt.Println(info.Kind, info.Size)
```

**MCP:** `fs_stat` returns `{ file: { path, name, kind, size, mode, modified_at_unix_nanos } }`.

### FsFileInfo fields

**path** `string` *required*

Full path.

**name** `string` *required*

Base name.

**kind** `string` *required*

One of `UNSPECIFIED`, `FILE`, `DIRECTORY`, `SYMLINK`, `OTHER`.

**size** `integer` *required*

Size in bytes.

**mode** `integer` *required*

Permission bits as reported by the guest, 0–4095.

**modified\_at\_unix\_nanos** `integer` *required*

Last-modified time.

## Creating a directory

```
POST /v1/sandbox/{sandbox_id}/fs/mkdir
```

Request body (`FsMkdirRequest`):

**path** `string` *required*

Directory path to create.

Returns `201` on success.

```shell cURL theme={null}
curl -s -X POST "https://api.bonya.ai/v1/sandbox/$SANDBOX_ID/fs/mkdir" \
  -H "Authorization: Bearer $BONYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"path": "/workspace/output"}'
```

```shell CLI theme={null}
bonya fs mkdir $SANDBOX_ID /workspace/output
```

```ts TypeScript theme={null}
await sandbox.mkdirFile("/workspace/output");
```

```python Python theme={null}
sandbox.mkdir_file("/workspace/output")
```

```go Go theme={null}
sandbox.MkdirFile(ctx, "/workspace/output")
```

**MCP:** `fs_mkdir` creates the directory (and any missing parents), returning `{ ok: true, path }`.

## Renaming or moving

```
POST /v1/sandbox/{sandbox_id}/fs/rename
```

Request body (`FsRenameRequest`):

**from** `string` *required*

Source path.

**to** `string` *required*

Destination path.

Returns `200` on success.

```shell cURL theme={null}
curl -s -X POST "https://api.bonya.ai/v1/sandbox/$SANDBOX_ID/fs/rename" \
  -H "Authorization: Bearer $BONYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from": "/workspace/hello.txt", "to": "/workspace/output/hello.txt"}'
```

```shell CLI theme={null}
bonya fs mv $SANDBOX_ID /workspace/hello.txt /workspace/output/hello.txt
```

```ts TypeScript theme={null}
await sandbox.moveFile("/workspace/hello.txt", "/workspace/output/hello.txt");
```

```python Python theme={null}
sandbox.move_file("/workspace/hello.txt", "/workspace/output/hello.txt")
```

```go Go theme={null}
sandbox.MoveFile(ctx, "/workspace/hello.txt", "/workspace/output/hello.txt")
```

**MCP:** `fs_rename` covers this, returning `{ ok: true, from, to }`.

## Deleting

```
DELETE /v1/sandbox/{sandbox_id}/fs
```

**path** `string` *required*

Path to remove.

**recursive** `boolean` (default: false)

Whether to remove a non-empty directory recursively.

Returns `204` on success.

```shell cURL theme={null}
curl -s -X DELETE "https://api.bonya.ai/v1/sandbox/$SANDBOX_ID/fs?path=/workspace/output&recursive=true" \
  -H "Authorization: Bearer $BONYA_API_KEY"
```

```shell CLI theme={null}
bonya fs rm $SANDBOX_ID /workspace/output --recursive
```

```ts TypeScript theme={null}
await sandbox.removeFile("/workspace/output", true);
```

```python Python theme={null}
sandbox.remove_file("/workspace/output", recursive=True)
```

```go Go theme={null}
sandbox.RemoveFile(ctx, "/workspace/output", true) // recursive
```

**MCP:** `fs_delete` covers this — pass `recursive: true` to delete a non-empty directory. Returns `{ ok: true, deleted: path }`.

## Related

> [card] [Sandboxes](https://docs.bonya.ai/concepts/sandboxes.md)

> [card] [Errors](https://docs.bonya.ai/concepts/errors.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.