# What Is the Restore Forger in Cloudflare OS Agent Execution?

> Discover the Cloudflare OS restore forger's purpose. Learn how this transient worker creates persistent RPC stubs for gadget restore methods without direct code invocation.

- Repository: [Cloudflare/cloudflare-os](https://github.com/cloudflare/cloudflare-os)
- Tags: deep-dive
- Published: 2026-09-05

---

**The restore forger is a transient worker that enables Cloudflare OS agents to create persistent RPC stubs for a gadget's `[restore]()` method without directly invoking the gadget's code.**

In Cloudflare OS, gadgets expose long-lived capabilities through a `[restore]()` method that reconstructs stateful RPC stubs. The overseer cannot call this method directly because it resides inside the gadget's isolated worker context. The restore forger bridges this gap by acting as a minimal, delegating worker that forwards the restoration request on behalf of the overseer.

## How the Restore Forger Works

The restore forger pattern consists of four distinct phases implemented in [`packages/workshop-backend/src/overseer.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts): loading the transient worker, forging the persistent stub, cleaning up temporary state, and scoping the resulting capability.

### Loading the Forger via ctx.restore()

When an agent needs to create a persistent stub, the overseer first loads a one-off forger worker. This worker is stored temporarily in the worker table under a `codeId` that points to a minimal script.

```typescript
forger = await this.ctx.restore({type: "gadget", gadgetId, codeId});

```

The `ctx.restore()` call targets the forger's code rather than the gadget's `[restore]()` method directly. This indirection is intentional: it allows the overseer to delegate capability creation while maintaining security boundaries between agents and gadgets.

Source: [`ctx.restore({type: "gadget", gadgetId, codeId})`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts#L9622)

### Forging the Persistent Stub

Once loaded, the forger receives a `forge()` call containing the parameters that the target gadget's `[restore]()` implementation expects.

```typescript
let stub = await forger.forge(params);

```

The forger then invokes `ctx.restore()` internally, targeting the actual gadget. This creates the persistent RPC stub that can be stored and reused across agent execution turns.

Source: [`let stub = await forger.forge(params);`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts#L9627)

### Cleaning Up Temporary State

After the forger completes its delegation, the overseer removes the temporary `codeId` entry from the worker table. This prevents the transient forger code from persisting or being reused:

> "...clear the ID from the table. When the forger then calls ctx.restore(P) on our behalf, the resulting..."

Source: [Cleanup logic](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts#L9682)

### Preserving Capability Security

The forger's transient nature is architecturally significant. According to the source comments:

> "The forger is a transient stub argument, so the capability to forge persistent..."

By loading the forger through `ctx.restore()` rather than embedding its logic in the overseer, Cloudflare OS ensures that the restored capability is correctly scoped to the gadget's namespace. The forger carries no bindings of its own—it exists solely to redirect the restoration request to the appropriate gadget.

Source: [Transient stub argument](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts#L8640)

## Why Cloudflare OS Uses a Restore Forger Pattern

The restore forger solves three specific problems in the Cloudflare OS agent execution model:

- **Isolation boundaries** — Agents cannot directly invoke gadget `[restore]()` methods; the forger provides a controlled delegation path
- **Capability scoping** — The restored stub is created within the gadget's security context, not the overseer's
- **Temporary code execution** — The forger's code lives only for the duration of the restoration, minimizing attack surface

This design aligns with the Cap'n Web RPC model throughout Cloudflare OS, where capabilities are tightly scoped and persistent references are explicitly constructed rather than implicitly inherited.

## Practical Example: Creating a Persistent Stub

```typescript
// Overseer logic to restore a gadget capability
async function forgeRestoreStubForBinding(
  ctx: WorkerContext,
  gadgetId: string,
  codeId: string,
  params: unknown
) {
  // Phase 1: Load the transient forger worker
  const forger = await ctx.restore({
    type: "gadget",
    gadgetId,  // Target gadget that owns the [restore]() method
    codeId,    // Temporary entry pointing to forger code
  });

  // Phase 2: Delegate to forger, which calls gadget's [restore]()
  const persistentStub = await forger.forge(params);

  // Phase 3: Cleanup - remove temporary codeId from table
  await ctx.clearCodeEntry(codeId);

  return persistentStub;
}

```

The `params` object typically includes type discriminators and initialization data that the gadget's `[restore]()` implementation uses to reconstruct its stateful behavior.

## Summary

- The **restore forger** is a minimal, transient worker that delegates `ctx.restore()` calls on behalf of the overseer
- It enables creation of **persistent RPC stubs** for gadget `[restore]()` methods while maintaining security isolation
- The pattern involves **four phases**: loading via `ctx.restore()`, forging through `forger.forge()`, cleanup of temporary state, and proper capability scoping
- Source implementation resides in [`packages/workshop-backend/src/overseer.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts) with key logic at lines 8640, 9613-9619, 9622, 9627, and 9681-9683

## Frequently Asked Questions

### What makes the restore forger "transient"?

The forger is transient because its code entry is **removed from the worker table immediately after use**. It exists only for the single restoration operation and carries no persistent state or bindings. As noted in [`overseer.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/overseer.ts) line 8640, it is explicitly a "transient stub argument" designed for one-time delegation.

### Why doesn't the overseer call ctx.restore() on the gadget directly?

Direct invocation would violate **capability scoping rules**. The overseer runs in a different security context than the gadget. By loading a forger that then calls `ctx.restore()`, the system ensures the resulting stub is created within the gadget's namespace and inherits the correct permission boundaries.

### How does the forger know which gadget to target?

The overseer passes both `gadgetId` and `codeId` to `ctx.restore()`. The `codeId` identifies the temporary forger script, while `gadgetId` specifies the ultimate target. The forger's internal logic uses this `gadgetId` when it performs its own `ctx.restore()` call to reach the actual gadget.

### Where is the forger's code stored before execution?

The forger's code is stored in the **worker table under a temporary `codeId`**. This table entry is created by the overseer, used once for the restoration, then explicitly cleared. Lines 9681-9683 in [`overseer.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/overseer.ts) describe this "put the tiny 'forger' worker's code into the table under `codeId`" pattern.