Workspace
Workspace creation, execution binding, copy/direct modes, access, write-back results and limitations.
A workspace is the file tree used by a run. It has no agent conversation and no
exec method. Attach it to a session to run agent turns
or shell commands. Import Workspace and WorkspaceError from @laufwerk/sdk.
Workspace.open(options)
| Property | Type | Required | Default / behavior |
|---|---|---|---|
source | string | Yes | Directory to work on; relative paths resolve from the consumer project root |
execution | ExecutionTarget | No | Omission selects legacy Microsandbox; pass a local/Docker execution object explicitly |
mode | "copy" | "direct" | No | "copy"; "direct" requires local execution |
Returns an Effect of WorkspaceReference, failing with WorkspaceError:
| Property | Type | Meaning |
|---|---|---|
id | string | Runtime-generated workspace identity; treat as opaque |
path | string | Working path inside the selected execution environment |
For Docker/Microsandbox, path is /workspace. For local execution it is the
actual host working path. Do not construct a reference by hand or reuse another
run's reference: the runtime checks the stored run/workspace binding.
The current implementation has one workspace per run. Opening again is the same durable operation; it is not a way to allocate another workspace or change its source. Use separate runs for independent workspace copies.
Copy mode
The runtime copies the source into managed storage and records a baseline
fingerprint. Changes remain there until write-back. Local and Docker copying skip
node_modules directories; install needed dependencies in the execution
environment. These modes reject sources whose .git is a file, such as an
existing Git worktree. Use a standalone checkout or local direct mode.
Source must be nonempty and resolve to a directory inside the consumer project, including after resolving symlinks; absolute paths inside that root are accepted. Managed copy storage cannot sit inside the copied source. If the source changes while it is copied, creation fails rather than silently accepting an inconsistent baseline.
Direct mode
The workspace points at the source itself. Changes happen immediately, and
Workspace.writeBack is unavailable. Separate runs pointing at the same direct
source still share physical files; their distinct workspace IDs do not provide
cross-run filesystem isolation or a common lock.
Workspace.writeBack({ workspace })
| Property | Type | Required | Meaning |
|---|---|---|---|
workspace | WorkspaceReference | Yes | This run's ready, copied workspace |
Returns an Effect of WorkspaceWriteBackResult, failing with WorkspaceError.
| Result property | Type | Meaning |
|---|---|---|
source | string | Managed workspace tree being copied back |
destination | string | Original source directory |
changedEntries | number | Number of changed filesystem entries applied |
execution | ExecutionTarget, optional in declared type | Currently not populated by the runtime result |
mode | "copy" | "direct", optional in declared type | Currently not populated by the runtime result |
The last two properties exist in the published TypeScript interface but are not returned by the current runtime. Do not use them to determine how a workspace ran.
Write-back compares the current destination with the original baseline and
refuses conflicts. It is not a Git merge, commit, push, or atomic filesystem
transaction. It is one named durable operation per run, not a repeated sync API.
The root .git directory is excluded from write-back: commits made inside the
working copy do not become commits in the original repository. Local/Docker
write-back also excludes node_modules, just as their initial copy does.
Close writing sessions first. An interrupted write-back can need inspection and
recovery before the run continues.
Access belongs to the session
WorkspaceAccess = "read-only" | "read-write" is supplied to Session.open/run,
not Workspace.open. Several sessions can therefore access the same workspace
with different permissions. Readers may overlap; a writer's turn or command
excludes all other managed operations until that operation releases its lease.
Local execution rejects read-only access because it cannot enforce it.
Example: copy, edit, approve, write back
import { Effect } from "effect";
import { Human, Session, Workspace } from "@laufwerk/sdk";
import { createLocalExecution } from "@laufwerk/execution";
import { createCodex } from "@laufwerk/sdk/harness/codex";
const execution = createLocalExecution({ credentials: "codex-subscription" });
const agent = execution.agent({ harness: createCodex() });
export const updateDocs = () => Effect.gen(function* () {
const workspace = yield* Workspace.open({ source: ".", execution, mode: "copy" });
yield* Session.run({
key: "edit-docs", agent, workspace, access: "read-write",
prompt: "Correct spelling mistakes in README.md and describe each change.",
});
const approved = yield* Human.confirm({
key: "write-back", title: "Apply the reviewed documentation changes?",
description: "Inspect the workspace changes before approving.",
});
if (!approved) return { applied: false as const };
const receipt = yield* Workspace.writeBack({ workspace });
return { applied: true as const, receipt };
});The human decision is a workflow choice in this example, not an implicit requirement
of writeBack. Add deterministic verification appropriate to the edited project.