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

# Filesystem

> Read, write, upload, download, search, and watch machine files.

`machine.files` manages files inside one machine. `/workspace` is the default
mutable work tree, but general filesystem APIs also accept valid machine-scoped
absolute paths such as `/tmp/result.txt`, `/context/input.json`, and
`/srv/app/config.json`.

## Read and write

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
from nullspace import Machine

with Machine.create() as machine:
    machine.files.write("/workspace/hello.txt", "hello\n")
    machine.files.write_files([
        ("/workspace/a.txt", "a\n"),
        ("/workspace/b.txt", "b\n"),
    ])
    print(machine.files.read("/workspace/hello.txt"))
    print(machine.files.read("/workspace/hello.txt", format="bytes"))
    print(machine.files.list("/workspace"))
```

Use `format="stream"` for large downloads:

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
for chunk in machine.files.read("/workspace/large.log", format="stream"):
    process_chunk(chunk)
```

Migration note:

No breaking change: `/workspace` is still the default mutable work tree.
General filesystem APIs also accept valid machine-scoped absolute paths such as
`/srv/app/...`; reserved runtime paths under
`/workspace/.nullspace` are rejected.

## Upload and download

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
machine.files.upload("./local.txt", "/workspace/local.txt")
machine.files.upload_dir("./src", "/workspace/src", max_concurrency=4)
machine.files.upload_file(
    "./large.bin",
    "/data/large.bin",
    resumable=True,
    checksum="auto",
    spool_to_disk="auto",
)
url = machine.files.download_url("/workspace/local.txt")
print(url)
```

## Metadata and search

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
info = machine.files.info("/workspace/local.txt")
exists = machine.files.exists("/workspace/local.txt")
matches = machine.files.search_files("/workspace", "*.txt")
print(info.path, exists, matches)
```

Other management helpers include `make_dir()`, `rename()`, `remove()`,
`set_permissions()`, and `get_info()` as an alias for `info()`.

## Replace and watch

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
paths = machine.files.search_files("/workspace", "*.py")
count = machine.files.replace_in_files(paths, "old_name", "new_name")
print(count)

def on_event(event):
    print(event.type, event.path)

with machine.files.watch_dir("/workspace", on_event, recursive=True, timeout=30):
    machine.files.write("/workspace/changed.txt", "changed\n")
```

Most file helpers accept `user=` when paths should be resolved for a specific
machine user.

## Async API

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
from nullspace import AsyncMachine

async with await AsyncMachine.create(template="base") as machine:
    await machine.files.write("/workspace/hello.txt", "hello\n")
    text = await machine.files.read("/workspace/hello.txt")
    matches = await machine.files.search_files("/workspace", "*.txt")
    print(text, matches)
```

Async file uploads, signed URLs, replace, and watch helpers mirror the
synchronous `machine.files` API.

Concept: [Exec](../../concepts/exec). API reference:
[listDir](../../api-reference), [readFile](../../api-reference),
[writeFile](../../api-reference), [uploadUrl](../../api-reference), and
[downloadUrl](../../api-reference).
