# How to Implement Custom beforeStop and afterStart Hooks for Open Agents Sandboxes

> Easily implement custom beforeStop and afterStart hooks for Open Agents sandboxes. Learn how to enhance your VM lifecycle with VercelSandbox.create and connectVercelSandbox.

- Repository: [Vercel Labs/open-agents](https://github.com/vercel-labs/open-agents)
- Tags: how-to-guide
- Published: 2026-04-16

---

**You can implement custom `beforeStop` and `afterStart` hooks for Open Agents sandboxes by passing an object containing async functions to the `hooks` property of `VercelSandbox.create()` or `connectVercelSandbox()`, where `afterStart` runs immediately after the VM is ready and `beforeStop` executes right before the sandbox shutdown sequence begins.**

The **vercel-labs/open-agents** repository provides a robust lifecycle hook system that allows you to execute arbitrary code during critical sandbox transitions. These hooks receive the full sandbox instance, enabling you to run commands, manipulate files, or persist data using the standard sandbox API.

## Understanding the Sandbox Hook Interface

### The SandboxHooks Interface

The hook contract is defined in **[`packages/sandbox/interface.ts`](https://github.com/vercel-labs/open-agents/blob/main/packages/sandbox/interface.ts)** at lines 27-38. The `SandboxHooks` interface accepts four optional lifecycle callbacks:

```typescript
export interface SandboxHooks {
  /** Called after the sandbox starts and is ready. */
  afterStart?: SandboxHook;

  /** Called before the sandbox stops. */
  beforeStop?: SandboxHook;

  /** Called when the sandbox is about to timeout (before beforeStop). */
  onTimeout?: SandboxHook;

  /** Called after timeout is successfully extended. */
  onTimeoutExtended?: (sandbox: Sandbox, additionalMs: number) => Promise<void>;
}

```

The `SandboxHook` type is a simple function signature: `(sandbox: Sandbox) => Promise<void>`.

### Hook Timing and Use Cases

| Hook | When it fires | Typical applications |
|------|---------------|----------------------|
| `afterStart` | Immediately after sandbox creation or reconnection, once the VM is ready to accept commands. | Installing extra CLI tools, injecting environment variables, starting background services, initializing git configs, or logging telemetry. |
| `beforeStop` | Right before the `stop()` method delegates to the Vercel SDK shutdown sequence. | Committing pending changes, uploading build artifacts, cleaning temporary files, persisting logs, or reporting final status. |

## Wiring Custom Hooks into the Sandbox Lifecycle

### Implementing afterStart Hooks

The `afterStart` hook is invoked in two code paths within **[`packages/sandbox/vercel/sandbox.ts`](https://github.com/vercel-labs/open-agents/blob/main/packages/sandbox/vercel/sandbox.ts)**.

During **initial creation** (lines 94-98):

```typescript
const sandbox = new VercelSandbox(...);

if (hooks?.afterStart) {
  await hooks.afterStart(sandbox);
}

```

During **reconnection** (lines 54-57):

```typescript
if (options.hooks?.afterStart) {
  await options.hooks.afterStart(sandbox);
}

```

This guarantees your initialization logic runs whether you are spawning a fresh micro-VM or attaching to an existing one.

### Implementing beforeStop Hooks

The `beforeStop` hook is invoked inside the `stop()` method (lines 58-68) before the SDK shutdown:

```typescript
if (this.hooks?.beforeStop) {
  try {
    await this.hooks.beforeStop(this);
  } catch (error) {
    console.error("[VercelSandbox] beforeStop hook failed:", error);
  }
}
await this.sdk.stop();

```

The implementation wraps the hook in a `try/catch` block, ensuring that a failure in your custom logic **does not prevent the sandbox from terminating**. This prevents resource leaks even when your artifact upload or git commit fails.

## Practical Implementation Examples

### Example 1: Install a CLI Tool After Startup

Use `afterStart` to install dependencies that are not baked into the base image:

```typescript
import { connectVercelSandbox } from "@open-agents/sandbox/vercel";

async function startSandbox() {
  const sandbox = await connectVercelSandbox({
    name: "my-session",
    source: { url: "https://github.com/owner/repo", branch: "main" },
    hooks: {
      afterStart: async (sb) => {
        // Install httpie globally inside the sandbox
        await sb.exec("npm i -g httpie", sb.workingDirectory, 60_000);
        console.log("✅ httpie installed inside sandbox");
      },
    },
  });

  return sandbox;
}

```

### Example 2: Commit Changes Before Shutdown

Use `beforeStop` to persist work before the micro-VM disappears:

```typescript
import { connectVercelSandbox } from "@open-agents/sandbox/vercel";

async function startAndMonitor() {
  const sandbox = await connectVercelSandbox({
    name: "demo-session",
    hooks: {
      beforeStop: async (sb) => {
        // Commit any pending edits to a git remote
        await sb.exec("git add -A", sb.workingDirectory, 30_000);
        await sb.exec(
          'git commit -m "autosave before stop"',
          sb.workingDirectory,
          30_000,
        );
        console.log("🗂️ Changes committed before sandbox shutdown");
      },
    },
  });

  // Later, when you decide to finish
  await sandbox.stop(); // beforeStop invoked automatically
}

```

### Example 3: Combined Setup and Teardown

Using both hooks together for a full lifecycle management cycle:

```typescript
const sandbox = await connectVercelSandbox({
  name: "full-cycle",
  hooks: {
    afterStart: async (sb) => {
      // Prepare a temporary directory for processing
      await sb.mkdir("/tmp/data", { recursive: true });
      await sb.writeFile("/tmp/data/.gitkeep", "");
    },
    beforeStop: async (sb) => {
      // Archive the temporary data before the VM disappears
      await sb.exec(
        "tar -czf /tmp/archive.tgz -C /tmp/data .",
        sb.workingDirectory,
        45_000,
      );
      // Upload the archive to external storage
      await sb.exec(
        `curl -X POST -F "file=@/tmp/archive.tgz" https://api.example.com/upload`,
        sb.workingDirectory,
        60_000,
      );
    },
  },
});

```

## Critical Implementation Details

| Aspect | Implementation Detail |
|--------|----------------------|
| **Timeout Buffer** | The sandbox adds a **30-second buffer** (`TIMEOUT_BUFFER_MS`) to the user-specified timeout, ensuring the `beforeStop` hook has time to finish before the Vercel SDK force-stops the VM. |
| **Idempotent Stops** | The `stop()` method checks `this.isStopped` and returns early on repeated calls. The `beforeStop` hook runs **only once** per instance. |
| **Error Isolation** | Hook invocations are wrapped in `try/catch` blocks. A failing `beforeStop` hook logs to `console.error` but **does not prevent** the sandbox from terminating. |
| **Proactive Timeout** | The `onTimeout` hook fires when the sandbox is about to hit its time limit, but `beforeStop` is **not** invoked automatically by the timeout timer—you must explicitly call `sandbox.stop()`. |
| **Hook Ordering** | `afterStart` runs **after** the sandbox object is fully constructed and any repository cloning completes. `beforeStop` runs **immediately before** the SDK stop request. |

## Key Source Files

| File | Purpose |
|------|---------|
| [`packages/sandbox/interface.ts`](https://github.com/vercel-labs/open-agents/blob/main/packages/sandbox/interface.ts) | Defines the `SandboxHooks` interface, `SandboxHook` type, and hook signatures (lines 27-38). |
| [`packages/sandbox/vercel/sandbox.ts`](https://github.com/vercel-labs/open-agents/blob/main/packages/sandbox/vercel/sandbox.ts) | Implements hook invocation in `create()`, `connect()`, and `stop()` methods (lines 54-68, 94-98). |
| [`packages/sandbox/vercel/config.ts`](https://github.com/vercel-labs/open-agents/blob/main/packages/sandbox/vercel/config.ts) | Exposes the `VercelSandboxConfig` and `VercelSandboxConnectConfig` types that include the optional `hooks` property. |
| [`apps/web/app/workflows/sandbox-lifecycle.ts`](https://github.com/vercel-labs/open-agents/blob/main/apps/web/app/workflows/sandbox-lifecycle.ts) | Demonstrates real-world usage of the hook system in the Open Agents web application. |

## Summary

- **Define hooks** as async functions matching the `(sandbox: Sandbox) => Promise<void>` signature.
- **Pass hooks** via the `hooks` property when calling `VercelSandbox.create()` or `connectVercelSandbox()`.
- **Use `afterStart`** to bootstrap the environment—install tools, clone additional repos, or start services once the VM is ready.
- **Use `beforeStop`** to persist state—commit code, upload artifacts, or clean resources before the micro-VM terminates.
- **Handle errors gracefully**—hook failures are logged but never block the sandbox lifecycle, ensuring resources are always released.

## Frequently Asked Questions

### How do I ensure my beforeStop hook has enough time to upload large files?

The Open Agents sandbox automatically adds a **30-second buffer** (`TIMEOUT_BUFFER_MS`) to your specified timeout. This buffer gives the `beforeStop` hook time to complete before the Vercel SDK force-terminates the VM. For very large uploads, consider compressing files or using the `onTimeout` hook to trigger uploads before the timeout deadline approaches.

### Can I modify the sandbox timeout from within a hook?

While you cannot directly modify the timeout from within `afterStart` or `beforeStop`, the `SandboxHooks` interface includes an `onTimeout` hook that fires when the sandbox is about to reach its time limit. If you implement `onTimeoutExtended`, you can handle timeout extension events. To extend a timeout, you typically call the appropriate sandbox management API outside the hook context before the deadline.

### What happens if my afterStart hook throws an error?

If the `afterStart` hook throws an error, the error is caught and logged to the console, but the sandbox creation or connection process continues. This design ensures that a failed bootstrap script (such as a failed npm install) does not indefinitely block the sandbox lifecycle. You should implement robust error handling inside your hook and consider retry logic for critical initialization steps.

### Is it possible to register multiple hooks or change hooks after sandbox creation?

The current implementation in [`packages/sandbox/vercel/sandbox.ts`](https://github.com/vercel-labs/open-agents/blob/main/packages/sandbox/vercel/sandbox.ts) stores the `hooks` object passed during construction and does not provide a public API to modify or add hooks after the sandbox instance is created. If you need dynamic behavior, you should implement conditional logic inside your hook functions or maintain state outside the sandbox that your hooks can reference. For completely different lifecycle behaviors, you would need to create a new sandbox instance with a different hooks configuration.