# Workspace Resolution and Isolated Execution Environment in Paperclip AI: A Technical Deep Dive

> Explore Paperclip AI's workspace resolution and isolated execution environment. Discover how monorepo discovery, type-safe contracts, and Git worktrees ensure safe, independent agent runs.

- Repository: [Paperclip/paperclip](https://github.com/paperclipai/paperclip)
- Tags: deep-dive
- Published: 2026-08-12

---

**Paperclip AI isolates every agent run inside a dedicated workspace that combines monorepo root discovery, type-safe workspace contracts, and Git worktree-based process isolation to prevent cross-contamination between executions.**

The Paperclip AI platform orchestrates AI agents within complex monorepo structures, requiring robust **workspace resolution and isolated execution environment** capabilities to ensure deterministic, secure runs. According to the `paperclipai/paperclip` source code, the system implements a three-layer architecture—discovery, definition, and isolation—that materializes ephemeral execution contexts and tears them down cleanly after each run.

## How Paperclip AI Discovers and Validates Workspace Roots

Every request begins with repository root resolution to ensure the server sees the exact source tree the UI and CLI are using. In [`server/src/services/workspace-runtime.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/workspace-runtime.ts), the `findWorkspaceRoot()` function walks upward from the current working directory until it locates [`pnpm-workspace.yaml`](https://github.com/paperclipai/paperclip/blob/main/pnpm-workspace.yaml), establishing the monorepo boundary.

Once the root is identified, `ensureServerWorkspaceLinksCurrent()` (lines 29-45) performs critical validation:

1. Verifies the server package is a linked Git worktree via `isLinkedGitWorktreeCheckout`
2. Scans all workspace packages using `discoverWorkspacePackagePaths`
3. Validates that each `workspace:` dependency in [`server/package.json`](https://github.com/paperclipai/paperclip/blob/main/server/package.json) resolves to the correct on-disk location
4. Recreates stale symlinks atomically using `fs.symlink` if any path is outdated

This prevents "missing-module" runtime crashes that occur when developers swap branches and `node_modules` links become stale.

```typescript
// Resolve the repository root from the current working directory
const repoRoot = findWorkspaceRoot(process.cwd());

// Verify that the server's workspace symlinks are up-to-date
await ensureServerWorkspaceLinksCurrent(process.cwd(), {
  onLog: async (stream, chunk) => {
    await logActivity(db, {
      companyId,
      actorType: "system",
      actorId: "workspace_runtime",
      action: "workspace.link.repair",
      details: { stream, message: chunk },
    });
  },
});

```

## Defining Execution Workspaces with Type-Safe Contracts

After discovery, the runtime transforms high-level requests into concrete workspace configurations using the type definitions in [`packages/shared/src/types/workspace-runtime.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/shared/src/types/workspace-runtime.ts). The system distinguishes between **input strategies** and **realized workspaces**:

- **`ExecutionWorkspaceInput`**: The initial request specifying desired strategy and mode
- **`RealizedExecutionWorkspace`**: The concrete configuration containing absolute `cwd`, resolved `branchName`, worktree path, and validation warnings (lines 9-19)

Key enumerations define the isolation semantics:

- **`ExecutionWorkspaceStrategyType`**: `project_primary`, `git_worktree`, `adapter_managed`, or `cloud_sandbox`
- **`ExecutionWorkspaceMode`**: `shared_workspace`, `isolated_workspace`, `operator_branch`, `reuse_existing`, or `agent_default`
- **`WorkspaceRuntimeDesiredState`**: `running`, `stopped`, or `manual`

Each workspace configuration includes lifecycle hooks defined in `ExecutionWorkspaceConfig`: `provisionCommand`, `runtimeProvisionCommand`, `teardownCommand`, and `cleanupCommand`.

```typescript
import { ExecutionWorkspaceInput, ExecutionWorkspaceStrategy } from "@paperclipai/shared";

async function realiseWorkspace(
  input: ExecutionWorkspaceInput,
  strategy: ExecutionWorkspaceStrategy,
) {
  const cwd = resolveConfiguredPath(input.baseCwd, "/tmp/paperclip/workspaces");
  const branch = sanitizeBranchName(input.repoRef ?? "main");

  const realised: RealizedExecutionWorkspace = {
    ...input,
    strategy: "git_worktree",
    cwd,
    branchName: branch,
    worktreePath: `${cwd}/.git-worktree`,
    warnings: [],
    created: true,
  };

  if (strategy.provisionCommand) {
    await executeProcess({
      command: strategy.provisionCommand,
      args: [],
      cwd,
      maxStdoutBytes: 1024 * 1024,
    });
  }

  return realised;
}

```

## Enforcing Process Isolation in Runtime Services

Once materialized, the workspace enforces isolation through the **Workspace Runtime** subsystem. When `ExecutionWorkspaceMode` is set to `isolated_workspace`, the runtime creates a fresh Git worktree using `git worktree add` under `.paperclip/workspaces`, ensuring each run receives a clean filesystem that no other process can observe.

The `executeProcess()` function (lines 31-44 in [`workspace-runtime.ts`](https://github.com/paperclipai/paperclip/blob/main/workspace-runtime.ts)) spawns services with strict resource limits:

```typescript
const { stdout, stderr, code } = await executeProcess({
  command: "node",
  args: ["my-agent.js"],
  cwd: realisedWorkspace.cwd,
  env: sanitizeRuntimeServiceBaseEnv(process.env),
  maxStdoutBytes: 256 * 1024, // DEFAULT_EXECUTE_PROCESS_OUTPUT_BYTES limit
});

if (code !== 0) {
  throw new Error(`Agent exited with ${code}\n${stderr}`);
}

```

**Environment sanitization** occurs via `sanitizeRuntimeServiceBaseEnv()` (lines 52-62), which strips all `PAPERCLIP_*` variables and secrets before spawning child processes, preventing credential leakage to agent code.

Service lifecycle is tracked in in-memory maps (`runtimeServicesById` and `runtimeServicesByReuseKey`) and persisted to the database (`workspaceRuntimeServices`). The [`local-service-supervisor.ts`](https://github.com/paperclipai/paperclip/blob/main/local-service-supervisor.ts) module handles process termination and port management, while idle timers (`clearIdleTimer`) enforce cleanup policies for unused workspaces.

## Validation and Safety Mechanisms

Before handing a workspace to an agent, the runtime executes validation chains to detect unsafe states. The `inspectGitWorktreeBranchIncoherence()` function (referenced around lines 511-531) detects:

- Mismatched branches between expected and actual state
- In-progress Git operations or detached HEAD scenarios
- Dirty working trees that could contaminate results

If a dirty state is detected on a clean worktree where the branch is an ancestor, the system automatically quarantines the dirty state by creating a rescue branch via `buildDirtyQuarantineRescueBranch`. This allows the agent to run against a clean checkout while preserving uncommitted changes safely.

Validation failures throw `WorkspaceRuntimeValidationFailure` with a JSON payload (`resultJson`) that surfaces user-friendly warnings in the UI.

## Lifecycle Hooks and Cleanup Policies

The runtime manages workspace birth and death through configurable commands:

- **Provision**: `provisionCommand` runs once when `created === true`, setting up language runtimes or Docker images
- **Runtime provisioning**: `runtimeProvisionCommand` executes after the workspace is ready but before agent code runs, typically for dependency installation
- **Teardown**: `terminationLocalService` stops stray processes and executes `teardownCommand` when runs complete
- **Cleanup**: For isolated workspaces, the entire worktree directory is deleted after `cleanupCommand` finishes

These hooks ensure that even if an agent crashes, the system returns to a clean state without orphaned processes or disk pollution.

## Summary

- **Three-layer architecture**: Workspace resolution and isolated execution environment in Paperclip AI operate through discovery (monorepo root finding), definition (type-safe contract realization), and isolation (Git worktree-based execution).
- **Git worktree isolation**: Each isolated workspace receives a unique worktree path under `.paperclip/workspaces`, guaranteeing filesystem separation between concurrent runs.
- **Automatic link repair**: `ensureServerWorkspaceLinksCurrent()` validates `workspace:` symlinks on every request, eliminating module resolution errors during branch switches.
- **Environment sanitization**: `sanitizeRuntimeServiceBaseEnv()` removes internal `PAPERCLIP_*` variables and secrets before spawning agent processes.
- **Dirty state quarantine**: The runtime detects incoherent Git states and can automatically create rescue branches to isolate uncommitted changes without blocking execution.

## Frequently Asked Questions

### How does Paperclip AI isolate agent executions from each other?

According to the source code in [`server/src/services/workspace-runtime.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/workspace-runtime.ts), Paperclip AI achieves isolation through Git worktrees and process-level separation. When using `isolated_workspace` mode, each run invokes `git worktree add` to create a distinct working directory under `.paperclip/workspaces`. The runtime spawns processes via `executeProcess()` with sanitized environments and tracks them in `runtimeServicesById`, ensuring no shared state exists between concurrent agent runs.

### What happens when a Git worktree is in a dirty state?

The runtime calls `inspectGitWorktreeBranchIncoherence()` to detect uncommitted changes or branch mismatches. If the worktree is dirty but the branch is an ancestor of the expected state, the system automatically quarantines the dirty state by creating a rescue branch using `buildDirtyQuarantineRescueBranch`. This preserves the developer's uncommitted work while allowing the agent to execute against a clean checkout. If the state cannot be safely repaired, a `WorkspaceRuntimeValidationFailure` is thrown.

### How does the workspace runtime prevent module resolution errors in the monorepo?

The `ensureServerWorkspaceLinksCurrent()` function validates that all `workspace:` dependencies in [`server/package.json`](https://github.com/paperclipai/paperclip/blob/main/server/package.json) point to the correct on-disk locations within the monorepo. It detects stale symlinks by comparing the current Git worktree state against the resolved package paths, and atomically recreates any broken links using `fs.symlink`. This ensures the Node.js module resolver always finds the correct source packages regardless of branch changes.

### What limits apply to process output in isolated execution environments?

The `executeProcess()` function enforces a default byte limit of `DEFAULT_EXECUTE_PROCESS_OUTPUT_BYTES` (256KB in standard configurations) on stdout and stderr streams. This prevents runaway agents from consuming excessive memory or disk space when capturing output. The limit is configurable per execution via the `maxStdoutBytes` parameter in the process options.