Skip to main content
Every ForgeAI project gets a dedicated E2B sandbox. The sandbox is a long-lived, isolated cloud environment where the AI agent writes files, installs packages, and runs the dev server. The live preview URL is exposed directly from the sandbox.

Required environment variable

E2B_API_KEY=your_e2b_api_key

Sandbox lifecycle

1

Check for an existing sandbox

When the Inngest function runs, it first checks whether the project already has a sandboxId stored in the database.
inngest/functions.ts
const project = await db.project.findUnique({
  where: { id: event.data.projectId },
  select: { sandboxId: true },
});
2

Connect or create

If a sandboxId exists, the function reconnects to the running sandbox. Otherwise it creates a new one from the forgeai-v1 template and saves the ID to the project record.
inngest/functions.ts
if (project?.sandboxId) {
  const sandbox = await Sandbox.connect(project.sandboxId, {
    timeoutMs: TIMEOUT_MS, // 3,600,000 ms (1 hour)
  });
  return sandbox.sandboxId;
}

const createdSandbox = await Sandbox.create("forgeai-v1", {
  timeoutMs: TIMEOUT_MS,
});

await db.project.update({
  where: { id: event.data.projectId },
  data: { sandboxId: createdSandbox.sandboxId },
});
One sandbox is shared across all agent runs for the same project. Reconnecting resets the timeout, keeping the sandbox alive for another hour.
3

Agent uses the sandbox via tools

The coding agent interacts with the sandbox through four tools. All file paths are resolved relative to the project root.
lib/sandbox.ts
export const PROJECTROOT = "/home/user/project";

export const toProjectPath = (p: string) => {
  const normalized = p.replace(/\\/g, "/").trim();
  if (normalized.startsWith("/")) return normalized;
  return path.posix.join(PROJECTROOT, normalized);
};
4

Retrieve the preview URL

After the agent network finishes, the sandbox host for port 3000 is retrieved and stored as the sandboxUrl on the code fragment.
inngest/functions.ts
const sandbox = await getSandbox(sandboxId);
const host = sandbox.getHost(3000);
return `https://${host}`;

Sandbox tools

The coding agent has access to four tools that operate directly inside the sandbox:
Executes arbitrary shell commands inside the sandbox. Used to install npm packages, run build commands, or inspect the environment.
createTool({
  name: "terminal",
  parameters: z.object({ command: z.string() }),
  handler: async ({ command }) => {
    const sandbox = await getSandbox(sandboxId);
    const result = await sandbox.commands.run(command, {
      onStdout: (data) => { buffers.stdout += data; },
      onStderr: (data) => { buffers.stderr += data; },
    });
    return result.stdout;
  },
});
Writes one or more files to the sandbox and updates the in-memory files map in network state. File paths are resolved against /home/user/project.
createTool({
  name: "createOrUpdateFiles",
  parameters: z.object({
    files: z.array(z.object({ path: z.string(), content: z.string() })),
  }),
  handler: async ({ files }, { network }) => {
    const sandbox = await getSandbox(sandboxId);
    for (const file of files) {
      const fullPath = toProjectPath(file.path);
      await sandbox.files.write(fullPath, file.content);
      updatedFiles[file.path] = file.content;
    }
  },
});
Reads one or more files from the sandbox and returns their contents as a JSON array of { path, content } objects.
createTool({
  name: "readFiles",
  parameters: z.object({ files: z.array(z.string()) }),
  handler: async ({ files }) => {
    const sandbox = await getSandbox(sandboxId);
    for (const file of files) {
      const content = await sandbox.files.read(toProjectPath(file));
      contents.push({ path: file, content });
    }
    return JSON.stringify(contents);
  },
});
Searches Unsplash, downloads a matching photo, and saves it to /public/assets/unsplash inside the sandbox. Returns the local public path and photographer attribution data.
createTool({
  name: "unsplashImage",
  parameters: z.object({
    query: z.string().min(2),
    orientation: z.enum(["landscape", "portrait", "squarish"]),
    purpose: z.enum(["hero", "feature", "testimonial", "background", "listing", "generic"]),
    filenameHint: z.string(),
  }),
  handler: async ({ query, orientation, purpose, filenameHint }) => {
    // Downloads to /home/user/project/public/assets/unsplash/<slug>.jpg
    // Returns { publicPath, localFile, attribution }
  },
});
Requires UNSPLASH_API_KEY in addition to E2B_API_KEY. The agent uses curl inside the sandbox to download images, so no file is transferred through the Next.js server.

Sandbox reference

PropertyValue
Templateforgeai-v1
Project root/home/user/project
Dev server port3000
Timeout1 hour (3,600,000 ms)
Image assets path/public/assets/unsplash
ScopeOne sandbox per project

Inngest background jobs

The Inngest function that manages sandbox creation and invokes the agent.

Live preview

How the sandbox URL is surfaced in the ForgeAI UI.

Build docs developers (and LLMs) love