# Using the Flue Local Sandbox in CI/CD Environments with Host Filesystem Access

> Unlock Flue local sandbox capabilities in CI/CD. Access host filesystem directly, read repo files, and write artifacts with Node.js fs/promises API, eliminating virtual layer overhead.

- Repository: [Astro/flue](https://github.com/withastro/flue)
- Tags: how-to-guide
- Published: 2026-05-11

---

**The Flue local sandbox (`sandbox: 'local'`) binds directly to the host filesystem, allowing agents to read repository files and write build artifacts using native Node.js `fs/promises` APIs without virtual layer overhead.**

When running Flue agents in continuous integration pipelines, you often need direct access to the build container's filesystem to analyze source code or persist generated outputs. The **local sandbox** option in the withastro/flue repository provides a direct bridge between the agent's execution environment and the host filesystem, bypassing the default in-memory isolation layer to match standard CI script behavior.

## How the Local Sandbox Works in Flue

Flue agents execute inside a sandbox that isolates the model’s execution from the host environment. By default, the sandbox uses an in-memory “empty” filesystem (`sandbox: 'empty'`). When you select **local sandbox** mode, the system delegates all filesystem operations directly to the host Node.js implementation.

### Direct Filesystem Delegation

All filesystem APIs (`readFile`, `writeFile`, `stat`, `readdir`, etc.) are delegated straight to Node’s `fs/promises` implementation through the `createCwdSessionEnv` helper in [`packages/sdk/src/sandbox.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/sandbox.ts). This eliminates the need to copy files into a virtual layer before processing.

### Host Shell Integration

Shell commands execute through the host’s shell with full access to `process.env` and the current working directory (`cwd`). No path remapping occurs—the paths you pass are the exact paths on the runner.

### Zero Overhead Architecture

No intermediate “just‑bash” layer is inserted between the agent and the host. When the Flue CLI runs inside a container (Docker, GitHub Actions runner, GitLab CI job), the container provides the isolation boundary while the local sandbox simply uses that boundary directly.

## Configuring the Local Sandbox in CI/CD

The sandbox choice is exposed via the `AgentInit` options defined in [`packages/sdk/src/types.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/types.ts):

```ts
export interface AgentInit {
  /** ...
   * - `'empty'` – in‑memory sandbox (default)
   * - `'local'` – direct host access
   * - SandboxFactory – custom remote sandbox connector
   */ 
  sandbox?: 'empty' | 'local' | SandboxFactory | BashFactory;
}

```

Internally, the `init` routine resolves the sandbox option in [`packages/sdk/src/client.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/client.ts) (around line 225). For `'local'`, it falls back to the Node-specific implementation in [`packages/sdk/src/node/local-env.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/node/local-env.ts), which creates a `SessionEnv` that forwards all operations to the host’s `fs` and `child_process` APIs while maintaining the same interface used by remote sandboxes.

## Practical CI/CD Scenarios

Using `sandbox: 'local'` is optimal for CI/CD workflows that require host filesystem interaction:

- **Reading source files** – Direct `fs.readFile` calls access the repository checkout without copying files into an in-memory sandbox.
- **Running build tools** – Commands like `npm run build` or `pnpm install` execute with the real `$PATH` and environment variables visible to the host shell.
- **Persisting generated artifacts** – Files written to the runner’s filesystem are automatically available for subsequent workflow steps (artifact upload, caching).
- **Accessing CI secrets** – Since the sandbox does not mask `process.env`, environment variables containing secrets remain accessible to tooling while staying out of the agent's explicit context.

**Important:** The local sandbox is *not* a security boundary. If you need to keep secrets off the host or prevent the LLM from accessing sensitive data, use a true remote sandbox connector (Daytona, E2B, Cloudflare Containers, etc.) and expose only necessary tools via Flue’s tool framework.

## GitHub Actions Workflow Example

The following workflow demonstrates running a Flue agent with local sandbox access in a GitHub Actions environment:

```yaml

# .github/workflows/test.yml

name: Flue CI
on: [push]

jobs:
  run-agent:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build SDK (required before running agents)
        run: pnpm --filter @flue/sdk run build

      - name: Run a Flue agent with local sandbox
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # Initialise a harness that points at the repository root.

          node packages/cli/bin/flue.mjs run hello \
            --target node \
            --id ci-run \
            --payload '{"name":"CI"}' \
            --sandbox local   # <-- NOTE: this flag is a shortcut for init({ sandbox:'local' })

```

## Agent Implementation Examples

Inside the agent code, use the `ctx.fs` surface to interact with the host filesystem. The following TypeScript agent ([`agents/hello.ts`](https://github.com/withastro/flue/blob/main/agents/hello.ts)) demonstrates reading a source file and executing a build command:

```ts
import { init } from '@flue/sdk/node';

export default async function () {
  const harness = await init({ sandbox: 'local' }); // <-- explicit, same as CLI flag

  // Read a source file from the host repository
  const source = await harness.fs.readFile('src/index.ts');
  console.log('First line of source:', source.split('\n')[0]);

  // Run a build step – the command executes in the CI container
  const { stdout } = await harness.exec('npm run build', { timeout: 60 });
  console.log('Build output:', stdout);
}

```

To persist results back to the CI workspace for later steps:

```ts
await harness.fs.writeFile('test-results.txt', testReport);

```

## Summary

- The **local sandbox** (`sandbox: 'local'`) delegates filesystem operations directly to Node.js `fs/promises` APIs via `createCwdSessionEnv` in [`packages/sdk/src/sandbox.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/sandbox.ts).
- Configuration occurs through the `AgentInit` interface in [`packages/sdk/src/types.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/types.ts), with resolution handled in [`packages/sdk/src/client.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/client.ts).
- Shell commands execute with full host environment access and no path remapping, matching standard CI script behavior.
- Ideal for CI/CD scenarios requiring direct repository access, build tool execution, and artifact persistence without virtualization overhead.
- Not a security boundary; use remote sandbox connectors for sensitive secret isolation according to [`docs/sandbox-connector-spec.md`](https://github.com/withastro/flue/blob/main/docs/sandbox-connector-spec.md).

## Frequently Asked Questions

### What is the difference between `sandbox: 'empty'` and `sandbox: 'local'` in Flue?

The `'empty'` option creates an in-memory virtual filesystem completely isolated from the host, requiring files to be explicitly provided to the agent. The `'local'` option delegates all filesystem operations to the host's Node.js implementation, providing direct access to the CI container's filesystem and environment.

### How do I enable host filesystem access when running Flue agents in GitHub Actions?

Pass the `--sandbox local` flag to the Flue CLI command, which maps to `init({ sandbox: 'local' })` in the SDK. This configuration delegates file operations to the host filesystem, allowing agents to read checked-out repository files and write artifacts that subsequent workflow steps can access.

### Is the local sandbox secure for running untrusted code in CI/CD pipelines?

No. The local sandbox is explicitly **not a security boundary**—it provides direct access to the host filesystem and environment variables. For untrusted code or when handling sensitive secrets that must remain invisible to the LLM, use a remote sandbox connector (such as Daytona, E2B, or Cloudflare Containers) that provides proper isolation.

### Which source files implement the local sandbox functionality?

The core implementation resides in [`packages/sdk/src/node/local-env.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/node/local-env.ts), which creates a `SessionEnv` forwarding operations to host APIs. The sandbox type resolution occurs in [`packages/sdk/src/client.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/client.ts) (around line 225), with type definitions in [`packages/sdk/src/types.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/types.ts) and the `FlueHarness` API exposed in [`packages/sdk/src/harness.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/harness.ts).