---
title: The runtime
description: Files, HTTP, images, and limits inside a call.
---

Every call is a fresh start. Subako instantiates the module, hands it one request, and stops it once it has answered: nothing in memory survives from one call to the next. What does survive is files, on the Session Volume.

## The filesystem

A call sees these directories, and nothing else:

| Path | Access | What it holds |
| --- | --- | --- |
| `/volume/tmp` | read-write | The Session Volume's **Temporary** area. Always there; cleared 24 hours after the session's last activity. |
| `/volume/data` | read-write | The **Data** area, when the agent version enables it. Kept until the session is deleted. |
| `/package` | read-only | The package's own `assets/`, by their paths: `assets/templates/report.typ` is `/package/templates/report.typ`. |
| `/skills/<name>` | read-only | Each skill the session's agent is granted, by its grant name. |

There is no working directory and no environment variables: use absolute paths. Every SDK reads and writes these with the language's ordinary file API — `std::fs`, `os`, or the TypeScript SDK's `fs`.

### The Session Volume

The volume belongs to the session, not to the call, so it is how tools hand work to each other: one function writes `/volume/tmp/export.csv`, another reads it, the platform `files` package lets the model look inside, and a person can download it from the session's **Session Volume** tab. Every tool of the session shares it, so give each tool its own directory.

Write a large result to a file and answer with its path and a short summary: what the model reads goes into its context, but a file it only knows the path of costs it nothing. The next tool can read the file, or the model can look into it with the platform `files` package, a page at a time.

A volume holds up to 10 GiB. One that reaches it takes no more writes until files are deleted; reads and deletes keep working.

### Package assets

A package can carry files of its own: templates, fonts, prompts, lookup tables, a small model's weights — anything the code reads but should not embed. Put them under `assets/` in the bundle, and every call reads them, read-only, at `/package`:

<FileTree>
  - subako-package.json
  - module.wasm
  - assets/
    - templates/
      - report.typ
    - fonts/
      - Inter.ttf
</FileTree>

**Rust**

```rust
let template = std::fs::read_to_string("/package/templates/report.typ")?;
```

**TypeScript**

```ts
const template = fs.readText("/package/templates/report.typ");
```

**Go**

```go
template, err := os.ReadFile("/package/templates/report.typ")
```

Each template's build script copies an `assets/` directory beside the code into the bundle. The assets are part of the version: a new template is a new upload, and a session keeps reading the files of the version it resolved. Assets are readable during the upload check too, so a module can load them at start-up. A bundle holds up to 10,000 asset files, within its 64 MiB. The [typst](/functions/examples) example ships its PDF templates this way.

## HTTP

A module has no sockets. It sends HTTP requests through Subako, which applies the grant's [network](/functions/granting#network) and attaches [credentials](/functions/calling-apis) on the way out. The SDKs make this the language's own HTTP:

**Rust**

```rust
use subako_function_sdk::http::{self, Request, ResponseBody};

let response = http::request(&Request::get("https://api.example.com/orders/1042"))?;
```

**Go**

```go
resp, err := http.Get("https://api.example.com/orders/1042") // net/http, as usual
```

**TypeScript**

```ts
const response = await fetch("https://api.example.com/orders/1042");
```

A response body up to 256 KiB of text comes back inline. A larger or binary one is saved straight to a volume file instead, and a volume file can be sent as a request body, so large transfers never pass through the module's memory. Redirects are followed up to 10 hops, each checked against the grant again; crossing to another origin drops `authorization` and cookie headers.

## Answering

A tool answers with a value — the SDKs serialize it as JSON for the model — or with an error the model reads:

- Return an error (`ToolError` in Rust, an `error` in Go, a thrown `Error` in TypeScript) for anything the model should know went wrong: "no order 1042", "the API said 429". The model reads the message and decides what to do.
- A panic, a trap, or a non-zero exit is a **crash**. The model is told only that the function stopped, with the last 4 KiB of what it wrote to stderr — so prefer an error it can act on.

Logs go to **stderr**. Stdout carries the protocol, and anything else printed there breaks the call.

### Images

A tool can show the model an image it made or found: return a path to a PNG, JPEG, GIF, or WebP file on the volume alongside the value. Subako reads the file after the call, downscales it to at most 2000 pixels on its long edge, and shows it to the model — when the agent version's model **Reads images** — and in the conversation under the call.

**Rust**

```rust
Ok(Answer::new(Plot { path: path.clone() }).with_image_file(path))
```

**Go**

```go
res, err := subakofn.ImageResult(plot, plot.Path)
return res, plot, err
```

**TypeScript**

```ts
return answer({ path }).withImageFile(path);
```

## Limits

| | Limit |
| --- | --- |
| Run time of one call | The grant's timeout: 60 seconds by default, up to 300 |
| Memory | 512 MiB |
| Writes to the volume in one call | 1 GiB |
| Everything the module writes to stdout | 1 MiB — write a larger result to a file |
| Stderr kept | 64 KiB; the last 4 KiB is reported on a crash |
| Inline HTTP response body | 256 KiB of UTF-8 text |
| HTTP request, as sent to Subako | 8 MiB — send a larger body as a volume file |
| Images in one result | 20, each at most 10 MiB |
| Session Volume | 10 GiB |

Waiting — on HTTP, or a sleep — counts toward the run time, and toward what the call is billed.

## When a package is uploaded

Subako runs the module once on upload to list its tools, with no volume, no network, and 10 seconds to answer. Start-up must not need either, and should be quick: it happens again at the start of every call.
