---
description: Code that agents run with @cloudflare/computer now survives deploys and crashes, and can pause for approvals or other external checks.
title: Cloudflare Computer now helps agents recover from interruptions and wait for approval
image: https://developers.cloudflare.com/changelog/post/2026-10-26-computer-durable-javascript/og.png?v=7d557f659dc43570
---

[Skip to content](#main-content)

[View RSS feeds](https://developers.cloudflare.com/fundamentals/new-features/available-rss-feeds/) [ Subscribe to RSS](https://developers.cloudflare.com/changelog/rss/index.xml)

[Back to all posts](https://developers.cloudflare.com/changelog)

October 26, 2026

## Cloudflare Computer now helps agents recover from interruptions and wait for approval

[Agents](https://developers.cloudflare.com/agents/) [Workers](https://developers.cloudflare.com/workers/)

Copy as Markdown| [View as Markdown](https://developers.cloudflare.com/changelog/post/2026-10-26-computer-durable-javascript/index.md)| [Agent setup](https://developers.cloudflare.com/agent-setup/)

[`@cloudflare/computer` ↗︎](https://github.com/cloudflare/computer) gives your agent a workspace to run code in. From v0.7.0, that code can resume after a deploy or crash, and pause on an external action, for example to approve a tool call.

#### Resume interrupted runs

Set `onInterrupt: "replay"` on `WorkerJavaScriptBackend`, or on a single run.

```js
import { DurableObject } from "cloudflare:workers";
import { Workspace } from "@cloudflare/computer";
import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";

export class MyAgent extends DurableObject {
	workspace = new Workspace({
		storage: this.ctx.storage,
		backends: [
			new WorkerJavaScriptBackend({
				loader: this.env.LOADER,
				onInterrupt: "replay",
			}),
		],
	});
}
```

```ts
import { DurableObject } from "cloudflare:workers";
import { Workspace } from "@cloudflare/computer";
import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";

export class MyAgent extends DurableObject<Env> {
	workspace = new Workspace({
		storage: this.ctx.storage,
		backends: [
			new WorkerJavaScriptBackend({
				loader: this.env.LOADER,
				onInterrupt: "replay",
			}),
		],
	});
}
```

When recovery is triggered, the JavaScript runs again from the beginning, reusing recorded results for completed calls without printing previously recorded output again. If a call's result was not recorded before the interruption, recovery may repeat the call — even if its action already succeeded. For retry handling, including `unsafeToRepeat()` for operations that cannot safely repeat, refer to [Calls that must not run twice](https://developers.cloudflare.com/agents/tools/filesystem/#calls-that-must-not-run-twice).

Recovery starts on the next call to `workspace.runtime`. To recover without waiting for traffic, call `workspace.runtime.recover()` from a [Durable Object alarm](https://developers.cloudflare.com/durable-objects/api/alarms/).

#### Wait for approvals

![A run pauses at an approval gate, then resumes when approved or fails when rejected](https://developers.cloudflare.com/cdn-cgi/image/onerror=redirect,width=920,height=292,format=svg/_astro/computer-approval-flow.CNEabsLO.svg)

Expose your application functions through [custom modules](https://developers.cloudflare.com/agents/tools/filesystem/#give-code-access-to-your-own-functions). A function can call `ctx.interrupt()` to pause the run until your application supplies an approval decision.

#### Require approval before posting a comment

For example, to provide a GitHub module that allows an agent to post a comment on an issue with approval, an implementation of `postComment` could look like this:

```js
new WorkerJavaScriptBackend({
	loader: this.env.LOADER,
	onInterrupt: "replay",
	modules: {
		// The agent's code imports this with `import { postComment } from "ws:github"`.
		"ws:github": {
			postComment: async ([issue, body], ctx) => {
				const { approved } = await ctx.interrupt({
					issue,
					body,
				});
				if (!approved) throw new Error("The comment was rejected.");
				return github.comment(issue, body, { idempotencyKey: ctx.callId });
			},
		},
	},
});
```

```ts
new WorkerJavaScriptBackend({
	loader: this.env.LOADER,
	onInterrupt: "replay",
	modules: {
		// The agent's code imports this with `import { postComment } from "ws:github"`.
		"ws:github": {
			postComment: async ([issue, body], ctx) => {
				const { approved } = await ctx.interrupt<{ approved: boolean }>({
					issue,
					body,
				});
				if (!approved) throw new Error("The comment was rejected.");
				return github.comment(issue, body, { idempotencyKey: ctx.callId });
			},
		},
	},
});
```

#### Call it from agent code

When the agent's code calls `postComment()`, the run pauses at `ctx.interrupt()` until your app responds. The agent's code calls it like any other function:

```js
import { postComment } from "ws:github";

export default async function ({ issue }) {
	return postComment(issue, "Hello world");
}
```

#### Respond to the approval request

The time spent waiting does not count toward its timeout. The wait also survives deploys. Fetch the pending calls with `workspace.runtime.pending()` and resolve them with `respond()`:

```js
for (const call of await workspace.runtime.pending()) {
	await workspace.runtime.respond(call.id, call.callId, { approved: true });
}
```

```ts
for (const call of await workspace.runtime.pending()) {
	await workspace.runtime.respond(call.id, call.callId, { approved: true });
}
```

The run continues once all pending calls are resolved.

For setup, current limitations, and how replay works, refer to [Resume runs after a restart](https://developers.cloudflare.com/agents/tools/filesystem/#resume-runs-after-a-restart).

```json
{"@context":"https://schema.org","@type":"BlogPosting","@id":"https://developers.cloudflare.com/changelog/post/2026-10-26-computer-durable-javascript/#page","headline":"Cloudflare Computer now helps agents recover from interruptions and wait for approval","description":"Code that agents run with @cloudflare/computer now survives deploys and crashes, and can pause for approvals or other external checks.","url":"https://developers.cloudflare.com/changelog/post/2026-10-26-computer-durable-javascript/","inLanguage":"en","image":"https://developers.cloudflare.com/changelog/post/2026-10-26-computer-durable-javascript/og.png?v=7d557f659dc43570","dateModified":"2026-10-26","datePublished":"2026-10-26","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
