How to Integrate Cloudflare Artifacts with the Computer Workspace Filesystem

Integrate Cloudflare Artifacts with the Computer workspace filesystem by wrapping your Worker entry-point with withWorkspace, registering the artifacts command via defineArtifactsCommand, and exposing an Artifacts binding in wrangler.toml.

The Computer project (cloudflare/computer) provides a Worker-Shell sandbox with a virtual workspace filesystem backed by Durable Objects and SQLite. This architecture lets you push and pull files to Cloudflare Artifacts without granting the sandbox direct network access—all I/O happens through a host-side bridge.

How the Artifacts Integration Works

The integration relies on three cooperating layers: a virtual filesystem for storage, a host-side client for network operations, and a command bridge that connects them over RPC.

The Workspace Filesystem Layer

The workspace is a Cap'n Proto-driven virtual filesystem mounted inside the worker-shell. It stores file hierarchies in SQLite via @cloudflare/dofs.

  • Source: packages/computer/src/workspace.ts
  • Key insight: The filesystem persists state across Worker invocations through Durable Objects, making it ideal for CI/CD artifacts that must survive between steps.

The withWorkspace Helper

withWorkspace transforms a standard Cloudflare Workers script into a workspace-enabled environment. It:

  1. Creates the Durable Object client for state persistence
  2. Boots the virtual FUSE driver
  3. Injects the git and artifacts commands into the shell
// packages/computer/src/with-workspace.ts usage pattern
export default withWorkspace({
  customCommands: [defineArtifactsCommand(host)],
});

Without this wrapper, the sandbox lacks both the filesystem mount and the custom command registration.

The Host-Side Artifacts Bridge

Network access violates the sandbox's "no-network" guarantee. The defineArtifactsCommand function solves this by forwarding artifacts calls from the sandbox to a host-side implementation that performs actual HTTP requests.

Core file: packages/computer/src/backends/worker-shell/artifacts-command.ts

This bridge handles:

Aspect Implementation
Command forwarding Receives argv, env, cwd from sandbox
Result marshalling Returns structured ArtifactsCLIResult (stdout, stderr, exitCode)
Error translation RPC failures become shell-visible non-zero exit codes
Git remote injection remoteAdd callback connects Artifacts create flow to workspace remotes

The remoteAdd shim is critical: when you run artifacts create, the CLI needs a Git remote to push a bundle. The bridge creates a temporary remote pointing at the workspace's sync driver, which then applies the bundle to the virtual filesystem.

Configuration Steps

Step 1: Add the Artifacts Binding

Declare the Artifacts client in your Worker's type definitions:

// worker-configuration.d.ts
export interface Bindings {
  /** Cloudflare Artifacts client injected by Wrangler */
  ARTIFACTS: Fetcher;
}

Then reference it in your wrangler.toml:

[[artifacts]]
binding = "ARTIFACTS"

Step 2: Implement the Host Interface

Create a host object satisfying the interface expected by defineArtifactsCommand:

// src/index.ts
import { withWorkspace } from "@cloudflare/computer";
import { defineArtifactsCommand } from "@cloudflare/computer/backends/worker-shell/artifacts-command";

interface Host {
  git: { cli(input: GitCLIInput): Promise<GitCLIResult> };
  artifacts: { cli(input: ArtifactsCLIInput): Promise<ArtifactsCLIResult> };
}

const host: Host = {
  git: {
    cli: async (input) => {
      // Your Git implementation (also host-side)
      return { stdout: "", stderr: "", exitCode: 0 };
    },
  },
  artifacts: {
    cli: async (input) => {
      // Forward to the bound Artifacts client
      const { ARTIFACTS } = env;
      return ARTIFACTS.cli(input);
    },
  },
};

export default withWorkspace({
  customCommands: [defineArtifactsCommand(host)],
});

The env object contains your Workers bindings. The Artifacts client runs outside the sandbox, preserving the security boundary.

Step 3: Use Artifacts Commands in Shell Scripts

Inside the worker-shell, the artifacts command behaves like a standard CLI:


# Push current workspace to a bucket

artifacts push my-bucket .

# Retrieve artifacts into the workspace

artifacts pull my-bucket .

# Inspect bucket contents

artifacts list my-bucket

