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

# Opus SDK

> Work with files in Opus storage from inside an Opus Code task — download, create, and upload files with the Opus SDK.

The Opus SDK lets you work with files from inside an [Opus Code](/tasks/agent/opus-code) task—download files from Opus storage, create new files, upload files back to storage, and more. Aside from the Opus SDK, you can use a wide range of Python packages; the full list is available in [Available Packages](/opus-sdk/available-packages).

## Setup

Inside an Opus Code task, `Opus` is already defined and ready to use.

## File Operations

All file operations are accessed via `Opus.file`.

### Downloading a File

Use `Opus.file.download(file_url)` to fetch a file from Opus storage by its URL:

```python theme={null}
file = Opus.file.download("https://files.opus.com/path/to/file.pdf")
```

This returns an [OpusFile](#opusfile-interface) object.

<Note>
  Modifications to downloaded files are local only unless uploaded via `Opus.file.upload`, which creates a new file and returns a new URL; the original remote file is never modified.
</Note>

### Getting a Presigned Download URL

Use `Opus.file.presigned_download(file_url, expiry=None)` to get a presigned URL for downloading a file without fetching it locally:

```python theme={null}
url = Opus.file.presigned_download("https://files.opus.com/path/to/file.pdf")
```

You can optionally set a custom expiry (in seconds, between 60 and 86400):

```python theme={null}
url = Opus.file.presigned_download("https://files.opus.com/path/to/file.pdf", expiry=3600)  # 1 hour
```

<Note>
  If no `expiry` is provided, the server default is used.
</Note>

<Warning>
  The `expiry` must be between 60 seconds (1 minute) and 86400 seconds (24 hours). Values outside this range raise `InvalidFileExpiryError`.
</Warning>

### Creating a File

Use `Opus.file.create(file_name, file_type)` to create a new empty file:

```python theme={null}
new_file = Opus.file.create("my_report", "PDF")
```

The first argument is the file name (without extension), the second is the file type. The extension is added automatically based on the type.

This returns an [OpusFile](#opusfile-interface) object.

<Note>
  If the file isn't uploaded via `Opus.file.upload`, the created file won't be persisted.
</Note>

<Warning>
  Creating a file with a name that already exists in the current session raises `FileAlreadyExistsError`.
</Warning>

#### Supported File Types

Pass any of these as the `file_type` argument:

| Type   | Extension | Content Type                        |
| ------ | --------- | ----------------------------------- |
| `JPEG` | `.jpeg`   | `image/jpeg`                        |
| `PNG`  | `.png`    | `image/png`                         |
| `JPG`  | `.jpg`    | `image/jpg`                         |
| `CSV`  | `.csv`    | `text/csv`                          |
| `PDF`  | `.pdf`    | `application/pdf`                   |
| `DOCX` | `.docx`   | `application/vnd.openxmlformats...` |
| `PPTX` | `.pptx`   | `application/vnd.openxmlformats...` |
| `XLS`  | `.xls`    | `application/vnd.ms-excel`          |
| `XLSX` | `.xlsx`   | `application/vnd.openxmlformats...` |
| `TXT`  | `.txt`    | `text/plain`                        |
| `MD`   | `.md`     | `text/markdown`                     |
| `JSON` | `.json`   | `application/json`                  |
| `HTML` | `.html`   | `text/html`                         |
| `XML`  | `.xml`    | `application/xml`                   |

The type is case-insensitive: `"pdf"`, `"PDF"`, and `"Pdf"` all work.

### Uploading a File

Use `Opus.file.upload(file, access_scope="all")` to upload an [OpusFile](#opusfile-interface) to Opus storage.

```python theme={null}
file_url = Opus.file.upload(new_file)
print(file_url)  # "https://files.opus.com/..."
```

<Note>
  The `access_scope` parameter is optional and defaults to `"all"`.
</Note>

<Info>
  **Code Playground:** In the code playground, the `access_scope` is always `"unlisted"` regardless of the value provided.
</Info>

<Note>
  You can upload the same file multiple times. Each upload returns a new URL.
</Note>

#### Supported Access Scopes

| Scope       | Description                                      |
| ----------- | ------------------------------------------------ |
| `all`       | Visible to everyone (default)                    |
| `workspace` | Visible only to current workspace members        |
| `unlisted`  | Not listed — accessible only via direct file URL |

The scope is case-insensitive: `"Workspace"`, `"WORKSPACE"`, and `"WorkSpace"` all work.

```python theme={null}
file_url = Opus.file.upload(new_file, access_scope="workspace")
```

### OpusFile Interface

`OpusFile` is the object returned by `download()` and `create()`. Its attributes are read-only.

#### Properties

| Property    | Type          | Description                                                                         |
| ----------- | ------------- | ----------------------------------------------------------------------------------- |
| `file_name` | `str \| None` | File name without extension.                                                        |
| `file_ext`  | `str`         | Extension including leading dot (e.g. `".pdf"`).                                    |
| `file_type` | `str`         | Resolved file type enum value. Check [Supported File Types](#supported-file-types). |
| `file_size` | `int`         | Current size on disk in bytes.                                                      |

```python theme={null}
file = Opus.file.create("report", "PDF")
print(file.file_name)  # "report"
print(file.file_ext)  # ".pdf"
print(file.file_type)  # FileType.PDF
print(file.file_size)  # 0 (empty file)
```

#### Operations

| Method                                    | Description                                        |
| ----------------------------------------- | -------------------------------------------------- |
| `read_bytes() -> bytes`                   | Read entire file content as bytes.                 |
| `read_text(encoding="utf-8") -> str`      | Read entire file content as a string.              |
| `write_bytes(data: bytes)`                | Replace file content with binary data.             |
| `write_text(data: str, encoding="utf-8")` | Replace file content with text.                    |
| `open(mode="rb")`                         | Open the underlying file and return a file handle. |

#### Examples

**Reading:**

```python theme={null}
# As text
text = file.read_text()

# As bytes
data = file.read_bytes()

# Using a file handle
with file.open("r") as f:
  for line in f:
    print(line)
```

**Writing:**

```python theme={null}
# Replace all content
file.write_text("Hello, world!")
file.write_bytes(b"\x50\x4b\x03\x04...")

# Streaming writes
with file.open("w") as f:
  f.write("line 1\n")
  f.write("line 2\n")

# Appending
with file.open("a") as f:
  f.write("appended line\n")
```

**Download, modify, and re-upload:**

```python theme={null}
file = Opus.file.download("https://files.opus.com/reports/data.csv")
original = file.read_text()
modified = original.replace("old_value", "new_value")
file.write_text(modified)
new_url = Opus.file.upload(file)
```

**Create a CSV from scratch:**

```python theme={null}
import csv

output = Opus.file.create("results", "CSV")

with output.open("w") as f:
  writer = csv.writer(f)
  writer.writerow(["name", "score"])
  writer.writerow(["Alice", 95])
  writer.writerow(["Bob", 87])

file_url = Opus.file.upload(output)
```

**Create a JSON file:**

```python theme={null}
import json

output = Opus.file.create("config", "JSON")
output.write_text(json.dumps({"key": "value", "count": 42}, indent=2))

file_url = Opus.file.upload(output)
```

**Process a downloaded file line by line:**

```python theme={null}
file = Opus.file.download("https://files.opus.com/logs/app.txt")

with file.open("r") as f:
  for line in f:
    if "ERROR" in line:
      print(line.strip())
```

### Working with File Formats

For format-specific helpers and patterns, check the dedicated guide: [Working with File Formats](/opus-sdk/file-formats).

## Errors

All SDK exceptions inherit from `OpusError` and are available via `Opus.errors`:

```python theme={null}
try:
  file = Opus.file.download("https://files.opus.com/missing.pdf")
except Opus.errors.FileAPIError as e:
  print(f"Download failed: {e}")
  print(f"Status code: {e.status_code}")
  print(f"Response: {e.response_body}")
```

```python theme={null}
try:
  Opus.file.create("report", "MP4")
except Opus.errors.UnsupportedFileTypeError as e:
  print(f"Bad type: {e}")
```

```python theme={null}
try:
  Opus.file.create("report", "PDF")
  Opus.file.create("report", "PDF")  # same name again
except Opus.errors.FileAlreadyExistsError as e:
  print(f"Duplicate: {e}")
```

| Exception                     | When it's raised                                                          |
| ----------------------------- | ------------------------------------------------------------------------- |
| `OpusError`                   | Base class for all SDK errors. Also raised directly for generic failures. |
| `FileAPIError`                | An API call failed (download or upload).                                  |
| `FileAlreadyExistsError`      | `create()` with a name that already exists.                               |
| `UnsupportedFileTypeError`    | `create()` with an unrecognized file type.                                |
| `InvalidFileExpiryError`      | `presigned_download()` with an expiry outside the range.                  |
| `UnsupportedAccessScopeError` | `upload()` with an invalid access scope.                                  |
| `PathTraversalError`          | File name attempted to escape the allowed directory.                      |

## Related

<CardGroup cols={2}>
  <Card title="Available Packages" icon="box-open" href="/opus-sdk/available-packages">
    Browse the full list of Python packages you can import in Opus Code.
  </Card>

  <Card title="Working with File Formats" icon="file-lines" href="/opus-sdk/file-formats">
    Format-specific helpers for reading and writing PDFs, spreadsheets, and more.
  </Card>

  <Card title="Opus Code" icon="code" href="/tasks/agent/opus-code">
    Write custom Python code directly in your workflow.
  </Card>
</CardGroup>
