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

# Agent Filesystem

> A full filesystem where agents create files, run scripts, and persist knowledge across executions

Every Asteroid agent has access to a **real filesystem**. During a run the agent can create files, update them, and execute scripts—just like a developer working on a local machine. This is what makes browser agents on Asteroid so capable: they don't just click through pages, they can **write code, run it, and build on it later**.

The agent interacts with the filesystem using standard tools — **Read**, **Write**, **Edit**, **Glob**, **Grep**, and **Bash** — with the working directory set to `/home/agent`.

## Agents that improve over time

The filesystem has a **persistent region** called **`shared/`** that survives between executions. Before each run, all previously saved shared files are restored into the sandbox. Anything the agent writes to `shared/` during the run is synced back to durable storage when the execution finishes. That means an agent can:

* **Remember how a workflow works** — save step-by-step procedures so future runs skip the trial-and-error phase.
* **Record site-specific gotchas** — note that a portal requires a specific click order, or that a form silently drops data if submitted too fast.
* **Store and refine scripts** — write Playwright scripts during one run, then reuse and improve them on the next (see [Scripted mode](/fundamentals/nodes/ai-task)).
* **Build up knowledge** — accumulate extracted data, summaries, or reference files the model can read via file tools.

This is a **frontier capability**: instead of starting from scratch every time, each execution makes the agent a little smarter. Workflows **compound in quality** over repeated runs.

## Directory layout

Each execution mounts a filesystem under `/home/agent` with four regions:

| Directory        | Scope                          | Quota  | Purpose                                                                      |
| ---------------- | ------------------------------ | ------ | ---------------------------------------------------------------------------- |
| **`shared/`**    | Persists across all executions | 50 MB  | Durable memory — scripts, notes, extracted data, learned procedures          |
| **`workspace/`** | Current execution only         | 500 MB | Scratch space for in-progress work                                           |
| **`downloads/`** | Current execution only         | 500 MB | Browser downloads land here (see [Environments](/fundamentals/environments)) |
| **`uploads/`**   | Current execution only         | 200 MB | Files attached via API or staging                                            |

Rule of thumb: if the agent should remember it next time, put it in **`shared/`**. Everything else goes in **`workspace/`**.

<Tip>
  The agent is automatically notified when new files appear in `downloads/` or `uploads/` (e.g. browser downloads or API uploads). Changes to `shared/` and `workspace/` don't trigger notifications since the agent created those files itself.
</Tip>

<CardGroup cols={2}>
  <Card title="Staging Files" icon="clock" href="#staging-files" horizontal>
    Pre-upload files before starting an execution
  </Card>

  <Card title="File Downloads" icon="download" href="#file-downloads" horizontal>
    Automatically download files from websites
  </Card>

  <Card title="File Reading" icon="eye" href="#file-reading" horizontal>
    Read and process images, PDFs, CSVs, and other file types
  </Card>

  <Card title="File Uploads" icon="upload" href="#file-uploads" horizontal>
    Upload files to web forms and applications
  </Card>

  <Card title="API Access" icon="code" href="#api-access" horizontal>
    Programmatically manage files through the Asteroid Odyssey SDK
  </Card>
</CardGroup>

## Staging Files

<Info>
  Use staging files when you need to provide files to an execution **before** it starts.
  If your execution is already running, use [Upload files to an execution](/api-reference/files/upload-execution-context-files) instead.
</Info>

Staging files is useful when you have files that the agent needs from the very start of execution.

### How It Works

```mermaid theme={null}
sequenceDiagram
    participant App
    participant StagingAPI as /temp-files
    participant ExecuteAPI as /agents/{id}/execute
    participant Execution

    App->>StagingAPI: POST files
    StagingAPI-->>App: tempFiles (id, name)
    Note over App: Must use within 60 mins
    App->>ExecuteAPI: POST with tempFiles array
    ExecuteAPI->>Execution: Start with files attached
```

1. **Stage**: Upload files via `POST /temp-files/{organizationId}` - this returns an array of temp file objects with `id` and `name`
2. **Execute**: Pass the temp file array in the `tempFiles` parameter when calling `POST /agents/{agentId}/execute`
3. When the execution starts, your staged files are automatically attached to the execution context

<Warning>
  Staged files expire after **60 minutes**. You must start an execution using the staged files within this time window, or the files will be automatically deleted.
</Warning>

### Code Examples

<CodeGroup>
  ```typescript staging-files.ts theme={null}
  import { client, tempFilesStage, agentExecutePost } from 'asteroid-odyssey';
  import { readFileSync } from 'node:fs';

  client.setConfig({
    headers: { 'X-Asteroid-Agents-Api-Key': process.env.ASTEROID_API_KEY! },
  });

  // Step 1: Stage files before execution
  const fileContent = readFileSync('document.pdf');
  const file = new File([fileContent], 'document.pdf', { type: 'application/pdf' });

  const { data: staged } = await tempFilesStage({
    path: { organizationId: 'YOUR_ORGANIZATION_ID' },
    body: { files: [file] },
  });
  // staged.tempFiles = [{ id: "uuid", name: "document.pdf" }]

  // Step 2: Execute agent with staged files
  const { data } = await agentExecutePost({
    path: { agentId: 'YOUR_AGENT_ID' },
    body: {
      tempFiles: staged?.tempFiles,
      inputs: {
        // your variables
      },
    },
  });

  console.log(`Execution ID: ${data?.executionId}`);
  ```

  ```python staging-files.py theme={null}
  import os
  import requests

  api_key = os.environ.get("ASTEROID_API_KEY", "YOUR_API_KEY")
  organization_id = "YOUR_ORGANIZATION_ID"
  agent_id = "YOUR_AGENT_ID"

  # Step 1: Stage files before execution
  with open("document.pdf", "rb") as f:
      stage_response = requests.post(
          f"https://odyssey.asteroid.ai/agents/v2/temp-files/{organization_id}",
          headers={"X-Asteroid-Agents-Api-Key": api_key},
          files={"files": ("document.pdf", f)},
      )

  temp_files = stage_response.json()["tempFiles"]
  # temp_files = [{"id": "uuid", "name": "document.pdf"}]

  # Step 2: Execute agent with staged files
  execute_response = requests.post(
      f"https://odyssey.asteroid.ai/agents/v2/agents/{agent_id}/execute",
      headers={
          "X-Asteroid-Agents-Api-Key": api_key,
          "Content-Type": "application/json",
      },
      json={
          "tempFiles": temp_files,
          "inputs": {  # your variables
          },
      },
  )

  execution_id = execute_response.json()["executionId"]
  ```
</CodeGroup>

## File Downloads

Your agents can download files from websites during browser automation sessions. Files land under **`/home/agent/downloads`** and sync like other agent directories; use **List Files** and related tools rather than forcing `download.saveAs()` into custom paths.

<Info>Downloaded files appear in the Files area of the execution UI and in API/SDK file listings.</Info>

## File Reading

Asteroid agents can read and process various file types.

### Supported File Types

* **Images (PNG, JPEG)**
* **PDFs**
* **Text Files (TXT, MD)**
* **CSVs**

## File Uploads

Agents can upload files to web applications using the **Upload File** tool, which supports:

* Local file uploads
* Previously downloaded files (using `downloads/filename` format)

## API Access

File upload and downloads are also available programmatically through the Asteroid Odyssey SDK:

<CardGroup cols={2}>
  <Card title="Stage Files Endpoint" icon="clock" href="/api-reference/files/stage-a-file-for-an-execution">
    Stage files before you start an execution.
  </Card>

  <Card title="Upload Files Endpoint" icon="upload" href="/api-reference/files/upload-execution-context-files">
    Upload files to an execution that is already running.
  </Card>
</CardGroup>

### Upload Files

```typescript theme={null}
import { client, executionContextFilesUpload } from 'asteroid-odyssey';
import { readFileSync } from 'node:fs';

client.setConfig({
  headers: { 'X-Asteroid-Agents-Api-Key': process.env.ASTEROID_API_KEY! },
});

// Upload files to a running execution
const fileContent = readFileSync('document.pdf');
const file = new File([fileContent], 'document.pdf', { type: 'application/pdf' });

await executionContextFilesUpload({
  path: { executionId: 'your-execution-id' },
  body: { files: [file] },
});
```

### Download Files

Each file in the list response includes a `downloadUrl`. Fetch it with your API key and the server will redirect you to the file contents.

<CodeGroup>
  ```typescript download-files.ts theme={null}
  import { client, executionContextFilesGet } from 'asteroid-odyssey';
  import { writeFileSync } from 'node:fs';

  client.setConfig({
    headers: { 'X-Asteroid-Agents-Api-Key': process.env.ASTEROID_API_KEY! },
  });

  const { data: files } = await executionContextFilesGet({
    path: { executionId: 'your-execution-id' },
  });

  for (const file of files ?? []) {
    const response = await fetch(file.downloadUrl, {
      headers: { 'X-Asteroid-Agents-Api-Key': process.env.ASTEROID_API_KEY! },
    });
    if (!response.ok) throw new Error(`Download failed: ${response.status}`);
    writeFileSync(`./downloads/${file.fileName}`, Buffer.from(await response.arrayBuffer()));
  }
  ```

  ```python download-files.py theme={null}
  import os
  import requests

  api_key = os.environ["ASTEROID_API_KEY"]
  headers = {"X-Asteroid-Agents-Api-Key": api_key}

  files = requests.get(
      f"https://odyssey.asteroid.ai/agents/v2/executions/your-execution-id/context-files",
      headers=headers,
  ).json()

  for file in files:
      data = requests.get(file["downloadUrl"], headers=headers).content
      with open(f"./downloads/{file['fileName']}", "wb") as f:
          f.write(data)
  ```
</CodeGroup>

<Tip>
  `downloadUrl` is an authenticated Asteroid URL, not a direct storage link. Your HTTP client follows the redirect automatically — no extra handling needed.
</Tip>