The shell automatically captures working directory and environment state. For programmatic use:

import { exec } from "just-bash";

// Create a new artifact version with automatic Git bundling
await exec(
  ["artifacts", "create", "--name", "release-v1.2.3", "--bucket", "my-bucket"],
  { env: new Map([["CI", "true"]]), cwd: "/build/output" }
);

// Push workspace contents
await exec(["artifacts", "push", "my-bucket", "."], { env: new Map(), cwd: "/" });

// Verify
const { stdout } = await exec(["artifacts", "list", "my-bucket"], { env: new Map(), cwd: "/" });

The artifacts create Flow Deep-Dive

The create sub-command requires special handling because Artifacts expects to push a Git bundle. The bridge implements this through the remoteAdd callback injected into the CLI environment:

  1. Sandbox invokes artifacts create --name X --bucket Y
  2. Bridge forwards to host-side Artifacts client
  3. Client calls remoteAdd(url) to register a temporary Git remote
  4. Remote URL points to the workspace's sync driver (loopback RPC)
  5. Artifacts CLI pushes Git bundle to this remote
  6. Sync driver applies bundle to the virtual filesystem
  7. Operation completes; temporary remote is cleaned up

This design lets the Artifacts CLI use standard Git operations while keeping all network I/O on the host side.

RPC Contract Reference

Communication between sandbox and host uses the loopback channel defined in docs/08_capnweb_interface.md. The sandbox only needs these type shapes:

// Input from sandbox to host
interface ArtifactsCLIInput {
  argv: string[];
  env: Map<string, string>;
  cwd: string;
}

// Result returned to sandbox
interface ArtifactsCLIResult {
  stdout: string;
  stderr: string;
  exitCode: number;
}

The remoteAdd callback signature:

type RemoteAddCallback = (url: string) => Promise<void>;

All actual HTTP requests to the Artifacts service occur in the host implementation, never in the sandbox.

Key Source Files

Path Purpose
packages/computer/src/backends/worker-shell/artifacts-command.ts Command bridge implementation
packages/computer/src/backends/worker-shell/artifacts-command.test.ts Unit tests for error handling and edge cases
packages/computer/src/workspace.ts Virtual filesystem backed by Durable Objects
packages/computer/src/with-workspace.ts Entry-point wrapper enabling workspace + commands
examples/artifacts/src/index.ts Minimal working integration example

Summary

  • Cloudflare Artifacts integration requires three components: a workspace filesystem, a host-side Artifacts client, and the defineArtifactsCommand bridge
  • withWorkspace wraps your Worker to enable the virtual filesystem and register custom commands
  • The host object performs all network I/O; the sandbox sees only structured CLI results
  • remoteAdd enables Git-based artifact creation without violating sandbox constraints
  • RPC over loopback keeps security boundaries intact while providing full Artifacts functionality

Frequently Asked Questions

What prevents the sandbox from making direct network calls to Artifacts?

The worker-shell sandbox has no native fetch capability. The artifacts command is a synthetic shell built-in that forwards arguments over an RPC channel to the host. The host, running outside the sandbox, possesses the actual ARTIFACTS binding and performs HTTP requests. This architecture is enforced by the Cap'n Proto capability system described in docs/08_capnweb_interface.md.

Why does artifacts create need a Git remote?

Artifacts stores versions as Git bundles for deduplication and efficient delta transfers. The create sub-command builds a bundle from the current workspace state and pushes it to the service. The remoteAdd shim creates a temporary remote pointing at the workspace's sync driver, allowing the standard Git push protocol to apply the bundle locally before the host uploads it.

Can I use Artifacts commands without the workspace filesystem?

No. The defineArtifactsCommand function expects a remoteAdd callback that connects to the workspace's Git sync driver. Without withWorkspace, this callback is unavailable, and artifacts create fails. For simple object storage without Git semantics, use the raw ARTIFACTS binding directly in your Worker handler instead of routing through the Computer shell.

How do I debug failed artifacts commands?

Check three locations: (1) the exitCode and stderr in ArtifactsCLIResult returned to the shell, (2) the host-side Artifacts client logs in your Worker tail, and (3) the workspace sync driver state in packages/computer/src/workspace.ts. The bridge converts all RPC errors to non-zero exit codes, so standard shell error handling applies.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →