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

# Filesystem

> Read, write, list, rename, remove, and watch files inside a sandbox using sbx.files in the TypeScript SDK.

```typescript theme={null}
import { Sandbox } from '@declaw/sdk';
import type { EntryInfo, WriteInfo, WriteEntry, FilesystemEvent } from '@declaw/sdk';
```

`sbx.files` is the `Filesystem` instance available on every `Sandbox`. All paths must be absolute paths within the sandbox filesystem.

## `sbx.files.read()`

Read a file's content as a string.

```typescript theme={null}
const content: string = await sbx.files.read('/home/user/script.py');
console.log(content);
```

<ParamField body="path" type="string" required>
  Absolute path inside the sandbox.
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context for the read operation.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<string>`

***

## `sbx.files.write()`

Write content to a file, creating parent directories automatically.

```typescript theme={null}
const info: WriteInfo = await sbx.files.write(
  '/home/user/hello.ts',
  'console.log("hello from sandbox");',
);
console.log(info.path, info.size);
```

<ParamField body="path" type="string" required>
  Absolute destination path.
</ParamField>

<ParamField body="data" type="string | Uint8Array" required>
  Content to write. Accepts a string or a `Uint8Array` (decoded as UTF-8).
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<WriteInfo>`

***

## `sbx.files.writeFiles()`

Write multiple files in a single batch request.

```typescript theme={null}
const results: WriteInfo[] = await sbx.files.writeFiles([
  { path: '/home/user/main.ts', data: 'console.log("main")' },
  { path: '/home/user/data.json', data: '{"key": "value"}' },
]);
```

<ParamField body="files" type="WriteEntry[]" required>
  Array of `WriteEntry` objects. Each has `path` (string) and `data` (string
  or `Uint8Array`).
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context applied to all files.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<WriteInfo[]>`

***

## `sbx.files.list()`

List entries in a directory.

```typescript theme={null}
const entries: EntryInfo[] = await sbx.files.list('/home/user', { depth: 2 });
for (const entry of entries) {
  console.log(entry.type, entry.path, entry.size);
}
```

<ParamField body="path" type="string" required>
  Absolute path to the directory.
</ParamField>

<ParamField body="opts.depth" type="number" default="1">
  Recursion depth. `1` lists only immediate children.
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<EntryInfo[]>`

***

## `sbx.files.exists()`

Check whether a path exists.

```typescript theme={null}
const exists: boolean = await sbx.files.exists('/home/user/output.csv');
if (exists) {
  const csv = await sbx.files.read('/home/user/output.csv');
}
```

<ParamField body="path" type="string" required>
  Absolute path to check.
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<boolean>`

***

## `sbx.files.getInfo()`

Get metadata about a file or directory.

```typescript theme={null}
const info: EntryInfo = await sbx.files.getInfo('/home/user/script.py');
console.log(info.name, info.type, info.size);
```

<ParamField body="path" type="string" required>
  Absolute path to query.
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<EntryInfo>`

***

## `sbx.files.remove()`

Remove a file or directory.

```typescript theme={null}
await sbx.files.remove('/home/user/temp.txt');
```

<ParamField body="path" type="string" required>
  Absolute path to remove.
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<void>`

***

## `sbx.files.rename()`

Rename or move a file or directory.

```typescript theme={null}
const moved: EntryInfo = await sbx.files.rename(
  '/home/user/draft.ts',
  '/home/user/final.ts',
);
```

<ParamField body="oldPath" type="string" required>
  Current absolute path.
</ParamField>

<ParamField body="newPath" type="string" required>
  New absolute path. Can be in a different directory (move semantics).
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<EntryInfo>` for the renamed entry.

***

## `sbx.files.makeDir()`

Create a directory (including parent directories if needed).

```typescript theme={null}
const created: boolean = await sbx.files.makeDir('/home/user/output/results');
```

<ParamField body="path" type="string" required>
  Absolute path of the directory to create.
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<boolean>` — `true` if the directory was created.

***

## `sbx.files.watchDir()`

Watch a directory for filesystem change events.

```typescript theme={null}
const handle = await sbx.files.watchDir('/home/user/data', {
  recursive: true,
});
```

<ParamField body="path" type="string" required>
  Absolute path of the directory to watch.
</ParamField>

<ParamField body="opts.user" type="string" default="'user'">
  Unix user context.
</ParamField>

<ParamField body="opts.recursive" type="boolean" default="false">
  Whether to watch subdirectories recursively.
</ParamField>

<ParamField body="opts.requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<WatchHandle>`

***

## Data models

### `EntryInfo`

```typescript theme={null}
interface EntryInfo {
  name: string;    // Filename or directory name
  path: string;    // Full absolute path
  type: FileType;  // 'file' or 'dir'
  size: number;    // Size in bytes (0 for directories)
}
```

### `FileType`

```typescript theme={null}
enum FileType {
  File = 'file',
  Dir  = 'dir',
}
```

### `WriteInfo`

```typescript theme={null}
interface WriteInfo {
  path: string;  // Absolute path of the written file
  size: number;  // Bytes written
}
```

### `WriteEntry`

```typescript theme={null}
interface WriteEntry {
  path: string;            // Absolute destination path
  data: string | Uint8Array; // Content to write
}
```

### `FilesystemEvent`

```typescript theme={null}
interface FilesystemEvent {
  type: FilesystemEventType;
  path: string;
  timestamp?: number;
}
```

### `FilesystemEventType`

```typescript theme={null}
enum FilesystemEventType {
  Create = 'create',
  Write  = 'write',
  Remove = 'remove',
  Rename = 'rename',
  Chmod  = 'chmod',
}
```

### `WatchHandle`

```typescript theme={null}
class WatchHandle {
  /** Stop accepting new events. Idempotent. */
  stop(): void;

  /** Drain and return all events buffered since the last call. */
  getNewEvents(): FilesystemEvent[];
}
```

The handle uses a poll-and-drain model — call `getNewEvents()` to pull
buffered events. There is no async iterator or callback subscription.

***

## Examples

### Upload and run a script

```typescript theme={null}
await sbx.files.write('/home/user/analyze.ts', `
  const data = [1, 2, 3, 4, 5];
  const sum = data.reduce((a, b) => a + b, 0);
  console.log('Sum:', sum);
`);

const result = await sbx.commands.run('npx ts-node /home/user/analyze.ts');
console.log(result.stdout);
```

### Batch upload a dataset

```typescript theme={null}
import { readFileSync, readdirSync } from 'fs';

const entries = readdirSync('./dataset').map((name) => ({
  path: `/data/${name}`,
  data: readFileSync(`./dataset/${name}`),
}));

await sbx.files.writeFiles(entries);
```

### Download generated output

```typescript theme={null}
await sbx.commands.run("node -e \"require('fs').writeFileSync('/tmp/out.csv','a,b\\n1,2')\"");
const csv = await sbx.files.read('/tmp/out.csv');
console.log(csv); // "a,b\n1,2"
```

### Check and create directories

```typescript theme={null}
const outputDir = '/home/user/results';
if (!(await sbx.files.exists(outputDir))) {
  await sbx.files.makeDir(outputDir);
}
await sbx.files.write(`${outputDir}/result.txt`, 'analysis complete');
```
