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

# Read and Write Files in a Wrenn Capsule

> Access the capsule filesystem via capsule.files. Write text or bytes, read files, list directories, and stream large files without buffering.

The `capsule.files` interface gives you direct access to the capsule's filesystem. You can write source files before running them, read output files after a command finishes, inspect directory trees, and stream large files in and out without buffering them in memory.

## Writing files

`write()` accepts either a string or bytes. When you pass a string, it is UTF-8 encoded automatically. Parent directories are created if they do not exist.

```python theme={null}
# Write a text file
capsule.files.write("/app/main.py", "print('hello from Wrenn')")

# Write bytes
capsule.files.write("/app/data.bin", b"\x00\x01\x02\x03")
```

## Reading files

`read()` returns the file as a UTF-8 string. `read_bytes()` returns the raw bytes.

```python theme={null}
content = capsule.files.read("/app/main.py")   # str
raw = capsule.files.read_bytes("/app/data.bin") # bytes
```

## Checking existence

```python theme={null}
if capsule.files.exists("/app/main.py"):
    print("file is there")
```

## Listing directory contents

`list()` returns a list of `FileEntry` objects representing the immediate children of a directory. Pass `depth` to recurse further.

```python theme={null}
entries = capsule.files.list("/home/user", depth=1)
for entry in entries:
    print(entry.name, entry.type, entry.size)
```

Each `FileEntry` has:

| Field         | Type          | Description                                              |
| ------------- | ------------- | -------------------------------------------------------- |
| `name`        | `str \| None` | Filename (not the full path).                            |
| `path`        | `str \| None` | Full absolute path.                                      |
| `type`        | `str \| None` | `"file"`, `"directory"`, or `"symlink"`.                 |
| `size`        | `int \| None` | File size in bytes (`None` for directories).             |
| `permissions` | `str \| None` | Human-readable permissions string (e.g. `"-rwxr-xr-x"`). |
| `owner`       | `str \| None` | Owner username.                                          |
| `modified_at` | `int \| None` | Last modified time as a Unix timestamp.                  |

## Creating directories

`make_dir()` creates a directory and all required parent directories. It is idempotent — calling it on an existing path does not raise an error.

```python theme={null}
capsule.files.make_dir("/app/data/results")
```

## Removing files and directories

`remove()` deletes a file or directory recursively.

```python theme={null}
capsule.files.remove("/app/old_data")
```

<Warning>
  `remove()` is recursive. Passing a directory path deletes the directory and everything inside it.
</Warning>

## Streaming large files

For files larger than a few megabytes, use the streaming methods to avoid loading the entire file into memory.

### Streaming upload

`upload_stream()` accepts any iterator that yields `bytes` chunks:

```python theme={null}
def read_chunks(path: str, chunk_size: int = 65536):
    with open(path, "rb") as f:
        while chunk := f.read(chunk_size):
            yield chunk

capsule.files.upload_stream("/data/model.bin", read_chunks("/local/model.bin"))
```

### Streaming download

`download_stream()` yields successive byte chunks:

```python theme={null}
with open("/local/output.bin", "wb") as f:
    for chunk in capsule.files.download_stream("/data/output.bin"):
        f.write(chunk)
```

<Tip>
  Use `upload_stream` and `download_stream` for any file over a few MB. Buffering large files in memory can exhaust the host process's heap and cause requests to time out.
</Tip>

## Complete example

```python theme={null}
from wrenn import Capsule

with Capsule(template="minimal", wait=True) as capsule:
    # Set up project structure
    capsule.files.make_dir("/app/data")

    # Write a script
    capsule.files.write("/app/process.py", """
import json, pathlib

data = [{"x": i, "y": i ** 2} for i in range(100)]
pathlib.Path("/app/data/output.json").write_text(json.dumps(data))
print("done")
""")

    # Run it
    capsule.commands.run("python /app/process.py")

    # Check what was produced
    entries = capsule.files.list("/app/data", depth=1)
    for e in entries:
        print(e.name, e.size)  # output.json  <size>

    # Read it back
    content = capsule.files.read("/app/data/output.json")
    print(content[:80])

    # Stream a large result file back to disk
    with open("/tmp/output.json", "wb") as f:
        for chunk in capsule.files.download_stream("/app/data/output.json"):
            f.write(chunk)
```
