# Flue integration
URL: /docs/core/flue

Use a @alineo-labs/sandbox SandboxHandle as a Flue session environment with @alineo-labs/flue.



`@alineo-labs/flue` adapts a `SandboxHandle` (from `@alineo-labs/sandbox`) to [Flue's](https://flueframework.com) `SandboxFactory` interface, so these sandboxes can back any Flue agent that needs a container to exec commands and manage files.

## Install [#install]

```bash
bun add @alineo-labs/flue @flue/runtime
```

## Usage [#usage]

Flue loads sandbox adapters from a file at `<source-dir>/sandboxes/<name>.ts`. Create `src/sandboxes/alineo.ts` in your Flue project:

```ts
// src/sandboxes/alineo.ts
import { alineo } from "@alineo-labs/flue";
import { Sandbox } from "@alineo-labs/sandbox";
import { SQLiteAdapter } from "@alineo-labs/sqlite";

const client = new Sandbox({
  baseUrl: "http://localhost:8080",
  adapter: new SQLiteAdapter("./ledger.db"),
});

export default alineo(
  await client.sandbox({
    image: "node:22",
    resources: { cpu: "500m", memory: "512Mi" },
  }),
);
```

Then reference it in your agent definition:

```ts
import { defineAgent } from "@flue/runtime";
import alineoSandbox from "./sandboxes/alineo.ts";

export default defineAgent({
  sandbox: alineoSandbox,
  // ...
});
```

## API [#api]

```ts
function alineo(sandbox: SandboxHandle, opts?: { cwd?: string }): SandboxFactory;
```

| Parameter  | Type            | Description                                                                                                           |
| ---------- | --------------- | --------------------------------------------------------------------------------------------------------------------- |
| `sandbox`  | `SandboxHandle` | An already-created sandbox instance. Lifecycle is the caller's responsibility — the adapter never calls `sb.close()`. |
| `opts.cwd` | `string`        | Working directory passed to `createSandboxSessionEnv`. Defaults to `"/"`.                                             |

## SandboxApi coverage [#sandboxapi-coverage]

The adapter implements all nine `SandboxApi` methods:

| Method                        | Backed by                                                                   |
| ----------------------------- | --------------------------------------------------------------------------- |
| `exec(cmd, opts?)`            | `sb.exec()` with `strict: false`. Timeout via `Promise.race` + `Math.ceil`. |
| `readFile(path)`              | `sb.readFile()`                                                             |
| `readFileBuffer(path)`        | `sb.exec("base64 -w0 <path>")` → decoded `Uint8Array`                       |
| `writeFile(path, string)`     | `sb.writeFile()`                                                            |
| `writeFile(path, Uint8Array)` | Base64-encoded, piped through `base64 -d` in the container                  |
| `stat(path)`                  | `sb.exec("stat -c '%F\|%s\|%Y' <path>")` → parsed `FileStat`                |
| `readdir(path)`               | `sb.listDirectory(path, { depth: 1 })` → entry names                        |
| `exists(path)`                | `sb.exec("test -e <path>")` → exit code check                               |
| `mkdir(path, opts?)`          | `sb.exec("mkdir [-p] <path>")`                                              |
| `rm(path, opts?)`             | `sb.exec("rm [-r] [-f] <path>")`                                            |

## Known limits [#known-limits]

**Binary write cap** — `writeFile` with a `Uint8Array` base64-encodes the content and passes it through the shell. This relies on the Linux `ARG_MAX` limit (\~2 MB), so binary writes are capped at roughly **1.5 MB**. String writes (`writeFile(path, string)`) use the native file upload API and have no size restriction.

**No mid-flight cancellation** — `exec` honors `timeoutMs` via `Promise.race`, but `AbortSignal` is ignored. The underlying `SandboxHandle.exec()` does not expose signal propagation to the HTTP layer.

## Sandbox lifecycle [#sandbox-lifecycle]

The adapter never calls `sb.close()`. You are responsible for closing the sandbox when your agent session ends:

```ts
const sb = await client.sandbox({ image: "node:22", resources: { cpu: "500m", memory: "512Mi" } });
try {
  const factory = alineo(sb);
  // pass factory to Flue agent...
} finally {
  await sb.close();
}
```
